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 <dlfcn.h> | 7 #include <CoreText/CoreText.h> |
8 #import <Foundation/Foundation.h> | 8 #import <Foundation/Foundation.h> |
9 #include <string> | |
10 #include <vector> | |
11 | 9 |
12 #include "base/mac/foundation_util.h" | 10 #include "base/mac/foundation_util.h" |
13 #import "base/mac/mac_util.h" | 11 #import "base/mac/mac_util.h" |
| 12 #include "base/mac/scoped_cftyperef.h" |
14 #import "base/strings/sys_string_conversions.h" | 13 #import "base/strings/sys_string_conversions.h" |
15 #include "ui/gfx/font.h" | 14 #include "ui/gfx/font.h" |
16 | 15 |
17 // TODO(thakis): Remove this prototype once the deployment target is 10.8+. | 16 namespace gfx { |
18 extern "C" CFArrayRef CTFontCopyDefaultCascadeListForLanguages( | 17 namespace { |
19 CTFontRef font, | |
20 CFArrayRef languagePrefList); | |
21 | 18 |
22 namespace gfx { | 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 |
23 | 41 |
24 std::vector<Font> GetFallbackFonts(const Font& font) { | 42 std::vector<Font> GetFallbackFonts(const Font& font) { |
25 // On Mac "There is a system default cascade list (which is polymorphic, based | 43 // On Mac "There is a system default cascade list (which is polymorphic, based |
26 // on the user's language setting and current font)" - CoreText Programming | 44 // on the user's language setting and current font)" - CoreText Programming |
27 // Guide. | 45 // 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(). | |
33 NSArray* languages = [[NSUserDefaults standardUserDefaults] | 46 NSArray* languages = [[NSUserDefaults standardUserDefaults] |
34 stringArrayForKey:@"AppleLanguages"]; | 47 stringArrayForKey:@"AppleLanguages"]; |
35 CFArrayRef languages_cf = base::mac::NSToCFCast(languages); | 48 CFArrayRef languages_cf = base::mac::NSToCFCast(languages); |
36 base::ScopedCFTypeRef<CFArrayRef> cascade_list( | 49 base::ScopedCFTypeRef<CFArrayRef> cascade_list( |
37 CTFontCopyDefaultCascadeListForLanguages( | 50 CTFontCopyDefaultCascadeListForLanguages( |
38 static_cast<CTFontRef>(font.GetNativeFont()), languages_cf)); | 51 static_cast<CTFontRef>(font.GetNativeFont()), languages_cf)); |
39 | 52 |
40 std::vector<Font> fallback_fonts; | 53 std::vector<Font> fallback_fonts; |
41 | 54 |
42 const CFIndex fallback_count = CFArrayGetCount(cascade_list); | 55 const CFIndex fallback_count = CFArrayGetCount(cascade_list); |
43 for (CFIndex i = 0; i < fallback_count; ++i) { | 56 for (CFIndex i = 0; i < fallback_count; ++i) { |
44 CTFontDescriptorRef descriptor = | 57 CTFontDescriptorRef descriptor = |
45 base::mac::CFCastStrict<CTFontDescriptorRef>( | 58 base::mac::CFCastStrict<CTFontDescriptorRef>( |
46 CFArrayGetValueAtIndex(cascade_list, i)); | 59 CFArrayGetValueAtIndex(cascade_list, i)); |
47 base::ScopedCFTypeRef<CTFontRef> font( | 60 base::ScopedCFTypeRef<CTFontRef> font( |
48 CTFontCreateWithFontDescriptor(descriptor, 0.0, nullptr)); | 61 CTFontCreateWithFontDescriptor(descriptor, 0.0, nullptr)); |
49 if (font.get()) | 62 if (font.get()) |
50 fallback_fonts.push_back(Font(static_cast<NSFont*>(font.get()))); | 63 fallback_fonts.push_back(Font(static_cast<NSFont*>(font.get()))); |
51 } | 64 } |
52 | 65 |
53 if (fallback_fonts.empty()) | 66 if (fallback_fonts.empty()) |
54 return std::vector<Font>(1, font); | 67 return std::vector<Font>(1, font); |
55 | 68 |
56 return fallback_fonts; | 69 return fallback_fonts; |
57 } | 70 } |
58 | 71 |
| 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 |
59 } // namespace gfx | 89 } // namespace gfx |
OLD | NEW |