1 /* 2 * Copyright (C) 2007, 2008, 2011 Apple Inc. All rights reserved. 3 * (C) 2007, 2008 Nikolas Zimmermann <zimmermann (at) kde.org> 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "config.h" 28 #include "core/css/CSSFontSelector.h" 29 30 #include "RuntimeEnabledFeatures.h" 31 #include "core/css/CSSFontFace.h" 32 #include "core/css/CSSFontFaceRule.h" 33 #include "core/css/CSSFontFaceSource.h" 34 #include "core/css/CSSSegmentedFontFace.h" 35 #include "core/css/CSSValueList.h" 36 #include "core/css/resolver/StyleResolver.h" 37 #include "core/dom/Document.h" 38 #include "core/fetch/FontResource.h" 39 #include "core/fetch/ResourceFetcher.h" 40 #include "core/loader/FrameLoader.h" 41 #include "core/frame/Frame.h" 42 #include "core/frame/Settings.h" 43 #include "platform/fonts/FontCache.h" 44 #include "platform/fonts/SimpleFontData.h" 45 #include "wtf/text/AtomicString.h" 46 47 using namespace std; 48 49 namespace WebCore { 50 51 FontLoader::FontLoader(ResourceFetcher* resourceFetcher) 52 : m_beginLoadingTimer(this, &FontLoader::beginLoadTimerFired) 53 , m_resourceFetcher(resourceFetcher) 54 { 55 } 56 57 void FontLoader::addFontToBeginLoading(FontResource* fontResource) 58 { 59 if (!m_resourceFetcher || !fontResource->stillNeedsLoad()) 60 return; 61 62 m_fontsToBeginLoading.append(fontResource); 63 // FIXME: Use RequestCountTracker??!! 64 // Increment the request count now, in order to prevent didFinishLoad from being dispatched 65 // after this font has been requested but before it began loading. Balanced by 66 // decrementRequestCount() in beginLoadTimerFired() and in clearDocument(). 67 m_resourceFetcher->incrementRequestCount(fontResource); 68 m_beginLoadingTimer.startOneShot(0); 69 } 70 71 void FontLoader::beginLoadTimerFired(Timer<WebCore::FontLoader>*) 72 { 73 loadPendingFonts(); 74 } 75 76 void FontLoader::loadPendingFonts() 77 { 78 ASSERT(m_resourceFetcher); 79 80 Vector<ResourcePtr<FontResource> > fontsToBeginLoading; 81 fontsToBeginLoading.swap(m_fontsToBeginLoading); 82 83 for (size_t i = 0; i < fontsToBeginLoading.size(); ++i) { 84 fontsToBeginLoading[i]->beginLoadIfNeeded(m_resourceFetcher); 85 // Balances incrementRequestCount() in beginLoadingFontSoon(). 86 m_resourceFetcher->decrementRequestCount(fontsToBeginLoading[i].get()); 87 } 88 } 89 90 void FontLoader::clearResourceFetcher() 91 { 92 if (!m_resourceFetcher) { 93 ASSERT(m_fontsToBeginLoading.isEmpty()); 94 return; 95 } 96 97 m_beginLoadingTimer.stop(); 98 99 for (size_t i = 0; i < m_fontsToBeginLoading.size(); ++i) { 100 // Balances incrementRequestCount() in beginLoadingFontSoon(). 101 m_resourceFetcher->decrementRequestCount(m_fontsToBeginLoading[i].get()); 102 } 103 104 m_fontsToBeginLoading.clear(); 105 m_resourceFetcher = 0; 106 } 107 108 CSSFontSelector::CSSFontSelector(Document* document) 109 : m_document(document) 110 , m_fontLoader(document->fetcher()) 111 , m_genericFontFamilySettings(document->frame()->settings()->genericFontFamilySettings()) 112 { 113 // FIXME: An old comment used to say there was no need to hold a reference to m_document 114 // because "we are guaranteed to be destroyed before the document". But there does not 115 // seem to be any such guarantee. 116 117 ASSERT(m_document); 118 ASSERT(m_document->frame()); 119 FontCache::fontCache()->addClient(this); 120 } 121 122 CSSFontSelector::~CSSFontSelector() 123 { 124 clearDocument(); 125 FontCache::fontCache()->removeClient(this); 126 } 127 128 void CSSFontSelector::registerForInvalidationCallbacks(FontSelectorClient* client) 129 { 130 m_clients.add(client); 131 } 132 133 void CSSFontSelector::unregisterForInvalidationCallbacks(FontSelectorClient* client) 134 { 135 m_clients.remove(client); 136 } 137 138 void CSSFontSelector::dispatchInvalidationCallbacks() 139 { 140 Vector<FontSelectorClient*> clients; 141 copyToVector(m_clients, clients); 142 for (size_t i = 0; i < clients.size(); ++i) 143 clients[i]->fontsNeedUpdate(this); 144 } 145 146 void CSSFontSelector::fontLoaded() 147 { 148 dispatchInvalidationCallbacks(); 149 } 150 151 void CSSFontSelector::fontCacheInvalidated() 152 { 153 dispatchInvalidationCallbacks(); 154 } 155 156 void CSSFontSelector::addFontFaceRule(const StyleRuleFontFace* fontFaceRule, PassRefPtr<CSSFontFace> cssFontFace) 157 { 158 m_cssSegmentedFontFaceCache.add(this, fontFaceRule, cssFontFace); 159 } 160 161 void CSSFontSelector::removeFontFaceRule(const StyleRuleFontFace* fontFaceRule) 162 { 163 m_cssSegmentedFontFaceCache.remove(fontFaceRule); 164 } 165 166 static AtomicString familyNameFromSettings(const GenericFontFamilySettings& settings, const FontDescription& fontDescription, const AtomicString& genericFamilyName) 167 { 168 UScriptCode script = fontDescription.script(); 169 170 #if OS(ANDROID) 171 if (fontDescription.genericFamily() == FontDescription::StandardFamily && !fontDescription.isSpecifiedFont()) 172 return FontCache::getGenericFamilyNameForScript(FontFamilyNames::webkit_standard, script); 173 174 if (genericFamilyName.startsWith("-webkit-")) 175 return FontCache::getGenericFamilyNameForScript(genericFamilyName, script); 176 #else 177 if (fontDescription.genericFamily() == FontDescription::StandardFamily && !fontDescription.isSpecifiedFont()) 178 return settings.standard(script); 179 if (genericFamilyName == FontFamilyNames::webkit_serif) 180 return settings.serif(script); 181 if (genericFamilyName == FontFamilyNames::webkit_sans_serif) 182 return settings.sansSerif(script); 183 if (genericFamilyName == FontFamilyNames::webkit_cursive) 184 return settings.cursive(script); 185 if (genericFamilyName == FontFamilyNames::webkit_fantasy) 186 return settings.fantasy(script); 187 if (genericFamilyName == FontFamilyNames::webkit_monospace) 188 return settings.fixed(script); 189 if (genericFamilyName == FontFamilyNames::webkit_pictograph) 190 return settings.pictograph(script); 191 if (genericFamilyName == FontFamilyNames::webkit_standard) 192 return settings.standard(script); 193 #endif 194 return emptyAtom; 195 } 196 197 PassRefPtr<FontData> CSSFontSelector::getFontData(const FontDescription& fontDescription, const AtomicString& familyName) 198 { 199 if (CSSSegmentedFontFace* face = m_cssSegmentedFontFaceCache.get(fontDescription, familyName)) 200 return face->getFontData(fontDescription); 201 202 // Try to return the correct font based off our settings, in case we were handed the generic font family name. 203 AtomicString settingsFamilyName = familyNameFromSettings(m_genericFontFamilySettings, fontDescription, familyName); 204 if (settingsFamilyName.isEmpty()) 205 return 0; 206 207 return FontCache::fontCache()->getFontData(fontDescription, settingsFamilyName); 208 } 209 210 CSSSegmentedFontFace* CSSFontSelector::getFontFace(const FontDescription& fontDescription, const AtomicString& familyName) 211 { 212 return m_cssSegmentedFontFaceCache.get(fontDescription, familyName); 213 } 214 215 void CSSFontSelector::willUseFontData(const FontDescription& fontDescription, const AtomicString& family) 216 { 217 CSSSegmentedFontFace* face = getFontFace(fontDescription, family); 218 if (face) 219 face->willUseFontData(fontDescription); 220 } 221 222 void CSSFontSelector::clearDocument() 223 { 224 m_fontLoader.clearResourceFetcher(); 225 m_document = 0; 226 } 227 228 void CSSFontSelector::beginLoadingFontSoon(FontResource* font) 229 { 230 m_fontLoader.addFontToBeginLoading(font); 231 } 232 233 void CSSFontSelector::loadPendingFonts() 234 { 235 m_fontLoader.loadPendingFonts(); 236 } 237 238 } 239