| 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 | 
|---|