| 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 |