mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 07:13:20 +00:00
Bug 967895 - Ask for placeholder data when image extraction is not allowed (Tor 6253). r=jrmuizel
MozReview-Commit-ID: AJ5F6M5S83U --HG-- extra : rebase_source : 894b16575ebbccc26c5b639d7526cb473501d9d2
This commit is contained in:
parent
de8dc32c1d
commit
6eb3e9c2c9
@ -124,7 +124,7 @@ DOMInterfaces = {
|
||||
|
||||
'CanvasRenderingContext2D': {
|
||||
'implicitJSContext': [
|
||||
'createImageData', 'getImageData'
|
||||
'createImageData', 'getImageData', 'isPointInPath', 'isPointInStroke'
|
||||
],
|
||||
'binaryNames': {
|
||||
'mozImageSmoothingEnabled': 'imageSmoothingEnabled'
|
||||
|
@ -4905,12 +4905,19 @@ CanvasRenderingContext2D::LineDashOffset() const {
|
||||
}
|
||||
|
||||
bool
|
||||
CanvasRenderingContext2D::IsPointInPath(double aX, double aY, const CanvasWindingRule& aWinding)
|
||||
CanvasRenderingContext2D::IsPointInPath(JSContext* aCx, double aX, double aY, const CanvasWindingRule& aWinding)
|
||||
{
|
||||
if (!FloatValidate(aX, aY)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for site-specific permission and return false if no permission.
|
||||
if (mCanvasElement) {
|
||||
nsCOMPtr<nsIDocument> ownerDoc = mCanvasElement->OwnerDoc();
|
||||
if (!ownerDoc || !CanvasUtils::IsImageExtractionAllowed(ownerDoc, aCx))
|
||||
return false;
|
||||
}
|
||||
|
||||
EnsureUserSpacePath(aWinding);
|
||||
if (!mPath) {
|
||||
return false;
|
||||
@ -4923,7 +4930,7 @@ CanvasRenderingContext2D::IsPointInPath(double aX, double aY, const CanvasWindin
|
||||
return mPath->ContainsPoint(Point(aX, aY), mTarget->GetTransform());
|
||||
}
|
||||
|
||||
bool CanvasRenderingContext2D::IsPointInPath(const CanvasPath& aPath, double aX, double aY, const CanvasWindingRule& aWinding)
|
||||
bool CanvasRenderingContext2D::IsPointInPath(JSContext* aCx, const CanvasPath& aPath, double aX, double aY, const CanvasWindingRule& aWinding)
|
||||
{
|
||||
if (!FloatValidate(aX, aY)) {
|
||||
return false;
|
||||
@ -4940,12 +4947,19 @@ bool CanvasRenderingContext2D::IsPointInPath(const CanvasPath& aPath, double aX,
|
||||
}
|
||||
|
||||
bool
|
||||
CanvasRenderingContext2D::IsPointInStroke(double aX, double aY)
|
||||
CanvasRenderingContext2D::IsPointInStroke(JSContext* aCx, double aX, double aY)
|
||||
{
|
||||
if (!FloatValidate(aX, aY)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for site-specific permission and return false if no permission.
|
||||
if (mCanvasElement) {
|
||||
nsCOMPtr<nsIDocument> ownerDoc = mCanvasElement->OwnerDoc();
|
||||
if (!ownerDoc || !CanvasUtils::IsImageExtractionAllowed(ownerDoc, aCx))
|
||||
return false;
|
||||
}
|
||||
|
||||
EnsureUserSpacePath();
|
||||
if (!mPath) {
|
||||
return false;
|
||||
@ -4967,7 +4981,7 @@ CanvasRenderingContext2D::IsPointInStroke(double aX, double aY)
|
||||
return mPath->StrokeContainsPoint(strokeOptions, Point(aX, aY), mTarget->GetTransform());
|
||||
}
|
||||
|
||||
bool CanvasRenderingContext2D::IsPointInStroke(const CanvasPath& aPath, double aX, double aY)
|
||||
bool CanvasRenderingContext2D::IsPointInStroke(JSContext* aCx, const CanvasPath& aPath, double aX, double aY)
|
||||
{
|
||||
if (!FloatValidate(aX, aY)) {
|
||||
return false;
|
||||
@ -5808,7 +5822,17 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx,
|
||||
IntRect dstWriteRect = srcReadRect;
|
||||
dstWriteRect.MoveBy(-aX, -aY);
|
||||
|
||||
{
|
||||
// Check for site-specific permission. This check is not needed if the
|
||||
// canvas was created with a docshell (that is only done for special
|
||||
// internal uses).
|
||||
bool usePlaceholder = false;
|
||||
if (mCanvasElement) {
|
||||
nsCOMPtr<nsIDocument> ownerDoc = mCanvasElement->OwnerDoc();
|
||||
usePlaceholder = !ownerDoc ||
|
||||
!CanvasUtils::IsImageExtractionAllowed(ownerDoc, aCx);
|
||||
}
|
||||
|
||||
do {
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
bool isShared;
|
||||
uint8_t* data = JS_GetUint8ClampedArrayData(darray, &isShared, nogc);
|
||||
@ -5816,6 +5840,13 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx,
|
||||
|
||||
uint32_t srcStride = rawData.mStride;
|
||||
uint8_t* src = rawData.mData + srcReadRect.y * srcStride + srcReadRect.x * 4;
|
||||
|
||||
// Return all-white, opaque pixel data if no permission.
|
||||
if (usePlaceholder) {
|
||||
memset(data, 0xFF, len.value());
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t* dst = data + dstWriteRect.y * (aWidth * 4) + dstWriteRect.x * 4;
|
||||
|
||||
if (mOpaque) {
|
||||
@ -5827,7 +5858,7 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx,
|
||||
dst, aWidth * 4, SurfaceFormat::R8G8B8A8,
|
||||
dstWriteRect.Size());
|
||||
}
|
||||
}
|
||||
} while (false);
|
||||
|
||||
readback->Unmap();
|
||||
*aRetval = darray;
|
||||
|
@ -204,10 +204,10 @@ public:
|
||||
bool DrawCustomFocusRing(mozilla::dom::Element& aElement);
|
||||
void Clip(const CanvasWindingRule& aWinding);
|
||||
void Clip(const CanvasPath& aPath, const CanvasWindingRule& aWinding);
|
||||
bool IsPointInPath(double aX, double aY, const CanvasWindingRule& aWinding);
|
||||
bool IsPointInPath(const CanvasPath& aPath, double aX, double aY, const CanvasWindingRule& aWinding);
|
||||
bool IsPointInStroke(double aX, double aY);
|
||||
bool IsPointInStroke(const CanvasPath& aPath, double aX, double aY);
|
||||
bool IsPointInPath(JSContext* aCx, double aX, double aY, const CanvasWindingRule& aWinding);
|
||||
bool IsPointInPath(JSContext* aCx, const CanvasPath& aPath, double aX, double aY, const CanvasWindingRule& aWinding);
|
||||
bool IsPointInStroke(JSContext* aCx, double aX, double aY);
|
||||
bool IsPointInStroke(JSContext* aCx, const CanvasPath& aPath, double aX, double aY);
|
||||
void FillText(const nsAString& aText, double aX, double aY,
|
||||
const Optional<double>& aMaxWidth,
|
||||
mozilla::ErrorResult& aError);
|
||||
|
@ -25,6 +25,7 @@ CanvasRenderingContextHelper::ToBlob(JSContext* aCx,
|
||||
BlobCallback& aCallback,
|
||||
const nsAString& aType,
|
||||
JS::Handle<JS::Value> aParams,
|
||||
bool aUsePlaceholder,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
// Encoder callback when encoding is complete.
|
||||
@ -58,7 +59,7 @@ CanvasRenderingContextHelper::ToBlob(JSContext* aCx,
|
||||
RefPtr<EncodeCompleteCallback> callback =
|
||||
new EncodeCallback(aGlobal, &aCallback);
|
||||
|
||||
ToBlob(aCx, aGlobal, callback, aType, aParams, aRv);
|
||||
ToBlob(aCx, aGlobal, callback, aType, aParams, aUsePlaceholder, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
@ -67,6 +68,7 @@ CanvasRenderingContextHelper::ToBlob(JSContext* aCx,
|
||||
EncodeCompleteCallback* aCallback,
|
||||
const nsAString& aType,
|
||||
JS::Handle<JS::Value> aParams,
|
||||
bool aUsePlaceholder,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsAutoString type;
|
||||
@ -107,6 +109,7 @@ CanvasRenderingContextHelper::ToBlob(JSContext* aCx,
|
||||
Move(imageBuffer),
|
||||
format,
|
||||
GetWidthHeight(),
|
||||
aUsePlaceholder,
|
||||
callback);
|
||||
}
|
||||
|
||||
|
@ -58,11 +58,11 @@ protected:
|
||||
|
||||
void ToBlob(JSContext* aCx, nsIGlobalObject* global, BlobCallback& aCallback,
|
||||
const nsAString& aType, JS::Handle<JS::Value> aParams,
|
||||
ErrorResult& aRv);
|
||||
bool aUsePlaceholder, ErrorResult& aRv);
|
||||
|
||||
void ToBlob(JSContext* aCx, nsIGlobalObject* aGlobal, EncodeCompleteCallback* aCallback,
|
||||
const nsAString& aType, JS::Handle<JS::Value> aParams,
|
||||
ErrorResult& aRv);
|
||||
bool aUsePlaceholder, ErrorResult& aRv);
|
||||
|
||||
virtual already_AddRefed<nsICanvasRenderingContextInternal>
|
||||
CreateContext(CanvasContextType aContextType);
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "nsICanvasRenderingContextInternal.h"
|
||||
#include "nsIHTMLCollection.h"
|
||||
#include "mozilla/dom/HTMLCanvasElement.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "nsIPrincipal.h"
|
||||
|
||||
#include "nsGfxCIID.h"
|
||||
@ -23,11 +24,150 @@
|
||||
#include "mozilla/gfx/Matrix.h"
|
||||
#include "WebGL2Context.h"
|
||||
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozIThirdPartyUtil.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsIConsoleService.h"
|
||||
#include "jsapi.h"
|
||||
|
||||
#define TOPIC_CANVAS_PERMISSIONS_PROMPT "canvas-permissions-prompt"
|
||||
#define PERMISSION_CANVAS_EXTRACT_DATA "canvas/extractData"
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
namespace mozilla {
|
||||
namespace CanvasUtils {
|
||||
|
||||
bool IsImageExtractionAllowed(nsIDocument *aDocument, JSContext *aCx)
|
||||
{
|
||||
// Do the rest of the checks only if privacy.resistFingerprinting is on.
|
||||
if (!nsContentUtils::ShouldResistFingerprinting()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Don't proceed if we don't have a document or JavaScript context.
|
||||
if (!aDocument || !aCx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Documents with system principal can always extract canvas data.
|
||||
nsPIDOMWindowOuter *win = aDocument->GetWindow();
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(win));
|
||||
if (sop && nsContentUtils::IsSystemPrincipal(sop->GetPrincipal())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Always give permission to chrome scripts (e.g. Page Inspector).
|
||||
if (nsContentUtils::ThreadsafeIsCallerChrome()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the document URI and its spec.
|
||||
nsIURI *docURI = aDocument->GetDocumentURI();
|
||||
nsCString docURISpec;
|
||||
docURI->GetSpec(docURISpec);
|
||||
|
||||
// Allow local files to extract canvas data.
|
||||
bool isFileURL;
|
||||
(void) docURI->SchemeIs("file", &isFileURL);
|
||||
if (isFileURL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get calling script file and line for logging.
|
||||
JS::AutoFilename scriptFile;
|
||||
unsigned scriptLine = 0;
|
||||
bool isScriptKnown = false;
|
||||
if (JS::DescribeScriptedCaller(aCx, &scriptFile, &scriptLine)) {
|
||||
isScriptKnown = true;
|
||||
// Don't show canvas prompt for PDF.js
|
||||
if (scriptFile.get() &&
|
||||
strcmp(scriptFile.get(), "resource://pdf.js/build/pdf.js") == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
nsIDocument* topLevelDocument = aDocument->GetTopLevelContentDocument();
|
||||
nsIURI *topLevelDocURI = topLevelDocument ? topLevelDocument->GetDocumentURI() : nullptr;
|
||||
nsCString topLevelDocURISpec;
|
||||
if (topLevelDocURI) {
|
||||
topLevelDocURI->GetSpec(topLevelDocURISpec);
|
||||
}
|
||||
|
||||
// Load Third Party Util service.
|
||||
nsresult rv;
|
||||
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
|
||||
do_GetService(THIRDPARTYUTIL_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
// Block all third-party attempts to extract canvas.
|
||||
bool isThirdParty = true;
|
||||
rv = thirdPartyUtil->IsThirdPartyURI(topLevelDocURI, docURI, &isThirdParty);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
if (isThirdParty) {
|
||||
nsAutoCString message;
|
||||
message.AppendPrintf("Blocked third party %s in page %s from extracting canvas data.",
|
||||
docURISpec.get(), topLevelDocURISpec.get());
|
||||
if (isScriptKnown) {
|
||||
message.AppendPrintf(" %s:%u.", scriptFile.get(), scriptLine);
|
||||
}
|
||||
nsContentUtils::LogMessageToConsole(message.get());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load Permission Manager service.
|
||||
nsCOMPtr<nsIPermissionManager> permissionManager =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
// Check if the site has permission to extract canvas data.
|
||||
// Either permit or block extraction if a stored permission setting exists.
|
||||
uint32_t permission;
|
||||
rv = permissionManager->TestPermission(topLevelDocURI,
|
||||
PERMISSION_CANVAS_EXTRACT_DATA,
|
||||
&permission);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
switch (permission) {
|
||||
case nsIPermissionManager::ALLOW_ACTION:
|
||||
return true;
|
||||
case nsIPermissionManager::DENY_ACTION:
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// At this point, permission is unknown (nsIPermissionManager::UNKNOWN_ACTION).
|
||||
nsAutoCString message;
|
||||
message.AppendPrintf("Blocked %s in page %s from extracting canvas data.",
|
||||
docURISpec.get(), topLevelDocURISpec.get());
|
||||
if (isScriptKnown) {
|
||||
message.AppendPrintf(" %s:%u.", scriptFile.get(), scriptLine);
|
||||
}
|
||||
nsContentUtils::LogMessageToConsole(message.get());
|
||||
|
||||
// Prompt the user (asynchronous).
|
||||
if (XRE_IsContentProcess()) {
|
||||
TabChild* tabChild = TabChild::GetFrom(win);
|
||||
if (tabChild) {
|
||||
tabChild->SendShowCanvasPermissionPrompt(topLevelDocURISpec);
|
||||
}
|
||||
} else {
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->NotifyObservers(win, TOPIC_CANVAS_PERMISSIONS_PROMPT,
|
||||
NS_ConvertUTF8toUTF16(topLevelDocURISpec).get());
|
||||
}
|
||||
}
|
||||
|
||||
// We don't extract the image for now -- user may override at prompt.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
GetCanvasContextType(const nsAString& str, dom::CanvasContextType* const out_type)
|
||||
{
|
||||
|
@ -49,6 +49,9 @@ void DoDrawImageSecurityCheck(dom::HTMLCanvasElement *aCanvasElement,
|
||||
// Check if the context is chrome or has the permission to drawWindow
|
||||
bool HasDrawWindowPrivilege(JSContext* aCx, JSObject* aObj);
|
||||
|
||||
// Check site-specific permission and display prompt if appropriate.
|
||||
bool IsImageExtractionAllowed(nsIDocument *aDocument, JSContext *aCx);
|
||||
|
||||
// Make a double out of |v|, treating undefined values as 0.0 (for
|
||||
// the sake of sparse arrays). Return true iff coercion
|
||||
// succeeded.
|
||||
|
@ -286,8 +286,13 @@ OffscreenCanvas::ToBlob(JSContext* aCx,
|
||||
RefPtr<EncodeCompleteCallback> callback =
|
||||
new EncodeCallback(global, promise);
|
||||
|
||||
CanvasRenderingContextHelper::ToBlob(aCx, global,
|
||||
callback, aType, aParams, aRv);
|
||||
// TODO: Can we obtain the context and document here somehow
|
||||
// so that we can decide when usePlaceholder should be true/false?
|
||||
// See https://trac.torproject.org/18599
|
||||
// For now, we always return a placeholder if fingerprinting resistance is on.
|
||||
bool usePlaceholder = nsContentUtils::ShouldResistFingerprinting();
|
||||
CanvasRenderingContextHelper::ToBlob(aCx, global, callback, aType, aParams,
|
||||
usePlaceholder, aRv);
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "nsRefreshDriver.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "ActiveLayerTracker.h"
|
||||
#include "CanvasUtils.h"
|
||||
#include "VRManagerChild.h"
|
||||
#include "WebGL1Context.h"
|
||||
#include "WebGL2Context.h"
|
||||
@ -62,8 +63,10 @@ class RequestedFrameRefreshObserver : public nsARefreshObserver
|
||||
|
||||
public:
|
||||
RequestedFrameRefreshObserver(HTMLCanvasElement* const aOwningElement,
|
||||
nsRefreshDriver* aRefreshDriver)
|
||||
nsRefreshDriver* aRefreshDriver,
|
||||
bool aReturnPlaceholderData)
|
||||
: mRegistered(false),
|
||||
mReturnPlaceholderData(aReturnPlaceholderData),
|
||||
mOwningElement(aOwningElement),
|
||||
mRefreshDriver(aRefreshDriver)
|
||||
{
|
||||
@ -71,7 +74,8 @@ public:
|
||||
}
|
||||
|
||||
static already_AddRefed<DataSourceSurface>
|
||||
CopySurface(const RefPtr<SourceSurface>& aSurface)
|
||||
CopySurface(const RefPtr<SourceSurface>& aSurface,
|
||||
bool aReturnPlaceholderData)
|
||||
{
|
||||
RefPtr<DataSourceSurface> data = aSurface->GetDataSurface();
|
||||
if (!data) {
|
||||
@ -100,12 +104,23 @@ public:
|
||||
MOZ_ASSERT(data->GetSize() == copy->GetSize());
|
||||
MOZ_ASSERT(data->GetFormat() == copy->GetFormat());
|
||||
|
||||
memcpy(write.GetData(), read.GetData(),
|
||||
write.GetStride() * copy->GetSize().height);
|
||||
if (aReturnPlaceholderData) {
|
||||
// If returning placeholder data, fill the frame copy with white pixels.
|
||||
memset(write.GetData(), 0xFF,
|
||||
write.GetStride() * copy->GetSize().height);
|
||||
} else {
|
||||
memcpy(write.GetData(), read.GetData(),
|
||||
write.GetStride() * copy->GetSize().height);
|
||||
}
|
||||
|
||||
return copy.forget();
|
||||
}
|
||||
|
||||
void SetReturnPlaceholderData(bool aReturnPlaceholderData)
|
||||
{
|
||||
mReturnPlaceholderData = aReturnPlaceholderData;
|
||||
}
|
||||
|
||||
void WillRefresh(TimeStamp aTime) override
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
@ -144,7 +159,7 @@ public:
|
||||
{
|
||||
AUTO_PROFILER_LABEL(
|
||||
"RequestedFrameRefreshObserver::WillRefresh:CopySurface", OTHER);
|
||||
copy = CopySurface(snapshot);
|
||||
copy = CopySurface(snapshot, mReturnPlaceholderData);
|
||||
if (!copy) {
|
||||
return;
|
||||
}
|
||||
@ -201,6 +216,7 @@ private:
|
||||
}
|
||||
|
||||
bool mRegistered;
|
||||
bool mReturnPlaceholderData;
|
||||
HTMLCanvasElement* const mOwningElement;
|
||||
RefPtr<nsRefreshDriver> mRefreshDriver;
|
||||
};
|
||||
@ -754,7 +770,14 @@ HTMLCanvasElement::CaptureStream(const Optional<double>& aFrameRate,
|
||||
new CanvasCaptureTrackSource(principal, stream));
|
||||
stream->AddTrackInternal(track);
|
||||
|
||||
rv = RegisterFrameCaptureListener(stream->FrameCaptureListener());
|
||||
// Check site-specific permission and display prompt if appropriate.
|
||||
// If no permission, arrange for the frame capture listener to return
|
||||
// all-white, opaque image data.
|
||||
bool usePlaceholder = !CanvasUtils::IsImageExtractionAllowed(
|
||||
OwnerDoc(),
|
||||
nsContentUtils::GetCurrentJSContext());
|
||||
|
||||
rv = RegisterFrameCaptureListener(stream->FrameCaptureListener(), usePlaceholder);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
return nullptr;
|
||||
@ -764,13 +787,18 @@ HTMLCanvasElement::CaptureStream(const Optional<double>& aFrameRate,
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLCanvasElement::ExtractData(nsAString& aType,
|
||||
HTMLCanvasElement::ExtractData(JSContext* aCx,
|
||||
nsAString& aType,
|
||||
const nsAString& aOptions,
|
||||
nsIInputStream** aStream)
|
||||
{
|
||||
// Check site-specific permission and display prompt if appropriate.
|
||||
// If no permission, return all-white, opaque image data.
|
||||
bool usePlaceholder = !CanvasUtils::IsImageExtractionAllowed(OwnerDoc(), aCx);
|
||||
return ImageEncoder::ExtractData(aType,
|
||||
aOptions,
|
||||
GetSize(),
|
||||
usePlaceholder,
|
||||
mCurrentContext,
|
||||
mAsyncCanvasRenderer,
|
||||
aStream);
|
||||
@ -800,12 +828,12 @@ HTMLCanvasElement::ToDataURLImpl(JSContext* aCx,
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
rv = ExtractData(type, params, getter_AddRefs(stream));
|
||||
rv = ExtractData(aCx, type, params, getter_AddRefs(stream));
|
||||
|
||||
// If there are unrecognized custom parse options, we should fall back to
|
||||
// the default values for the encoder without any options at all.
|
||||
if (rv == NS_ERROR_INVALID_ARG && usingCustomParseOptions) {
|
||||
rv = ExtractData(type, EmptyString(), getter_AddRefs(stream));
|
||||
rv = ExtractData(aCx, type, EmptyString(), getter_AddRefs(stream));
|
||||
}
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -855,8 +883,11 @@ HTMLCanvasElement::ToBlob(JSContext* aCx,
|
||||
return;
|
||||
}
|
||||
|
||||
// Check site-specific permission and display prompt if appropriate.
|
||||
// If no permission, return all-white, opaque image data.
|
||||
bool usePlaceholder = !CanvasUtils::IsImageExtractionAllowed(OwnerDoc(), aCx);
|
||||
CanvasRenderingContextHelper::ToBlob(aCx, global, aCallback, aType,
|
||||
aParams, aRv);
|
||||
aParams, usePlaceholder, aRv);
|
||||
|
||||
}
|
||||
|
||||
@ -925,7 +956,8 @@ HTMLCanvasElement::MozGetAsFileImpl(const nsAString& aName,
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
nsAutoString type(aType);
|
||||
nsresult rv = ExtractData(type, EmptyString(), getter_AddRefs(stream));
|
||||
nsresult rv = ExtractData(nsContentUtils::GetCurrentJSContext(),
|
||||
type, EmptyString(), getter_AddRefs(stream));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint64_t imgSize;
|
||||
@ -1246,7 +1278,8 @@ HTMLCanvasElement::IsContextCleanForFrameCapture()
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLCanvasElement::RegisterFrameCaptureListener(FrameCaptureListener* aListener)
|
||||
HTMLCanvasElement::RegisterFrameCaptureListener(FrameCaptureListener* aListener,
|
||||
bool aReturnPlaceholderData)
|
||||
{
|
||||
WeakPtr<FrameCaptureListener> listener = aListener;
|
||||
|
||||
@ -1285,7 +1318,9 @@ HTMLCanvasElement::RegisterFrameCaptureListener(FrameCaptureListener* aListener)
|
||||
}
|
||||
|
||||
mRequestedFrameRefreshObserver =
|
||||
new RequestedFrameRefreshObserver(this, driver);
|
||||
new RequestedFrameRefreshObserver(this, driver, aReturnPlaceholderData);
|
||||
} else {
|
||||
mRequestedFrameRefreshObserver->SetReturnPlaceholderData(aReturnPlaceholderData);
|
||||
}
|
||||
|
||||
mRequestedFrameListeners.AppendElement(listener);
|
||||
|
@ -262,7 +262,8 @@ public:
|
||||
* caller's responsibility to keep them alive. Once a registered
|
||||
* FrameCaptureListener is destroyed it will be automatically deregistered.
|
||||
*/
|
||||
nsresult RegisterFrameCaptureListener(FrameCaptureListener* aListener);
|
||||
nsresult RegisterFrameCaptureListener(FrameCaptureListener* aListener,
|
||||
bool aReturnPlaceholderData);
|
||||
|
||||
/*
|
||||
* Returns true when there is at least one registered FrameCaptureListener
|
||||
@ -348,7 +349,8 @@ protected:
|
||||
virtual already_AddRefed<nsICanvasRenderingContextInternal>
|
||||
CreateContext(CanvasContextType aContextType) override;
|
||||
|
||||
nsresult ExtractData(nsAString& aType,
|
||||
nsresult ExtractData(JSContext* aCx,
|
||||
nsAString& aType,
|
||||
const nsAString& aOptions,
|
||||
nsIInputStream** aStream);
|
||||
nsresult ToDataURLImpl(JSContext* aCx,
|
||||
|
@ -594,6 +594,14 @@ parent:
|
||||
*/
|
||||
async RequestCrossBrowserNavigation(uint32_t aGlobalIndex);
|
||||
|
||||
/**
|
||||
* This function is used to notify the parent that it should display a
|
||||
* canvas permission prompt.
|
||||
*
|
||||
* @param aFirstPartyURI first party of the tab that is requesting access.
|
||||
*/
|
||||
async ShowCanvasPermissionPrompt(nsCString aFirstPartyURI);
|
||||
|
||||
child:
|
||||
/**
|
||||
* Notify the remote browser that it has been Show()n on this
|
||||
|
@ -3604,6 +3604,27 @@ TabParent::RecvRequestCrossBrowserNavigation(const uint32_t& aGlobalIndex)
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
TabParent::RecvShowCanvasPermissionPrompt(const nsCString& aFirstPartyURI)
|
||||
{
|
||||
nsCOMPtr<nsIBrowser> browser = do_QueryInterface(mFrameElement);
|
||||
if (!browser) {
|
||||
// If the tab is being closed, the browser may not be available.
|
||||
// In this case we can ignore the request.
|
||||
return IPC_OK();
|
||||
}
|
||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||
if (!os) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
nsresult rv = os->NotifyObservers(browser, "canvas-permissions-prompt",
|
||||
NS_ConvertUTF8toUTF16(aFirstPartyURI).get());
|
||||
if (NS_FAILED(rv)) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::LiveResizeStarted()
|
||||
{
|
||||
|
@ -648,6 +648,7 @@ protected:
|
||||
const bool& aTruncate) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvRequestCrossBrowserNavigation(const uint32_t& aGlobalIndex) override;
|
||||
virtual mozilla::ipc::IPCResult RecvShowCanvasPermissionPrompt(const nsCString& aFirstPartyURI) override;
|
||||
|
||||
ContentCacheInParent mContentCache;
|
||||
|
||||
|
@ -157,6 +157,7 @@ CaptureTask::SetCurrentFrames(const VideoSegment& aSegment)
|
||||
options,
|
||||
false,
|
||||
image,
|
||||
false,
|
||||
new EncodeComplete(this));
|
||||
if (NS_FAILED(rv)) {
|
||||
PostTrackEndEvent();
|
||||
|
Loading…
Reference in New Issue
Block a user