• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * This file is part of the internal font implementation.
3 *
4 * Copyright (c) 2010 Google Inc. All rights reserved.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB.  If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23// This file provides additional functionality to the Mac FontPlatformData class
24// defined in WebCore/platform/cocoa/FontPlatformDataCocoa.mm .
25// Because we want to support loading fonts between processes in the face of
26// font loading being blocked by the sandbox, we need a mechnasim to both
27// do the loading of in-memory fonts and keep track of them.
28
29#import "config.h"
30#import "CrossProcessFontLoading.h"
31
32#import "../graphics/FontPlatformData.h"
33#import "PlatformBridge.h"
34#import <AppKit/NSFont.h>
35#import <wtf/HashMap.h>
36
37namespace WebCore {
38
39namespace {
40
41typedef HashMap<ATSFontContainerRef, MemoryActivatedFont*> FontContainerRefMemoryFontHash;
42
43// On 10.5, font loading is not blocked by the sandbox and thus there is no
44// need for the cross-process font loading mechanim.
45// On system versions >=10.6 cross-process font loading is required.
46bool OutOfProcessFontLoadingEnabled()
47{
48    static SInt32 systemVersion = 0;
49    if (!systemVersion) {
50        if (Gestalt(gestaltSystemVersion, &systemVersion) != noErr)
51            return false;
52    }
53
54    return systemVersion >= 0x1060;
55}
56
57FontContainerRefMemoryFontHash& fontCacheBySrcFontContainerRef()
58{
59    DEFINE_STATIC_LOCAL(FontContainerRefMemoryFontHash, srcFontRefCache, ());
60    return srcFontRefCache;
61}
62
63ATSFontContainerRef fontContainerRefFromNSFont(NSFont* srcFont)
64{
65    ATSFontRef fontRef = CTFontGetPlatformFont(toCTFontRef(srcFont), 0);
66    if (!fontRef)
67        return kATSFontContainerRefUnspecified;
68    ATSFontContainerRef fontContainer = kATSFontContainerRefUnspecified;
69    if (ATSFontGetContainer(fontRef, 0, &fontContainer) != noErr)
70        return kATSFontContainerRefUnspecified;
71    return fontContainer;
72}
73
74// The only way we can tell that an in-process font has failed to load
75// is if CTFontCopyGraphicsFont() returns the LastResort font.
76bool isLastResortFont(CGFontRef cgFont)
77{
78    NSString* fontName = (NSString*)CGFontCopyPostScriptName(cgFont);
79    return [fontName isEqualToString:@"LastResort"];
80}
81
82// Given an in-process font which has failed to load, return a
83// MemoryActivatedFont* corresponding to an in-memory representation of the
84// same font loaded from the browser process.
85// On failure this function returns a PassRefPtr pointing to 0.
86PassRefPtr<MemoryActivatedFont> loadFontFromBrowserProcess(NSFont* nsFont)
87{
88    ATSFontContainerRef container;
89    // Send cross-process request to load font.
90    if (!PlatformBridge::loadFont(nsFont, &container))
91        return 0;
92
93    ATSFontContainerRef srcFontContainerRef = fontContainerRefFromNSFont(nsFont);
94    if (!srcFontContainerRef) {
95        ATSFontDeactivate(container, 0, kATSOptionFlagsDefault);
96        return 0;
97    }
98
99    PassRefPtr<MemoryActivatedFont> font = adoptRef(fontCacheBySrcFontContainerRef().get(srcFontContainerRef));
100    if (font.get())
101        return font;
102
103    return MemoryActivatedFont::create(srcFontContainerRef, container);
104}
105
106} // namespace
107
108PassRefPtr<MemoryActivatedFont> MemoryActivatedFont::create(ATSFontContainerRef srcFontContainerRef, ATSFontContainerRef container)
109{
110  MemoryActivatedFont* font = new MemoryActivatedFont(srcFontContainerRef, container);
111  if (!font->cgFont())  // Object construction failed.
112  {
113      delete font;
114      return 0;
115  }
116  return adoptRef(font);
117}
118
119MemoryActivatedFont::MemoryActivatedFont(ATSFontContainerRef srcFontContainerRef, ATSFontContainerRef container)
120    : m_fontContainer(container)
121    , m_atsFontRef(kATSFontRefUnspecified)
122    , m_srcFontContainerRef(srcFontContainerRef)
123{
124    if (!container)
125        return;
126
127    // Count the number of fonts in the container.
128    ItemCount fontCount = 0;
129    OSStatus err = ATSFontFindFromContainer(container, kATSOptionFlagsDefault, 0, 0, &fontCount);
130    if (err != noErr || fontCount < 1)
131        return;
132
133    // For now always assume that we want the first font in the container.
134    ATSFontFindFromContainer(container, kATSOptionFlagsDefault, 1, &m_atsFontRef, 0);
135
136    if (!m_atsFontRef)
137        return;
138
139    // Cache CGFont representation of the font.
140    m_cgFont.adoptCF(CGFontCreateWithPlatformFont(&m_atsFontRef));
141
142    if (!m_cgFont.get())
143        return;
144
145    // Add ourselves to cache.
146    fontCacheBySrcFontContainerRef().add(m_srcFontContainerRef, this);
147}
148
149// Destructor - Unload font container from memory and remove ourselves
150// from cache.
151MemoryActivatedFont::~MemoryActivatedFont()
152{
153    if (m_cgFont.get()) {
154        // First remove ourselves from the caches.
155        ASSERT(fontCacheBySrcFontContainerRef().contains(m_srcFontContainerRef));
156
157        fontCacheBySrcFontContainerRef().remove(m_srcFontContainerRef);
158
159        // Make sure the CGFont is destroyed before its font container.
160        m_cgFont.releaseRef();
161    }
162
163    if (m_fontContainer != kATSFontContainerRefUnspecified)
164        ATSFontDeactivate(m_fontContainer, 0, kATSOptionFlagsDefault);
165}
166
167// Given an NSFont, try to load a representation of that font into the cgFont
168// parameter.  If loading is blocked by the sandbox, the font may be loaded
169// cross-process.
170// If sandbox loading also fails, a fallback font is loaded.
171//
172// Considerations:
173// * cgFont must be CFRelease()ed by the caller when done.
174//
175// Parameters:
176// * nsFont - The font we wish to load.
177// * fontSize - point size of the font we wish to load.
178// * outNSFont - The font that was actually loaded, may be different from nsFont
179//   if a fallback font was used.
180// * cgFont - on output this contains the CGFontRef corresponding to the NSFont
181//   that was picked in the end.  The caller is responsible for calling
182//   CFRelease() on this parameter when done with it.
183// * fontID - on output, the ID corresponding to nsFont.
184void FontPlatformData::loadFont(NSFont* nsFont, float fontSize, NSFont*& outNSFont, CGFontRef& cgFont)
185{
186    outNSFont = nsFont;
187    cgFont = CTFontCopyGraphicsFont(toCTFontRef(outNSFont), 0);
188    if (OutOfProcessFontLoadingEnabled() && outNSFont && cgFont && isLastResortFont(cgFont)) {
189        // Release old CGFontRef since it points at the LastResort font which we don't want.
190        CFRelease(cgFont);
191        cgFont = 0;
192
193        // Font loading was blocked by the Sandbox.
194        m_inMemoryFont = loadFontFromBrowserProcess(outNSFont);
195        if (m_inMemoryFont.get()) {
196            cgFont = m_inMemoryFont->cgFont();
197
198            // Need to add an extra retain so output semantics of this function
199            // are consistent.
200            CFRetain(cgFont);
201        } else {
202            // If we still can't load the font, then return Times,
203            // rather than the LastResort font.
204            outNSFont = [NSFont fontWithName:@"Times" size:fontSize];
205            cgFont = CTFontCopyGraphicsFont(toCTFontRef(outNSFont), 0);
206        }
207    }
208}
209
210} // namespace WebCore
211