diff options
Diffstat (limited to 'gfx/2d/NativeFontResourceMac.cpp')
-rw-r--r-- | gfx/2d/NativeFontResourceMac.cpp | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/gfx/2d/NativeFontResourceMac.cpp b/gfx/2d/NativeFontResourceMac.cpp new file mode 100644 index 0000000000..448db76726 --- /dev/null +++ b/gfx/2d/NativeFontResourceMac.cpp @@ -0,0 +1,173 @@ +/* -*- 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 <unordered_map> +#include <unordered_set> +#include "NativeFontResourceMac.h" +#include "UnscaledFontMac.h" +#include "Types.h" + +#include "mozilla/RefPtr.h" +#include "mozilla/DataMutex.h" + +#ifdef MOZ_WIDGET_UIKIT +# include <CoreFoundation/CoreFoundation.h> +#endif + +#include "nsIMemoryReporter.h" + +namespace mozilla { +namespace gfx { + +#define FONT_NAME_MAX 32 +static StaticDataMutex<std::unordered_map<void*, nsAutoCStringN<FONT_NAME_MAX>>> + 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("<anonymized-%p>", 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> 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<FONT_NAME_MAX> 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<NativeFontResourceMac> fontResource = + new NativeFontResourceMac(ctFontDesc, fontRef, aDataLength); + + return fontResource.forget(); +} + +already_AddRefed<UnscaledFont> NativeFontResourceMac::CreateUnscaledFont( + uint32_t aIndex, const uint8_t* aInstanceData, + uint32_t aInstanceDataLength) { + RefPtr<UnscaledFont> unscaledFont = + new UnscaledFontMac(mFontDescRef, mFontRef, true); + + return unscaledFont.forget(); +} + +} // namespace gfx +} // namespace mozilla |