1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/thebes/gfxFontInfoLoader.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,238 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "gfxFontInfoLoader.h" 1.10 +#include "nsCRT.h" 1.11 +#include "nsIObserverService.h" 1.12 +#include "nsThreadUtils.h" // for nsRunnable 1.13 +#include "gfxPlatformFontList.h" 1.14 + 1.15 +using namespace mozilla; 1.16 +using mozilla::services::GetObserverService; 1.17 + 1.18 +void 1.19 +FontInfoData::Load() 1.20 +{ 1.21 + TimeStamp start = TimeStamp::Now(); 1.22 + 1.23 + uint32_t i, n = mFontFamiliesToLoad.Length(); 1.24 + mLoadStats.families = n; 1.25 + for (i = 0; i < n; i++) { 1.26 + LoadFontFamilyData(mFontFamiliesToLoad[i]); 1.27 + } 1.28 + 1.29 + mLoadTime = TimeStamp::Now() - start; 1.30 +} 1.31 + 1.32 +class FontInfoLoadCompleteEvent : public nsRunnable { 1.33 + NS_DECL_THREADSAFE_ISUPPORTS 1.34 + 1.35 + FontInfoLoadCompleteEvent(FontInfoData *aFontInfo) : 1.36 + mFontInfo(aFontInfo) 1.37 + {} 1.38 + virtual ~FontInfoLoadCompleteEvent() {} 1.39 + 1.40 + NS_IMETHOD Run(); 1.41 + 1.42 + nsRefPtr<FontInfoData> mFontInfo; 1.43 +}; 1.44 + 1.45 +class AsyncFontInfoLoader : public nsRunnable { 1.46 + NS_DECL_THREADSAFE_ISUPPORTS 1.47 + 1.48 + AsyncFontInfoLoader(FontInfoData *aFontInfo) : 1.49 + mFontInfo(aFontInfo) 1.50 + { 1.51 + mCompleteEvent = new FontInfoLoadCompleteEvent(aFontInfo); 1.52 + } 1.53 + virtual ~AsyncFontInfoLoader() {} 1.54 + 1.55 + NS_IMETHOD Run(); 1.56 + 1.57 + nsRefPtr<FontInfoData> mFontInfo; 1.58 + nsRefPtr<FontInfoLoadCompleteEvent> mCompleteEvent; 1.59 +}; 1.60 + 1.61 +// runs on main thread after async font info loading is done 1.62 +nsresult 1.63 +FontInfoLoadCompleteEvent::Run() 1.64 +{ 1.65 + gfxFontInfoLoader *loader = 1.66 + static_cast<gfxFontInfoLoader*>(gfxPlatformFontList::PlatformFontList()); 1.67 + 1.68 + loader->FinalizeLoader(mFontInfo); 1.69 + 1.70 + mFontInfo = nullptr; 1.71 + return NS_OK; 1.72 +} 1.73 + 1.74 +NS_IMPL_ISUPPORTS(FontInfoLoadCompleteEvent, nsIRunnable); 1.75 + 1.76 +// runs on separate thread 1.77 +nsresult 1.78 +AsyncFontInfoLoader::Run() 1.79 +{ 1.80 + // load platform-specific font info 1.81 + mFontInfo->Load(); 1.82 + 1.83 + // post a completion event that transfer the data to the fontlist 1.84 + NS_DispatchToMainThread(mCompleteEvent, NS_DISPATCH_NORMAL); 1.85 + mFontInfo = nullptr; 1.86 + 1.87 + return NS_OK; 1.88 +} 1.89 + 1.90 +NS_IMPL_ISUPPORTS(AsyncFontInfoLoader, nsIRunnable); 1.91 + 1.92 +NS_IMPL_ISUPPORTS(gfxFontInfoLoader::ShutdownObserver, nsIObserver) 1.93 + 1.94 +NS_IMETHODIMP 1.95 +gfxFontInfoLoader::ShutdownObserver::Observe(nsISupports *aSubject, 1.96 + const char *aTopic, 1.97 + const char16_t *someData) 1.98 +{ 1.99 + if (!nsCRT::strcmp(aTopic, "quit-application")) { 1.100 + mLoader->CancelLoader(); 1.101 + } else { 1.102 + NS_NOTREACHED("unexpected notification topic"); 1.103 + } 1.104 + return NS_OK; 1.105 +} 1.106 + 1.107 +void 1.108 +gfxFontInfoLoader::StartLoader(uint32_t aDelay, uint32_t aInterval) 1.109 +{ 1.110 + mInterval = aInterval; 1.111 + 1.112 + // sanity check 1.113 + if (mState != stateInitial && 1.114 + mState != stateTimerOff && 1.115 + mState != stateTimerOnDelay) { 1.116 + CancelLoader(); 1.117 + } 1.118 + 1.119 + // set up timer 1.120 + if (!mTimer) { 1.121 + mTimer = do_CreateInstance("@mozilla.org/timer;1"); 1.122 + if (!mTimer) { 1.123 + NS_WARNING("Failure to create font info loader timer"); 1.124 + return; 1.125 + } 1.126 + } 1.127 + 1.128 + AddShutdownObserver(); 1.129 + 1.130 + // delay? ==> start async thread after a delay 1.131 + if (aDelay) { 1.132 + mState = stateTimerOnDelay; 1.133 + mTimer->InitWithFuncCallback(DelayedStartCallback, this, aDelay, 1.134 + nsITimer::TYPE_ONE_SHOT); 1.135 + return; 1.136 + } 1.137 + 1.138 + mFontInfo = CreateFontInfoData(); 1.139 + 1.140 + // initialize 1.141 + InitLoader(); 1.142 + 1.143 + // start async load 1.144 + mState = stateAsyncLoad; 1.145 + nsresult rv = NS_NewNamedThread("Font Loader", 1.146 + getter_AddRefs(mFontLoaderThread), 1.147 + nullptr); 1.148 + if (NS_FAILED(rv)) { 1.149 + return; 1.150 + } 1.151 + 1.152 + nsCOMPtr<nsIRunnable> loadEvent = new AsyncFontInfoLoader(mFontInfo); 1.153 + 1.154 + mFontLoaderThread->Dispatch(loadEvent, NS_DISPATCH_NORMAL); 1.155 +} 1.156 + 1.157 +void 1.158 +gfxFontInfoLoader::FinalizeLoader(FontInfoData *aFontInfo) 1.159 +{ 1.160 + // avoid loading data if loader has already been canceled 1.161 + if (mState != stateAsyncLoad) { 1.162 + return; 1.163 + } 1.164 + 1.165 + mLoadTime = mFontInfo->mLoadTime; 1.166 + 1.167 + // try to load all font data immediately 1.168 + if (LoadFontInfo()) { 1.169 + CancelLoader(); 1.170 + return; 1.171 + } 1.172 + 1.173 + // not all work completed ==> run load on interval 1.174 + mState = stateTimerOnInterval; 1.175 + mTimer->InitWithFuncCallback(LoadFontInfoCallback, this, mInterval, 1.176 + nsITimer::TYPE_REPEATING_SLACK); 1.177 +} 1.178 + 1.179 +void 1.180 +gfxFontInfoLoader::CancelLoader() 1.181 +{ 1.182 + if (mState == stateInitial) { 1.183 + return; 1.184 + } 1.185 + mState = stateTimerOff; 1.186 + if (mTimer) { 1.187 + mTimer->Cancel(); 1.188 + mTimer = nullptr; 1.189 + } 1.190 + if (mFontLoaderThread) { 1.191 + mFontLoaderThread->Shutdown(); 1.192 + mFontLoaderThread = nullptr; 1.193 + } 1.194 + RemoveShutdownObserver(); 1.195 + CleanupLoader(); 1.196 +} 1.197 + 1.198 +void 1.199 +gfxFontInfoLoader::LoadFontInfoTimerFire() 1.200 +{ 1.201 + if (mState == stateTimerOnDelay) { 1.202 + mState = stateTimerOnInterval; 1.203 + mTimer->SetDelay(mInterval); 1.204 + } 1.205 + 1.206 + bool done = LoadFontInfo(); 1.207 + if (done) { 1.208 + CancelLoader(); 1.209 + } 1.210 +} 1.211 + 1.212 +gfxFontInfoLoader::~gfxFontInfoLoader() 1.213 +{ 1.214 + RemoveShutdownObserver(); 1.215 +} 1.216 + 1.217 +void 1.218 +gfxFontInfoLoader::AddShutdownObserver() 1.219 +{ 1.220 + if (mObserver) { 1.221 + return; 1.222 + } 1.223 + 1.224 + nsCOMPtr<nsIObserverService> obs = GetObserverService(); 1.225 + if (obs) { 1.226 + mObserver = new ShutdownObserver(this); 1.227 + obs->AddObserver(mObserver, "quit-application", false); 1.228 + } 1.229 +} 1.230 + 1.231 +void 1.232 +gfxFontInfoLoader::RemoveShutdownObserver() 1.233 +{ 1.234 + if (mObserver) { 1.235 + nsCOMPtr<nsIObserverService> obs = GetObserverService(); 1.236 + if (obs) { 1.237 + obs->RemoveObserver(mObserver, "quit-application"); 1.238 + mObserver = nullptr; 1.239 + } 1.240 + } 1.241 +}