tor-browser

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

nsICanvasRenderingContextInternal.cpp (8976B)


      1 /* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      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/. */
      5 
      6 #include "nsICanvasRenderingContextInternal.h"
      7 
      8 #include "mozilla/ErrorResult.h"
      9 #include "mozilla/PresShell.h"
     10 #include "mozilla/dom/CanvasUtils.h"
     11 #include "mozilla/dom/Document.h"
     12 #include "mozilla/dom/Event.h"
     13 #include "mozilla/dom/WorkerCommon.h"
     14 #include "mozilla/dom/WorkerPrivate.h"
     15 #include "mozilla/dom/WorkerRunnable.h"
     16 #include "mozilla/gfx/DrawTargetRecording.h"
     17 #include "nsContentUtils.h"
     18 #include "nsPIDOMWindow.h"
     19 #include "nsRFPService.h"
     20 #include "nsRefreshDriver.h"
     21 #include "nsThreadUtils.h"
     22 
     23 static mozilla::LazyLogModule gFingerprinterDetection("FingerprinterDetection");
     24 
     25 nsICanvasRenderingContextInternal::nsICanvasRenderingContextInternal() =
     26    default;
     27 
     28 nsICanvasRenderingContextInternal::~nsICanvasRenderingContextInternal() =
     29    default;
     30 
     31 mozilla::PresShell* nsICanvasRenderingContextInternal::GetPresShell() {
     32  if (mCanvasElement) {
     33    return mCanvasElement->OwnerDoc()->GetPresShell();
     34  }
     35  return nullptr;
     36 }
     37 
     38 nsIGlobalObject* nsICanvasRenderingContextInternal::GetParentObject() const {
     39  if (mCanvasElement) {
     40    return mCanvasElement->OwnerDoc()->GetScopeObject();
     41  }
     42  if (mOffscreenCanvas) {
     43    return mOffscreenCanvas->GetParentObject();
     44  }
     45  return nullptr;
     46 }
     47 
     48 class RecordCanvasUsageRunnable final
     49    : public mozilla::dom::WorkerMainThreadRunnable {
     50 public:
     51  RecordCanvasUsageRunnable(mozilla::dom::WorkerPrivate* aWorkerPrivate,
     52                            const mozilla::CanvasUsage& aUsage)
     53      : WorkerMainThreadRunnable(aWorkerPrivate,
     54                                 "RecordCanvasUsageRunnable"_ns),
     55        mUsage(aUsage) {
     56    MOZ_ASSERT(aWorkerPrivate);
     57    aWorkerPrivate->AssertIsOnWorkerThread();
     58  }
     59 
     60 protected:
     61  MOZ_CAN_RUN_SCRIPT_BOUNDARY bool MainThreadRun() override {
     62    mozilla::AssertIsOnMainThread();
     63    RefPtr<mozilla::dom::Document> doc;
     64    if (!mWorkerRef) {
     65      MOZ_LOG(gFingerprinterDetection, mozilla::LogLevel::Error,
     66              ("RecordCanvasUsageRunnable::MainThreadRun - null mWorkerRef"));
     67      return false;
     68    }
     69    auto* priv = mWorkerRef->Private();
     70    if (!priv) {
     71      MOZ_LOG(
     72          gFingerprinterDetection, mozilla::LogLevel::Error,
     73          ("RecordCanvasUsageRunnable::MainThreadRun - null worker private"));
     74      return false;
     75    }
     76    doc = priv->GetDocument();
     77    if (!doc) {
     78      MOZ_LOG(gFingerprinterDetection, mozilla::LogLevel::Error,
     79              ("RecordCanvasUsageRunnable::MainThreadRun - null document"));
     80      return false;
     81    }
     82    doc->RecordCanvasUsage(mUsage);
     83    return true;
     84  }
     85 
     86 private:
     87  mozilla::CanvasUsage mUsage;
     88 };
     89 
     90 void nsICanvasRenderingContextInternal::RecordCanvasUsage(
     91    mozilla::CanvasExtractionAPI aAPI, mozilla::CSSIntSize size) const {
     92  mozilla::dom::CanvasContextType contextType;
     93  if (mCanvasElement) {
     94    contextType = mCanvasElement->GetCurrentContextType();
     95    auto usage =
     96        mozilla::CanvasUsage::CreateUsage(false, contextType, aAPI, size, this);
     97    mCanvasElement->OwnerDoc()->RecordCanvasUsage(usage);
     98  }
     99  if (mOffscreenCanvas) {
    100    contextType = mOffscreenCanvas->GetContextType();
    101    auto usage =
    102        mozilla::CanvasUsage::CreateUsage(true, contextType, aAPI, size, this);
    103    if (NS_IsMainThread()) {
    104      nsIGlobalObject* global = mOffscreenCanvas->GetOwnerGlobal();
    105      if (global) {
    106        if (nsPIDOMWindowInner* inner = global->GetAsInnerWindow()) {
    107          if (mozilla::dom::Document* doc = inner->GetExtantDoc()) {
    108            doc->RecordCanvasUsage(usage);
    109          }
    110        }
    111      }
    112    } else {
    113      mozilla::dom::WorkerPrivate* workerPrivate =
    114          mozilla::dom::GetCurrentThreadWorkerPrivate();
    115      if (workerPrivate) {
    116        RefPtr<RecordCanvasUsageRunnable> runnable =
    117            new RecordCanvasUsageRunnable(workerPrivate, usage);
    118        mozilla::ErrorResult rv;
    119        runnable->Dispatch(workerPrivate, mozilla::dom::WorkerStatus::Canceling,
    120                           rv);
    121        if (rv.Failed()) {
    122          rv.SuppressException();
    123          MOZ_LOG(gFingerprinterDetection, mozilla::LogLevel::Error,
    124                  ("RecordCanvasUsageRunnable dispatch failed"));
    125        }
    126      }
    127    }
    128  }
    129 }
    130 
    131 nsIPrincipal* nsICanvasRenderingContextInternal::PrincipalOrNull() const {
    132  if (mCanvasElement) {
    133    return mCanvasElement->NodePrincipal();
    134  }
    135  if (mOffscreenCanvas) {
    136    nsIGlobalObject* global = mOffscreenCanvas->GetParentObject();
    137    if (global) {
    138      return global->PrincipalOrNull();
    139    }
    140  }
    141  return nullptr;
    142 }
    143 
    144 nsICookieJarSettings* nsICanvasRenderingContextInternal::GetCookieJarSettings()
    145    const {
    146  if (mCanvasElement) {
    147    return mCanvasElement->OwnerDoc()->CookieJarSettings();
    148  }
    149 
    150  // If there is an offscreen canvas, attempt to retrieve its owner window
    151  // and return the cookieJarSettings for the window's document, if available.
    152  if (mOffscreenCanvas) {
    153    nsCOMPtr<nsPIDOMWindowInner> win =
    154        do_QueryInterface(mOffscreenCanvas->GetOwnerGlobal());
    155 
    156    if (win) {
    157      return win->GetExtantDoc()->CookieJarSettings();
    158    }
    159 
    160    // If the owner window cannot be retrieved, check if there is a current
    161    // worker and return its cookie jar settings if available.
    162    mozilla::dom::WorkerPrivate* worker =
    163        mozilla::dom::GetCurrentThreadWorkerPrivate();
    164 
    165    if (worker) {
    166      return worker->CookieJarSettings();
    167    }
    168  }
    169 
    170  return nullptr;
    171 }
    172 
    173 void nsICanvasRenderingContextInternal::RemovePostRefreshObserver() {
    174  if (mRefreshDriver) {
    175    mRefreshDriver->RemovePostRefreshObserver(this);
    176    mRefreshDriver = nullptr;
    177  }
    178 }
    179 
    180 void nsICanvasRenderingContextInternal::AddPostRefreshObserverIfNecessary() {
    181  if (!GetPresShell() || !GetPresShell()->GetPresContext() ||
    182      !GetPresShell()->GetPresContext()->RefreshDriver()) {
    183    return;
    184  }
    185  mRefreshDriver = GetPresShell()->GetPresContext()->RefreshDriver();
    186  mRefreshDriver->AddPostRefreshObserver(this);
    187 }
    188 
    189 void nsICanvasRenderingContextInternal::DoSecurityCheck(
    190    nsIPrincipal* aPrincipal, bool aForceWriteOnly, bool aCORSUsed) {
    191  if (mCanvasElement) {
    192    mozilla::CanvasUtils::DoDrawImageSecurityCheck(mCanvasElement, aPrincipal,
    193                                                   aForceWriteOnly, aCORSUsed);
    194  } else if (mOffscreenCanvas) {
    195    mozilla::CanvasUtils::DoDrawImageSecurityCheck(mOffscreenCanvas, aPrincipal,
    196                                                   aForceWriteOnly, aCORSUsed);
    197  }
    198 }
    199 
    200 bool nsICanvasRenderingContextInternal::ShouldResistFingerprinting(
    201    mozilla::RFPTarget aTarget) const {
    202  if (mCanvasElement) {
    203    return mCanvasElement->OwnerDoc()->ShouldResistFingerprinting(aTarget);
    204  }
    205  if (mOffscreenCanvas) {
    206    return mOffscreenCanvas->ShouldResistFingerprinting(aTarget);
    207  }
    208  // Last resort, just check the global preference
    209  return nsContentUtils::ShouldResistFingerprinting("Fallback", aTarget);
    210 }
    211 
    212 bool nsICanvasRenderingContextInternal::DispatchEvent(
    213    const nsAString& eventName, mozilla::CanBubble aCanBubble,
    214    mozilla::Cancelable aIsCancelable) const {
    215  bool useDefaultHandler = true;
    216 
    217  if (mCanvasElement) {
    218    nsContentUtils::DispatchTrustedEvent(mCanvasElement->OwnerDoc(),
    219                                         mCanvasElement, eventName, aCanBubble,
    220                                         aIsCancelable, &useDefaultHandler);
    221  } else if (mOffscreenCanvas) {
    222    // OffscreenCanvas case
    223    auto event = mozilla::MakeRefPtr<mozilla::dom::Event>(mOffscreenCanvas,
    224                                                          nullptr, nullptr);
    225    event->InitEvent(eventName, aCanBubble, aIsCancelable);
    226    event->SetTrusted(true);
    227    useDefaultHandler = mOffscreenCanvas->DispatchEvent(
    228        *event, mozilla::dom::CallerType::System, mozilla::IgnoreErrors());
    229  }
    230  return useDefaultHandler;
    231 }
    232 
    233 already_AddRefed<mozilla::gfx::SourceSurface>
    234 nsICanvasRenderingContextInternal::GetOptimizedSnapshot(
    235    mozilla::gfx::DrawTarget* aTarget, gfxAlphaType* out_alphaType) {
    236  if (aTarget &&
    237      aTarget->GetBackendType() == mozilla::gfx::BackendType::RECORDING) {
    238    if (auto* actor = SupportsSnapshotExternalCanvas()) {
    239      // If this snapshot is for a recording target, then try to avoid reading
    240      // back any data by using SnapshotExternalCanvas instead. This avoids
    241      // having sync interactions between GPU and content process.
    242      if (RefPtr<mozilla::gfx::SourceSurface> surf =
    243              static_cast<mozilla::gfx::DrawTargetRecording*>(aTarget)
    244                  ->SnapshotExternalCanvas(this, actor)) {
    245        if (out_alphaType) {
    246          *out_alphaType =
    247              GetIsOpaque() ? gfxAlphaType::Opaque : gfxAlphaType::Premult;
    248        }
    249        return surf.forget();
    250      }
    251    }
    252  }
    253 
    254  return GetSurfaceSnapshot(out_alphaType);
    255 }