gfx/thebes/gfxFontInfoLoader.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "gfxFontInfoLoader.h"
     7 #include "nsCRT.h"
     8 #include "nsIObserverService.h"
     9 #include "nsThreadUtils.h"              // for nsRunnable
    10 #include "gfxPlatformFontList.h"
    12 using namespace mozilla;
    13 using mozilla::services::GetObserverService;
    15 void
    16 FontInfoData::Load()
    17 {
    18     TimeStamp start = TimeStamp::Now();
    20     uint32_t i, n = mFontFamiliesToLoad.Length();
    21     mLoadStats.families = n;
    22     for (i = 0; i < n; i++) {
    23         LoadFontFamilyData(mFontFamiliesToLoad[i]);
    24     }
    26     mLoadTime = TimeStamp::Now() - start;
    27 }
    29 class FontInfoLoadCompleteEvent : public nsRunnable {
    30     NS_DECL_THREADSAFE_ISUPPORTS
    32     FontInfoLoadCompleteEvent(FontInfoData *aFontInfo) :
    33         mFontInfo(aFontInfo)
    34     {}
    35     virtual ~FontInfoLoadCompleteEvent() {}
    37     NS_IMETHOD Run();
    39     nsRefPtr<FontInfoData> mFontInfo;
    40 };
    42 class AsyncFontInfoLoader : public nsRunnable {
    43     NS_DECL_THREADSAFE_ISUPPORTS
    45     AsyncFontInfoLoader(FontInfoData *aFontInfo) :
    46         mFontInfo(aFontInfo)
    47     {
    48         mCompleteEvent = new FontInfoLoadCompleteEvent(aFontInfo);
    49     }
    50     virtual ~AsyncFontInfoLoader() {}
    52     NS_IMETHOD Run();
    54     nsRefPtr<FontInfoData> mFontInfo;
    55     nsRefPtr<FontInfoLoadCompleteEvent> mCompleteEvent;
    56 };
    58 // runs on main thread after async font info loading is done
    59 nsresult
    60 FontInfoLoadCompleteEvent::Run()
    61 {
    62     gfxFontInfoLoader *loader =
    63         static_cast<gfxFontInfoLoader*>(gfxPlatformFontList::PlatformFontList());
    65     loader->FinalizeLoader(mFontInfo);
    67     mFontInfo = nullptr;
    68     return NS_OK;
    69 }
    71 NS_IMPL_ISUPPORTS(FontInfoLoadCompleteEvent, nsIRunnable);
    73 // runs on separate thread
    74 nsresult
    75 AsyncFontInfoLoader::Run()
    76 {
    77     // load platform-specific font info
    78     mFontInfo->Load();
    80     // post a completion event that transfer the data to the fontlist
    81     NS_DispatchToMainThread(mCompleteEvent, NS_DISPATCH_NORMAL);
    82     mFontInfo = nullptr;
    84     return NS_OK;
    85 }
    87 NS_IMPL_ISUPPORTS(AsyncFontInfoLoader, nsIRunnable);
    89 NS_IMPL_ISUPPORTS(gfxFontInfoLoader::ShutdownObserver, nsIObserver)
    91 NS_IMETHODIMP
    92 gfxFontInfoLoader::ShutdownObserver::Observe(nsISupports *aSubject,
    93                                              const char *aTopic,
    94                                              const char16_t *someData)
    95 {
    96     if (!nsCRT::strcmp(aTopic, "quit-application")) {
    97         mLoader->CancelLoader();
    98     } else {
    99         NS_NOTREACHED("unexpected notification topic");
   100     }
   101     return NS_OK;
   102 }
   104 void
   105 gfxFontInfoLoader::StartLoader(uint32_t aDelay, uint32_t aInterval)
   106 {
   107     mInterval = aInterval;
   109     // sanity check
   110     if (mState != stateInitial &&
   111         mState != stateTimerOff &&
   112         mState != stateTimerOnDelay) {
   113         CancelLoader();
   114     }
   116     // set up timer
   117     if (!mTimer) {
   118         mTimer = do_CreateInstance("@mozilla.org/timer;1");
   119         if (!mTimer) {
   120             NS_WARNING("Failure to create font info loader timer");
   121             return;
   122         }
   123     }
   125     AddShutdownObserver();
   127     // delay? ==> start async thread after a delay
   128     if (aDelay) {
   129         mState = stateTimerOnDelay;
   130         mTimer->InitWithFuncCallback(DelayedStartCallback, this, aDelay,
   131                                      nsITimer::TYPE_ONE_SHOT);
   132         return;
   133     }
   135     mFontInfo = CreateFontInfoData();
   137     // initialize
   138     InitLoader();
   140     // start async load
   141     mState = stateAsyncLoad;
   142     nsresult rv = NS_NewNamedThread("Font Loader",
   143                                     getter_AddRefs(mFontLoaderThread),
   144                                     nullptr);
   145     if (NS_FAILED(rv)) {
   146         return;
   147     }
   149     nsCOMPtr<nsIRunnable> loadEvent = new AsyncFontInfoLoader(mFontInfo);
   151     mFontLoaderThread->Dispatch(loadEvent, NS_DISPATCH_NORMAL);
   152 }
   154 void
   155 gfxFontInfoLoader::FinalizeLoader(FontInfoData *aFontInfo)
   156 {
   157     // avoid loading data if loader has already been canceled
   158     if (mState != stateAsyncLoad) {
   159         return;
   160     }
   162     mLoadTime = mFontInfo->mLoadTime;
   164     // try to load all font data immediately
   165     if (LoadFontInfo()) {
   166         CancelLoader();
   167         return;
   168     }
   170     // not all work completed ==> run load on interval
   171     mState = stateTimerOnInterval;
   172     mTimer->InitWithFuncCallback(LoadFontInfoCallback, this, mInterval,
   173                                  nsITimer::TYPE_REPEATING_SLACK);
   174 }
   176 void
   177 gfxFontInfoLoader::CancelLoader()
   178 {
   179     if (mState == stateInitial) {
   180         return;
   181     }
   182     mState = stateTimerOff;
   183     if (mTimer) {
   184         mTimer->Cancel();
   185         mTimer = nullptr;
   186     }
   187     if (mFontLoaderThread) {
   188         mFontLoaderThread->Shutdown();
   189         mFontLoaderThread = nullptr;
   190     }
   191     RemoveShutdownObserver();
   192     CleanupLoader();
   193 }
   195 void
   196 gfxFontInfoLoader::LoadFontInfoTimerFire()
   197 {
   198     if (mState == stateTimerOnDelay) {
   199         mState = stateTimerOnInterval;
   200         mTimer->SetDelay(mInterval);
   201     }
   203     bool done = LoadFontInfo();
   204     if (done) {
   205         CancelLoader();
   206     }
   207 }
   209 gfxFontInfoLoader::~gfxFontInfoLoader()
   210 {
   211     RemoveShutdownObserver();
   212 }
   214 void
   215 gfxFontInfoLoader::AddShutdownObserver()
   216 {
   217     if (mObserver) {
   218         return;
   219     }
   221     nsCOMPtr<nsIObserverService> obs = GetObserverService();
   222     if (obs) {
   223         mObserver = new ShutdownObserver(this);
   224         obs->AddObserver(mObserver, "quit-application", false);
   225     }
   226 }
   228 void
   229 gfxFontInfoLoader::RemoveShutdownObserver()
   230 {
   231     if (mObserver) {
   232         nsCOMPtr<nsIObserverService> obs = GetObserverService();
   233         if (obs) {
   234             obs->RemoveObserver(mObserver, "quit-application");
   235             mObserver = nullptr;
   236         }
   237     }
   238 }

mercurial