/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include "NativeFontResourceMac.h" #include "UnscaledFontMac.h" #include "Types.h" #include "mozilla/RefPtr.h" #include "mozilla/DataMutex.h" #ifdef MOZ_WIDGET_UIKIT # include #endif #include "nsIMemoryReporter.h" #include "nsCocoaFeatures.h" namespace mozilla { namespace gfx { #define FONT_NAME_MAX 32 static StaticDataMutex>> sWeakFontDataMap("WeakFonts"); void FontDataDeallocate(void*, void* info) { auto fontMap = sWeakFontDataMap.Lock(); fontMap->erase(info); free(info); } class NativeFontResourceMacReporter final : public nsIMemoryReporter { ~NativeFontResourceMacReporter() = default; MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf) public: NS_DECL_ISUPPORTS NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize) override { auto fontMap = sWeakFontDataMap.Lock(); nsAutoCString path("explicit/gfx/native-font-resource-mac/font("); unsigned int unknownFontIndex = 0; for (auto& i : *fontMap) { nsAutoCString subPath(path); if (aAnonymize) { subPath.AppendPrintf("", this); } else { if (i.second.Length()) { subPath.AppendLiteral("psname="); subPath.Append(i.second); } else { subPath.AppendPrintf("Unknown(%d)", unknownFontIndex); } } size_t bytes = MallocSizeOf(i.first) + FONT_NAME_MAX; subPath.Append(")"); aHandleReport->Callback(""_ns, subPath, KIND_HEAP, UNITS_BYTES, bytes, "Memory used by this native font."_ns, aData); unknownFontIndex++; } return NS_OK; } }; NS_IMPL_ISUPPORTS(NativeFontResourceMacReporter, nsIMemoryReporter) void NativeFontResourceMac::RegisterMemoryReporter() { RegisterStrongMemoryReporter(new NativeFontResourceMacReporter); } /* static */ already_AddRefed NativeFontResourceMac::Create( uint8_t* aFontData, uint32_t aDataLength) { uint8_t* fontData = (uint8_t*)malloc(aDataLength); if (!fontData) { return nullptr; } memcpy(fontData, aFontData, aDataLength); CFAllocatorContext context = {0, fontData, nullptr, nullptr, nullptr, nullptr, nullptr, FontDataDeallocate, nullptr}; CFAllocatorRef allocator = CFAllocatorCreate(kCFAllocatorDefault, &context); // We create a CFDataRef here that we'l hold until we've determined that we // have a valid font. If and only if we can create a font from the data, // we'll store the font data in our map. Whether or not the font is valid, // we'll later release this CFDataRef. CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, fontData, aDataLength, allocator); if (!data) { free(fontData); return nullptr; } CTFontDescriptorRef ctFontDesc = CTFontManagerCreateFontDescriptorFromData(data); if (!ctFontDesc) { CFRelease(data); return nullptr; } // creating the CGFontRef via the CTFont avoids the data being held alive // in a cache. CTFontRef ctFont = CTFontCreateWithFontDescriptor(ctFontDesc, 0, NULL); // Creating the CGFont from the CTFont prevents the font data from being // held in the TDescriptorSource cache. This appears to be true even // if we later create a CTFont from the CGFont. CGFontRef fontRef = CTFontCopyGraphicsFont(ctFont, NULL); CFRelease(ctFont); if (!fontRef) { // Not a valid font; release the structures we've been holding. CFRelease(data); CFRelease(ctFontDesc); return nullptr; } // Determine the font name and store it with the font data in the map. nsAutoCStringN fontName; CFStringRef psname = CGFontCopyPostScriptName(fontRef); if (psname) { const char* cstr = CFStringGetCStringPtr(psname, kCFStringEncodingUTF8); if (cstr) { fontName.Assign(cstr); } else { char buf[FONT_NAME_MAX]; if (CFStringGetCString(psname, buf, FONT_NAME_MAX, kCFStringEncodingUTF8)) { fontName.Assign(buf); } } CFRelease(psname); } { auto fontMap = sWeakFontDataMap.Lock(); void* key = (void*)fontData; fontMap->insert({key, fontName}); } // It's now safe to release our CFDataRef. CFRelease(data); // passes ownership of fontRef to the NativeFontResourceMac instance RefPtr fontResource = new NativeFontResourceMac(ctFontDesc, fontRef, aDataLength); return fontResource.forget(); } already_AddRefed NativeFontResourceMac::CreateUnscaledFont( uint32_t aIndex, const uint8_t* aInstanceData, uint32_t aInstanceDataLength) { RefPtr unscaledFont = new UnscaledFontMac(mFontDescRef, mFontRef, true); return unscaledFont.forget(); } } // namespace gfx } // namespace mozilla