diff -r 000000000000 -r 6474c204b198 gfx/thebes/gfxFontInfoLoader.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/thebes/gfxFontInfoLoader.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,238 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "gfxFontInfoLoader.h" +#include "nsCRT.h" +#include "nsIObserverService.h" +#include "nsThreadUtils.h" // for nsRunnable +#include "gfxPlatformFontList.h" + +using namespace mozilla; +using mozilla::services::GetObserverService; + +void +FontInfoData::Load() +{ + TimeStamp start = TimeStamp::Now(); + + uint32_t i, n = mFontFamiliesToLoad.Length(); + mLoadStats.families = n; + for (i = 0; i < n; i++) { + LoadFontFamilyData(mFontFamiliesToLoad[i]); + } + + mLoadTime = TimeStamp::Now() - start; +} + +class FontInfoLoadCompleteEvent : public nsRunnable { + NS_DECL_THREADSAFE_ISUPPORTS + + FontInfoLoadCompleteEvent(FontInfoData *aFontInfo) : + mFontInfo(aFontInfo) + {} + virtual ~FontInfoLoadCompleteEvent() {} + + NS_IMETHOD Run(); + + nsRefPtr mFontInfo; +}; + +class AsyncFontInfoLoader : public nsRunnable { + NS_DECL_THREADSAFE_ISUPPORTS + + AsyncFontInfoLoader(FontInfoData *aFontInfo) : + mFontInfo(aFontInfo) + { + mCompleteEvent = new FontInfoLoadCompleteEvent(aFontInfo); + } + virtual ~AsyncFontInfoLoader() {} + + NS_IMETHOD Run(); + + nsRefPtr mFontInfo; + nsRefPtr mCompleteEvent; +}; + +// runs on main thread after async font info loading is done +nsresult +FontInfoLoadCompleteEvent::Run() +{ + gfxFontInfoLoader *loader = + static_cast(gfxPlatformFontList::PlatformFontList()); + + loader->FinalizeLoader(mFontInfo); + + mFontInfo = nullptr; + return NS_OK; +} + +NS_IMPL_ISUPPORTS(FontInfoLoadCompleteEvent, nsIRunnable); + +// runs on separate thread +nsresult +AsyncFontInfoLoader::Run() +{ + // load platform-specific font info + mFontInfo->Load(); + + // post a completion event that transfer the data to the fontlist + NS_DispatchToMainThread(mCompleteEvent, NS_DISPATCH_NORMAL); + mFontInfo = nullptr; + + return NS_OK; +} + +NS_IMPL_ISUPPORTS(AsyncFontInfoLoader, nsIRunnable); + +NS_IMPL_ISUPPORTS(gfxFontInfoLoader::ShutdownObserver, nsIObserver) + +NS_IMETHODIMP +gfxFontInfoLoader::ShutdownObserver::Observe(nsISupports *aSubject, + const char *aTopic, + const char16_t *someData) +{ + if (!nsCRT::strcmp(aTopic, "quit-application")) { + mLoader->CancelLoader(); + } else { + NS_NOTREACHED("unexpected notification topic"); + } + return NS_OK; +} + +void +gfxFontInfoLoader::StartLoader(uint32_t aDelay, uint32_t aInterval) +{ + mInterval = aInterval; + + // sanity check + if (mState != stateInitial && + mState != stateTimerOff && + mState != stateTimerOnDelay) { + CancelLoader(); + } + + // set up timer + if (!mTimer) { + mTimer = do_CreateInstance("@mozilla.org/timer;1"); + if (!mTimer) { + NS_WARNING("Failure to create font info loader timer"); + return; + } + } + + AddShutdownObserver(); + + // delay? ==> start async thread after a delay + if (aDelay) { + mState = stateTimerOnDelay; + mTimer->InitWithFuncCallback(DelayedStartCallback, this, aDelay, + nsITimer::TYPE_ONE_SHOT); + return; + } + + mFontInfo = CreateFontInfoData(); + + // initialize + InitLoader(); + + // start async load + mState = stateAsyncLoad; + nsresult rv = NS_NewNamedThread("Font Loader", + getter_AddRefs(mFontLoaderThread), + nullptr); + if (NS_FAILED(rv)) { + return; + } + + nsCOMPtr loadEvent = new AsyncFontInfoLoader(mFontInfo); + + mFontLoaderThread->Dispatch(loadEvent, NS_DISPATCH_NORMAL); +} + +void +gfxFontInfoLoader::FinalizeLoader(FontInfoData *aFontInfo) +{ + // avoid loading data if loader has already been canceled + if (mState != stateAsyncLoad) { + return; + } + + mLoadTime = mFontInfo->mLoadTime; + + // try to load all font data immediately + if (LoadFontInfo()) { + CancelLoader(); + return; + } + + // not all work completed ==> run load on interval + mState = stateTimerOnInterval; + mTimer->InitWithFuncCallback(LoadFontInfoCallback, this, mInterval, + nsITimer::TYPE_REPEATING_SLACK); +} + +void +gfxFontInfoLoader::CancelLoader() +{ + if (mState == stateInitial) { + return; + } + mState = stateTimerOff; + if (mTimer) { + mTimer->Cancel(); + mTimer = nullptr; + } + if (mFontLoaderThread) { + mFontLoaderThread->Shutdown(); + mFontLoaderThread = nullptr; + } + RemoveShutdownObserver(); + CleanupLoader(); +} + +void +gfxFontInfoLoader::LoadFontInfoTimerFire() +{ + if (mState == stateTimerOnDelay) { + mState = stateTimerOnInterval; + mTimer->SetDelay(mInterval); + } + + bool done = LoadFontInfo(); + if (done) { + CancelLoader(); + } +} + +gfxFontInfoLoader::~gfxFontInfoLoader() +{ + RemoveShutdownObserver(); +} + +void +gfxFontInfoLoader::AddShutdownObserver() +{ + if (mObserver) { + return; + } + + nsCOMPtr obs = GetObserverService(); + if (obs) { + mObserver = new ShutdownObserver(this); + obs->AddObserver(mObserver, "quit-application", false); + } +} + +void +gfxFontInfoLoader::RemoveShutdownObserver() +{ + if (mObserver) { + nsCOMPtr obs = GetObserverService(); + if (obs) { + obs->RemoveObserver(mObserver, "quit-application"); + mObserver = nullptr; + } + } +}