| Index: Source/platform/fonts/mac/MemoryActivatedFont.mm
|
| diff --git a/Source/platform/fonts/mac/MemoryActivatedFont.mm b/Source/platform/fonts/mac/MemoryActivatedFont.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..22ac44c35b439b7fc4753c38fe5295cc7852f4b6
|
| --- /dev/null
|
| +++ b/Source/platform/fonts/mac/MemoryActivatedFont.mm
|
| @@ -0,0 +1,207 @@
|
| +/*
|
| + * This file is part of the internal font implementation.
|
| + *
|
| + * Copyright (c) 2010 Google Inc. All rights reserved.
|
| + *
|
| + * This library is free software; you can redistribute it and/or
|
| + * modify it under the terms of the GNU Library General Public
|
| + * License as published by the Free Software Foundation; either
|
| + * version 2 of the License, or (at your option) any later version.
|
| + *
|
| + * This library is distributed in the hope that it will be useful,
|
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| + * Library General Public License for more details.
|
| + *
|
| + * You should have received a copy of the GNU Library General Public License
|
| + * along with this library; see the file COPYING.LIB. If not, write to
|
| + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
| + * Boston, MA 02110-1301, USA.
|
| + *
|
| + */
|
| +
|
| +// This file provides additional functionality to the Mac FontPlatformData class
|
| +// defined in WebCore/platform/mac/FontPlatformDataMac.mm.
|
| +// Because we want to support loading fonts between processes in the face of
|
| +// font loading being blocked by the sandbox, we need a mechnasim to both
|
| +// do the loading of in-memory fonts and keep track of them.
|
| +
|
| +#import "config.h"
|
| +#import "platform/fonts/mac/MemoryActivatedFont.h"
|
| +
|
| +#import <AppKit/NSFont.h>
|
| +#import "platform/LinkHash.h"
|
| +#import "platform/fonts/FontPlatformData.h"
|
| +#import "public/platform/mac/WebSandboxSupport.h"
|
| +#import "public/platform/Platform.h"
|
| +#import "wtf/HashMap.h"
|
| +
|
| +namespace blink {
|
| +
|
| +namespace {
|
| +
|
| +typedef HashMap<uint32_t, MemoryActivatedFont*> FontContainerRefMemoryFontHash;
|
| +typedef HashMap<WTF::String, MemoryActivatedFont*> FontNameMemoryFontHash;
|
| +
|
| +// Caching:
|
| +//
|
| +// Requesting a font from the browser process is expensive and so is
|
| +// "activating" said font. Caching of loaded fonts is complicated by the fact
|
| +// that it's impossible to get a unique identifier for the on-disk font file
|
| +// from inside the sandboxed renderer process.
|
| +// This means that when loading a font we need to round-trip through the browser
|
| +// process in order to get the unique font file identifer which we might already
|
| +// have activated and cached.
|
| +//
|
| +// In order to save as much work as we can, we maintain 2 levels of caching
|
| +// for the font data:
|
| +// 1. A dumb cache keyed by the font name/style (information we can determine
|
| +// from inside the sandbox).
|
| +// 2. A smarter cache keyed by the real "unique font id".
|
| +//
|
| +// In order to perform a lookup in #2 we need to consult with the browser to get
|
| +// us the lookup key. While this doesn't save us the font load, it does save
|
| +// us font activation.
|
| +//
|
| +// It's important to remember that existing FontPlatformData objects are already
|
| +// cached, so a cache miss in the code in this file isn't necessarily so bad.
|
| +
|
| +FontContainerRefMemoryFontHash& fontCacheByFontID()
|
| +{
|
| + DEFINE_STATIC_LOCAL(FontContainerRefMemoryFontHash, srcFontIDCache, ());
|
| + return srcFontIDCache;
|
| +}
|
| +
|
| +
|
| +FontNameMemoryFontHash& fontCacheByFontName()
|
| +{
|
| + DEFINE_STATIC_LOCAL(FontNameMemoryFontHash, srcFontNameCache, ());
|
| + return srcFontNameCache;
|
| +}
|
| +
|
| +// Given a font specified by |srcFont|, use the information we can query in
|
| +// the sandbox to construct a key which we hope will be as unique as possible
|
| +// to the containing font file.
|
| +WTF::String hashKeyFromNSFont(NSFont* srcFont)
|
| +{
|
| + NSFontDescriptor* desc = [srcFont fontDescriptor];
|
| + NSFontSymbolicTraits traits = [desc symbolicTraits];
|
| + return WTF::String::format("%s %x", [[srcFont fontName] UTF8String], traits);
|
| +}
|
| +
|
| +// The only way we can tell that an in-process font has failed to load
|
| +// is if CTFontCopyGraphicsFont() returns the LastResort font.
|
| +bool isLastResortFont(CGFontRef cgFont)
|
| +{
|
| + NSString* fontName = (NSString*)CGFontCopyPostScriptName(cgFont);
|
| + return [fontName isEqualToString:@"LastResort"];
|
| +}
|
| +
|
| +// Given an in-process font which has failed to load, return a
|
| +// MemoryActivatedFont* corresponding to an in-memory representation of the
|
| +// same font loaded from the browser process.
|
| +// On failure this function returns a PassRefPtr pointing to 0.
|
| +PassRefPtr<MemoryActivatedFont> loadFontFromBrowserProcess(NSFont* nsFont)
|
| +{
|
| + // First try to lookup in our cache with the limited information we have.
|
| + WTF::String hashKey = hashKeyFromNSFont(nsFont);
|
| + RefPtr<MemoryActivatedFont> font(fontCacheByFontName().get(hashKey));
|
| + if (font)
|
| + return font;
|
| +
|
| + CGFontRef tmpCGFont;
|
| + uint32_t fontID;
|
| + // Send cross-process request to load font.
|
| + blink::WebSandboxSupport* sandboxSupport = blink::Platform::current()->sandboxSupport();
|
| + if (!sandboxSupport) {
|
| + // This function should only be called in response to an error loading a
|
| + // font due to being blocked by the sandbox.
|
| + // This by definition shouldn't happen if there is no sandbox support.
|
| + ASSERT_NOT_REACHED();
|
| + return nullptr;
|
| + }
|
| + if (!sandboxSupport->loadFont(nsFont, &tmpCGFont, &fontID))
|
| + return nullptr;
|
| +
|
| + RetainPtr<CGFontRef> cgFont(tmpCGFont);
|
| + // Now that we have the fontID from the browser process, we can consult
|
| + // the ID cache.
|
| + font = fontCacheByFontID().get(fontID);
|
| + if (font)
|
| + // FIXME: WebSandboxSupport::loadFont() should consult the id cache
|
| + // before activating the font.
|
| + return font;
|
| +
|
| + return MemoryActivatedFont::create(fontID, nsFont, cgFont.get());
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +PassRefPtr<MemoryActivatedFont> MemoryActivatedFont::create(uint32_t fontID, NSFont* nsFont, CGFontRef cgFont)
|
| +{
|
| + return adoptRef(new MemoryActivatedFont(fontID, nsFont, cgFont));
|
| +}
|
| +
|
| +MemoryActivatedFont::MemoryActivatedFont(uint32_t fontID, NSFont* nsFont, CGFontRef cgFont)
|
| + : m_cgFont(cgFont)
|
| + , m_fontID(fontID)
|
| + , m_inSandboxHashKey(hashKeyFromNSFont(nsFont))
|
| +{
|
| + // Add ourselves to caches.
|
| + fontCacheByFontID().add(fontID, this);
|
| + fontCacheByFontName().add(m_inSandboxHashKey, this);
|
| +}
|
| +
|
| +// Destructor - Unload font container from memory and remove ourselves
|
| +// from cache.
|
| +MemoryActivatedFont::~MemoryActivatedFont()
|
| +{
|
| + // First remove ourselves from the caches.
|
| + ASSERT(fontCacheByFontID().contains(m_fontID));
|
| + ASSERT(fontCacheByFontName().contains(m_inSandboxHashKey));
|
| +
|
| + fontCacheByFontID().remove(m_fontID);
|
| + fontCacheByFontName().remove(m_inSandboxHashKey);
|
| +}
|
| +
|
| +// Given an NSFont, try to load a representation of that font into the cgFont
|
| +// parameter. If loading is blocked by the sandbox, the font may be loaded
|
| +// cross-process.
|
| +// If sandbox loading also fails, a fallback font is loaded.
|
| +//
|
| +// Considerations:
|
| +// * cgFont must be CFRelease()ed by the caller when done.
|
| +//
|
| +// Parameters:
|
| +// * nsFont - The font we wish to load.
|
| +// * fontSize - point size of the font we wish to load.
|
| +// * outNSFont - The font that was actually loaded or null if loading failed.
|
| +// * cgFont - on output this contains the CGFontRef corresponding to the NSFont
|
| +// that was picked in the end. The caller is responsible for calling
|
| +// CFRelease() on this parameter when done with it.
|
| +// * fontID - on output, the ID corresponding to nsFont.
|
| +void FontPlatformData::loadFont(NSFont* nsFont, float fontSize, NSFont*& outNSFont, CGFontRef& cgFont)
|
| +{
|
| + outNSFont = nsFont;
|
| + cgFont = CTFontCopyGraphicsFont(toCTFontRef(outNSFont), 0);
|
| + if (outNSFont && cgFont && isLastResortFont(cgFont)) {
|
| + // Release old CGFontRef since it points at the LastResort font which we don't want.
|
| + CFRelease(cgFont);
|
| + cgFont = 0;
|
| +
|
| + // Font loading was blocked by the Sandbox.
|
| + m_inMemoryFont = loadFontFromBrowserProcess(outNSFont);
|
| + if (m_inMemoryFont) {
|
| + cgFont = m_inMemoryFont->cgFont();
|
| +
|
| + // Need to add an extra retain so output semantics of this function
|
| + // are consistent.
|
| + CFRetain(cgFont);
|
| + } else {
|
| + // If we still can't load the font, set |outNSFont| to null so that FontPlatformData won't be used.
|
| + outNSFont = 0;
|
| + }
|
| + }
|
| +}
|
| +
|
| +} // namespace blink
|
|
|