Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(234)

Side by Side Diff: third_party/harfbuzz-ng/src/hb-coretext.cc

Issue 475363002: Roll HarfBuzz to 0.9.35 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Windows build fix attempt Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/harfbuzz-ng/src/hb-common.cc ('k') | third_party/harfbuzz-ng/src/hb-face.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
11 * all copies of this software. 11 * all copies of this software.
12 * 12 *
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17 * DAMAGE. 17 * DAMAGE.
18 * 18 *
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 * 24 *
25 * Mozilla Author(s): Jonathan Kew 25 * Mozilla Author(s): Jonathan Kew
26 * Google Author(s): Behdad Esfahbod 26 * Google Author(s): Behdad Esfahbod
27 */ 27 */
28 28
29 #define HB_SHAPER coretext 29 #define HB_SHAPER coretext
30 #define hb_coretext_shaper_face_data_t CGFont
30 #include "hb-shaper-impl-private.hh" 31 #include "hb-shaper-impl-private.hh"
31 32
32 #include "hb-coretext.h" 33 #include "hb-coretext.h"
33 34
34 35
35 #ifndef HB_DEBUG_CORETEXT 36 #ifndef HB_DEBUG_CORETEXT
36 #define HB_DEBUG_CORETEXT (HB_DEBUG+0) 37 #define HB_DEBUG_CORETEXT (HB_DEBUG+0)
37 #endif 38 #endif
38 39
39 40
(...skipping 30 matching lines...) Expand all
70 71
71 72
72 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face) 73 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face)
73 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font) 74 HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font)
74 75
75 76
76 /* 77 /*
77 * shaper face data 78 * shaper face data
78 */ 79 */
79 80
80 struct hb_coretext_shaper_face_data_t {
81 CGFontRef cg_font;
82 };
83
84 static void 81 static void
85 release_data (void *info, const void *data, size_t size) 82 release_data (void *info, const void *data, size_t size)
86 { 83 {
87 assert (hb_blob_get_length ((hb_blob_t *) info) == size && 84 assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
88 hb_blob_get_data ((hb_blob_t *) info, NULL) == data); 85 hb_blob_get_data ((hb_blob_t *) info, NULL) == data);
89 86
90 hb_blob_destroy ((hb_blob_t *) info); 87 hb_blob_destroy ((hb_blob_t *) info);
91 } 88 }
92 89
93 hb_coretext_shaper_face_data_t * 90 hb_coretext_shaper_face_data_t *
94 _hb_coretext_shaper_face_data_create (hb_face_t *face) 91 _hb_coretext_shaper_face_data_create (hb_face_t *face)
95 { 92 {
96 hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) call oc (1, sizeof (hb_coretext_shaper_face_data_t)); 93 hb_coretext_shaper_face_data_t *data = NULL;
97 if (unlikely (!data))
98 return NULL;
99 94
100 if (face->destroy == (hb_destroy_func_t) CGFontRelease) 95 if (face->destroy == (hb_destroy_func_t) CGFontRelease)
101 { 96 {
102 data->cg_font = CGFontRetain ((CGFontRef) face->user_data); 97 data = CGFontRetain ((CGFontRef) face->user_data);
103 } 98 }
104 else 99 else
105 { 100 {
106 hb_blob_t *blob = hb_face_reference_blob (face); 101 hb_blob_t *blob = hb_face_reference_blob (face);
107 unsigned int blob_length; 102 unsigned int blob_length;
108 const char *blob_data = hb_blob_get_data (blob, &blob_length); 103 const char *blob_data = hb_blob_get_data (blob, &blob_length);
109 if (unlikely (!blob_length)) 104 if (unlikely (!blob_length))
110 DEBUG_MSG (CORETEXT, face, "Face has empty blob"); 105 DEBUG_MSG (CORETEXT, face, "Face has empty blob");
111 106
112 CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data); 107 CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
113 data->cg_font = CGFontCreateWithDataProvider (provider); 108 if (likely (provider))
114 CGDataProviderRelease (provider); 109 {
110 data = CGFontCreateWithDataProvider (provider);
111 CGDataProviderRelease (provider);
112 }
115 } 113 }
116 114
117 if (unlikely (!data->cg_font)) { 115 if (unlikely (!data)) {
118 DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed"); 116 DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
119 free (data);
120 return NULL;
121 } 117 }
122 118
123 return data; 119 return data;
124 } 120 }
125 121
126 void 122 void
127 _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data) 123 _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
128 { 124 {
129 CFRelease (data->cg_font); 125 CFRelease (data);
130 free (data);
131 } 126 }
132 127
133 CGFontRef 128 CGFontRef
134 hb_coretext_face_get_cg_font (hb_face_t *face) 129 hb_coretext_face_get_cg_font (hb_face_t *face)
135 { 130 {
136 if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL; 131 if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
137 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 132 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
138 return face_data->cg_font; 133 return face_data;
139 } 134 }
140 135
141 136
142 /* 137 /*
143 * shaper font data 138 * shaper font data
144 */ 139 */
145 140
146 struct hb_coretext_shaper_font_data_t { 141 struct hb_coretext_shaper_font_data_t {
147 CTFontRef ct_font; 142 CTFontRef ct_font;
148 }; 143 };
149 144
150 hb_coretext_shaper_font_data_t * 145 hb_coretext_shaper_font_data_t *
151 _hb_coretext_shaper_font_data_create (hb_font_t *font) 146 _hb_coretext_shaper_font_data_create (hb_font_t *font)
152 { 147 {
153 if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL; 148 if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL;
154 149
155 hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) call oc (1, sizeof (hb_coretext_shaper_font_data_t)); 150 hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) call oc (1, sizeof (hb_coretext_shaper_font_data_t));
156 if (unlikely (!data)) 151 if (unlikely (!data))
157 return NULL; 152 return NULL;
158 153
159 hb_face_t *face = font->face; 154 hb_face_t *face = font->face;
160 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 155 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
161 156
162 data->ct_font = CTFontCreateWithGraphicsFont (face_data->cg_font, font->y_scal e, NULL, NULL); 157 data->ct_font = CTFontCreateWithGraphicsFont (face_data, font->y_scale, NULL, NULL);
163 if (unlikely (!data->ct_font)) { 158 if (unlikely (!data->ct_font)) {
164 DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed"); 159 DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
165 free (data); 160 free (data);
166 return NULL; 161 return NULL;
167 } 162 }
168 163
169 return data; 164 return data;
170 } 165 }
171 166
172 void 167 void
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
429 _hb_coretext_shape (hb_shape_plan_t *shape_plan, 424 _hb_coretext_shape (hb_shape_plan_t *shape_plan,
430 hb_font_t *font, 425 hb_font_t *font,
431 hb_buffer_t *buffer, 426 hb_buffer_t *buffer,
432 const hb_feature_t *features, 427 const hb_feature_t *features,
433 unsigned int num_features) 428 unsigned int num_features)
434 { 429 {
435 hb_face_t *face = font->face; 430 hb_face_t *face = font->face;
436 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); 431 hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
437 hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); 432 hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
438 433
434 /* Attach marks to their bases, to match the 'ot' shaper.
435 * Adapted from hb-ot-shape:hb_form_clusters().
436 * Note that this only makes us be closer to the 'ot' shaper,
437 * but by no means the same. For example, if there's
438 * B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will
439 * continue pointing to B2 even though B2 was merged into B1's
440 * cluster... */
441 {
442 hb_unicode_funcs_t *unicode = buffer->unicode;
443 unsigned int count = buffer->len;
444 hb_glyph_info_t *info = buffer->info;
445 for (unsigned int i = 1; i < count; i++)
446 if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (unicode->general_category (info[i ].codepoint)))
447 buffer->merge_clusters (i - 1, i + 1);
448 }
449
450 hb_auto_array_t<feature_record_t> feature_records;
451 hb_auto_array_t<range_record_t> range_records;
452
439 /* 453 /*
440 * Set up features. 454 * Set up features.
441 * (copied + modified from code from hb-uniscribe.cc) 455 * (copied + modified from code from hb-uniscribe.cc)
442 */ 456 */
443 hb_auto_array_t<feature_record_t> feature_records;
444 hb_auto_array_t<range_record_t> range_records;
445 if (num_features) 457 if (num_features)
446 { 458 {
447 /* Sort features by start/end events. */ 459 /* Sort features by start/end events. */
448 hb_auto_array_t<feature_event_t> feature_events; 460 hb_auto_array_t<feature_event_t> feature_events;
449 for (unsigned int i = 0; i < num_features; i++) 461 for (unsigned int i = 0; i < num_features; i++)
450 { 462 {
451 const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (& features[i].tag, 463 const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (& features[i].tag,
452 f eature_mappings, 464 f eature_mappings,
453 A RRAY_LENGTH (feature_mappings), 465 A RRAY_LENGTH (feature_mappings),
454 s izeof (feature_mappings[0]), 466 s izeof (feature_mappings[0]),
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
542 (const void **) &feat ures_array, 554 (const void **) &feat ures_array,
543 1, 555 1,
544 &kCFTypeDictionaryKey CallBacks, 556 &kCFTypeDictionaryKey CallBacks,
545 &kCFTypeDictionaryVal ueCallBacks); 557 &kCFTypeDictionaryVal ueCallBacks);
546 CFRelease (features_array); 558 CFRelease (features_array);
547 559
548 CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes ( attributes); 560 CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes ( attributes);
549 CFRelease (attributes); 561 CFRelease (attributes);
550 562
551 range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc); 563 range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc);
552
553 CFRelease (font_desc); 564 CFRelease (font_desc);
554 } 565 }
555 else 566 else
556 { 567 {
557 range->font = NULL; 568 range->font = NULL;
558 } 569 }
559 570
560 range->index_first = last_index; 571 range->index_first = last_index;
561 range->index_last = event->index - 1; 572 range->index_last = event->index - 1;
562 573
(...skipping 14 matching lines...) Expand all
577 588
578 if (!range_records.len) /* No active feature found. */ 589 if (!range_records.len) /* No active feature found. */
579 goto fail_features; 590 goto fail_features;
580 } 591 }
581 else 592 else
582 { 593 {
583 fail_features: 594 fail_features:
584 num_features = 0; 595 num_features = 0;
585 } 596 }
586 597
587 #define FAIL(...) \
588 HB_STMT_START { \
589 DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \
590 return false; \
591 } HB_STMT_END;
592
593 unsigned int scratch_size; 598 unsigned int scratch_size;
594 hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_ size); 599 hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_ size);
595 600
596 #define ALLOCATE_ARRAY(Type, name, len) \ 601 #define ALLOCATE_ARRAY(Type, name, len, on_no_room) \
597 Type *name = (Type *) scratch; \ 602 Type *name = (Type *) scratch; \
598 { \ 603 { \
599 unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)) ; \ 604 unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)) ; \
600 assert (_consumed <= scratch_size); \ 605 if (unlikely (_consumed > scratch_size)) \
606 { \
607 on_no_room; \
608 assert (0); \
609 } \
601 scratch += _consumed; \ 610 scratch += _consumed; \
602 scratch_size -= _consumed; \ 611 scratch_size -= _consumed; \
603 } 612 }
604 613
605 #define utf16_index() var1.u32 614 ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, /*nothing*/);
606
607 ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2);
608
609 unsigned int chars_len = 0; 615 unsigned int chars_len = 0;
610 for (unsigned int i = 0; i < buffer->len; i++) { 616 for (unsigned int i = 0; i < buffer->len; i++) {
611 hb_codepoint_t c = buffer->info[i].codepoint; 617 hb_codepoint_t c = buffer->info[i].codepoint;
612 buffer->info[i].utf16_index() = chars_len;
613 if (likely (c <= 0xFFFFu)) 618 if (likely (c <= 0xFFFFu))
614 pchars[chars_len++] = c; 619 pchars[chars_len++] = c;
615 else if (unlikely (c > 0x10FFFFu)) 620 else if (unlikely (c > 0x10FFFFu))
616 pchars[chars_len++] = 0xFFFDu; 621 pchars[chars_len++] = 0xFFFDu;
617 else { 622 else {
618 pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10); 623 pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
619 pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1)); 624 pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
620 } 625 }
621 } 626 }
622 627
623 #undef utf16_index 628 ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len, /*nothing*/);
624 629 chars_len = 0;
625 CFStringRef string_ref = CFStringCreateWithCharactersNoCopy (NULL, 630 for (unsigned int i = 0; i < buffer->len; i++)
626 pchars, chars_len ,
627 kCFAllocatorNull) ;
628
629 CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (NU LL, chars_len);
630 CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref);
631 CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
632 » » » » kCTFontAttributeName, font_data->ct_font);
633
634 if (num_features)
635 { 631 {
636 ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len); 632 hb_codepoint_t c = buffer->info[i].codepoint;
637 633 unsigned int cluster = buffer->info[i].cluster;
638 /* Need log_clusters to assign features. */ 634 log_clusters[chars_len++] = cluster;
639 chars_len = 0; 635 if (hb_in_range (c, 0x10000u, 0x10FFFFu))
640 for (unsigned int i = 0; i < buffer->len; i++) 636 log_clusters[chars_len++] = cluster; /* Surrogates. */
637 }
638
639 #define FAIL(...) \
640 HB_STMT_START { \
641 DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \
642 ret = false; \
643 goto fail; \
644 } HB_STMT_END;
645
646 bool ret = true;
647 CFStringRef string_ref = NULL;
648 CTLineRef line = NULL;
649
650 if (0)
651 {
652 resize_and_retry:
653 DEBUG_MSG (CORETEXT, buffer, "Buffer resize");
654 /* string_ref uses the scratch-buffer for backing store, and line references
655 * string_ref (via attr_string). We must release those before resizing buff er. */
656 assert (string_ref);
657 assert (line);
658 CFRelease (string_ref);
659 CFRelease (line);
660 string_ref = NULL;
661 line = NULL;
662
663 /* Get previous start-of-scratch-area, that we use later for readjusting
664 * our existing scratch arrays. */
665 unsigned int old_scratch_used;
666 hb_buffer_t::scratch_buffer_t *old_scratch;
667 old_scratch = buffer->get_scratch_buffer (&old_scratch_used);
668 old_scratch_used = scratch - old_scratch;
669
670 if (unlikely (!buffer->ensure (buffer->allocated * 2)))
671 FAIL ("Buffer resize failed");
672
673 /* Adjust scratch, pchars, and log_cluster arrays. This is ugly, but really the
674 * cleanest way to do without completely restructuring the rest of this shap er. */
675 scratch = buffer->get_scratch_buffer (&scratch_size);
676 pchars = reinterpret_cast<UniChar *> (((char *) scratch + ((char *) pchars - (char *) old_scratch)));
677 log_clusters = reinterpret_cast<unsigned int *> (((char *) scratch + ((char *) log_clusters - (char *) old_scratch)));
678 scratch += old_scratch_used;
679 scratch_size -= old_scratch_used;
680 }
681 retry:
682 {
683 string_ref = CFStringCreateWithCharactersNoCopy (NULL,
684 » » » » » » pchars, chars_len,
685 » » » » » » kCFAllocatorNull);
686 if (unlikely (!string_ref))
687 FAIL ("CFStringCreateWithCharactersNoCopy failed");
688
689 /* Create an attributed string, populate it, and create a line from it, then release attributed string. */
641 { 690 {
642 hb_codepoint_t c = buffer->info[i].codepoint; 691 CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (kCFAllocatorDefault,
643 unsigned int cluster = buffer->info[i].cluster; 692 » » » » » » » » » » chars_len);
644 log_clusters[chars_len++] = cluster; 693 if (unlikely (!attr_string))
645 if (hb_in_range (c, 0x10000u, 0x10FFFFu)) 694 » FAIL ("CFAttributedStringCreateMutable failed");
646 » log_clusters[chars_len++] = cluster; /* Surrogates. */ 695 CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_r ef);
696 if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
697 {
698 » CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
699 » » » » » kCTVerticalFormsAttributeName, kCFBoolea nTrue);
700 }
701
702 if (buffer->props.language)
703 {
704 /* What's the iOS equivalent of this check?
705 * The symbols was introduced in iOS 7.0.
706 * At any rate, our fallback is safe and works fine. */
707 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
708 # define kCTLanguageAttributeName CFSTR ("NSLanguage")
709 #endif
710 CFStringRef lang = CFStringCreateWithCStringNoCopy (kCFAllocatorDefault,
711 » » » » » » » hb_language_to_strin g (buffer->props.language),
712 » » » » » » » kCFStringEncodingUTF 8,
713 » » » » » » » kCFAllocatorNull);
714 » if (unlikely (!lang))
715 » FAIL ("CFStringCreateWithCStringNoCopy failed");
716 » CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
717 » » » » » kCTLanguageAttributeName, lang);
718 » CFRelease (lang);
719 }
720 CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
721 » » » » kCTFontAttributeName, font_data->ct_font);
722
723 if (num_features)
724 {
725 » unsigned int start = 0;
726 » range_record_t *last_range = &range_records[0];
727 » for (unsigned int k = 0; k < chars_len; k++)
728 » {
729 » range_record_t *range = last_range;
730 » while (log_clusters[k] < range->index_first)
731 » range--;
732 » while (log_clusters[k] > range->index_last)
733 » range++;
734 » if (range != last_range)
735 » {
736 » if (last_range->font)
737 » CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, k - start),
738 » » » » » kCTFontAttributeName, last_range-> font);
739
740 » start = k;
741 » }
742
743 » last_range = range;
744 » }
745 » if (start != chars_len && last_range->font)
746 » CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars _len - start),
747 » » » » » kCTFontAttributeName, last_range->font );
748 }
749
750 int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
751 CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberI ntType, &level);
752 CFDictionaryRef options = CFDictionaryCreate (kCFAllocatorDefault,
753 » » » » » » (const void **) &kCTTypesett erOptionForcedEmbeddingLevel,
754 » » » » » » (const void **) &level_numbe r,
755 » » » » » » 1,
756 » » » » » » &kCFTypeDictionaryKeyCallBac ks,
757 » » » » » » &kCFTypeDictionaryValueCallB acks);
758 if (unlikely (!options))
759 FAIL ("CFDictionaryCreate failed");
760
761 CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedStringAndOpti ons (attr_string, options);
762 CFRelease (options);
763 CFRelease (attr_string);
764 if (unlikely (!typesetter))
765 » FAIL ("CTTypesetterCreateWithAttributedStringAndOptions failed");
766
767 line = CTTypesetterCreateLine (typesetter, CFRangeMake(0, 0));
768 CFRelease (typesetter);
769 if (unlikely (!line))
770 » FAIL ("CTTypesetterCreateLine failed");
647 } 771 }
648 772
649 unsigned int start = 0; 773 CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
650 range_record_t *last_range = &range_records[0]; 774 unsigned int num_runs = CFArrayGetCount (glyph_runs);
651 for (unsigned int k = 0; k < chars_len; k++) 775 DEBUG_MSG (CORETEXT, NULL, "Num runs: %d", num_runs);
776
777 buffer->len = 0;
778 uint32_t status_and = ~0, status_or = 0;
779
780 const CFRange range_all = CFRangeMake (0, 0);
781
782 for (unsigned int i = 0; i < num_runs; i++)
652 { 783 {
653 range_record_t *range = last_range; 784 CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex (glyph_runs, i ));
654 while (log_clusters[k] < range->index_first) 785 CTRunStatus run_status = CTRunGetStatus (run);
655 » range--; 786 status_or |= run_status;
656 while (log_clusters[k] > range->index_last) 787 status_and &= run_status;
657 » range++; 788 DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status);
658 if (range != last_range) 789
659 { 790 /* CoreText does automatic font fallback (AKA "cascading") for characters
660 if (last_range->font) 791 * not supported by the requested font, and provides no way to turn it off ,
661 » CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, k - s tart), 792 * so we must detect if the returned run uses a font other than the reques ted
662 » » » » » kCTFontAttributeName, last_range->font ); 793 * one and fill in the buffer with .notdef glyphs instead of random glyph
663 794 * indices from a different font.
664 » start = k; 795 */
665 } 796 CFDictionaryRef attributes = CTRunGetAttributes (run);
666 797 CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attri butes, kCTFontAttributeName));
667 last_range = range; 798 if (!CFEqual (run_ct_font, font_data->ct_font))
799 {
800 » /* The run doesn't use our main font instance. We have to figure out
801 » * whether font fallback happened, or this is just CoreText giving us
802 » * another CTFont using the same underlying CGFont. CoreText seems
803 » * to do that in a variety of situations, one of which being vertical
804 » * text, but also perhaps for caching reasons.
805 » *
806 » * First, see if it uses any of our subfonts created to set font feature s...
807 » *
808 » * Next, compare the CGFont to the one we used to create our fonts.
809 » * Even this doesn't work all the time.
810 » *
811 » * Finally, we compare PS names, which I don't think are unique...
812 » *
813 » * Looks like if we really want to be sure here we have to modify the
814 » * font to change the name table, similar to what we do in the uniscribe
815 » * backend.
816 » *
817 » * However, even that wouldn't work if we were passed in the CGFont to
818 » * begin with.
819 » *
820 » * Webkit uses a slightly different approach: it installs LastResort
821 » * as fallback chain, and then checks PS name of used font against
822 » * LastResort. That one is safe for any font except for LastResort,
823 » * as opposed to ours, which can fail if we are using any uninstalled
824 » * font that has the same name as an installed font.
825 » *
826 » * See: http://github.com/behdad/harfbuzz/pull/36
827 » */
828 » bool matched = false;
829 » for (unsigned int i = 0; i < range_records.len; i++)
830 » if (range_records[i].font && CFEqual (run_ct_font, range_records[i].fo nt))
831 » {
832 » matched = true;
833 » break;
834 » }
835 » if (!matched)
836 » {
837 » CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
838 » if (run_cg_font)
839 » {
840 » matched = CFEqual (run_cg_font, face_data);
841 » CFRelease (run_cg_font);
842 » }
843 » }
844 » if (!matched)
845 » {
846 » CFStringRef font_ps_name = CTFontCopyName (font_data->ct_font, kCTFont PostScriptNameKey);
847 » CFStringRef run_ps_name = CTFontCopyName (run_ct_font, kCTFontPostScri ptNameKey);
848 » CFComparisonResult result = CFStringCompare (run_ps_name, font_ps_name , 0);
849 » CFRelease (run_ps_name);
850 » CFRelease (font_ps_name);
851 » if (result == kCFCompareEqualTo)
852 » matched = true;
853 » }
854 » if (!matched)
855 » {
856 » CFRange range = CTRunGetStringRange (run);
857 DEBUG_MSG (CORETEXT, run, "Run used fallback font: %ld..%ld",
858 » » range.location, range.location + range.length);
859 » if (!buffer->ensure_inplace (buffer->len + range.length))
860 » goto resize_and_retry;
861 » hb_glyph_info_t *info = buffer->info + buffer->len;
862
863 » CGGlyph notdef = 0;
864 » double advance = CTFontGetAdvancesForGlyphs (font_data->ct_font, kCTFo ntHorizontalOrientation, &notdef, NULL, 1);
865
866 » unsigned int old_len = buffer->len;
867 » for (CFIndex j = range.location; j < range.location + range.length; j+ +)
868 » {
869 » UniChar ch = CFStringGetCharacterAtIndex (string_ref, j);
870 » if (hb_in_range<UniChar> (ch, 0xDC00u, 0xDFFFu) && range.location < j)
871 » {
872 » » ch = CFStringGetCharacterAtIndex (string_ref, j - 1);
873 » » if (hb_in_range<UniChar> (ch, 0xD800u, 0xDBFFu))
874 » » /* This is the second of a surrogate pair. Don't need .notdef
875 » » * for this one. */
876 » » continue;
877 » }
878
879 » info->codepoint = notdef;
880 » info->cluster = log_clusters[j];
881
882 » info->mask = advance;
883 » info->var1.u32 = 0;
884 » info->var2.u32 = 0;
885
886 » info++;
887 » buffer->len++;
888 » }
889 » if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
890 » buffer->reverse_range (old_len, buffer->len);
891 » continue;
892 » }
893 }
894
895 unsigned int num_glyphs = CTRunGetGlyphCount (run);
896 if (num_glyphs == 0)
897 » continue;
898
899 if (!buffer->ensure_inplace (buffer->len + num_glyphs))
900 » goto resize_and_retry;
901
902 hb_glyph_info_t *run_info = buffer->info + buffer->len;
903
904 /* Testing used to indicate that CTRunGetGlyphsPtr, etc (almost?) always
905 * 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
907 * frequently. At any rate, we can test that codepath by setting USE_PTR
908 * to false. */
909
910 #define USE_PTR true
911
912 #define SCRATCH_SAVE() \
913 unsigned int scratch_size_saved = scratch_size; \
914 hb_buffer_t::scratch_buffer_t *scratch_saved = scratch
915
916 #define SCRATCH_RESTORE() \
917 scratch_size = scratch_size_saved; \
918 scratch = scratch_saved;
919
920 {
921 SCRATCH_SAVE();
922 » const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : NULL;
923 » if (!glyphs) {
924 » ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs, goto resize_and_retry) ;
925 » CTRunGetGlyphs (run, range_all, glyph_buf);
926 » glyphs = glyph_buf;
927 » }
928 » const CFIndex* string_indices = USE_PTR ? CTRunGetStringIndicesPtr (run) : NULL;
929 » if (!string_indices) {
930 » ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs, goto resize_and_retry) ;
931 » CTRunGetStringIndices (run, range_all, index_buf);
932 » string_indices = index_buf;
933 » }
934 » hb_glyph_info_t *info = run_info;
935 » for (unsigned int j = 0; j < num_glyphs; j++)
936 » {
937 » info->codepoint = glyphs[j];
938 » info->cluster = log_clusters[string_indices[j]];
939 » info++;
940 » }
941 » SCRATCH_RESTORE();
942 }
943 {
944 SCRATCH_SAVE();
945 » const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : NULL;
946 » if (!positions) {
947 » ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_ret ry);
948 » CTRunGetPositions (run, range_all, position_buf);
949 » positions = position_buf;
950 » }
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;
954 » if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
955 » {
956 » for (unsigned int j = 0; j < num_glyphs; j++)
957 » {
958 » double advance = (j + 1 < num_glyphs ? positions[j + 1].x : position s[0].x + run_advance) - positions[j].x;
959 » info->mask = advance;
960 » info->var1.u32 = positions[0].x; /* Yes, zero. */
961 » info->var2.u32 = positions[j].y;
962 » info++;
963 » }
964 » }
965 » else
966 » {
967 » run_advance = -run_advance;
968 » for (unsigned int j = 0; j < num_glyphs; j++)
969 » {
970 » double advance = (j + 1 < num_glyphs ? positions[j + 1].y : position s[0].y + run_advance) - positions[j].y;
971 » info->mask = advance;
972 » info->var1.u32 = positions[j].x;
973 » info->var2.u32 = positions[0].y; /* Yes, zero. */
974 » info++;
975 » }
976 » }
977 » SCRATCH_RESTORE();
978 }
979 #undef SCRATCH_RESTORE
980 #undef SCRATCH_SAVE
981 #undef USE_PTR
982 #undef ALLOCATE_ARRAY
983
984 buffer->len += num_glyphs;
668 } 985 }
669 if (start != chars_len && last_range->font) 986
670 CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start - 1), 987 /* Make sure all runs had the expected direction. */
671 » » » » kCTFontAttributeName, last_range->font); 988 bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
672 989 assert (bool (status_and & kCTRunStatusRightToLeft) == backward);
673 for (unsigned int i = 0; i < range_records.len; i++) 990 assert (bool (status_or & kCTRunStatusRightToLeft) == backward);
674 if (range_records[i].font) 991
675 » CFRelease (range_records[i].font); 992 buffer->clear_positions ();
676 } 993
677 994 unsigned int count = buffer->len;
678 CTLineRef line = CTLineCreateWithAttributedString (attr_string); 995 hb_glyph_info_t *info = buffer->info;
679 CFRelease (attr_string); 996 hb_glyph_position_t *pos = buffer->pos;
680 997 if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
681 CFArrayRef glyph_runs = CTLineGetGlyphRuns (line); 998 for (unsigned int i = 0; i < count; i++)
682 unsigned int num_runs = CFArrayGetCount (glyph_runs); 999 {
683 1000 » pos->x_advance = info->mask;
684 buffer->len = 0; 1001 » pos->x_offset = info->var1.u32;
685 1002 » pos->y_offset = info->var2.u32;
686 const CFRange range_all = CFRangeMake (0, 0); 1003 » info++, pos++;
687 1004 }
688 for (unsigned int i = 0; i < num_runs; i++) 1005 else
689 { 1006 for (unsigned int i = 0; i < count; i++)
690 CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (glyph_runs, i); 1007 {
691 1008 » pos->y_advance = info->mask;
692 /* CoreText does automatic font fallback (AKA "cascading") for characters 1009 » pos->x_offset = info->var1.u32;
693 * not supported by the requested font, and provides no way to turn it off, 1010 » pos->y_offset = info->var2.u32;
694 * so we detect if the returned run uses a font other than the requested 1011 » info++, pos++;
695 * one and fill in the buffer with .notdef glyphs instead of random glyph 1012 }
696 * indices from a different font. 1013
697 */ 1014 /* Fix up clusters so that we never return out-of-order indices;
698 CFDictionaryRef attributes = CTRunGetAttributes (run); 1015 * if core text has reordered glyphs, we'll merge them to the
699 CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attribu tes, kCTFontAttributeName)); 1016 * beginning of the reordered cluster. CoreText is nice enough
700 CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0); 1017 * to tell us whenever it has produced nonmonotonic results...
701 if (!CFEqual (run_cg_font, face_data->cg_font)) 1018 * Note that we assume the input clusters were nonmonotonic to
1019 * begin with.
1020 *
1021 * This does *not* mean we'll form the same clusters as Uniscribe
1022 * or the native OT backend, only that the cluster indices will be
1023 * monotonic in the output buffer. */
1024 if (count > 1 && (status_or & kCTRunStatusNonMonotonic))
702 { 1025 {
703 CFRelease (run_cg_font); 1026 hb_glyph_info_t *info = buffer->info;
704 1027 if (HB_DIRECTION_IS_FORWARD (buffer->props.direction))
705 » CFRange range = CTRunGetStringRange (run); 1028 {
706 » buffer->ensure (buffer->len + range.length); 1029 » unsigned int cluster = info[count - 1].cluster;
707 » if (buffer->in_error) 1030 » for (unsigned int i = count - 1; i > 0; i--)
708 » FAIL ("Buffer resize failed"); 1031 » {
709 » hb_glyph_info_t *info = buffer->info + buffer->len; 1032 » cluster = MIN (cluster, info[i - 1].cluster);
710 1033 » info[i - 1].cluster = cluster;
711 » CGGlyph notdef = 0; 1034 » }
712 » double advance = CTFontGetAdvancesForGlyphs (font_data->ct_font, kCTFont HorizontalOrientation, &notdef, NULL, 1); 1035 }
713 1036 else
714 for (CFIndex j = range.location; j < range.location + range.length; j++) 1037 {
715 » { 1038 » unsigned int cluster = info[0].cluster;
716 » UniChar ch = CFStringGetCharacterAtIndex (string_ref, j); 1039 » for (unsigned int i = 1; i < count; i++)
717 » if (hb_in_range<UniChar> (ch, 0xDC00u, 0xDFFFu) && range.location < j) 1040 » {
718 » { 1041 » cluster = MIN (cluster, info[i].cluster);
719 » ch = CFStringGetCharacterAtIndex (string_ref, j - 1); 1042 » info[i].cluster = cluster;
720 » if (hb_in_range<UniChar> (ch, 0xD800u, 0xDBFFu)) 1043 » }
721 » /* This is the second of a surrogate pair. Don't need .notdef 1044 }
722 » » * for this one. */
723 » continue;
724 » }
725
726 info->codepoint = notdef;
727 » /* TODO We have to fixup clusters later. See vis_clusters in
728 » * hb-uniscribe.cc for example. */
729 info->cluster = j;
730
731 info->mask = advance;
732 info->var1.u32 = 0;
733 info->var2.u32 = 0;
734
735 » info++;
736 » buffer->len++;
737 }
738 continue;
739 }
740 CFRelease (run_cg_font);
741
742 unsigned int num_glyphs = CTRunGetGlyphCount (run);
743 if (num_glyphs == 0)
744 continue;
745
746 buffer->ensure (buffer->len + num_glyphs);
747
748 scratch = buffer->get_scratch_buffer (&scratch_size);
749
750 /* Testing indicates that CTRunGetGlyphsPtr, etc (almost?) always
751 * succeed, and so copying data to our own buffer will be rare. */
752
753 const CGGlyph* glyphs = CTRunGetGlyphsPtr (run);
754 if (!glyphs) {
755 ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs);
756 CTRunGetGlyphs (run, range_all, glyph_buf);
757 glyphs = glyph_buf;
758 }
759
760 const CGPoint* positions = CTRunGetPositionsPtr (run);
761 if (!positions) {
762 ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs);
763 CTRunGetPositions (run, range_all, position_buf);
764 positions = position_buf;
765 }
766
767 const CFIndex* string_indices = CTRunGetStringIndicesPtr (run);
768 if (!string_indices) {
769 ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs);
770 CTRunGetStringIndices (run, range_all, index_buf);
771 string_indices = index_buf;
772 }
773
774 #undef ALLOCATE_ARRAY
775
776 double run_width = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NU LL);
777
778 for (unsigned int j = 0; j < num_glyphs; j++) {
779 double advance = (j + 1 < num_glyphs ? positions[j + 1].x : positions[0].x + run_width) - positions[j].x;
780
781 hb_glyph_info_t *info = &buffer->info[buffer->len];
782
783 info->codepoint = glyphs[j];
784 info->cluster = string_indices[j];
785
786 /* Currently, we do all x-positioning by setting the advance, we never use x-offset. */
787 info->mask = advance;
788 info->var1.u32 = 0;
789 info->var2.u32 = positions[j].y;
790
791 buffer->len++;
792 } 1045 }
793 } 1046 }
794 1047
795 buffer->clear_positions (); 1048 #undef FAIL
796 1049
797 unsigned int count = buffer->len; 1050 fail:
798 for (unsigned int i = 0; i < count; ++i) { 1051 if (string_ref)
799 hb_glyph_info_t *info = &buffer->info[i]; 1052 CFRelease (string_ref);
800 hb_glyph_position_t *pos = &buffer->pos[i]; 1053 if (line)
801 1054 CFRelease (line);
802 /* TODO vertical */ 1055
803 pos->x_advance = info->mask; 1056 for (unsigned int i = 0; i < range_records.len; i++)
804 pos->x_offset = info->var1.u32; 1057 if (range_records[i].font)
805 pos->y_offset = info->var2.u32; 1058 CFRelease (range_records[i].font);
806 } 1059
807 1060 return ret;
808 /* Fix up clusters so that we never return out-of-order indices;
809 * if core text has reordered glyphs, we'll merge them to the
810 * beginning of the reordered cluster.
811 *
812 * This does *not* mean we'll form the same clusters as Uniscribe
813 * or the native OT backend, only that the cluster indices will be
814 * monotonic in the output buffer. */
815 if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
816 unsigned int prev_cluster = 0;
817 for (unsigned int i = 0; i < count; i++) {
818 unsigned int curr_cluster = buffer->info[i].cluster;
819 if (curr_cluster < prev_cluster) {
820 for (unsigned int j = i; j > 0; j--) {
821 if (buffer->info[j - 1].cluster > curr_cluster)
822 buffer->info[j - 1].cluster = curr_cluster;
823 else
824 break;
825 }
826 }
827 prev_cluster = curr_cluster;
828 }
829 } else {
830 unsigned int prev_cluster = (unsigned int)-1;
831 for (unsigned int i = 0; i < count; i++) {
832 unsigned int curr_cluster = buffer->info[i].cluster;
833 if (curr_cluster > prev_cluster) {
834 for (unsigned int j = i; j > 0; j--) {
835 if (buffer->info[j - 1].cluster < curr_cluster)
836 buffer->info[j - 1].cluster = curr_cluster;
837 else
838 break;
839 }
840 }
841 prev_cluster = curr_cluster;
842 }
843 }
844
845 CFRelease (string_ref);
846 CFRelease (line);
847
848 return true;
849 } 1061 }
850 1062
851 1063
852 /* 1064 /*
853 * AAT shaper 1065 * AAT shaper
854 */ 1066 */
855 1067
856 HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face) 1068 HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face)
857 HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font) 1069 HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font)
858 1070
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
934 1146
935 hb_bool_t 1147 hb_bool_t
936 _hb_coretext_aat_shape (hb_shape_plan_t *shape_plan, 1148 _hb_coretext_aat_shape (hb_shape_plan_t *shape_plan,
937 hb_font_t *font, 1149 hb_font_t *font,
938 hb_buffer_t *buffer, 1150 hb_buffer_t *buffer,
939 const hb_feature_t *features, 1151 const hb_feature_t *features,
940 unsigned int num_features) 1152 unsigned int num_features)
941 { 1153 {
942 return _hb_coretext_shape (shape_plan, font, buffer, features, num_features); 1154 return _hb_coretext_shape (shape_plan, font, buffer, features, num_features);
943 } 1155 }
OLDNEW
« no previous file with comments | « third_party/harfbuzz-ng/src/hb-common.cc ('k') | third_party/harfbuzz-ng/src/hb-face.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698