OLD | NEW |
| (Empty) |
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 "core/platform/graphics/mac/MemoryActivatedFont.h" | |
31 | |
32 #import <AppKit/NSFont.h> | |
33 #import "core/platform/graphics/FontPlatformData.h" | |
34 #include "platform/LinkHash.h" | |
35 #import "public/platform/mac/WebSandboxSupport.h" | |
36 #import "public/platform/Platform.h" | |
37 #import "wtf/HashMap.h" | |
38 | |
39 namespace WebCore { | |
40 | |
41 namespace { | |
42 | |
43 typedef HashMap<uint32, MemoryActivatedFont*> FontContainerRefMemoryFontHash; | |
44 typedef HashMap<WTF::String, MemoryActivatedFont*> FontNameMemoryFontHash; | |
45 | |
46 // Caching: | |
47 // | |
48 // Requesting a font from the browser process is expensive and so is | |
49 // "activating" said font. Caching of loaded fonts is complicated by the fact | |
50 // that it's impossible to get a unique identifier for the on-disk font file | |
51 // from inside the sandboxed renderer process. | |
52 // This means that when loading a font we need to round-trip through the browser | |
53 // process in order to get the unique font file identifer which we might already | |
54 // have activated and cached. | |
55 // | |
56 // In order to save as much work as we can, we maintain 2 levels of caching | |
57 // for the font data: | |
58 // 1. A dumb cache keyed by the font name/style (information we can determine | |
59 // from inside the sandbox). | |
60 // 2. A smarter cache keyed by the real "unique font id". | |
61 // | |
62 // In order to perform a lookup in #2 we need to consult with the browser to get | |
63 // us the lookup key. While this doesn't save us the font load, it does save | |
64 // us font activation. | |
65 // | |
66 // It's important to remember that existing FontPlatformData objects are already | |
67 // cached, so a cache miss in the code in this file isn't necessarily so bad. | |
68 | |
69 FontContainerRefMemoryFontHash& fontCacheByFontID() | |
70 { | |
71 DEFINE_STATIC_LOCAL(FontContainerRefMemoryFontHash, srcFontIDCache, ()); | |
72 return srcFontIDCache; | |
73 } | |
74 | |
75 | |
76 FontNameMemoryFontHash& fontCacheByFontName() | |
77 { | |
78 DEFINE_STATIC_LOCAL(FontNameMemoryFontHash, srcFontNameCache, ()); | |
79 return srcFontNameCache; | |
80 } | |
81 | |
82 // Given a font specified by |srcFont|, use the information we can query in | |
83 // the sandbox to construct a key which we hope will be as unique as possible | |
84 // to the containing font file. | |
85 WTF::String hashKeyFromNSFont(NSFont* srcFont) | |
86 { | |
87 NSFontDescriptor* desc = [srcFont fontDescriptor]; | |
88 NSFontSymbolicTraits traits = [desc symbolicTraits]; | |
89 return WTF::String::format("%s %x", [[srcFont fontName] UTF8String], traits)
; | |
90 } | |
91 | |
92 // The only way we can tell that an in-process font has failed to load | |
93 // is if CTFontCopyGraphicsFont() returns the LastResort font. | |
94 bool isLastResortFont(CGFontRef cgFont) | |
95 { | |
96 NSString* fontName = (NSString*)CGFontCopyPostScriptName(cgFont); | |
97 return [fontName isEqualToString:@"LastResort"]; | |
98 } | |
99 | |
100 // Given an in-process font which has failed to load, return a | |
101 // MemoryActivatedFont* corresponding to an in-memory representation of the | |
102 // same font loaded from the browser process. | |
103 // On failure this function returns a PassRefPtr pointing to 0. | |
104 PassRefPtr<MemoryActivatedFont> loadFontFromBrowserProcess(NSFont* nsFont) | |
105 { | |
106 // First try to lookup in our cache with the limited information we have. | |
107 WTF::String hashKey = hashKeyFromNSFont(nsFont); | |
108 RefPtr<MemoryActivatedFont> font(fontCacheByFontName().get(hashKey)); | |
109 if (font) | |
110 return font; | |
111 | |
112 CGFontRef tmpCGFont; | |
113 uint32_t fontID; | |
114 // Send cross-process request to load font. | |
115 blink::WebSandboxSupport* sandboxSupport = blink::Platform::current()->sandb
oxSupport(); | |
116 if (!sandboxSupport) { | |
117 // This function should only be called in response to an error loading a | |
118 // font due to being blocked by the sandbox. | |
119 // This by definition shouldn't happen if there is no sandbox support. | |
120 ASSERT_NOT_REACHED(); | |
121 return 0; | |
122 } | |
123 if (!sandboxSupport->loadFont(nsFont, &tmpCGFont, &fontID)) | |
124 return 0; | |
125 | |
126 RetainPtr<CGFontRef> cgFont(tmpCGFont); | |
127 // Now that we have the fontID from the browser process, we can consult | |
128 // the ID cache. | |
129 font = fontCacheByFontID().get(fontID); | |
130 if (font) | |
131 // FIXME: WebSandboxSupport::loadFont() should consult the id cache | |
132 // before activating the font. | |
133 return font; | |
134 | |
135 return MemoryActivatedFont::create(fontID, nsFont, cgFont.get()); | |
136 } | |
137 | |
138 } // namespace | |
139 | |
140 PassRefPtr<MemoryActivatedFont> MemoryActivatedFont::create(uint32_t fontID, NSF
ont* nsFont, CGFontRef cgFont) | |
141 { | |
142 return adoptRef(new MemoryActivatedFont(fontID, nsFont, cgFont)); | |
143 } | |
144 | |
145 MemoryActivatedFont::MemoryActivatedFont(uint32_t fontID, NSFont* nsFont, CGFont
Ref cgFont) | |
146 : m_cgFont(cgFont) | |
147 , m_fontID(fontID) | |
148 , m_inSandboxHashKey(hashKeyFromNSFont(nsFont)) | |
149 { | |
150 // Add ourselves to caches. | |
151 fontCacheByFontID().add(fontID, this); | |
152 fontCacheByFontName().add(m_inSandboxHashKey, this); | |
153 } | |
154 | |
155 // Destructor - Unload font container from memory and remove ourselves | |
156 // from cache. | |
157 MemoryActivatedFont::~MemoryActivatedFont() | |
158 { | |
159 // First remove ourselves from the caches. | |
160 ASSERT(fontCacheByFontID().contains(m_fontID)); | |
161 ASSERT(fontCacheByFontName().contains(m_inSandboxHashKey)); | |
162 | |
163 fontCacheByFontID().remove(m_fontID); | |
164 fontCacheByFontName().remove(m_inSandboxHashKey); | |
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 or null if loading failed. | |
179 // * cgFont - on output this contains the CGFontRef corresponding to the NSFont | |
180 // that was picked in the end. The caller is responsible for calling | |
181 // CFRelease() on this parameter when done with it. | |
182 // * fontID - on output, the ID corresponding to nsFont. | |
183 void FontPlatformData::loadFont(NSFont* nsFont, float fontSize, NSFont*& outNSFo
nt, CGFontRef& cgFont) | |
184 { | |
185 outNSFont = nsFont; | |
186 cgFont = CTFontCopyGraphicsFont(toCTFontRef(outNSFont), 0); | |
187 if (outNSFont && cgFont && isLastResortFont(cgFont)) { | |
188 // Release old CGFontRef since it points at the LastResort font which we
don't want. | |
189 CFRelease(cgFont); | |
190 cgFont = 0; | |
191 | |
192 // Font loading was blocked by the Sandbox. | |
193 m_inMemoryFont = loadFontFromBrowserProcess(outNSFont); | |
194 if (m_inMemoryFont) { | |
195 cgFont = m_inMemoryFont->cgFont(); | |
196 | |
197 // Need to add an extra retain so output semantics of this function | |
198 // are consistent. | |
199 CFRetain(cgFont); | |
200 } else { | |
201 // If we still can't load the font, set |outNSFont| to null so that
FontPlatformData won't be used. | |
202 outNSFont = 0; | |
203 } | |
204 } | |
205 } | |
206 | |
207 } // namespace WebCore | |
OLD | NEW |