tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

FontFaceSetWorkerImpl.cpp (12080B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "FontFaceSetWorkerImpl.h"
      8 
      9 #include "mozilla/FontLoaderUtils.h"
     10 #include "mozilla/LoadInfo.h"
     11 #include "mozilla/dom/WorkerPrivate.h"
     12 #include "mozilla/dom/WorkerRef.h"
     13 #include "mozilla/dom/WorkerRunnable.h"
     14 #include "nsContentPolicyUtils.h"
     15 #include "nsFontFaceLoader.h"
     16 #include "nsIWebNavigation.h"
     17 
     18 using namespace mozilla;
     19 using namespace mozilla::css;
     20 
     21 namespace mozilla::dom {
     22 
     23 #define LOG(...)                                                       \
     24  MOZ_LOG(gfxUserFontSet::GetUserFontsLog(), mozilla::LogLevel::Debug, \
     25          (__VA_ARGS__))
     26 #define LOG_ENABLED() \
     27  MOZ_LOG_TEST(gfxUserFontSet::GetUserFontsLog(), LogLevel::Debug)
     28 
     29 NS_IMPL_ISUPPORTS_INHERITED0(FontFaceSetWorkerImpl, FontFaceSetImpl);
     30 
     31 FontFaceSetWorkerImpl::FontFaceSetWorkerImpl(FontFaceSet* aOwner)
     32    : FontFaceSetImpl(aOwner) {}
     33 
     34 FontFaceSetWorkerImpl::~FontFaceSetWorkerImpl() = default;
     35 
     36 bool FontFaceSetWorkerImpl::Initialize(WorkerPrivate* aWorkerPrivate) {
     37  MOZ_ASSERT(aWorkerPrivate);
     38 
     39  RefPtr<StrongWorkerRef> workerRef =
     40      StrongWorkerRef::Create(aWorkerPrivate, "FontFaceSetWorkerImpl",
     41                              [self = RefPtr{this}] { self->Destroy(); });
     42  if (NS_WARN_IF(!workerRef)) {
     43    return false;
     44  }
     45 
     46  {
     47    RecursiveMutexAutoLock lock(mMutex);
     48    mWorkerRef = new ThreadSafeWorkerRef(workerRef);
     49  }
     50 
     51  class InitRunnable final : public WorkerMainThreadRunnable {
     52   public:
     53    InitRunnable(WorkerPrivate* aWorkerPrivate, FontFaceSetWorkerImpl* aImpl)
     54        : WorkerMainThreadRunnable(aWorkerPrivate,
     55                                   "FontFaceSetWorkerImpl :: Initialize"_ns),
     56          mImpl(aImpl) {}
     57 
     58   protected:
     59    ~InitRunnable() override = default;
     60 
     61    bool MainThreadRun() override {
     62      mImpl->InitializeOnMainThread();
     63      return true;
     64    }
     65 
     66    FontFaceSetWorkerImpl* mImpl;
     67  };
     68 
     69  IgnoredErrorResult rv;
     70  auto runnable = MakeRefPtr<InitRunnable>(aWorkerPrivate, this);
     71  runnable->Dispatch(aWorkerPrivate, Canceling, rv);
     72  return !NS_WARN_IF(rv.Failed());
     73 }
     74 
     75 void FontFaceSetWorkerImpl::InitializeOnMainThread() {
     76  MOZ_ASSERT(NS_IsMainThread());
     77  RecursiveMutexAutoLock lock(mMutex);
     78 
     79  if (!mWorkerRef) {
     80    return;
     81  }
     82 
     83  WorkerPrivate* workerPrivate = mWorkerRef->Private();
     84  nsIPrincipal* principal = workerPrivate->GetPrincipal();
     85  nsIPrincipal* loadingPrincipal = workerPrivate->GetLoadingPrincipal();
     86  nsIPrincipal* partitionedPrincipal = workerPrivate->GetPartitionedPrincipal();
     87  nsIPrincipal* defaultPrincipal = principal ? principal : loadingPrincipal;
     88 
     89  nsLoadFlags loadFlags = workerPrivate->GetLoadFlags();
     90  uint32_t loadType = 0;
     91 
     92  // Get the top-level worker.
     93  WorkerPrivate* topWorkerPrivate = workerPrivate;
     94  WorkerPrivate* parent = workerPrivate->GetParent();
     95  while (parent) {
     96    topWorkerPrivate = parent;
     97    parent = topWorkerPrivate->GetParent();
     98  }
     99 
    100  // If the top-level worker is a dedicated worker and has a window, and the
    101  // window has a docshell, the caching behavior of this worker should match
    102  // that of that docshell. This matches the behaviour from
    103  // WorkerScriptLoader::LoadScript.
    104  if (topWorkerPrivate->IsDedicatedWorker()) {
    105    nsCOMPtr<nsPIDOMWindowInner> window = topWorkerPrivate->GetWindow();
    106    if (window) {
    107      nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
    108      if (docShell) {
    109        docShell->GetDefaultLoadFlags(&loadFlags);
    110        docShell->GetLoadType(&loadType);
    111      }
    112    }
    113  }
    114 
    115  // Record the state of the "bypass cache" flags now. In theory the load type
    116  // of a docshell could change after the document is loaded, but handling that
    117  // doesn't seem too important. This matches the behaviour from
    118  // FontFaceSetDocumentImpl::Initialize.
    119  mBypassCache =
    120      ((loadType >> 16) & nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE) ||
    121      (loadFlags & nsIRequest::LOAD_BYPASS_CACHE);
    122 
    123  // Same for the "private browsing" flag.
    124  if (defaultPrincipal) {
    125    mPrivateBrowsing = defaultPrincipal->GetIsInPrivateBrowsing();
    126  }
    127 
    128  mStandardFontLoadPrincipal =
    129      MakeRefPtr<gfxFontSrcPrincipal>(defaultPrincipal, partitionedPrincipal);
    130 
    131  mURLExtraData =
    132      new URLExtraData(workerPrivate->GetBaseURI(),
    133                       workerPrivate->GetReferrerInfo(), defaultPrincipal);
    134 }
    135 
    136 void FontFaceSetWorkerImpl::Destroy() {
    137  RecursiveMutexAutoLock lock(mMutex);
    138 
    139  mWorkerRef = nullptr;
    140  FontFaceSetImpl::Destroy();
    141 }
    142 
    143 bool FontFaceSetWorkerImpl::IsOnOwningThread() {
    144  RecursiveMutexAutoLock lock(mMutex);
    145  if (!mWorkerRef) {
    146    return false;
    147  }
    148 
    149  return mWorkerRef->Private()->IsOnCurrentThread();
    150 }
    151 
    152 #ifdef DEBUG
    153 void FontFaceSetWorkerImpl::AssertIsOnOwningThread() {
    154  RecursiveMutexAutoLock lock(mMutex);
    155  if (mWorkerRef) {
    156    MOZ_ASSERT(mWorkerRef->Private()->IsOnCurrentThread());
    157  } else {
    158    // Asserting during cycle collection if we are tearing down the worker is
    159    // difficult. The only other thread that uses FontFace(Set)Impl objects is
    160    // the main thread (if created from a worker).
    161    MOZ_ASSERT(!NS_IsMainThread());
    162  }
    163 }
    164 #endif
    165 
    166 void FontFaceSetWorkerImpl::DispatchToOwningThread(
    167    const char* aName, std::function<void()>&& aFunc) {
    168  RecursiveMutexAutoLock lock(mMutex);
    169  if (!mWorkerRef) {
    170    return;
    171  }
    172 
    173  WorkerPrivate* workerPrivate = mWorkerRef->Private();
    174  if (workerPrivate->IsOnCurrentThread()) {
    175    NS_DispatchToCurrentThread(
    176        NS_NewCancelableRunnableFunction(aName, std::move(aFunc)));
    177    return;
    178  }
    179 
    180  class FontFaceSetWorkerRunnable final : public WorkerThreadRunnable {
    181   public:
    182    FontFaceSetWorkerRunnable(WorkerPrivate* aWorkerPrivate,
    183                              std::function<void()>&& aFunc)
    184        : WorkerThreadRunnable("FontFaceSetWorkerRunnable"),
    185          mFunc(std::move(aFunc)) {}
    186 
    187    bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
    188      mFunc();
    189      return true;
    190    }
    191 
    192   private:
    193    std::function<void()> mFunc;
    194  };
    195 
    196  auto runnable =
    197      MakeRefPtr<FontFaceSetWorkerRunnable>(workerPrivate, std::move(aFunc));
    198  runnable->Dispatch(workerPrivate);
    199 }
    200 
    201 uint64_t FontFaceSetWorkerImpl::GetInnerWindowID() {
    202  RecursiveMutexAutoLock lock(mMutex);
    203  if (!mWorkerRef) {
    204    return 0;
    205  }
    206 
    207  return mWorkerRef->Private()->WindowID();
    208 }
    209 
    210 void FontFaceSetWorkerImpl::FlushUserFontSet() {
    211  RecursiveMutexAutoLock lock(mMutex);
    212 
    213  // If there was a change to the mNonRuleFaces array, then there could
    214  // have been a modification to the user font set.
    215  const bool modified = mNonRuleFacesDirty;
    216  mNonRuleFacesDirty = false;
    217 
    218  for (size_t i = 0, i_end = mNonRuleFaces.Length(); i < i_end; ++i) {
    219    InsertNonRuleFontFace(mNonRuleFaces[i].mFontFace);
    220  }
    221 
    222  // Remove any residual families that have no font entries.
    223  for (auto it = mFontFamilies.Iter(); !it.Done(); it.Next()) {
    224    if (!it.Data()->FontListLength()) {
    225      it.Remove();
    226    }
    227  }
    228 
    229  if (modified) {
    230    IncrementGenerationLocked(true);
    231    mHasLoadingFontFacesIsDirty = true;
    232    CheckLoadingStarted();
    233    CheckLoadingFinished();
    234  }
    235 }
    236 
    237 already_AddRefed<gfxUserFontFamily> FontFaceSetWorkerImpl::LookupFamily(
    238    const nsACString& aName) const {
    239  RecursiveMutexAutoLock lock(mMutex);
    240  return gfxUserFontSet::LookupFamily(aName);
    241 }
    242 
    243 nsresult FontFaceSetWorkerImpl::StartLoad(gfxUserFontEntry* aUserFontEntry,
    244                                          uint32_t aSrcIndex) {
    245  RecursiveMutexAutoLock lock(mMutex);
    246 
    247  if (NS_WARN_IF(!mWorkerRef)) {
    248    return NS_ERROR_FAILURE;
    249  }
    250 
    251  nsresult rv;
    252 
    253  nsCOMPtr<nsIStreamLoader> streamLoader;
    254 
    255  const gfxFontFaceSrc& src = aUserFontEntry->SourceAt(aSrcIndex);
    256 
    257  nsCOMPtr<nsILoadGroup> loadGroup(mWorkerRef->Private()->GetLoadGroup());
    258  nsCOMPtr<nsIChannel> channel;
    259  rv = FontLoaderUtils::BuildChannel(
    260      getter_AddRefs(channel), src.mURI->get(), CORS_ANONYMOUS,
    261      dom::ReferrerPolicy::_empty /* not used */, aUserFontEntry, &src,
    262      mWorkerRef->Private(), loadGroup, nullptr);
    263  NS_ENSURE_SUCCESS(rv, rv);
    264 
    265  auto fontLoader =
    266      MakeRefPtr<nsFontFaceLoader>(aUserFontEntry, aSrcIndex, this, channel);
    267 
    268  if (LOG_ENABLED()) {
    269    nsCOMPtr<nsIURI> referrer =
    270        src.mReferrerInfo ? src.mReferrerInfo->GetOriginalReferrer() : nullptr;
    271    LOG("userfonts (%p) download start - font uri: (%s) referrer uri: (%s)\n",
    272        fontLoader.get(), src.mURI->GetSpecOrDefault().get(),
    273        referrer ? referrer->GetSpecOrDefault().get() : "");
    274  }
    275 
    276  rv = NS_NewStreamLoader(getter_AddRefs(streamLoader), fontLoader, fontLoader);
    277  NS_ENSURE_SUCCESS(rv, rv);
    278 
    279  rv = channel->AsyncOpen(streamLoader);
    280  if (NS_FAILED(rv)) {
    281    fontLoader->DropChannel();  // explicitly need to break ref cycle
    282  }
    283 
    284  mLoaders.PutEntry(fontLoader);
    285 
    286  if (NS_SUCCEEDED(rv)) {
    287    fontLoader->StartedLoading(streamLoader);
    288    // let the font entry remember the loader, in case we need to cancel it
    289    aUserFontEntry->SetLoader(fontLoader);
    290  }
    291 
    292  return rv;
    293 }
    294 
    295 bool FontFaceSetWorkerImpl::IsFontLoadAllowed(const gfxFontFaceSrc& aSrc) {
    296  MOZ_ASSERT(aSrc.mSourceType == gfxFontFaceSrc::eSourceType_URL);
    297  MOZ_ASSERT(NS_IsMainThread());
    298 
    299  RecursiveMutexAutoLock lock(mMutex);
    300 
    301  if (aSrc.mUseOriginPrincipal) {
    302    return true;
    303  }
    304 
    305  if (NS_WARN_IF(!mWorkerRef)) {
    306    return false;
    307  }
    308 
    309  RefPtr<gfxFontSrcPrincipal> gfxPrincipal =
    310      aSrc.mURI->InheritsSecurityContext() ? nullptr
    311                                           : aSrc.LoadPrincipal(*this);
    312 
    313  nsIPrincipal* principal =
    314      gfxPrincipal ? gfxPrincipal->NodePrincipal() : nullptr;
    315 
    316  Result<RefPtr<net::LoadInfo>, nsresult> maybeLoadInfo = net::LoadInfo::Create(
    317      mWorkerRef->Private()->GetLoadingPrincipal(),  // loading principal
    318      principal,                                     // triggering principal
    319      nullptr, nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
    320      nsIContentPolicy::TYPE_FONT);
    321  if (NS_WARN_IF(maybeLoadInfo.isErr())) {
    322    return false;
    323  }
    324  RefPtr<net::LoadInfo> secCheckLoadInfo = maybeLoadInfo.unwrap();
    325 
    326  int16_t shouldLoad = nsIContentPolicy::ACCEPT;
    327  nsresult rv =
    328      NS_CheckContentLoadPolicy(aSrc.mURI->get(), secCheckLoadInfo, &shouldLoad,
    329                                nsContentUtils::GetContentPolicy());
    330 
    331  return NS_SUCCEEDED(rv) && NS_CP_ACCEPTED(shouldLoad);
    332 }
    333 
    334 nsresult FontFaceSetWorkerImpl::CreateChannelForSyncLoadFontData(
    335    nsIChannel** aOutChannel, gfxUserFontEntry* aFontToLoad,
    336    const gfxFontFaceSrc* aFontFaceSrc) {
    337  RecursiveMutexAutoLock lock(mMutex);
    338  if (NS_WARN_IF(!mWorkerRef)) {
    339    return NS_ERROR_FAILURE;
    340  }
    341 
    342  gfxFontSrcPrincipal* principal = aFontToLoad->GetPrincipal();
    343 
    344  // We only get here for data: loads, so it doesn't really matter whether we
    345  // use SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT or not, to be more
    346  // restrictive we use SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT.
    347  return NS_NewChannelWithTriggeringPrincipal(
    348      aOutChannel, aFontFaceSrc->mURI->get(),
    349      mWorkerRef->Private()->GetLoadingPrincipal(),
    350      principal ? principal->NodePrincipal() : nullptr,
    351      nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT,
    352      aFontFaceSrc->mUseOriginPrincipal ? nsIContentPolicy::TYPE_UA_FONT
    353                                        : nsIContentPolicy::TYPE_FONT);
    354 }
    355 
    356 FontVisibilityProvider* FontFaceSetWorkerImpl::GetFontVisibilityProvider()
    357    const {
    358  RecursiveMutexAutoLock lock(mMutex);
    359  return mWorkerRef->Private();
    360 }
    361 
    362 TimeStamp FontFaceSetWorkerImpl::GetNavigationStartTimeStamp() {
    363  RecursiveMutexAutoLock lock(mMutex);
    364  if (!mWorkerRef) {
    365    return TimeStamp();
    366  }
    367 
    368  return mWorkerRef->Private()->CreationTimeStamp();
    369 }
    370 
    371 already_AddRefed<URLExtraData> FontFaceSetWorkerImpl::GetURLExtraData() {
    372  RecursiveMutexAutoLock lock(mMutex);
    373  return RefPtr{mURLExtraData}.forget();
    374 }
    375 
    376 #undef LOG_ENABLED
    377 #undef LOG
    378 
    379 }  // namespace mozilla::dom