| OLD | NEW |
| 1 /* | 1 /* |
| 2 * This file is part of the internal font implementation. | 2 * This file is part of the internal font implementation. |
| 3 * | 3 * |
| 4 * Copyright (c) 2010 Google Inc. All rights reserved. | 4 * Copyright (c) 2010 Google Inc. All rights reserved. |
| 5 * | 5 * |
| 6 * This library is free software; you can redistribute it and/or | 6 * This library is free software; you can redistribute it and/or |
| 7 * modify it under the terms of the GNU Library General Public | 7 * modify it under the terms of the GNU Library General Public |
| 8 * License as published by the Free Software Foundation; either | 8 * License as published by the Free Software Foundation; either |
| 9 * version 2 of the License, or (at your option) any later version. | 9 * version 2 of the License, or (at your option) any later version. |
| 10 * | 10 * |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 | 31 |
| 32 #import "../graphics/FontPlatformData.h" | 32 #import "../graphics/FontPlatformData.h" |
| 33 #import "PlatformBridge.h" | 33 #import "PlatformBridge.h" |
| 34 #import <AppKit/NSFont.h> | 34 #import <AppKit/NSFont.h> |
| 35 #import <wtf/HashMap.h> | 35 #import <wtf/HashMap.h> |
| 36 | 36 |
| 37 namespace WebCore { | 37 namespace WebCore { |
| 38 | 38 |
| 39 namespace { | 39 namespace { |
| 40 | 40 |
| 41 typedef HashMap<ATSFontContainerRef, MemoryActivatedFont*> FontContainerRefMemor
yFontHash; | 41 typedef HashMap<uint32, MemoryActivatedFont*> FontContainerRefMemoryFontHash; |
| 42 typedef HashMap<WTF::String, MemoryActivatedFont*> FontNameMemoryFontHash; |
| 42 | 43 |
| 43 // On 10.5, font loading is not blocked by the sandbox and thus there is no | 44 // 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 // need for the cross-process font loading mechanim. |
| 45 // On system versions >=10.6 cross-process font loading is required. | 46 // On system versions >=10.6 cross-process font loading is required. |
| 46 bool OutOfProcessFontLoadingEnabled() | 47 bool OutOfProcessFontLoadingEnabled() |
| 47 { | 48 { |
| 48 static SInt32 systemVersion = 0; | 49 static SInt32 systemVersion = 0; |
| 49 if (!systemVersion) { | 50 if (!systemVersion) { |
| 50 if (Gestalt(gestaltSystemVersion, &systemVersion) != noErr) | 51 if (Gestalt(gestaltSystemVersion, &systemVersion) != noErr) |
| 51 return false; | 52 return false; |
| 52 } | 53 } |
| 53 | 54 |
| 54 return systemVersion >= 0x1060; | 55 return systemVersion >= 0x1060; |
| 55 } | 56 } |
| 56 | 57 |
| 57 FontContainerRefMemoryFontHash& fontCacheBySrcFontContainerRef() | 58 // Caching: |
| 59 // |
| 60 // Requesting a font from the browser process is expensive and so is |
| 61 // "activating" said font. Caching of loaded fonts is complicated by the fact |
| 62 // that it's impossible to get a unique identifier for the on-disk font file |
| 63 // from inside the sandboxed renderer process. |
| 64 // This means that when loading a font we need to round-trip through the browser |
| 65 // process in order to get the unique font file identifer which we might already |
| 66 // have activated and cached. |
| 67 // |
| 68 // In order to save as much work as we can, we maintain 2 levels of caching |
| 69 // for the font data: |
| 70 // 1. A dumb cache keyed by the font name/style (information we can determine |
| 71 // from inside the sandbox). |
| 72 // 2. A smarter cache keyed by the real "unique font id". |
| 73 // |
| 74 // In order to perform a lookup in #2 we need to consult with the browser to get |
| 75 // us the lookup key. While this doesn't save us the font load, it does save |
| 76 // us font activation. |
| 77 // |
| 78 // It's important to remember that existing FontPlatformData objects are already |
| 79 // cached, so a cache miss in the code in this file isn't necessarily so bad. |
| 80 |
| 81 FontContainerRefMemoryFontHash& fontCacheByFontID() |
| 58 { | 82 { |
| 59 DEFINE_STATIC_LOCAL(FontContainerRefMemoryFontHash, srcFontRefCache, ()); | 83 DEFINE_STATIC_LOCAL(FontContainerRefMemoryFontHash, srcFontIDCache, ()); |
| 60 return srcFontRefCache; | 84 return srcFontIDCache; |
| 85 } |
| 86 |
| 87 |
| 88 FontNameMemoryFontHash& fontCacheByFontName() |
| 89 { |
| 90 DEFINE_STATIC_LOCAL(FontNameMemoryFontHash, srcFontNameCache, ()); |
| 91 return srcFontNameCache; |
| 92 } |
| 93 |
| 94 // Given a font specified by |srcFont|, use the information we can query in |
| 95 // the sandbox to construct a key which we hope will be as unique as possible |
| 96 // to the containing font file. |
| 97 WTF::String hashKeyFromNSFont(NSFont* srcFont) |
| 98 { |
| 99 NSFontDescriptor* desc = [srcFont fontDescriptor]; |
| 100 NSFontSymbolicTraits traits = [desc symbolicTraits]; |
| 101 return WTF::String::format("%s %x", [[srcFont fontName] UTF8String], traits)
; |
| 61 } | 102 } |
| 62 | 103 |
| 63 ATSFontContainerRef fontContainerRefFromNSFont(NSFont* srcFont) | 104 ATSFontContainerRef fontContainerRefFromNSFont(NSFont* srcFont) |
| 64 { | 105 { |
| 65 ATSFontRef fontRef = CTFontGetPlatformFont(toCTFontRef(srcFont), 0); | 106 ATSFontRef fontRef = CTFontGetPlatformFont(toCTFontRef(srcFont), 0); |
| 66 if (!fontRef) | 107 if (!fontRef) |
| 67 return kATSFontContainerRefUnspecified; | 108 return kATSFontContainerRefUnspecified; |
| 68 ATSFontContainerRef fontContainer = kATSFontContainerRefUnspecified; | 109 ATSFontContainerRef fontContainer = kATSFontContainerRefUnspecified; |
| 69 if (ATSFontGetContainer(fontRef, 0, &fontContainer) != noErr) | 110 if (ATSFontGetContainer(fontRef, 0, &fontContainer) != noErr) |
| 70 return kATSFontContainerRefUnspecified; | 111 return kATSFontContainerRefUnspecified; |
| 71 return fontContainer; | 112 return fontContainer; |
| 72 } | 113 } |
| 73 | 114 |
| 74 // The only way we can tell that an in-process font has failed to load | 115 // The only way we can tell that an in-process font has failed to load |
| 75 // is if CTFontCopyGraphicsFont() returns the LastResort font. | 116 // is if CTFontCopyGraphicsFont() returns the LastResort font. |
| 76 bool isLastResortFont(CGFontRef cgFont) | 117 bool isLastResortFont(CGFontRef cgFont) |
| 77 { | 118 { |
| 78 NSString* fontName = (NSString*)CGFontCopyPostScriptName(cgFont); | 119 NSString* fontName = (NSString*)CGFontCopyPostScriptName(cgFont); |
| 79 return [fontName isEqualToString:@"LastResort"]; | 120 return [fontName isEqualToString:@"LastResort"]; |
| 80 } | 121 } |
| 81 | 122 |
| 82 // Given an in-process font which has failed to load, return a | 123 // Given an in-process font which has failed to load, return a |
| 83 // MemoryActivatedFont* corresponding to an in-memory representation of the | 124 // MemoryActivatedFont* corresponding to an in-memory representation of the |
| 84 // same font loaded from the browser process. | 125 // same font loaded from the browser process. |
| 85 // On failure this function returns a PassRefPtr pointing to 0. | 126 // On failure this function returns a PassRefPtr pointing to 0. |
| 86 PassRefPtr<MemoryActivatedFont> loadFontFromBrowserProcess(NSFont* nsFont) | 127 PassRefPtr<MemoryActivatedFont> loadFontFromBrowserProcess(NSFont* nsFont) |
| 87 { | 128 { |
| 88 ATSFontContainerRef container; | 129 // First try to lookup in our cache with the limited information we have. |
| 89 // Send cross-process request to load font. | 130 WTF::String hashKey = hashKeyFromNSFont(nsFont); |
| 90 if (!PlatformBridge::loadFont(nsFont, &container)) | 131 RefPtr<MemoryActivatedFont> font(fontCacheByFontName().get(hashKey)); |
| 91 return 0; | 132 if (font) |
| 92 | |
| 93 ATSFontContainerRef srcFontContainerRef = fontContainerRefFromNSFont(nsFont)
; | |
| 94 if (!srcFontContainerRef) { | |
| 95 ATSFontDeactivate(container, 0, kATSOptionFlagsDefault); | |
| 96 return 0; | |
| 97 } | |
| 98 | |
| 99 PassRefPtr<MemoryActivatedFont> font = adoptRef(fontCacheBySrcFontContainerR
ef().get(srcFontContainerRef)); | |
| 100 if (font.get()) | |
| 101 return font; | 133 return font; |
| 102 | 134 |
| 103 return MemoryActivatedFont::create(srcFontContainerRef, container); | 135 ATSFontContainerRef container; |
| 136 uint32_t fontID; |
| 137 // Send cross-process request to load font. |
| 138 if (!PlatformBridge::loadFont(nsFont, &container, &fontID)) |
| 139 return 0; |
| 140 |
| 141 // Now that we have the fontID from the browser process, we can consult |
| 142 // the ID cache. |
| 143 font = fontCacheByFontID().get(fontID); |
| 144 if (font) { |
| 145 // We can safely discard the new container since we already have the |
| 146 // font in our cache. |
| 147 // FIXME: PlatformBridge::loadFont() should consult the id cache |
| 148 // before activating the font. Then we can save this activate/deactive |
| 149 // dance altogether. |
| 150 ATSFontDeactivate(container, 0, kATSOptionFlagsDefault); |
| 151 return font; |
| 152 } |
| 153 |
| 154 return MemoryActivatedFont::create(fontID, nsFont, container); |
| 104 } | 155 } |
| 105 | 156 |
| 106 } // namespace | 157 } // namespace |
| 107 | 158 |
| 108 PassRefPtr<MemoryActivatedFont> MemoryActivatedFont::create(ATSFontContainerRef
srcFontContainerRef, ATSFontContainerRef container) | 159 PassRefPtr<MemoryActivatedFont> MemoryActivatedFont::create(uint32_t fontID, NSF
ont* nsFont, ATSFontContainerRef container) |
| 109 { | 160 { |
| 110 MemoryActivatedFont* font = new MemoryActivatedFont(srcFontContainerRef, conta
iner); | 161 MemoryActivatedFont* font = new MemoryActivatedFont(fontID, nsFont, container)
; |
| 111 if (!font->cgFont()) // Object construction failed. | 162 if (!font->cgFont()) // Object construction failed. |
| 112 { | 163 { |
| 113 delete font; | 164 delete font; |
| 114 return 0; | 165 return 0; |
| 115 } | 166 } |
| 116 return adoptRef(font); | 167 return adoptRef(font); |
| 117 } | 168 } |
| 118 | 169 |
| 119 MemoryActivatedFont::MemoryActivatedFont(ATSFontContainerRef srcFontContainerRef
, ATSFontContainerRef container) | 170 MemoryActivatedFont::MemoryActivatedFont(uint32_t fontID, NSFont* nsFont, ATSFon
tContainerRef container) |
| 120 : m_fontContainer(container) | 171 : m_fontContainer(container) |
| 121 , m_atsFontRef(kATSFontRefUnspecified) | 172 , m_atsFontRef(kATSFontRefUnspecified) |
| 122 , m_srcFontContainerRef(srcFontContainerRef) | 173 , m_fontID(fontID) |
| 174 , m_inSandboxHashKey(hashKeyFromNSFont(nsFont)) |
| 123 { | 175 { |
| 124 if (!container) | 176 if (!container) |
| 125 return; | 177 return; |
| 126 | 178 |
| 127 // Count the number of fonts in the container. | 179 // Count the number of fonts in the container. |
| 128 ItemCount fontCount = 0; | 180 ItemCount fontCount = 0; |
| 129 OSStatus err = ATSFontFindFromContainer(container, kATSOptionFlagsDefault, 0
, 0, &fontCount); | 181 OSStatus err = ATSFontFindFromContainer(container, kATSOptionFlagsDefault, 0
, 0, &fontCount); |
| 130 if (err != noErr || fontCount < 1) | 182 if (err != noErr || fontCount < 1) |
| 131 return; | 183 return; |
| 132 | 184 |
| 133 // For now always assume that we want the first font in the container. | 185 // For now always assume that we want the first font in the container. |
| 134 ATSFontFindFromContainer(container, kATSOptionFlagsDefault, 1, &m_atsFontRef
, 0); | 186 ATSFontFindFromContainer(container, kATSOptionFlagsDefault, 1, &m_atsFontRef
, 0); |
| 135 | 187 |
| 136 if (!m_atsFontRef) | 188 if (!m_atsFontRef) |
| 137 return; | 189 return; |
| 138 | 190 |
| 139 // Cache CGFont representation of the font. | 191 // Cache CGFont representation of the font. |
| 140 m_cgFont.adoptCF(CGFontCreateWithPlatformFont(&m_atsFontRef)); | 192 m_cgFont.adoptCF(CGFontCreateWithPlatformFont(&m_atsFontRef)); |
| 141 | 193 |
| 142 if (!m_cgFont.get()) | 194 if (!m_cgFont) |
| 143 return; | 195 return; |
| 144 | 196 |
| 145 // Add ourselves to cache. | 197 // Add ourselves to caches. |
| 146 fontCacheBySrcFontContainerRef().add(m_srcFontContainerRef, this); | 198 fontCacheByFontID().add(fontID, this); |
| 199 fontCacheByFontName().add(m_inSandboxHashKey, this); |
| 147 } | 200 } |
| 148 | 201 |
| 149 // Destructor - Unload font container from memory and remove ourselves | 202 // Destructor - Unload font container from memory and remove ourselves |
| 150 // from cache. | 203 // from cache. |
| 151 MemoryActivatedFont::~MemoryActivatedFont() | 204 MemoryActivatedFont::~MemoryActivatedFont() |
| 152 { | 205 { |
| 153 if (m_cgFont.get()) { | 206 if (m_cgFont) { |
| 154 // First remove ourselves from the caches. | 207 // First remove ourselves from the caches. |
| 155 ASSERT(fontCacheBySrcFontContainerRef().contains(m_srcFontContainerRef))
; | 208 ASSERT(fontCacheByFontID().contains(m_fontID)); |
| 209 ASSERT(fontCacheByFontName().contains(m_inSandboxHashKey)); |
| 156 | 210 |
| 157 fontCacheBySrcFontContainerRef().remove(m_srcFontContainerRef); | 211 fontCacheByFontID().remove(m_fontID); |
| 212 fontCacheByFontName().remove(m_inSandboxHashKey); |
| 158 | 213 |
| 159 // Make sure the CGFont is destroyed before its font container. | 214 // Make sure the CGFont is destroyed before its font container. |
| 160 m_cgFont.releaseRef(); | 215 m_cgFont.releaseRef(); |
| 161 } | 216 } |
| 162 | 217 |
| 163 if (m_fontContainer != kATSFontContainerRefUnspecified) | 218 if (m_fontContainer != kATSFontContainerRefUnspecified) |
| 164 ATSFontDeactivate(m_fontContainer, 0, kATSOptionFlagsDefault); | 219 ATSFontDeactivate(m_fontContainer, 0, kATSOptionFlagsDefault); |
| 165 } | 220 } |
| 166 | 221 |
| 167 // Given an NSFont, try to load a representation of that font into the cgFont | 222 // Given an NSFont, try to load a representation of that font into the cgFont |
| (...skipping 17 matching lines...) Expand all Loading... |
| 185 { | 240 { |
| 186 outNSFont = nsFont; | 241 outNSFont = nsFont; |
| 187 cgFont = CTFontCopyGraphicsFont(toCTFontRef(outNSFont), 0); | 242 cgFont = CTFontCopyGraphicsFont(toCTFontRef(outNSFont), 0); |
| 188 if (OutOfProcessFontLoadingEnabled() && outNSFont && cgFont && isLastResortF
ont(cgFont)) { | 243 if (OutOfProcessFontLoadingEnabled() && outNSFont && cgFont && isLastResortF
ont(cgFont)) { |
| 189 // Release old CGFontRef since it points at the LastResort font which we
don't want. | 244 // Release old CGFontRef since it points at the LastResort font which we
don't want. |
| 190 CFRelease(cgFont); | 245 CFRelease(cgFont); |
| 191 cgFont = 0; | 246 cgFont = 0; |
| 192 | 247 |
| 193 // Font loading was blocked by the Sandbox. | 248 // Font loading was blocked by the Sandbox. |
| 194 m_inMemoryFont = loadFontFromBrowserProcess(outNSFont); | 249 m_inMemoryFont = loadFontFromBrowserProcess(outNSFont); |
| 195 if (m_inMemoryFont.get()) { | 250 if (m_inMemoryFont) { |
| 196 cgFont = m_inMemoryFont->cgFont(); | 251 cgFont = m_inMemoryFont->cgFont(); |
| 197 | 252 |
| 198 // Need to add an extra retain so output semantics of this function | 253 // Need to add an extra retain so output semantics of this function |
| 199 // are consistent. | 254 // are consistent. |
| 200 CFRetain(cgFont); | 255 CFRetain(cgFont); |
| 201 } else { | 256 } else { |
| 202 // If we still can't load the font, then return Times, | 257 // If we still can't load the font, then return Times, |
| 203 // rather than the LastResort font. | 258 // rather than the LastResort font. |
| 204 outNSFont = [NSFont fontWithName:@"Times" size:fontSize]; | 259 outNSFont = [NSFont fontWithName:@"Times" size:fontSize]; |
| 205 cgFont = CTFontCopyGraphicsFont(toCTFontRef(outNSFont), 0); | 260 cgFont = CTFontCopyGraphicsFont(toCTFontRef(outNSFont), 0); |
| 206 } | 261 } |
| 207 } | 262 } |
| 208 } | 263 } |
| 209 | 264 |
| 210 } // namespace WebCore | 265 } // namespace WebCore |
| OLD | NEW |