OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/gfx/font_fallback.h" | 5 #include "ui/gfx/font_fallback.h" |
6 | 6 |
7 #include <CoreText/CoreText.h> | 7 #include <dlfcn.h> |
8 #import <Foundation/Foundation.h> | 8 #import <Foundation/Foundation.h> |
| 9 #include <string> |
| 10 #include <vector> |
9 | 11 |
10 #include "base/mac/foundation_util.h" | 12 #include "base/mac/foundation_util.h" |
11 #import "base/mac/mac_util.h" | 13 #import "base/mac/mac_util.h" |
12 #include "base/mac/scoped_cftyperef.h" | |
13 #import "base/strings/sys_string_conversions.h" | 14 #import "base/strings/sys_string_conversions.h" |
14 #include "ui/gfx/font.h" | 15 #include "ui/gfx/font.h" |
15 | 16 |
| 17 // TODO(thakis): Remove this prototype once the deployment target is 10.8+. |
| 18 extern "C" CFArrayRef CTFontCopyDefaultCascadeListForLanguages( |
| 19 CTFontRef font, |
| 20 CFArrayRef languagePrefList); |
| 21 |
16 namespace gfx { | 22 namespace gfx { |
17 namespace { | |
18 | |
19 // CTFontCreateForString() sometimes re-wraps its result in a new CTFontRef with | |
20 // identical attributes. This wastes time shaping the text run and confounds | |
21 // Skia's internal typeface cache. | |
22 bool FontsEqual(CTFontRef lhs, CTFontRef rhs) { | |
23 if (lhs == rhs) | |
24 return true; | |
25 | |
26 // Compare ATSFontRef typeface IDs. These are typedef uint32_t. Typically if | |
27 // RenderText decided to hunt for a fallback in the first place, this check | |
28 // fails and FontsEqual returns here. | |
29 if (CTFontGetPlatformFont(lhs, nil) != CTFontGetPlatformFont(rhs, nil)) | |
30 return false; | |
31 | |
32 // Comparing addresses of descriptors seems to be sufficient for other cases. | |
33 base::ScopedCFTypeRef<CTFontDescriptorRef> lhs_descriptor( | |
34 CTFontCopyFontDescriptor(lhs)); | |
35 base::ScopedCFTypeRef<CTFontDescriptorRef> rhs_descriptor( | |
36 CTFontCopyFontDescriptor(rhs)); | |
37 return lhs_descriptor.get() == rhs_descriptor.get(); | |
38 } | |
39 | |
40 } // namespace | |
41 | 23 |
42 std::vector<Font> GetFallbackFonts(const Font& font) { | 24 std::vector<Font> GetFallbackFonts(const Font& font) { |
43 // On Mac "There is a system default cascade list (which is polymorphic, based | 25 // On Mac "There is a system default cascade list (which is polymorphic, based |
44 // on the user's language setting and current font)" - CoreText Programming | 26 // on the user's language setting and current font)" - CoreText Programming |
45 // Guide. | 27 // Guide. |
| 28 // The CoreText APIs provide CTFontCreateForString(font, string, range), but |
| 29 // it requires a text string "hint", and the returned font can't be |
| 30 // represented by name for easy retrieval later. |
| 31 // In 10.8, CTFontCopyDefaultCascadeListForLanguages(font, language_list) |
| 32 // showed up which is a good fit GetFallbackFonts(). |
46 NSArray* languages = [[NSUserDefaults standardUserDefaults] | 33 NSArray* languages = [[NSUserDefaults standardUserDefaults] |
47 stringArrayForKey:@"AppleLanguages"]; | 34 stringArrayForKey:@"AppleLanguages"]; |
48 CFArrayRef languages_cf = base::mac::NSToCFCast(languages); | 35 CFArrayRef languages_cf = base::mac::NSToCFCast(languages); |
49 base::ScopedCFTypeRef<CFArrayRef> cascade_list( | 36 base::ScopedCFTypeRef<CFArrayRef> cascade_list( |
50 CTFontCopyDefaultCascadeListForLanguages( | 37 CTFontCopyDefaultCascadeListForLanguages( |
51 static_cast<CTFontRef>(font.GetNativeFont()), languages_cf)); | 38 static_cast<CTFontRef>(font.GetNativeFont()), languages_cf)); |
52 | 39 |
53 std::vector<Font> fallback_fonts; | 40 std::vector<Font> fallback_fonts; |
54 | 41 |
55 const CFIndex fallback_count = CFArrayGetCount(cascade_list); | 42 const CFIndex fallback_count = CFArrayGetCount(cascade_list); |
56 for (CFIndex i = 0; i < fallback_count; ++i) { | 43 for (CFIndex i = 0; i < fallback_count; ++i) { |
57 CTFontDescriptorRef descriptor = | 44 CTFontDescriptorRef descriptor = |
58 base::mac::CFCastStrict<CTFontDescriptorRef>( | 45 base::mac::CFCastStrict<CTFontDescriptorRef>( |
59 CFArrayGetValueAtIndex(cascade_list, i)); | 46 CFArrayGetValueAtIndex(cascade_list, i)); |
60 base::ScopedCFTypeRef<CTFontRef> font( | 47 base::ScopedCFTypeRef<CTFontRef> font( |
61 CTFontCreateWithFontDescriptor(descriptor, 0.0, nullptr)); | 48 CTFontCreateWithFontDescriptor(descriptor, 0.0, nullptr)); |
62 if (font.get()) | 49 if (font.get()) |
63 fallback_fonts.push_back(Font(static_cast<NSFont*>(font.get()))); | 50 fallback_fonts.push_back(Font(static_cast<NSFont*>(font.get()))); |
64 } | 51 } |
65 | 52 |
66 if (fallback_fonts.empty()) | 53 if (fallback_fonts.empty()) |
67 return std::vector<Font>(1, font); | 54 return std::vector<Font>(1, font); |
68 | 55 |
69 return fallback_fonts; | 56 return fallback_fonts; |
70 } | 57 } |
71 | 58 |
72 bool GetFallbackFont(const Font& font, | |
73 const base::char16* text, | |
74 int text_length, | |
75 Font* result) { | |
76 base::ScopedCFTypeRef<CFStringRef> cf_string( | |
77 CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, text, text_length, | |
78 kCFAllocatorNull)); | |
79 CTFontRef ct_font = base::mac::NSToCFCast(font.GetNativeFont()); | |
80 base::ScopedCFTypeRef<CTFontRef> ct_result( | |
81 CTFontCreateForString(ct_font, cf_string, {0, text_length})); | |
82 if (FontsEqual(ct_font, ct_result)) | |
83 return false; | |
84 | |
85 *result = Font(base::mac::CFToNSCast(ct_result.get())); | |
86 return true; | |
87 } | |
88 | |
89 } // namespace gfx | 59 } // namespace gfx |
OLD | NEW |