NativeFontResourceMac.cpp (5367B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include <unordered_map> 8 #include "NativeFontResourceMac.h" 9 #include "UnscaledFontMac.h" 10 #include "Types.h" 11 12 #include "mozilla/RefPtr.h" 13 #include "mozilla/DataMutex.h" 14 15 #ifdef MOZ_WIDGET_UIKIT 16 # include <CoreFoundation/CoreFoundation.h> 17 #endif 18 19 #include "nsIMemoryReporter.h" 20 21 namespace mozilla { 22 namespace gfx { 23 24 #define FONT_NAME_MAX 32 25 MOZ_RUNINIT static StaticDataMutex< 26 std::unordered_map<void*, nsAutoCStringN<FONT_NAME_MAX>>> 27 sWeakFontDataMap("WeakFonts"); 28 29 void FontDataDeallocate(void*, void* info) { 30 auto fontMap = sWeakFontDataMap.Lock(); 31 fontMap->erase(info); 32 free(info); 33 } 34 35 class NativeFontResourceMacReporter final : public nsIMemoryReporter { 36 ~NativeFontResourceMacReporter() = default; 37 38 MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf) 39 public: 40 NS_DECL_ISUPPORTS 41 42 NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, 43 nsISupports* aData, bool aAnonymize) override { 44 auto fontMap = sWeakFontDataMap.Lock(); 45 46 nsAutoCString path("explicit/gfx/native-font-resource-mac/font("); 47 48 unsigned int unknownFontIndex = 0; 49 for (auto& i : *fontMap) { 50 nsAutoCString subPath(path); 51 52 if (aAnonymize) { 53 subPath.AppendPrintf("<anonymized-%p>", this); 54 } else { 55 if (i.second.Length()) { 56 subPath.AppendLiteral("psname="); 57 subPath.Append(i.second); 58 } else { 59 subPath.AppendPrintf("Unknown(%d)", unknownFontIndex); 60 } 61 } 62 63 size_t bytes = MallocSizeOf(i.first) + FONT_NAME_MAX; 64 65 subPath.Append(")"); 66 67 aHandleReport->Callback(""_ns, subPath, KIND_HEAP, UNITS_BYTES, bytes, 68 "Memory used by this native font."_ns, aData); 69 70 unknownFontIndex++; 71 } 72 return NS_OK; 73 } 74 }; 75 76 NS_IMPL_ISUPPORTS(NativeFontResourceMacReporter, nsIMemoryReporter) 77 78 void NativeFontResourceMac::RegisterMemoryReporter() { 79 RegisterStrongMemoryReporter(new NativeFontResourceMacReporter); 80 } 81 82 /* static */ 83 already_AddRefed<NativeFontResourceMac> NativeFontResourceMac::Create( 84 const uint8_t* aFontData, uint32_t aDataLength) { 85 uint8_t* fontData = (uint8_t*)malloc(aDataLength); 86 if (!fontData) { 87 return nullptr; 88 } 89 memcpy(fontData, aFontData, aDataLength); 90 CFAllocatorContext context = {0, fontData, nullptr, nullptr, 91 nullptr, nullptr, nullptr, FontDataDeallocate, 92 nullptr}; 93 CFAllocatorRef allocator = CFAllocatorCreate(kCFAllocatorDefault, &context); 94 95 // We create a CFDataRef here that we'l hold until we've determined that we 96 // have a valid font. If and only if we can create a font from the data, 97 // we'll store the font data in our map. Whether or not the font is valid, 98 // we'll later release this CFDataRef. 99 CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, fontData, 100 aDataLength, allocator); 101 if (!data) { 102 free(fontData); 103 return nullptr; 104 } 105 106 CTFontDescriptorRef ctFontDesc = 107 CTFontManagerCreateFontDescriptorFromData(data); 108 if (!ctFontDesc) { 109 CFRelease(data); 110 return nullptr; 111 } 112 113 // creating the CGFontRef via the CTFont avoids the data being held alive 114 // in a cache. 115 CTFontRef ctFont = CTFontCreateWithFontDescriptor(ctFontDesc, 0, NULL); 116 117 // Creating the CGFont from the CTFont prevents the font data from being 118 // held in the TDescriptorSource cache. This appears to be true even 119 // if we later create a CTFont from the CGFont. 120 CGFontRef fontRef = CTFontCopyGraphicsFont(ctFont, NULL); 121 CFRelease(ctFont); 122 123 if (!fontRef) { 124 // Not a valid font; release the structures we've been holding. 125 CFRelease(data); 126 CFRelease(ctFontDesc); 127 return nullptr; 128 } 129 130 // Determine the font name and store it with the font data in the map. 131 nsAutoCStringN<FONT_NAME_MAX> fontName; 132 133 CFStringRef psname = CGFontCopyPostScriptName(fontRef); 134 if (psname) { 135 const char* cstr = CFStringGetCStringPtr(psname, kCFStringEncodingUTF8); 136 if (cstr) { 137 fontName.Assign(cstr); 138 } else { 139 char buf[FONT_NAME_MAX]; 140 if (CFStringGetCString(psname, buf, FONT_NAME_MAX, 141 kCFStringEncodingUTF8)) { 142 fontName.Assign(buf); 143 } 144 } 145 CFRelease(psname); 146 } 147 148 { 149 auto fontMap = sWeakFontDataMap.Lock(); 150 void* key = (void*)fontData; 151 fontMap->insert({key, fontName}); 152 } 153 // It's now safe to release our CFDataRef. 154 CFRelease(data); 155 156 // passes ownership of fontRef to the NativeFontResourceMac instance 157 RefPtr<NativeFontResourceMac> fontResource = 158 new NativeFontResourceMac(ctFontDesc, fontRef, aDataLength); 159 160 return fontResource.forget(); 161 } 162 163 already_AddRefed<UnscaledFont> NativeFontResourceMac::CreateUnscaledFont( 164 uint32_t aIndex, const uint8_t* aInstanceData, 165 uint32_t aInstanceDataLength) { 166 RefPtr<UnscaledFont> unscaledFont = 167 new UnscaledFontMac(mFontDescRef, mFontRef, true); 168 169 return unscaledFont.forget(); 170 } 171 172 } // namespace gfx 173 } // namespace mozilla