OffscreenCanvas.cpp (23317B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ 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 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "OffscreenCanvas.h" 8 9 #include "CanvasRenderingContext2D.h" 10 #include "CanvasUtils.h" 11 #include "ClientWebGLContext.h" 12 #include "GLContext.h" 13 #include "GLScreenBuffer.h" 14 #include "ImageBitmap.h" 15 #include "ImageBitmapRenderingContext.h" 16 #include "WebGLChild.h" 17 #include "mozilla/Atomics.h" 18 #include "mozilla/CheckedInt.h" 19 #include "mozilla/Logging.h" 20 #include "mozilla/dom/BlobImpl.h" 21 #include "mozilla/dom/DocumentInlines.h" 22 #include "mozilla/dom/OffscreenCanvasBinding.h" 23 #include "mozilla/dom/OffscreenCanvasDisplayHelper.h" 24 #include "mozilla/dom/OffscreenCanvasRenderingContext2D.h" 25 #include "mozilla/dom/Promise.h" 26 #include "mozilla/dom/WorkerPrivate.h" 27 #include "mozilla/dom/WorkerRef.h" 28 #include "mozilla/dom/WorkerScope.h" 29 #include "mozilla/layers/ImageBridgeChild.h" 30 #include "mozilla/webgpu/CanvasContext.h" 31 #include "nsContentUtils.h" 32 #include "nsIPermissionManager.h" 33 #include "nsProxyRelease.h" 34 35 namespace mozilla::dom { 36 37 static mozilla::LazyLogModule gFingerprinterDetection("FingerprinterDetection"); 38 39 OffscreenCanvasCloneData::OffscreenCanvasCloneData( 40 OffscreenCanvasDisplayHelper* aDisplay, uint32_t aWidth, uint32_t aHeight, 41 layers::LayersBackend aCompositorBackend, bool aNeutered, bool aIsWriteOnly, 42 nsIPrincipal* aExpandedReader) 43 : mDisplay(aDisplay), 44 mWidth(aWidth), 45 mHeight(aHeight), 46 mCompositorBackendType(aCompositorBackend), 47 mNeutered(aNeutered), 48 mIsWriteOnly(aIsWriteOnly), 49 mExpandedReader(aExpandedReader) {} 50 51 OffscreenCanvasCloneData::~OffscreenCanvasCloneData() { 52 NS_ReleaseOnMainThread("OffscreenCanvasCloneData::mExpandedReader", 53 mExpandedReader.forget()); 54 } 55 56 OffscreenCanvas::OffscreenCanvas(nsIGlobalObject* aGlobal, uint32_t aWidth, 57 uint32_t aHeight) 58 : DOMEventTargetHelper(aGlobal), 59 mWidth(aWidth), 60 mHeight(aHeight), 61 mFontVisibility(ComputeFontVisibility()) {} 62 63 OffscreenCanvas::OffscreenCanvas( 64 nsIGlobalObject* aGlobal, uint32_t aWidth, uint32_t aHeight, 65 layers::LayersBackend aCompositorBackend, 66 already_AddRefed<OffscreenCanvasDisplayHelper> aDisplay) 67 : DOMEventTargetHelper(aGlobal), 68 mWidth(aWidth), 69 mHeight(aHeight), 70 mCompositorBackendType(aCompositorBackend), 71 mDisplay(aDisplay), 72 mFontVisibility(ComputeFontVisibility()) {} 73 74 OffscreenCanvas::~OffscreenCanvas() { 75 Destroy(); 76 NS_ReleaseOnMainThread("OffscreenCanvas::mExpandedReader", 77 mExpandedReader.forget()); 78 } 79 80 void OffscreenCanvas::Destroy() { 81 if (mDisplay) { 82 mDisplay->DestroyCanvas(); 83 } 84 } 85 86 JSObject* OffscreenCanvas::WrapObject(JSContext* aCx, 87 JS::Handle<JSObject*> aGivenProto) { 88 return OffscreenCanvas_Binding::Wrap(aCx, this, aGivenProto); 89 } 90 91 /* static */ 92 already_AddRefed<OffscreenCanvas> OffscreenCanvas::Constructor( 93 const GlobalObject& aGlobal, uint32_t aWidth, uint32_t aHeight, 94 ErrorResult& aRv) { 95 // CanvasRenderingContextHelper::GetWidthHeight wants us to return 96 // an nsIntSize, so make sure that that will work. 97 if (!CheckedInt<int32_t>(aWidth).isValid()) { 98 aRv.ThrowRangeError( 99 nsPrintfCString("OffscreenCanvas width %u is out of range: must be no " 100 "greater than 2147483647.", 101 aWidth)); 102 return nullptr; 103 } 104 if (!CheckedInt<int32_t>(aHeight).isValid()) { 105 aRv.ThrowRangeError( 106 nsPrintfCString("OffscreenCanvas height %u is out of range: must be no " 107 "greater than 2147483647.", 108 aHeight)); 109 return nullptr; 110 } 111 112 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); 113 RefPtr<OffscreenCanvas> offscreenCanvas = 114 new OffscreenCanvas(global, aWidth, aHeight); 115 return offscreenCanvas.forget(); 116 } 117 118 void OffscreenCanvas::SetWidth(uint32_t aWidth, ErrorResult& aRv) { 119 if (mNeutered) { 120 aRv.ThrowInvalidStateError("Cannot set width of detached OffscreenCanvas."); 121 return; 122 } 123 124 // CanvasRenderingContextHelper::GetWidthHeight wants us to return 125 // an nsIntSize, so make sure that that will work. 126 if (!CheckedInt<int32_t>(aWidth).isValid()) { 127 aRv.ThrowRangeError( 128 nsPrintfCString("OffscreenCanvas width %u is out of range: must be no " 129 "greater than 2147483647.", 130 aWidth)); 131 return; 132 } 133 134 mWidth = aWidth; 135 CanvasAttrChanged(); 136 } 137 138 void OffscreenCanvas::SetHeight(uint32_t aHeight, ErrorResult& aRv) { 139 if (mNeutered) { 140 aRv.ThrowInvalidStateError( 141 "Cannot set height of detached OffscreenCanvas."); 142 return; 143 } 144 145 // CanvasRenderingContextHelper::GetWidthHeight wants us to return 146 // an nsIntSize, so make sure that that will work. 147 if (!CheckedInt<int32_t>(aHeight).isValid()) { 148 aRv.ThrowRangeError( 149 nsPrintfCString("OffscreenCanvas height %u is out of range: must be no " 150 "greater than 2147483647.", 151 aHeight)); 152 return; 153 } 154 155 mHeight = aHeight; 156 CanvasAttrChanged(); 157 } 158 159 void OffscreenCanvas::SetSize(const nsIntSize& aSize, ErrorResult& aRv) { 160 if (mNeutered) { 161 aRv.ThrowInvalidStateError( 162 "Cannot set dimensions of detached OffscreenCanvas."); 163 return; 164 } 165 166 if (NS_WARN_IF(aSize.IsEmpty())) { 167 aRv.ThrowRangeError("OffscreenCanvas size is empty, must be non-empty."); 168 return; 169 } 170 171 mWidth = aSize.width; 172 mHeight = aSize.height; 173 CanvasAttrChanged(); 174 } 175 176 void OffscreenCanvas::GetContext( 177 JSContext* aCx, const OffscreenRenderingContextId& aContextId, 178 JS::Handle<JS::Value> aContextOptions, 179 Nullable<OwningOffscreenRenderingContext>& aResult, ErrorResult& aRv) { 180 if (mNeutered) { 181 aResult.SetNull(); 182 aRv.ThrowInvalidStateError( 183 "Cannot create context for detached OffscreenCanvas."); 184 return; 185 } 186 187 CanvasContextType contextType; 188 switch (aContextId) { 189 case OffscreenRenderingContextId::_2d: 190 contextType = CanvasContextType::OffscreenCanvas2D; 191 break; 192 case OffscreenRenderingContextId::Bitmaprenderer: 193 contextType = CanvasContextType::ImageBitmap; 194 break; 195 case OffscreenRenderingContextId::Webgl: 196 contextType = CanvasContextType::WebGL1; 197 break; 198 case OffscreenRenderingContextId::Webgl2: 199 contextType = CanvasContextType::WebGL2; 200 break; 201 case OffscreenRenderingContextId::Webgpu: 202 contextType = CanvasContextType::WebGPU; 203 break; 204 default: 205 MOZ_ASSERT_UNREACHABLE("Unhandled canvas type!"); 206 aResult.SetNull(); 207 aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); 208 return; 209 } 210 211 // If we are on a worker, we need to give our OffscreenCanvasDisplayHelper 212 // object access to a worker ref so we can dispatch properly during painting 213 // if we need to flush our contents to its ImageContainer for display. 214 RefPtr<ThreadSafeWorkerRef> workerRef; 215 if (mDisplay) { 216 if (WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate()) { 217 RefPtr<StrongWorkerRef> strongRef = StrongWorkerRef::Create( 218 workerPrivate, "OffscreenCanvas::GetContext", 219 [display = mDisplay]() { display->DestroyCanvas(); }); 220 if (NS_WARN_IF(!strongRef)) { 221 aResult.SetNull(); 222 aRv.ThrowUnknownError("Worker shutting down"); 223 return; 224 } 225 226 workerRef = new ThreadSafeWorkerRef(strongRef); 227 } else { 228 MOZ_ASSERT(NS_IsMainThread()); 229 } 230 } 231 232 RefPtr<nsISupports> result = CanvasRenderingContextHelper::GetOrCreateContext( 233 aCx, contextType, aContextOptions, aRv); 234 if (!result) { 235 aResult.SetNull(); 236 return; 237 } 238 239 Maybe<mozilla::ipc::ActorId> childId; 240 241 MOZ_ASSERT(mCurrentContext); 242 switch (mCurrentContextType) { 243 case CanvasContextType::OffscreenCanvas2D: 244 aResult.SetValue().SetAsOffscreenCanvasRenderingContext2D() = 245 *static_cast<OffscreenCanvasRenderingContext2D*>( 246 mCurrentContext.get()); 247 break; 248 case CanvasContextType::ImageBitmap: 249 aResult.SetValue().SetAsImageBitmapRenderingContext() = 250 *static_cast<ImageBitmapRenderingContext*>(mCurrentContext.get()); 251 break; 252 case CanvasContextType::WebGL1: 253 case CanvasContextType::WebGL2: { 254 auto* webgl = static_cast<ClientWebGLContext*>(mCurrentContext.get()); 255 WebGLChild* webglChild = webgl->GetChild(); 256 if (webglChild) { 257 childId.emplace(webglChild->Id()); 258 } 259 aResult.SetValue().SetAsWebGLRenderingContext() = *webgl; 260 break; 261 } 262 case CanvasContextType::WebGPU: 263 aResult.SetValue().SetAsGPUCanvasContext() = 264 *static_cast<webgpu::CanvasContext*>(mCurrentContext.get()); 265 break; 266 default: 267 MOZ_ASSERT_UNREACHABLE("Unhandled canvas type!"); 268 aResult.SetNull(); 269 break; 270 } 271 272 if (mDisplay) { 273 mDisplay->UpdateContext(this, std::move(workerRef), mCurrentContextType, 274 childId); 275 } 276 } 277 278 already_AddRefed<nsICanvasRenderingContextInternal> 279 OffscreenCanvas::CreateContext(CanvasContextType aContextType) { 280 RefPtr<nsICanvasRenderingContextInternal> ret = 281 CanvasRenderingContextHelper::CreateContext(aContextType); 282 if (NS_WARN_IF(!ret)) { 283 return nullptr; 284 } 285 286 ret->SetOffscreenCanvas(this); 287 return ret.forget(); 288 } 289 290 Maybe<uint64_t> OffscreenCanvas::GetWindowID() const { 291 if (NS_IsMainThread()) { 292 if (nsIGlobalObject* global = GetOwnerGlobal()) { 293 if (auto* window = global->GetAsInnerWindow()) { 294 return Some(window->WindowID()); 295 } 296 } 297 } else if (auto* workerPrivate = GetCurrentThreadWorkerPrivate()) { 298 return Some(workerPrivate->WindowID()); 299 } 300 return Nothing(); 301 } 302 303 void OffscreenCanvas::UpdateDisplayData( 304 const OffscreenCanvasDisplayData& aData) { 305 if (!mDisplay) { 306 return; 307 } 308 309 mPendingUpdate = Some(aData); 310 QueueCommitToCompositor(); 311 } 312 313 void OffscreenCanvas::QueueCommitToCompositor() { 314 if (!mDisplay || !mCurrentContext || mPendingCommit) { 315 // If we already have a commit pending, or we have no bound display/context, 316 // just bail out. 317 return; 318 } 319 320 mPendingCommit = NS_NewCancelableRunnableFunction( 321 "OffscreenCanvas::QueueCommitToCompositor", 322 [self = RefPtr{this}] { self->DequeueCommitToCompositor(); }); 323 NS_DispatchToCurrentThread(mPendingCommit); 324 } 325 326 void OffscreenCanvas::DequeueCommitToCompositor() { 327 MOZ_ASSERT(mPendingCommit); 328 mPendingCommit = nullptr; 329 Maybe<OffscreenCanvasDisplayData> update = std::move(mPendingUpdate); 330 mDisplay->CommitFrameToCompositor(mCurrentContext, update); 331 } 332 333 void OffscreenCanvas::CommitFrameToCompositor() { 334 if (!mDisplay || !mCurrentContext) { 335 // This offscreen canvas doesn't associate to any HTML canvas element. 336 // So, just bail out. 337 return; 338 } 339 340 if (mPendingCommit) { 341 // We got an explicit commit while waiting for an implicit. 342 mPendingCommit->Cancel(); 343 mPendingCommit = nullptr; 344 } 345 346 Maybe<OffscreenCanvasDisplayData> update = std::move(mPendingUpdate); 347 mDisplay->CommitFrameToCompositor(mCurrentContext, update); 348 } 349 350 UniquePtr<OffscreenCanvasCloneData> OffscreenCanvas::ToCloneData( 351 JSContext* aCx) { 352 if (NS_WARN_IF(mNeutered)) { 353 ErrorResult rv; 354 rv.ThrowDataCloneError( 355 "Cannot clone OffscreenCanvas that is already transferred."); 356 MOZ_ALWAYS_TRUE(rv.MaybeSetPendingException(aCx)); 357 return nullptr; 358 } 359 360 if (NS_WARN_IF(mCurrentContext)) { 361 ErrorResult rv; 362 rv.ThrowInvalidStateError("Cannot clone canvas with context."); 363 MOZ_ALWAYS_TRUE(rv.MaybeSetPendingException(aCx)); 364 return nullptr; 365 } 366 367 // Check if we are using HTMLCanvasElement::captureStream. This is not 368 // defined by the spec yet, so it is better to fail now than implement 369 // something not compliant: 370 // https://github.com/w3c/mediacapture-fromelement/issues/65 371 // https://github.com/w3c/mediacapture-extensions/pull/26 372 // https://github.com/web-platform-tests/wpt/issues/21102 373 if (mDisplay && NS_WARN_IF(mDisplay->UsingElementCaptureStream())) { 374 ErrorResult rv; 375 rv.ThrowNotSupportedError( 376 "Cannot transfer OffscreenCanvas bound to element using " 377 "captureStream."); 378 MOZ_ALWAYS_TRUE(rv.MaybeSetPendingException(aCx)); 379 return nullptr; 380 } 381 382 auto cloneData = MakeUnique<OffscreenCanvasCloneData>( 383 mDisplay, mWidth, mHeight, mCompositorBackendType, mNeutered, 384 mIsWriteOnly, mExpandedReader); 385 SetNeutered(); 386 return cloneData; 387 } 388 389 already_AddRefed<ImageBitmap> OffscreenCanvas::TransferToImageBitmap( 390 ErrorResult& aRv) { 391 if (mNeutered) { 392 aRv.ThrowInvalidStateError( 393 "Cannot get bitmap from detached OffscreenCanvas."); 394 return nullptr; 395 } 396 397 if (!mCurrentContext) { 398 aRv.ThrowInvalidStateError( 399 "Cannot get bitmap from canvas without a context."); 400 return nullptr; 401 } 402 403 RefPtr<ImageBitmap> result = 404 ImageBitmap::CreateFromOffscreenCanvas(GetOwnerGlobal(), *this, aRv); 405 if (!result) { 406 return nullptr; 407 } 408 409 if (mCurrentContext) { 410 mCurrentContext->ResetBitmap(); 411 } 412 return result.forget(); 413 } 414 415 already_AddRefed<EncodeCompleteCallback> 416 OffscreenCanvas::CreateEncodeCompleteCallback(Promise* aPromise) { 417 // Encoder callback when encoding is complete. 418 class EncodeCallback : public EncodeCompleteCallback { 419 public: 420 explicit EncodeCallback(Promise* aPromise) 421 : mPromise(aPromise), mCanceled(false) {} 422 423 void MaybeInitWorkerRef() { 424 WorkerPrivate* wp = GetCurrentThreadWorkerPrivate(); 425 if (wp) { 426 mWorkerRef = WeakWorkerRef::Create( 427 wp, [self = RefPtr{this}]() { self->Cancel(); }); 428 if (!mWorkerRef) { 429 Cancel(); 430 } 431 } 432 } 433 434 nsresult ReceiveBlobImpl(already_AddRefed<BlobImpl> aBlobImpl) override { 435 RefPtr<BlobImpl> blobImpl = aBlobImpl; 436 mWorkerRef = nullptr; 437 438 if (mPromise) { 439 RefPtr<nsIGlobalObject> global = mPromise->GetGlobalObject(); 440 if (NS_WARN_IF(!global) || NS_WARN_IF(!blobImpl)) { 441 mPromise->MaybeReject(NS_ERROR_FAILURE); 442 } else { 443 RefPtr<Blob> blob = Blob::Create(global, blobImpl); 444 if (NS_WARN_IF(!blob)) { 445 mPromise->MaybeReject(NS_ERROR_FAILURE); 446 } else { 447 mPromise->MaybeResolve(blob); 448 } 449 } 450 } 451 452 mPromise = nullptr; 453 454 return NS_OK; 455 } 456 457 bool CanBeDeletedOnAnyThread() override { return mCanceled; } 458 459 void Cancel() { 460 mPromise = nullptr; 461 mWorkerRef = nullptr; 462 mCanceled = true; 463 } 464 465 RefPtr<Promise> mPromise; 466 RefPtr<WeakWorkerRef> mWorkerRef; 467 Atomic<bool> mCanceled; 468 }; 469 470 RefPtr<EncodeCallback> p = MakeAndAddRef<EncodeCallback>(aPromise); 471 p->MaybeInitWorkerRef(); 472 return p.forget(); 473 } 474 475 already_AddRefed<Promise> OffscreenCanvas::ConvertToBlob( 476 const ImageEncodeOptions& aOptions, ErrorResult& aRv) { 477 // do a trust check if this is a write-only canvas 478 if (mIsWriteOnly) { 479 aRv.ThrowSecurityError("Cannot get blob from write-only canvas."); 480 return nullptr; 481 } 482 483 if (mNeutered) { 484 aRv.ThrowInvalidStateError( 485 "Cannot get blob from detached OffscreenCanvas."); 486 return nullptr; 487 } 488 489 if (mWidth == 0 || mHeight == 0) { 490 aRv.ThrowIndexSizeError("Cannot get blob from empty canvas."); 491 return nullptr; 492 } 493 494 nsCOMPtr<nsIGlobalObject> global = GetOwnerGlobal(); 495 496 RefPtr<Promise> promise = Promise::Create(global, aRv); 497 if (aRv.Failed()) { 498 return nullptr; 499 } 500 501 nsAutoString type; 502 nsContentUtils::ASCIIToLower(aOptions.mType, type); 503 504 nsAutoString encodeOptions; 505 506 // Only image/jpeg and image/webp support the quality parameter. 507 if (aOptions.mQuality.WasPassed() && 508 (type.EqualsLiteral("image/jpeg") || type.EqualsLiteral("image/webp"))) { 509 encodeOptions.AppendLiteral("quality="); 510 encodeOptions.AppendInt(NS_lround(aOptions.mQuality.Value() * 100.0)); 511 } 512 513 RefPtr<EncodeCompleteCallback> callback = 514 CreateEncodeCompleteCallback(promise); 515 516 CanvasUtils::ImageExtraction extractionBehaviour = 517 CanvasUtils::ImageExtractionResult( 518 this, nsContentUtils::GetCurrentJSContext(), 519 mCurrentContext ? mCurrentContext->PrincipalOrNull() : nullptr); 520 521 if (extractionBehaviour != CanvasUtils::ImageExtraction::Placeholder && 522 GetContext()) { 523 GetContext()->RecordCanvasUsage(CanvasExtractionAPI::ToBlob, 524 GetWidthHeight()); 525 } 526 527 CanvasRenderingContextHelper::ToBlob(callback, type, encodeOptions, 528 /* aUsingCustomOptions */ false, 529 extractionBehaviour, aRv); 530 531 if (aRv.Failed()) { 532 promise->MaybeReject(std::move(aRv)); 533 } 534 535 return promise.forget(); 536 } 537 538 already_AddRefed<Promise> OffscreenCanvas::ToBlob(JSContext* aCx, 539 const nsAString& aType, 540 JS::Handle<JS::Value> aParams, 541 ErrorResult& aRv) { 542 // do a trust check if this is a write-only canvas 543 if (mIsWriteOnly) { 544 aRv.ThrowSecurityError("Cannot get blob from write-only canvas."); 545 return nullptr; 546 } 547 548 if (mNeutered) { 549 aRv.ThrowInvalidStateError( 550 "Cannot get blob from detached OffscreenCanvas."); 551 return nullptr; 552 } 553 554 if (mWidth == 0 || mHeight == 0) { 555 aRv.ThrowIndexSizeError("Cannot get blob from empty canvas."); 556 return nullptr; 557 } 558 559 nsCOMPtr<nsIGlobalObject> global = GetOwnerGlobal(); 560 561 RefPtr<Promise> promise = Promise::Create(global, aRv); 562 if (aRv.Failed()) { 563 return nullptr; 564 } 565 566 RefPtr<EncodeCompleteCallback> callback = 567 CreateEncodeCompleteCallback(promise); 568 CanvasUtils::ImageExtraction extractionBehaviour = 569 CanvasUtils::ImageExtractionResult( 570 this, aCx, 571 mCurrentContext ? mCurrentContext->PrincipalOrNull() : nullptr); 572 573 if (extractionBehaviour != CanvasUtils::ImageExtraction::Placeholder && 574 GetContext()) { 575 GetContext()->RecordCanvasUsage(CanvasExtractionAPI::ToBlob, 576 GetWidthHeight()); 577 } 578 579 CanvasRenderingContextHelper::ToBlob(aCx, callback, aType, aParams, 580 extractionBehaviour, aRv); 581 582 return promise.forget(); 583 } 584 585 already_AddRefed<gfx::SourceSurface> OffscreenCanvas::GetSurfaceSnapshot( 586 gfxAlphaType* const aOutAlphaType) { 587 if (!mCurrentContext) { 588 return nullptr; 589 } 590 591 return mCurrentContext->GetSurfaceSnapshot(aOutAlphaType); 592 } 593 594 void OffscreenCanvas::SetWriteOnly(RefPtr<nsIPrincipal>&& aExpandedReader) { 595 NS_ReleaseOnMainThread("OffscreenCanvas::mExpandedReader", 596 mExpandedReader.forget()); 597 mExpandedReader = std::move(aExpandedReader); 598 mIsWriteOnly = true; 599 600 if (mDisplay) { 601 mDisplay->SetWriteOnly(mExpandedReader); 602 } 603 } 604 605 bool OffscreenCanvas::CallerCanRead(nsIPrincipal& aPrincipal) const { 606 if (!mIsWriteOnly) { 607 return true; 608 } 609 610 // If mExpandedReader is set, this canvas was tainted only by 611 // mExpandedReader's resources. So allow reading if the subject 612 // principal subsumes mExpandedReader. 613 if (mExpandedReader && aPrincipal.Subsumes(mExpandedReader)) { 614 return true; 615 } 616 617 return nsContentUtils::PrincipalHasPermission(aPrincipal, 618 nsGkAtoms::all_urlsPermission); 619 } 620 621 bool OffscreenCanvas::ShouldResistFingerprinting(RFPTarget aTarget) const { 622 return nsContentUtils::ShouldResistFingerprinting(GetOwnerGlobal(), aTarget); 623 } 624 625 /* static */ 626 already_AddRefed<OffscreenCanvas> OffscreenCanvas::CreateFromCloneData( 627 nsIGlobalObject* aGlobal, OffscreenCanvasCloneData* aData) { 628 MOZ_ASSERT(aData); 629 RefPtr<OffscreenCanvas> wc = new OffscreenCanvas( 630 aGlobal, aData->mWidth, aData->mHeight, aData->mCompositorBackendType, 631 aData->mDisplay.forget()); 632 if (aData->mNeutered) { 633 wc->SetNeutered(); 634 } 635 if (aData->mIsWriteOnly) { 636 wc->SetWriteOnly(std::move(aData->mExpandedReader)); 637 } 638 return wc.forget(); 639 } 640 641 // FontVisibilityProvider implementation 642 FontVisibility OffscreenCanvas::GetFontVisibility() const { 643 return mFontVisibility; 644 } 645 646 void OffscreenCanvas::ReportBlockedFontFamily(const nsCString& aMsg) const { 647 MOZ_LOG(gFingerprinterDetection, mozilla::LogLevel::Info, ("%s", aMsg.get())); 648 if (Maybe<uint64_t> windowID = GetWindowID()) { 649 nsContentUtils::ReportToConsoleByWindowID(NS_ConvertUTF8toUTF16(aMsg), 650 nsIScriptError::warningFlag, 651 "Security"_ns, *windowID); 652 return; 653 } 654 } 655 656 bool OffscreenCanvas::IsChrome() const { 657 if (NS_IsMainThread()) { 658 nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(GetOwnerGlobal()); 659 NS_ENSURE_TRUE(win, false); 660 661 nsCOMPtr<Document> doc = win->GetExtantDoc(); 662 NS_ENSURE_TRUE(doc, false); 663 664 return doc->ChromeRulesEnabled(); 665 } 666 667 dom::WorkerPrivate* worker = dom::GetCurrentThreadWorkerPrivate(); 668 NS_ENSURE_TRUE(worker, false); 669 670 return worker->IsChromeWorker(); 671 } 672 673 bool OffscreenCanvas::IsPrivateBrowsing() const { 674 if (NS_IsMainThread()) { 675 nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(GetOwnerGlobal()); 676 NS_ENSURE_TRUE(win, false); 677 678 nsCOMPtr<Document> doc = win->GetExtantDoc(); 679 NS_ENSURE_TRUE(doc, false); 680 681 return doc->IsInPrivateBrowsing(); 682 } 683 684 dom::WorkerPrivate* worker = dom::GetCurrentThreadWorkerPrivate(); 685 NS_ENSURE_TRUE(worker, false); 686 687 return worker->IsPrivateBrowsing(); 688 } 689 690 nsICookieJarSettings* OffscreenCanvas::GetCookieJarSettings() const { 691 if (nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(GetOwnerGlobal())) { 692 if (nsCOMPtr<Document> doc = win->GetExtantDoc()) { 693 return doc->CookieJarSettings(); 694 } 695 } 696 697 if (dom::WorkerPrivate* worker = dom::GetCurrentThreadWorkerPrivate()) { 698 return worker->CookieJarSettings(); 699 } 700 701 return nullptr; 702 } 703 704 Maybe<FontVisibility> OffscreenCanvas::MaybeInheritFontVisibility() const { 705 if (NS_IsMainThread()) { 706 nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(GetOwnerGlobal()); 707 NS_ENSURE_TRUE(win, Nothing()); 708 709 nsCOMPtr<Document> doc = win->GetExtantDoc(); 710 NS_ENSURE_TRUE(doc, Nothing()); 711 712 nsPresContext* presContext = doc->GetPresContext(); 713 NS_ENSURE_TRUE(presContext, Nothing()); 714 715 return Some(presContext->GetFontVisibility()); 716 } 717 718 dom::WorkerPrivate* worker = dom::GetCurrentThreadWorkerPrivate(); 719 NS_ENSURE_TRUE(worker, Nothing()); 720 721 return Some(worker->GetFontVisibility()); 722 } 723 724 void OffscreenCanvas::UserFontSetUpdated(gfxUserFontEntry*) {} 725 726 NS_IMPL_CYCLE_COLLECTION_INHERITED(OffscreenCanvas, DOMEventTargetHelper, 727 mCurrentContext) 728 729 NS_IMPL_ADDREF_INHERITED(OffscreenCanvas, DOMEventTargetHelper) 730 NS_IMPL_RELEASE_INHERITED(OffscreenCanvas, DOMEventTargetHelper) 731 732 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(OffscreenCanvas) 733 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, EventTarget) 734 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) 735 736 } // namespace mozilla::dom