diff options
Diffstat (limited to 'gfx/thebes/gfxFontInfoLoader.cpp')
-rw-r--r-- | gfx/thebes/gfxFontInfoLoader.cpp | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/gfx/thebes/gfxFontInfoLoader.cpp b/gfx/thebes/gfxFontInfoLoader.cpp new file mode 100644 index 000000000..a53c96369 --- /dev/null +++ b/gfx/thebes/gfxFontInfoLoader.cpp @@ -0,0 +1,281 @@ +/* -*- 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 services::GetObserverService; + +#define LOG_FONTINIT(args) MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontinit), \ + LogLevel::Debug, args) +#define LOG_FONTINIT_ENABLED() MOZ_LOG_TEST( \ + gfxPlatform::GetLog(eGfxLog_fontinit), \ + LogLevel::Debug) + +void +FontInfoData::Load() +{ + TimeStamp start = TimeStamp::Now(); + + uint32_t i, n = mFontFamiliesToLoad.Length(); + mLoadStats.families = n; + for (i = 0; i < n && !mCanceled; i++) { + // font file memory mapping sometimes causes exceptions - bug 1100949 + MOZ_SEH_TRY { + LoadFontFamilyData(mFontFamiliesToLoad[i]); + } MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + gfxCriticalError() << + "Exception occurred reading font data for " << + NS_ConvertUTF16toUTF8(mFontFamiliesToLoad[i]).get(); + } + } + + mLoadTime = TimeStamp::Now() - start; +} + +class FontInfoLoadCompleteEvent : public Runnable { + virtual ~FontInfoLoadCompleteEvent() {} + + NS_DECL_ISUPPORTS_INHERITED + + explicit FontInfoLoadCompleteEvent(FontInfoData *aFontInfo) : + mFontInfo(aFontInfo) + {} + + NS_IMETHOD Run() override; + + RefPtr<FontInfoData> mFontInfo; +}; + +class AsyncFontInfoLoader : public Runnable { + virtual ~AsyncFontInfoLoader() {} + + NS_DECL_ISUPPORTS_INHERITED + + explicit AsyncFontInfoLoader(FontInfoData *aFontInfo) : + mFontInfo(aFontInfo) + { + mCompleteEvent = new FontInfoLoadCompleteEvent(aFontInfo); + } + + NS_IMETHOD Run() override; + + RefPtr<FontInfoData> mFontInfo; + RefPtr<FontInfoLoadCompleteEvent> mCompleteEvent; +}; + +class ShutdownThreadEvent : public Runnable { + virtual ~ShutdownThreadEvent() {} + + NS_DECL_ISUPPORTS_INHERITED + + explicit ShutdownThreadEvent(nsIThread* aThread) : mThread(aThread) {} + NS_IMETHOD Run() override { + mThread->Shutdown(); + return NS_OK; + } + nsCOMPtr<nsIThread> mThread; +}; + +NS_IMPL_ISUPPORTS_INHERITED0(ShutdownThreadEvent, Runnable); + +// runs on main thread after async font info loading is done +nsresult +FontInfoLoadCompleteEvent::Run() +{ + gfxFontInfoLoader *loader = + static_cast<gfxFontInfoLoader*>(gfxPlatformFontList::PlatformFontList()); + + loader->FinalizeLoader(mFontInfo); + + return NS_OK; +} + +NS_IMPL_ISUPPORTS_INHERITED0(FontInfoLoadCompleteEvent, Runnable); + +// 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); + + return NS_OK; +} + +NS_IMPL_ISUPPORTS_INHERITED0(AsyncFontInfoLoader, Runnable); + +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; + + NS_ASSERTION(!mFontInfo, + "fontinfo should be null when starting font loader"); + + // 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 + nsresult rv = NS_NewNamedThread("Font Loader", + getter_AddRefs(mFontLoaderThread), + nullptr); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + mState = stateAsyncLoad; + + nsCOMPtr<nsIRunnable> loadEvent = new AsyncFontInfoLoader(mFontInfo); + + mFontLoaderThread->Dispatch(loadEvent.forget(), NS_DISPATCH_NORMAL); + + if (LOG_FONTINIT_ENABLED()) { + LOG_FONTINIT(("(fontinit) fontloader started (fontinfo: %p)\n", + mFontInfo.get())); + } +} + +void +gfxFontInfoLoader::FinalizeLoader(FontInfoData *aFontInfo) +{ + // Avoid loading data if loader has already been canceled. + // This should mean that CancelLoader() ran and the Load + // thread has already Shutdown(), and likely before processing + // the Shutdown event it handled the load event and sent back + // our Completion event, thus we end up here. + if (mState != stateAsyncLoad || mFontInfo != aFontInfo) { + 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 (mFontInfo) // null during any initial delay + mFontInfo->mCanceled = true; + if (mFontLoaderThread) { + NS_DispatchToMainThread(new ShutdownThreadEvent(mFontLoaderThread)); + mFontLoaderThread = nullptr; + } + RemoveShutdownObserver(); + CleanupLoader(); +} + +void +gfxFontInfoLoader::LoadFontInfoTimerFire() +{ + if (mState == stateTimerOnDelay) { + mState = stateTimerOnInterval; + mTimer->SetDelay(mInterval); + } + + bool done = LoadFontInfo(); + if (done) { + CancelLoader(); + } +} + +gfxFontInfoLoader::~gfxFontInfoLoader() +{ + RemoveShutdownObserver(); + MOZ_COUNT_DTOR(gfxFontInfoLoader); +} + +void +gfxFontInfoLoader::AddShutdownObserver() +{ + if (mObserver) { + return; + } + + nsCOMPtr<nsIObserverService> obs = GetObserverService(); + if (obs) { + mObserver = new ShutdownObserver(this); + obs->AddObserver(mObserver, "quit-application", false); + } +} + +void +gfxFontInfoLoader::RemoveShutdownObserver() +{ + if (mObserver) { + nsCOMPtr<nsIObserverService> obs = GetObserverService(); + if (obs) { + obs->RemoveObserver(mObserver, "quit-application"); + mObserver = nullptr; + } + } +} |