зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 11 changesets (bug 709490) for webgl-color-test.html failures a=backout
Backed out changeset fc04c5d43550 (bug 709490) Backed out changeset cd8f9410d335 (bug 709490) Backed out changeset 6e687c9143c1 (bug 709490) Backed out changeset 9b20f2c833c4 (bug 709490) Backed out changeset f9d130aea88e (bug 709490) Backed out changeset fc513b410949 (bug 709490) Backed out changeset acf6220b431a (bug 709490) Backed out changeset 9bceaf913791 (bug 709490) Backed out changeset 37fba20111e2 (bug 709490) Backed out changeset 2285ce1596b8 (bug 709490) Backed out changeset fb4e09920569 (bug 709490)
This commit is contained in:
Родитель
131b0cd1dd
Коммит
c1750b75c7
|
@ -8,7 +8,6 @@
|
|||
#include "mozilla/dom/CanvasRenderingContext2D.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/DataSurfaceHelpers.h"
|
||||
#include "mozilla/layers/AsyncCanvasRenderer.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/SyncRunnable.h"
|
||||
#include "mozilla/unused.h"
|
||||
|
@ -166,7 +165,6 @@ public:
|
|||
mSize,
|
||||
mImage,
|
||||
nullptr,
|
||||
nullptr,
|
||||
getter_AddRefs(stream),
|
||||
mEncoder);
|
||||
|
||||
|
@ -180,7 +178,6 @@ public:
|
|||
mSize,
|
||||
mImage,
|
||||
nullptr,
|
||||
nullptr,
|
||||
getter_AddRefs(stream),
|
||||
mEncoder);
|
||||
}
|
||||
|
@ -237,7 +234,6 @@ ImageEncoder::ExtractData(nsAString& aType,
|
|||
const nsAString& aOptions,
|
||||
const nsIntSize aSize,
|
||||
nsICanvasRenderingContextInternal* aContext,
|
||||
layers::AsyncCanvasRenderer* aRenderer,
|
||||
nsIInputStream** aStream)
|
||||
{
|
||||
nsCOMPtr<imgIEncoder> encoder = ImageEncoder::GetImageEncoder(aType);
|
||||
|
@ -246,9 +242,10 @@ ImageEncoder::ExtractData(nsAString& aType,
|
|||
}
|
||||
|
||||
return ExtractDataInternal(aType, aOptions, nullptr, 0, aSize, nullptr,
|
||||
aContext, aRenderer, aStream, encoder);
|
||||
aContext, aStream, encoder);
|
||||
}
|
||||
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
ImageEncoder::ExtractDataFromLayersImageAsync(nsAString& aType,
|
||||
|
@ -344,7 +341,6 @@ ImageEncoder::ExtractDataInternal(const nsAString& aType,
|
|||
const nsIntSize aSize,
|
||||
layers::Image* aImage,
|
||||
nsICanvasRenderingContextInternal* aContext,
|
||||
layers::AsyncCanvasRenderer* aRenderer,
|
||||
nsIInputStream** aStream,
|
||||
imgIEncoder* aEncoder)
|
||||
{
|
||||
|
@ -370,11 +366,6 @@ ImageEncoder::ExtractDataInternal(const nsAString& aType,
|
|||
rv = aContext->GetInputStream(encoderType.get(),
|
||||
nsPromiseFlatString(aOptions).get(),
|
||||
getter_AddRefs(imgStream));
|
||||
} else if (aRenderer) {
|
||||
NS_ConvertUTF16toUTF8 encoderType(aType);
|
||||
rv = aRenderer->GetInputStream(encoderType.get(),
|
||||
nsPromiseFlatString(aOptions).get(),
|
||||
getter_AddRefs(imgStream));
|
||||
} else if (aImage) {
|
||||
// It is safe to convert PlanarYCbCr format from YUV to RGB off-main-thread.
|
||||
// Other image formats could have problem to convert format off-main-thread.
|
||||
|
|
|
@ -19,7 +19,6 @@ class nsICanvasRenderingContextInternal;
|
|||
namespace mozilla {
|
||||
|
||||
namespace layers {
|
||||
class AsyncCanvasRenderer;
|
||||
class Image;
|
||||
} // namespace layers
|
||||
|
||||
|
@ -41,7 +40,6 @@ public:
|
|||
const nsAString& aOptions,
|
||||
const nsIntSize aSize,
|
||||
nsICanvasRenderingContextInternal* aContext,
|
||||
layers::AsyncCanvasRenderer* aRenderer,
|
||||
nsIInputStream** aStream);
|
||||
|
||||
// Extracts data asynchronously. aType may change to "image/png" if we had to
|
||||
|
@ -86,7 +84,7 @@ public:
|
|||
nsIInputStream** aStream);
|
||||
|
||||
private:
|
||||
// When called asynchronously, aContext and aRenderer are null.
|
||||
// When called asynchronously, aContext is null.
|
||||
static nsresult
|
||||
ExtractDataInternal(const nsAString& aType,
|
||||
const nsAString& aOptions,
|
||||
|
@ -95,7 +93,6 @@ private:
|
|||
const nsIntSize aSize,
|
||||
layers::Image* aImage,
|
||||
nsICanvasRenderingContextInternal* aContext,
|
||||
layers::AsyncCanvasRenderer* aRenderer,
|
||||
nsIInputStream** aStream,
|
||||
imgIEncoder* aEncoder);
|
||||
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
#include "mozilla/dom/StructuredClone.h"
|
||||
#include "mozilla/dom/MessagePort.h"
|
||||
#include "mozilla/dom/MessagePortBinding.h"
|
||||
#include "mozilla/dom/OffscreenCanvas.h"
|
||||
#include "mozilla/dom/OffscreenCanvasBinding.h"
|
||||
#include "mozilla/dom/PMessagePort.h"
|
||||
#include "mozilla/dom/StructuredCloneTags.h"
|
||||
#include "mozilla/dom/SubtleCryptoBinding.h"
|
||||
|
@ -1066,25 +1064,6 @@ StructuredCloneHolder::CustomReadTransferHandler(JSContext* aCx,
|
|||
return true;
|
||||
}
|
||||
|
||||
if (aTag == SCTAG_DOM_CANVAS) {
|
||||
MOZ_ASSERT(mSupportedContext == SameProcessSameThread ||
|
||||
mSupportedContext == SameProcessDifferentThread);
|
||||
MOZ_ASSERT(aContent);
|
||||
OffscreenCanvasCloneData* data =
|
||||
static_cast<OffscreenCanvasCloneData*>(aContent);
|
||||
nsRefPtr<OffscreenCanvas> canvas = OffscreenCanvas::CreateFromCloneData(data);
|
||||
delete data;
|
||||
|
||||
JS::Rooted<JS::Value> value(aCx);
|
||||
if (!GetOrCreateDOMReflector(aCx, canvas, &value)) {
|
||||
JS_ClearPendingException(aCx);
|
||||
return false;
|
||||
}
|
||||
|
||||
aReturnObject.set(&value.toObject());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1116,24 +1095,6 @@ StructuredCloneHolder::CustomWriteTransferHandler(JSContext* aCx,
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mSupportedContext == SameProcessSameThread ||
|
||||
mSupportedContext == SameProcessDifferentThread) {
|
||||
OffscreenCanvas* canvas = nullptr;
|
||||
rv = UNWRAP_OBJECT(OffscreenCanvas, aObj, canvas);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
MOZ_ASSERT(canvas);
|
||||
|
||||
*aExtraData = 0;
|
||||
*aTag = SCTAG_DOM_CANVAS;
|
||||
*aOwnership = JS::SCTAG_TMO_CUSTOM;
|
||||
*aContent = canvas->ToCloneData();
|
||||
MOZ_ASSERT(*aContent);
|
||||
canvas->SetNeutered();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -1151,17 +1112,6 @@ StructuredCloneHolder::CustomFreeTransferHandler(uint32_t aTag,
|
|||
MOZ_ASSERT(!aContent);
|
||||
MOZ_ASSERT(aExtraData < mPortIdentifiers.Length());
|
||||
MessagePort::ForceClose(mPortIdentifiers[aExtraData]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aTag == SCTAG_DOM_CANVAS) {
|
||||
MOZ_ASSERT(mSupportedContext == SameProcessSameThread ||
|
||||
mSupportedContext == SameProcessDifferentThread);
|
||||
MOZ_ASSERT(aContent);
|
||||
OffscreenCanvasCloneData* data =
|
||||
static_cast<OffscreenCanvasCloneData*>(aContent);
|
||||
delete data;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,9 +48,6 @@ enum StructuredCloneTags {
|
|||
|
||||
SCTAG_DOM_FORMDATA,
|
||||
|
||||
// This tag is for OffscreenCanvas.
|
||||
SCTAG_DOM_CANVAS,
|
||||
|
||||
SCTAG_DOM_MAX
|
||||
};
|
||||
|
||||
|
|
|
@ -1,265 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "CanvasRenderingContextHelper.h"
|
||||
#include "ImageEncoder.h"
|
||||
#include "mozilla/dom/CanvasRenderingContext2D.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMJSUtils.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "WebGL1Context.h"
|
||||
#include "WebGL2Context.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
void
|
||||
CanvasRenderingContextHelper::ToBlob(JSContext* aCx,
|
||||
nsIGlobalObject* aGlobal,
|
||||
FileCallback& aCallback,
|
||||
const nsAString& aType,
|
||||
JS::Handle<JS::Value> aParams,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsAutoString type;
|
||||
nsContentUtils::ASCIIToLower(aType, type);
|
||||
|
||||
nsAutoString params;
|
||||
bool usingCustomParseOptions;
|
||||
aRv = ParseParams(aCx, type, aParams, params, &usingCustomParseOptions);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCurrentContext) {
|
||||
// We disallow canvases of width or height zero, and set them to 1, so
|
||||
// we will have a discrepancy with the sizes of the canvas and the context.
|
||||
// That discrepancy is OK, the rest are not.
|
||||
nsIntSize elementSize = GetWidthHeight();
|
||||
if ((elementSize.width != mCurrentContext->GetWidth() &&
|
||||
(elementSize.width != 0 || mCurrentContext->GetWidth() != 1)) ||
|
||||
(elementSize.height != mCurrentContext->GetHeight() &&
|
||||
(elementSize.height != 0 || mCurrentContext->GetHeight() != 1))) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* imageBuffer = nullptr;
|
||||
int32_t format = 0;
|
||||
if (mCurrentContext) {
|
||||
mCurrentContext->GetImageBuffer(&imageBuffer, &format);
|
||||
}
|
||||
|
||||
// Encoder callback when encoding is complete.
|
||||
class EncodeCallback : public EncodeCompleteCallback
|
||||
{
|
||||
public:
|
||||
EncodeCallback(nsIGlobalObject* aGlobal, FileCallback* aCallback)
|
||||
: mGlobal(aGlobal)
|
||||
, mFileCallback(aCallback) {}
|
||||
|
||||
// This is called on main thread.
|
||||
nsresult ReceiveBlob(already_AddRefed<Blob> aBlob)
|
||||
{
|
||||
nsRefPtr<Blob> blob = aBlob;
|
||||
|
||||
ErrorResult rv;
|
||||
uint64_t size = blob->GetSize(rv);
|
||||
if (rv.Failed()) {
|
||||
rv.SuppressException();
|
||||
} else {
|
||||
AutoJSAPI jsapi;
|
||||
if (jsapi.Init(mGlobal)) {
|
||||
JS_updateMallocCounter(jsapi.cx(), size);
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<Blob> newBlob = Blob::Create(mGlobal, blob->Impl());
|
||||
|
||||
mFileCallback->Call(*newBlob, rv);
|
||||
|
||||
mGlobal = nullptr;
|
||||
mFileCallback = nullptr;
|
||||
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
nsRefPtr<FileCallback> mFileCallback;
|
||||
};
|
||||
|
||||
nsRefPtr<EncodeCompleteCallback> callback =
|
||||
new EncodeCallback(aGlobal, &aCallback);
|
||||
|
||||
aRv = ImageEncoder::ExtractDataAsync(type,
|
||||
params,
|
||||
usingCustomParseOptions,
|
||||
imageBuffer,
|
||||
format,
|
||||
GetWidthHeight(),
|
||||
callback);
|
||||
}
|
||||
|
||||
already_AddRefed<nsICanvasRenderingContextInternal>
|
||||
CanvasRenderingContextHelper::CreateContext(CanvasContextType aContextType)
|
||||
{
|
||||
MOZ_ASSERT(aContextType != CanvasContextType::NoContext);
|
||||
nsRefPtr<nsICanvasRenderingContextInternal> ret;
|
||||
|
||||
switch (aContextType) {
|
||||
case CanvasContextType::NoContext:
|
||||
break;
|
||||
|
||||
case CanvasContextType::Canvas2D:
|
||||
Telemetry::Accumulate(Telemetry::CANVAS_2D_USED, 1);
|
||||
ret = new CanvasRenderingContext2D();
|
||||
break;
|
||||
|
||||
case CanvasContextType::WebGL1:
|
||||
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
|
||||
|
||||
ret = WebGL1Context::Create();
|
||||
if (!ret)
|
||||
return nullptr;
|
||||
|
||||
break;
|
||||
|
||||
case CanvasContextType::WebGL2:
|
||||
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
|
||||
|
||||
ret = WebGL2Context::Create();
|
||||
if (!ret)
|
||||
return nullptr;
|
||||
|
||||
break;
|
||||
}
|
||||
MOZ_ASSERT(ret);
|
||||
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<nsISupports>
|
||||
CanvasRenderingContextHelper::GetContext(JSContext* aCx,
|
||||
const nsAString& aContextId,
|
||||
JS::Handle<JS::Value> aContextOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
CanvasContextType contextType;
|
||||
if (!CanvasUtils::GetCanvasContextType(aContextId, &contextType))
|
||||
return nullptr;
|
||||
|
||||
if (!mCurrentContext) {
|
||||
// This canvas doesn't have a context yet.
|
||||
nsRefPtr<nsICanvasRenderingContextInternal> context;
|
||||
context = CreateContext(contextType);
|
||||
if (!context) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Ensure that the context participates in CC. Note that returning a
|
||||
// CC participant from QI doesn't addref.
|
||||
nsXPCOMCycleCollectionParticipant* cp = nullptr;
|
||||
CallQueryInterface(context, &cp);
|
||||
if (!cp) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mCurrentContext = context.forget();
|
||||
mCurrentContextType = contextType;
|
||||
|
||||
aRv = UpdateContext(aCx, aContextOptions);
|
||||
if (aRv.Failed()) {
|
||||
aRv = NS_OK; // See bug 645792
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
// We already have a context of some type.
|
||||
if (contextType != mCurrentContextType)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsICanvasRenderingContextInternal> context = mCurrentContext;
|
||||
return context.forget();
|
||||
}
|
||||
|
||||
nsresult
|
||||
CanvasRenderingContextHelper::UpdateContext(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aNewContextOptions)
|
||||
{
|
||||
if (!mCurrentContext)
|
||||
return NS_OK;
|
||||
|
||||
nsIntSize sz = GetWidthHeight();
|
||||
|
||||
nsCOMPtr<nsICanvasRenderingContextInternal> currentContext = mCurrentContext;
|
||||
|
||||
nsresult rv = currentContext->SetIsOpaque(GetOpaqueAttr());
|
||||
if (NS_FAILED(rv)) {
|
||||
mCurrentContext = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = currentContext->SetContextOptions(aCx, aNewContextOptions);
|
||||
if (NS_FAILED(rv)) {
|
||||
mCurrentContext = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = currentContext->SetDimensions(sz.width, sz.height);
|
||||
if (NS_FAILED(rv)) {
|
||||
mCurrentContext = nullptr;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CanvasRenderingContextHelper::ParseParams(JSContext* aCx,
|
||||
const nsAString& aType,
|
||||
const JS::Value& aEncoderOptions,
|
||||
nsAString& outParams,
|
||||
bool* const outUsingCustomParseOptions)
|
||||
{
|
||||
// Quality parameter is only valid for the image/jpeg MIME type
|
||||
if (aType.EqualsLiteral("image/jpeg")) {
|
||||
if (aEncoderOptions.isNumber()) {
|
||||
double quality = aEncoderOptions.toNumber();
|
||||
// Quality must be between 0.0 and 1.0, inclusive
|
||||
if (quality >= 0.0 && quality <= 1.0) {
|
||||
outParams.AppendLiteral("quality=");
|
||||
outParams.AppendInt(NS_lround(quality * 100.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we haven't parsed the aParams check for proprietary options.
|
||||
// The proprietary option -moz-parse-options will take a image lib encoder
|
||||
// parse options string as is and pass it to the encoder.
|
||||
*outUsingCustomParseOptions = false;
|
||||
if (outParams.Length() == 0 && aEncoderOptions.isString()) {
|
||||
NS_NAMED_LITERAL_STRING(mozParseOptions, "-moz-parse-options:");
|
||||
nsAutoJSString paramString;
|
||||
if (!paramString.init(aCx, aEncoderOptions.toString())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (StringBeginsWith(paramString, mozParseOptions)) {
|
||||
nsDependentSubstring parseOptions = Substring(paramString,
|
||||
mozParseOptions.Length(),
|
||||
paramString.Length() -
|
||||
mozParseOptions.Length());
|
||||
outParams.Append(parseOptions);
|
||||
*outUsingCustomParseOptions = true;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -1,71 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MOZILLA_DOM_CANVASRENDERINGCONTEXTHELPER_H_
|
||||
#define MOZILLA_DOM_CANVASRENDERINGCONTEXTHELPER_H_
|
||||
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "nsSize.h"
|
||||
|
||||
class nsICanvasRenderingContextInternal;
|
||||
class nsIGlobalObject;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class FileCallback;
|
||||
|
||||
enum class CanvasContextType : uint8_t {
|
||||
NoContext,
|
||||
Canvas2D,
|
||||
WebGL1,
|
||||
WebGL2
|
||||
};
|
||||
|
||||
/**
|
||||
* Povides common RenderingContext functionality used by both OffscreenCanvas
|
||||
* and HTMLCanvasElement.
|
||||
*/
|
||||
class CanvasRenderingContextHelper
|
||||
{
|
||||
public:
|
||||
virtual already_AddRefed<nsISupports>
|
||||
GetContext(JSContext* aCx,
|
||||
const nsAString& aContextId,
|
||||
JS::Handle<JS::Value> aContextOptions,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual bool GetOpaqueAttr() = 0;
|
||||
|
||||
protected:
|
||||
virtual nsresult UpdateContext(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aNewContextOptions);
|
||||
|
||||
virtual nsresult ParseParams(JSContext* aCx,
|
||||
const nsAString& aType,
|
||||
const JS::Value& aEncoderOptions,
|
||||
nsAString& outParams,
|
||||
bool* const outCustomParseOptions);
|
||||
|
||||
void ToBlob(JSContext* aCx, nsIGlobalObject* global, FileCallback& aCallback,
|
||||
const nsAString& aType, JS::Handle<JS::Value> aParams,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual already_AddRefed<nsICanvasRenderingContextInternal>
|
||||
CreateContext(CanvasContextType aContextType);
|
||||
|
||||
virtual nsIntSize GetWidthHeight() = 0;
|
||||
|
||||
CanvasContextType mCurrentContextType;
|
||||
nsCOMPtr<nsICanvasRenderingContextInternal> mCurrentContext;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // MOZILLA_DOM_CANVASRENDERINGCONTEXTHELPER_H_
|
|
@ -23,47 +23,12 @@
|
|||
|
||||
#include "CanvasUtils.h"
|
||||
#include "mozilla/gfx/Matrix.h"
|
||||
#include "WebGL2Context.h"
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
namespace mozilla {
|
||||
namespace CanvasUtils {
|
||||
|
||||
bool
|
||||
GetCanvasContextType(const nsAString& str, dom::CanvasContextType* const out_type)
|
||||
{
|
||||
if (str.EqualsLiteral("2d")) {
|
||||
*out_type = dom::CanvasContextType::Canvas2D;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (str.EqualsLiteral("experimental-webgl")) {
|
||||
*out_type = dom::CanvasContextType::WebGL1;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WEBGL_CONFORMANT
|
||||
if (str.EqualsLiteral("webgl")) {
|
||||
/* WebGL 1.0, $2.1 "Context Creation":
|
||||
* If the user agent supports both the webgl and experimental-webgl
|
||||
* canvas context types, they shall be treated as aliases.
|
||||
*/
|
||||
*out_type = dom::CanvasContextType::WebGL1;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (WebGL2Context::IsSupported()) {
|
||||
if (str.EqualsLiteral("webgl2")) {
|
||||
*out_type = dom::CanvasContextType::WebGL2;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This security check utility might be called from an source that never taints
|
||||
* others. For example, while painting a CanvasPattern, which is created from an
|
||||
|
|
|
@ -21,7 +21,6 @@ class HTMLCanvasElement;
|
|||
|
||||
namespace CanvasUtils {
|
||||
|
||||
bool GetCanvasContextType(const nsAString& str, dom::CanvasContextType* const out_type);
|
||||
|
||||
// Check that the rectangle [x,y,w,h] is a subrectangle of [0,0,realWidth,realHeight]
|
||||
|
||||
|
|
|
@ -1,242 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "OffscreenCanvas.h"
|
||||
|
||||
#include "mozilla/dom/OffscreenCanvasBinding.h"
|
||||
#include "mozilla/dom/WorkerPrivate.h"
|
||||
#include "mozilla/layers/AsyncCanvasRenderer.h"
|
||||
#include "mozilla/layers/CanvasClient.h"
|
||||
#include "mozilla/layers/ImageBridgeChild.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "CanvasRenderingContext2D.h"
|
||||
#include "CanvasUtils.h"
|
||||
#include "GLScreenBuffer.h"
|
||||
#include "WebGL1Context.h"
|
||||
#include "WebGL2Context.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
OffscreenCanvasCloneData::OffscreenCanvasCloneData(layers::AsyncCanvasRenderer* aRenderer,
|
||||
uint32_t aWidth, uint32_t aHeight,
|
||||
layers::LayersBackend aCompositorBackend,
|
||||
bool aNeutered)
|
||||
: mRenderer(aRenderer)
|
||||
, mWidth(aWidth)
|
||||
, mHeight(aHeight)
|
||||
, mCompositorBackendType(aCompositorBackend)
|
||||
, mNeutered(aNeutered)
|
||||
{
|
||||
}
|
||||
|
||||
OffscreenCanvasCloneData::~OffscreenCanvasCloneData()
|
||||
{
|
||||
}
|
||||
|
||||
OffscreenCanvas::OffscreenCanvas(uint32_t aWidth,
|
||||
uint32_t aHeight,
|
||||
layers::LayersBackend aCompositorBackend,
|
||||
layers::AsyncCanvasRenderer* aRenderer)
|
||||
: mAttrDirty(false)
|
||||
, mNeutered(false)
|
||||
, mWidth(aWidth)
|
||||
, mHeight(aHeight)
|
||||
, mCompositorBackendType(aCompositorBackend)
|
||||
, mCanvasClient(nullptr)
|
||||
, mCanvasRenderer(aRenderer)
|
||||
{}
|
||||
|
||||
OffscreenCanvas::~OffscreenCanvas()
|
||||
{
|
||||
ClearResources();
|
||||
}
|
||||
|
||||
OffscreenCanvas*
|
||||
OffscreenCanvas::GetParentObject() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
OffscreenCanvas::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return OffscreenCanvasBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void
|
||||
OffscreenCanvas::ClearResources()
|
||||
{
|
||||
if (mCanvasClient) {
|
||||
mCanvasClient->Clear();
|
||||
ImageBridgeChild::DispatchReleaseCanvasClient(mCanvasClient);
|
||||
mCanvasClient = nullptr;
|
||||
|
||||
if (mCanvasRenderer) {
|
||||
nsCOMPtr<nsIThread> activeThread = mCanvasRenderer->GetActiveThread();
|
||||
MOZ_RELEASE_ASSERT(activeThread);
|
||||
MOZ_RELEASE_ASSERT(activeThread == NS_GetCurrentThread());
|
||||
mCanvasRenderer->SetCanvasClient(nullptr);
|
||||
mCanvasRenderer->mContext = nullptr;
|
||||
mCanvasRenderer->mGLContext = nullptr;
|
||||
mCanvasRenderer->ResetActiveThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<nsISupports>
|
||||
OffscreenCanvas::GetContext(JSContext* aCx,
|
||||
const nsAString& aContextId,
|
||||
JS::Handle<JS::Value> aContextOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (mNeutered) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// We only support WebGL in workers for now
|
||||
CanvasContextType contextType;
|
||||
if (!CanvasUtils::GetCanvasContextType(aContextId, &contextType)) {
|
||||
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!(contextType == CanvasContextType::WebGL1 ||
|
||||
contextType == CanvasContextType::WebGL2))
|
||||
{
|
||||
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<nsISupports> result =
|
||||
CanvasRenderingContextHelper::GetContext(aCx,
|
||||
aContextId,
|
||||
aContextOptions,
|
||||
aRv);
|
||||
|
||||
if (!mCurrentContext) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mCanvasRenderer) {
|
||||
WebGLContext* webGL = static_cast<WebGLContext*>(mCurrentContext.get());
|
||||
gl::GLContext* gl = webGL->GL();
|
||||
mCanvasRenderer->mContext = mCurrentContext;
|
||||
mCanvasRenderer->SetActiveThread();
|
||||
mCanvasRenderer->mGLContext = gl;
|
||||
mCanvasRenderer->SetIsAlphaPremultiplied(webGL->IsPremultAlpha() || !gl->Caps().alpha);
|
||||
|
||||
if (ImageBridgeChild::IsCreated()) {
|
||||
TextureFlags flags = TextureFlags::ORIGIN_BOTTOM_LEFT;
|
||||
mCanvasClient = ImageBridgeChild::GetSingleton()->
|
||||
CreateCanvasClient(CanvasClient::CanvasClientTypeShSurf, flags).take();
|
||||
mCanvasRenderer->SetCanvasClient(mCanvasClient);
|
||||
|
||||
gl::GLScreenBuffer* screen = gl->Screen();
|
||||
gl::SurfaceCaps caps = screen->mCaps;
|
||||
auto forwarder = mCanvasClient->GetForwarder();
|
||||
|
||||
UniquePtr<gl::SurfaceFactory> factory =
|
||||
gl::GLScreenBuffer::CreateFactory(gl, caps, forwarder, flags);
|
||||
|
||||
if (factory)
|
||||
screen->Morph(Move(factory));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
already_AddRefed<nsICanvasRenderingContextInternal>
|
||||
OffscreenCanvas::CreateContext(CanvasContextType aContextType)
|
||||
{
|
||||
nsRefPtr<nsICanvasRenderingContextInternal> ret =
|
||||
CanvasRenderingContextHelper::CreateContext(aContextType);
|
||||
|
||||
ret->SetOffscreenCanvas(this);
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
void
|
||||
OffscreenCanvas::CommitFrameToCompositor()
|
||||
{
|
||||
// The attributes has changed, we have to notify main
|
||||
// thread to change canvas size.
|
||||
if (mAttrDirty) {
|
||||
if (mCanvasRenderer) {
|
||||
mCanvasRenderer->SetWidth(mWidth);
|
||||
mCanvasRenderer->SetHeight(mHeight);
|
||||
mCanvasRenderer->NotifyElementAboutAttributesChanged();
|
||||
}
|
||||
mAttrDirty = false;
|
||||
}
|
||||
|
||||
if (mCurrentContext) {
|
||||
static_cast<WebGLContext*>(mCurrentContext.get())->PresentScreenBuffer();
|
||||
}
|
||||
|
||||
if (mCanvasRenderer && mCanvasRenderer->mGLContext) {
|
||||
mCanvasRenderer->NotifyElementAboutInvalidation();
|
||||
ImageBridgeChild::GetSingleton()->
|
||||
UpdateAsyncCanvasRenderer(mCanvasRenderer);
|
||||
}
|
||||
}
|
||||
|
||||
OffscreenCanvasCloneData*
|
||||
OffscreenCanvas::ToCloneData()
|
||||
{
|
||||
return new OffscreenCanvasCloneData(mCanvasRenderer, mWidth, mHeight,
|
||||
mCompositorBackendType, mNeutered);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<OffscreenCanvas>
|
||||
OffscreenCanvas::CreateFromCloneData(OffscreenCanvasCloneData* aData)
|
||||
{
|
||||
MOZ_ASSERT(aData);
|
||||
nsRefPtr<OffscreenCanvas> wc =
|
||||
new OffscreenCanvas(aData->mWidth, aData->mHeight,
|
||||
aData->mCompositorBackendType, aData->mRenderer);
|
||||
if (aData->mNeutered) {
|
||||
wc->SetNeutered();
|
||||
}
|
||||
return wc.forget();
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
OffscreenCanvas::PrefEnabled(JSContext* aCx, JSObject* aObj)
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
return Preferences::GetBool("gfx.offscreencanvas.enabled");
|
||||
} else {
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
return workerPrivate->OffscreenCanvasEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
OffscreenCanvas::PrefEnabledOnWorkerThread(JSContext* aCx, JSObject* aObj)
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return PrefEnabled(aCx, aObj);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(OffscreenCanvas, DOMEventTargetHelper, mCurrentContext)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(OffscreenCanvas, DOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(OffscreenCanvas, DOMEventTargetHelper)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(OffscreenCanvas)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -1,179 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MOZILLA_DOM_OFFSCREENCANVAS_H_
|
||||
#define MOZILLA_DOM_OFFSCREENCANVAS_H_
|
||||
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "CanvasRenderingContextHelper.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
struct JSContext;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
namespace layers {
|
||||
class AsyncCanvasRenderer;
|
||||
class CanvasClient;
|
||||
} // namespace layers
|
||||
|
||||
namespace dom {
|
||||
|
||||
// This is helper class for transferring OffscreenCanvas to worker thread.
|
||||
// Because OffscreenCanvas is not thread-safe. So we cannot pass Offscreen-
|
||||
// Canvas to worker thread directly. Thus, we create this helper class and
|
||||
// store necessary data in it then pass it to worker thread.
|
||||
struct OffscreenCanvasCloneData final
|
||||
{
|
||||
OffscreenCanvasCloneData(layers::AsyncCanvasRenderer* aRenderer,
|
||||
uint32_t aWidth, uint32_t aHeight,
|
||||
layers::LayersBackend aCompositorBackend,
|
||||
bool aNeutered);
|
||||
~OffscreenCanvasCloneData();
|
||||
|
||||
RefPtr<layers::AsyncCanvasRenderer> mRenderer;
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
layers::LayersBackend mCompositorBackendType;
|
||||
bool mNeutered;
|
||||
};
|
||||
|
||||
class OffscreenCanvas final : public DOMEventTargetHelper
|
||||
, public CanvasRenderingContextHelper
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(OffscreenCanvas, DOMEventTargetHelper)
|
||||
|
||||
OffscreenCanvas(uint32_t aWidth,
|
||||
uint32_t aHeight,
|
||||
layers::LayersBackend aCompositorBackend,
|
||||
layers::AsyncCanvasRenderer* aRenderer);
|
||||
|
||||
OffscreenCanvas* GetParentObject() const;
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
void ClearResources();
|
||||
|
||||
uint32_t Width() const
|
||||
{
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
uint32_t Height() const
|
||||
{
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
void SetWidth(uint32_t aWidth, ErrorResult& aRv)
|
||||
{
|
||||
if (mNeutered) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mWidth != aWidth) {
|
||||
mWidth = aWidth;
|
||||
CanvasAttrChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void SetHeight(uint32_t aHeight, ErrorResult& aRv)
|
||||
{
|
||||
if (mNeutered) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mHeight != aHeight) {
|
||||
mHeight = aHeight;
|
||||
CanvasAttrChanged();
|
||||
}
|
||||
}
|
||||
|
||||
nsICanvasRenderingContextInternal* GetContext() const
|
||||
{
|
||||
return mCurrentContext;
|
||||
}
|
||||
|
||||
static already_AddRefed<OffscreenCanvas>
|
||||
CreateFromCloneData(OffscreenCanvasCloneData* aData);
|
||||
|
||||
static bool PrefEnabled(JSContext* aCx, JSObject* aObj);
|
||||
|
||||
// Return true on main-thread, and return gfx.offscreencanvas.enabled
|
||||
// on worker thread.
|
||||
static bool PrefEnabledOnWorkerThread(JSContext* aCx, JSObject* aObj);
|
||||
|
||||
OffscreenCanvasCloneData* ToCloneData();
|
||||
|
||||
void CommitFrameToCompositor();
|
||||
|
||||
virtual bool GetOpaqueAttr() override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual nsIntSize GetWidthHeight() override
|
||||
{
|
||||
return nsIntSize(mWidth, mHeight);
|
||||
}
|
||||
|
||||
virtual already_AddRefed<nsICanvasRenderingContextInternal>
|
||||
CreateContext(CanvasContextType aContextType) override;
|
||||
|
||||
virtual already_AddRefed<nsISupports>
|
||||
GetContext(JSContext* aCx,
|
||||
const nsAString& aContextId,
|
||||
JS::Handle<JS::Value> aContextOptions,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
void SetNeutered()
|
||||
{
|
||||
mNeutered = true;
|
||||
}
|
||||
|
||||
bool IsNeutered() const
|
||||
{
|
||||
return mNeutered;
|
||||
}
|
||||
|
||||
layers::LayersBackend GetCompositorBackendType() const
|
||||
{
|
||||
return mCompositorBackendType;
|
||||
}
|
||||
|
||||
private:
|
||||
~OffscreenCanvas();
|
||||
|
||||
void CanvasAttrChanged()
|
||||
{
|
||||
mAttrDirty = true;
|
||||
UpdateContext(nullptr, JS::NullHandleValue);
|
||||
}
|
||||
|
||||
bool mAttrDirty;
|
||||
bool mNeutered;
|
||||
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
|
||||
layers::LayersBackend mCompositorBackendType;
|
||||
|
||||
layers::CanvasClient* mCanvasClient;
|
||||
RefPtr<layers::AsyncCanvasRenderer> mCanvasRenderer;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // MOZILLA_DOM_OFFSCREENCANVAS_H_
|
|
@ -22,7 +22,6 @@
|
|||
#include "ImageEncoder.h"
|
||||
#include "Layers.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/HTMLVideoElement.h"
|
||||
#include "mozilla/dom/ImageData.h"
|
||||
#include "mozilla/EnumeratedArrayCycleCollection.h"
|
||||
|
@ -80,6 +79,125 @@ using namespace mozilla::gfx;
|
|||
using namespace mozilla::gl;
|
||||
using namespace mozilla::layers;
|
||||
|
||||
WebGLObserver::WebGLObserver(WebGLContext* webgl)
|
||||
: mWebGL(webgl)
|
||||
{
|
||||
}
|
||||
|
||||
WebGLObserver::~WebGLObserver()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
WebGLObserver::Destroy()
|
||||
{
|
||||
UnregisterMemoryPressureEvent();
|
||||
UnregisterVisibilityChangeEvent();
|
||||
mWebGL = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLObserver::RegisterVisibilityChangeEvent()
|
||||
{
|
||||
if (!mWebGL)
|
||||
return;
|
||||
|
||||
HTMLCanvasElement* canvas = mWebGL->GetCanvas();
|
||||
MOZ_ASSERT(canvas);
|
||||
|
||||
if (canvas) {
|
||||
nsIDocument* document = canvas->OwnerDoc();
|
||||
|
||||
document->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
|
||||
this, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLObserver::UnregisterVisibilityChangeEvent()
|
||||
{
|
||||
if (!mWebGL)
|
||||
return;
|
||||
|
||||
HTMLCanvasElement* canvas = mWebGL->GetCanvas();
|
||||
|
||||
if (canvas) {
|
||||
nsIDocument* document = canvas->OwnerDoc();
|
||||
|
||||
document->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
|
||||
this, true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLObserver::RegisterMemoryPressureEvent()
|
||||
{
|
||||
if (!mWebGL)
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
|
||||
MOZ_ASSERT(observerService);
|
||||
|
||||
if (observerService)
|
||||
observerService->AddObserver(this, "memory-pressure", false);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLObserver::UnregisterMemoryPressureEvent()
|
||||
{
|
||||
if (!mWebGL)
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
|
||||
// Do not assert on observerService here. This might be triggered by
|
||||
// the cycle collector at a late enough time, that XPCOM services are
|
||||
// no longer available. See bug 1029504.
|
||||
if (observerService)
|
||||
observerService->RemoveObserver(this, "memory-pressure");
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebGLObserver::Observe(nsISupports*, const char* topic, const char16_t*)
|
||||
{
|
||||
if (!mWebGL || strcmp(topic, "memory-pressure")) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool wantToLoseContext = mWebGL->mLoseContextOnMemoryPressure;
|
||||
|
||||
if (!mWebGL->mCanLoseContextInForeground &&
|
||||
ProcessPriorityManager::CurrentProcessIsForeground())
|
||||
{
|
||||
wantToLoseContext = false;
|
||||
}
|
||||
|
||||
if (wantToLoseContext)
|
||||
mWebGL->ForceLoseContext();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebGLObserver::HandleEvent(nsIDOMEvent* event)
|
||||
{
|
||||
nsAutoString type;
|
||||
event->GetType(type);
|
||||
if (!mWebGL || !type.EqualsLiteral("visibilitychange"))
|
||||
return NS_OK;
|
||||
|
||||
HTMLCanvasElement* canvas = mWebGL->GetCanvas();
|
||||
MOZ_ASSERT(canvas);
|
||||
|
||||
if (canvas && !canvas->OwnerDoc()->Hidden())
|
||||
mWebGL->ForceRestoreContext();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
WebGLContextOptions::WebGLContextOptions()
|
||||
: alpha(true)
|
||||
, depth(true)
|
||||
|
@ -90,7 +208,7 @@ WebGLContextOptions::WebGLContextOptions()
|
|||
, failIfMajorPerformanceCaveat(false)
|
||||
{
|
||||
// Set default alpha state based on preference.
|
||||
if (gfxPrefs::WebGLDefaultNoAlpha())
|
||||
if (Preferences::GetBool("webgl.default-no-alpha", false))
|
||||
alpha = false;
|
||||
}
|
||||
|
||||
|
@ -164,10 +282,7 @@ WebGLContext::WebGLContext()
|
|||
mPixelStorePackAlignment = 4;
|
||||
mPixelStoreUnpackAlignment = 4;
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
// XXX mtseng: bug 709490, not thread safe
|
||||
WebGLMemoryTracker::AddWebGLContext(this);
|
||||
}
|
||||
WebGLMemoryTracker::AddWebGLContext(this);
|
||||
|
||||
mAllowContextRestore = true;
|
||||
mLastLossWasSimulated = false;
|
||||
|
@ -181,12 +296,15 @@ WebGLContext::WebGLContext()
|
|||
mAlreadyWarnedAboutFakeVertexAttrib0 = false;
|
||||
mAlreadyWarnedAboutViewportLargerThanDest = false;
|
||||
|
||||
mMaxWarnings = gfxPrefs::WebGLMaxWarningsPerContext();
|
||||
mMaxWarnings = Preferences::GetInt("webgl.max-warnings-per-context", 32);
|
||||
if (mMaxWarnings < -1) {
|
||||
GenerateWarning("webgl.max-warnings-per-context size is too large (seems like a negative value wrapped)");
|
||||
mMaxWarnings = 0;
|
||||
}
|
||||
|
||||
mContextObserver = new WebGLObserver(this);
|
||||
MOZ_RELEASE_ASSERT(mContextObserver, "Can't alloc WebGLContextObserver");
|
||||
|
||||
mLastUseIndex = 0;
|
||||
|
||||
InvalidateBufferFetching();
|
||||
|
@ -201,12 +319,10 @@ WebGLContext::WebGLContext()
|
|||
WebGLContext::~WebGLContext()
|
||||
{
|
||||
RemovePostRefreshObserver();
|
||||
mContextObserver->Destroy();
|
||||
|
||||
DestroyResourcesAndContext();
|
||||
if (NS_IsMainThread()) {
|
||||
// XXX mtseng: bug 709490, not thread safe
|
||||
WebGLMemoryTracker::RemoveWebGLContext(this);
|
||||
}
|
||||
WebGLMemoryTracker::RemoveWebGLContext(this);
|
||||
|
||||
mContextLossHandler->DisableTimer();
|
||||
mContextLossHandler = nullptr;
|
||||
|
@ -215,6 +331,8 @@ WebGLContext::~WebGLContext()
|
|||
void
|
||||
WebGLContext::DestroyResourcesAndContext()
|
||||
{
|
||||
mContextObserver->UnregisterMemoryPressureEvent();
|
||||
|
||||
if (!gl)
|
||||
return;
|
||||
|
||||
|
@ -313,35 +431,6 @@ WebGLContext::Invalidate()
|
|||
mCanvasElement->InvalidateCanvasContent(nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::OnVisibilityChange()
|
||||
{
|
||||
if (!IsContextLost()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mRestoreWhenVisible || mLastLossWasSimulated) {
|
||||
return;
|
||||
}
|
||||
|
||||
ForceRestoreContext();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::OnMemoryPressure()
|
||||
{
|
||||
bool shouldLoseContext = mLoseContextOnMemoryPressure;
|
||||
|
||||
if (!mCanLoseContextInForeground &&
|
||||
ProcessPriorityManager::CurrentProcessIsForeground())
|
||||
{
|
||||
shouldLoseContext = false;
|
||||
}
|
||||
|
||||
if (shouldLoseContext)
|
||||
ForceLoseContext();
|
||||
}
|
||||
|
||||
//
|
||||
// nsICanvasRenderingContextInternal
|
||||
//
|
||||
|
@ -424,7 +513,7 @@ static bool
|
|||
IsFeatureInBlacklist(const nsCOMPtr<nsIGfxInfo>& gfxInfo, int32_t feature)
|
||||
{
|
||||
int32_t status;
|
||||
if (!NS_SUCCEEDED(gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, feature, &status)))
|
||||
if (!NS_SUCCEEDED(gfxInfo->GetFeatureStatus(feature, &status)))
|
||||
return false;
|
||||
|
||||
return status != nsIGfxInfo::FEATURE_STATUS_OK;
|
||||
|
@ -435,29 +524,19 @@ HasAcceleratedLayers(const nsCOMPtr<nsIGfxInfo>& gfxInfo)
|
|||
{
|
||||
int32_t status;
|
||||
|
||||
gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
|
||||
nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS,
|
||||
&status);
|
||||
gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &status);
|
||||
if (status)
|
||||
return true;
|
||||
gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
|
||||
nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS,
|
||||
&status);
|
||||
gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS, &status);
|
||||
if (status)
|
||||
return true;
|
||||
gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
|
||||
nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS,
|
||||
&status);
|
||||
gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS, &status);
|
||||
if (status)
|
||||
return true;
|
||||
gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
|
||||
nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS,
|
||||
&status);
|
||||
gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status);
|
||||
if (status)
|
||||
return true;
|
||||
gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
|
||||
nsIGfxInfo::FEATURE_OPENGL_LAYERS,
|
||||
&status);
|
||||
gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &status);
|
||||
if (status)
|
||||
return true;
|
||||
|
||||
|
@ -514,14 +593,11 @@ BaseCaps(const WebGLContextOptions& options, WebGLContext* webgl)
|
|||
// we should really have this behind a
|
||||
// |gfxPlatform::GetPlatform()->GetScreenDepth() == 16| check, but
|
||||
// for now it's just behind a pref for testing/evaluation.
|
||||
baseCaps.bpp16 = gfxPrefs::WebGLPrefer16bpp();
|
||||
baseCaps.bpp16 = Preferences::GetBool("webgl.prefer-16bpp", false);
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
do {
|
||||
auto canvasElement = webgl->GetCanvas();
|
||||
if (!canvasElement)
|
||||
break;
|
||||
|
||||
auto ownerDoc = canvasElement->OwnerDoc();
|
||||
nsIWidget* docWidget = nsContentUtils::WidgetForDocument(ownerDoc);
|
||||
if (!docWidget)
|
||||
|
@ -542,7 +618,7 @@ BaseCaps(const WebGLContextOptions& options, WebGLContext* webgl)
|
|||
|
||||
// Done with baseCaps construction.
|
||||
|
||||
bool forceAllowAA = gfxPrefs::WebGLForceMSAA();
|
||||
bool forceAllowAA = Preferences::GetBool("webgl.msaa-force", false);
|
||||
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
|
||||
if (!forceAllowAA &&
|
||||
IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_MSAA))
|
||||
|
@ -662,7 +738,7 @@ bool
|
|||
WebGLContext::CreateAndInitGL(bool forceEnabled)
|
||||
{
|
||||
bool preferEGL = PR_GetEnv("MOZ_WEBGL_PREFER_EGL");
|
||||
bool disableANGLE = gfxPrefs::WebGLDisableANGLE();
|
||||
bool disableANGLE = Preferences::GetBool("webgl.disable-angle", false);
|
||||
|
||||
if (PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL"))
|
||||
disableANGLE = true;
|
||||
|
@ -743,6 +819,10 @@ WebGLContext::ResizeBackbuffer(uint32_t requestedWidth,
|
|||
NS_IMETHODIMP
|
||||
WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
|
||||
{
|
||||
// Early error return cases
|
||||
if (!GetCanvas())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (signedWidth < 0 || signedHeight < 0) {
|
||||
GenerateWarning("Canvas size is too large (seems like a negative value wrapped)");
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
@ -752,10 +832,7 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
|
|||
uint32_t height = signedHeight;
|
||||
|
||||
// Early success return cases
|
||||
|
||||
// May have a OffscreenCanvas instead of an HTMLCanvasElement
|
||||
if (GetCanvas())
|
||||
GetCanvas()->InvalidateCanvas();
|
||||
GetCanvas()->InvalidateCanvas();
|
||||
|
||||
// Zero-sized surfaces can cause problems.
|
||||
if (width == 0)
|
||||
|
@ -828,7 +905,10 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
|
|||
// pick up the old generation.
|
||||
++mGeneration;
|
||||
|
||||
bool disabled = gfxPrefs::WebGLDisabled();
|
||||
// Get some prefs for some preferred/overriden things
|
||||
NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
|
||||
|
||||
bool disabled = Preferences::GetBool("webgl.disabled", false);
|
||||
|
||||
// TODO: When we have software webgl support we should use that instead.
|
||||
disabled |= gfxPlatform::InSafeMode();
|
||||
|
@ -851,7 +931,7 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
|
|||
}
|
||||
|
||||
// Alright, now let's start trying.
|
||||
bool forceEnabled = gfxPrefs::WebGLForceEnabled();
|
||||
bool forceEnabled = Preferences::GetBool("webgl.force-enabled", false);
|
||||
ScopedGfxFeatureReporter reporter("WebGL", forceEnabled);
|
||||
|
||||
MOZ_ASSERT(!gl);
|
||||
|
@ -972,11 +1052,6 @@ WebGLContext::LoseOldestWebGLContextIfLimitExceeded()
|
|||
#endif
|
||||
MOZ_ASSERT(kMaxWebGLContextsPerPrincipal < kMaxWebGLContexts);
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
// XXX mtseng: bug 709490, WebGLMemoryTracker is not thread safe.
|
||||
return;
|
||||
}
|
||||
|
||||
// it's important to update the index on a new context before losing old contexts,
|
||||
// otherwise new unused contexts would all have index 0 and we couldn't distinguish older ones
|
||||
// when choosing which one to lose first.
|
||||
|
@ -1064,8 +1139,32 @@ WebGLContext::GetImageBuffer(uint8_t** out_imageBuffer, int32_t* out_format)
|
|||
|
||||
RefPtr<DataSourceSurface> dataSurface = snapshot->GetDataSurface();
|
||||
|
||||
return gfxUtils::GetImageBuffer(dataSurface, mOptions.premultipliedAlpha,
|
||||
out_imageBuffer, out_format);
|
||||
DataSourceSurface::MappedSurface map;
|
||||
if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map))
|
||||
return;
|
||||
|
||||
uint8_t* imageBuffer = new (fallible) uint8_t[mWidth * mHeight * 4];
|
||||
if (!imageBuffer) {
|
||||
dataSurface->Unmap();
|
||||
return;
|
||||
}
|
||||
memcpy(imageBuffer, map.mData, mWidth * mHeight * 4);
|
||||
|
||||
dataSurface->Unmap();
|
||||
|
||||
int32_t format = imgIEncoder::INPUT_FORMAT_HOSTARGB;
|
||||
if (!mOptions.premultipliedAlpha) {
|
||||
// We need to convert to INPUT_FORMAT_RGBA, otherwise
|
||||
// we are automatically considered premult, and unpremult'd.
|
||||
// Yes, it is THAT silly.
|
||||
// Except for different lossy conversions by color,
|
||||
// we could probably just change the label, and not change the data.
|
||||
gfxUtils::ConvertBGRAtoRGBA(imageBuffer, mWidth * mHeight * 4);
|
||||
format = imgIEncoder::INPUT_FORMAT_RGBA;
|
||||
}
|
||||
|
||||
*out_imageBuffer = imageBuffer;
|
||||
*out_format = format;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1077,18 +1176,20 @@ WebGLContext::GetInputStream(const char* mimeType,
|
|||
if (!gl)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Use GetSurfaceSnapshot() to make sure that appropriate y-flip gets applied
|
||||
bool premult;
|
||||
RefPtr<SourceSurface> snapshot =
|
||||
GetSurfaceSnapshot(mOptions.premultipliedAlpha ? nullptr : &premult);
|
||||
if (!snapshot)
|
||||
nsCString enccid("@mozilla.org/image/encoder;2?type=");
|
||||
enccid += mimeType;
|
||||
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(enccid.get());
|
||||
if (!encoder)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
MOZ_ASSERT(mOptions.premultipliedAlpha || !premult, "We must get unpremult when we ask for it!");
|
||||
nsAutoArrayPtr<uint8_t> imageBuffer;
|
||||
int32_t format = 0;
|
||||
GetImageBuffer(getter_Transfers(imageBuffer), &format);
|
||||
if (!imageBuffer)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
RefPtr<DataSourceSurface> dataSurface = snapshot->GetDataSurface();
|
||||
return gfxUtils::GetInputStream(dataSurface, mOptions.premultipliedAlpha, mimeType,
|
||||
encoderOptions, out_stream);
|
||||
return ImageEncoder::GetInputStream(mWidth, mHeight, imageBuffer, format,
|
||||
encoder, encoderOptions, out_stream);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1167,26 +1268,25 @@ WebGLContext::GetCanvasLayer(nsDisplayListBuilder* builder,
|
|||
}
|
||||
|
||||
WebGLContextUserData* userData = nullptr;
|
||||
if (builder->IsPaintingToWindow() && mCanvasElement) {
|
||||
// Make the layer tell us whenever a transaction finishes (including
|
||||
// the current transaction), so we can clear our invalidation state and
|
||||
// start invalidating again. We need to do this for the layer that is
|
||||
// being painted to a window (there shouldn't be more than one at a time,
|
||||
// and if there is, flushing the invalidation state more often than
|
||||
// necessary is harmless).
|
||||
if (builder->IsPaintingToWindow()) {
|
||||
// Make the layer tell us whenever a transaction finishes (including
|
||||
// the current transaction), so we can clear our invalidation state and
|
||||
// start invalidating again. We need to do this for the layer that is
|
||||
// being painted to a window (there shouldn't be more than one at a time,
|
||||
// and if there is, flushing the invalidation state more often than
|
||||
// necessary is harmless).
|
||||
|
||||
// The layer will be destroyed when we tear down the presentation
|
||||
// (at the latest), at which time this userData will be destroyed,
|
||||
// releasing the reference to the element.
|
||||
// The userData will receive DidTransactionCallbacks, which flush the
|
||||
// the invalidation state to indicate that the canvas is up to date.
|
||||
userData = new WebGLContextUserData(mCanvasElement);
|
||||
canvasLayer->SetDidTransactionCallback(
|
||||
WebGLContextUserData::DidTransactionCallback, userData);
|
||||
canvasLayer->SetPreTransactionCallback(
|
||||
WebGLContextUserData::PreTransactionCallback, userData);
|
||||
// The layer will be destroyed when we tear down the presentation
|
||||
// (at the latest), at which time this userData will be destroyed,
|
||||
// releasing the reference to the element.
|
||||
// The userData will receive DidTransactionCallbacks, which flush the
|
||||
// the invalidation state to indicate that the canvas is up to date.
|
||||
userData = new WebGLContextUserData(mCanvasElement);
|
||||
canvasLayer->SetDidTransactionCallback(
|
||||
WebGLContextUserData::DidTransactionCallback, userData);
|
||||
canvasLayer->SetPreTransactionCallback(
|
||||
WebGLContextUserData::PreTransactionCallback, userData);
|
||||
}
|
||||
|
||||
canvasLayer->SetUserData(&gWebGLLayerUserData, userData);
|
||||
|
||||
CanvasLayer::Data data;
|
||||
|
@ -1208,36 +1308,14 @@ WebGLContext::GetCanvasLayer(nsDisplayListBuilder* builder,
|
|||
layers::LayersBackend
|
||||
WebGLContext::GetCompositorBackendType() const
|
||||
{
|
||||
if (mCanvasElement) {
|
||||
return mCanvasElement->GetCompositorBackendType();
|
||||
} else if (mOffscreenCanvas) {
|
||||
return mOffscreenCanvas->GetCompositorBackendType();
|
||||
nsIWidget* docWidget = nsContentUtils::WidgetForDocument(mCanvasElement->OwnerDoc());
|
||||
if (docWidget) {
|
||||
layers::LayerManager* layerManager = docWidget->GetLayerManager();
|
||||
return layerManager->GetCompositorBackendType();
|
||||
}
|
||||
|
||||
return LayersBackend::LAYERS_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::Commit()
|
||||
{
|
||||
if (mOffscreenCanvas) {
|
||||
mOffscreenCanvas->CommitFrameToCompositor();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::GetCanvas(Nullable<dom::OwningHTMLCanvasElementOrOffscreenCanvas>& retval)
|
||||
{
|
||||
if (mCanvasElement) {
|
||||
MOZ_RELEASE_ASSERT(!mOffscreenCanvas);
|
||||
retval.SetValue().SetAsHTMLCanvasElement() = mCanvasElement;
|
||||
} else if (mOffscreenCanvas) {
|
||||
retval.SetValue().SetAsOffscreenCanvas() = mOffscreenCanvas;
|
||||
} else {
|
||||
retval.SetNull();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::GetContextAttributes(dom::Nullable<dom::WebGLContextAttributes>& retval)
|
||||
{
|
||||
|
@ -1546,7 +1624,7 @@ WebGLContext::RunContextLossTimer()
|
|||
mContextLossHandler->RunTimer();
|
||||
}
|
||||
|
||||
class UpdateContextLossStatusTask : public nsCancelableRunnable
|
||||
class UpdateContextLossStatusTask : public nsRunnable
|
||||
{
|
||||
nsRefPtr<WebGLContext> mWebGL;
|
||||
|
||||
|
@ -1557,16 +1635,10 @@ public:
|
|||
}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
if (mWebGL)
|
||||
mWebGL->UpdateContextLossStatus();
|
||||
mWebGL->UpdateContextLossStatus();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD Cancel() {
|
||||
mWebGL = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -1593,7 +1665,7 @@ WebGLContext::EnqueueUpdateContextLossStatus()
|
|||
void
|
||||
WebGLContext::UpdateContextLossStatus()
|
||||
{
|
||||
if (!mCanvasElement && !mOffscreenCanvas) {
|
||||
if (!mCanvasElement) {
|
||||
// the canvas is gone. That happens when the page was closed before we got
|
||||
// this timer event. In this case, there's nothing to do here, just don't crash.
|
||||
return;
|
||||
|
@ -1621,23 +1693,12 @@ WebGLContext::UpdateContextLossStatus()
|
|||
// callback, so do that now.
|
||||
|
||||
bool useDefaultHandler;
|
||||
|
||||
if (mCanvasElement) {
|
||||
nsContentUtils::DispatchTrustedEvent(
|
||||
mCanvasElement->OwnerDoc(),
|
||||
static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement),
|
||||
NS_LITERAL_STRING("webglcontextlost"),
|
||||
true,
|
||||
true,
|
||||
&useDefaultHandler);
|
||||
} else {
|
||||
// OffscreenCanvas case
|
||||
nsRefPtr<Event> event = new Event(mOffscreenCanvas, nullptr, nullptr);
|
||||
event->InitEvent(NS_LITERAL_STRING("webglcontextlost"), true, true);
|
||||
event->SetTrusted(true);
|
||||
mOffscreenCanvas->DispatchEvent(event, &useDefaultHandler);
|
||||
}
|
||||
|
||||
nsContentUtils::DispatchTrustedEvent(mCanvasElement->OwnerDoc(),
|
||||
static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement),
|
||||
NS_LITERAL_STRING("webglcontextlost"),
|
||||
true,
|
||||
true,
|
||||
&useDefaultHandler);
|
||||
// We sent the callback, so we're just 'regular lost' now.
|
||||
mContextStatus = ContextLost;
|
||||
// If we're told to use the default handler, it means the script
|
||||
|
@ -1689,22 +1750,11 @@ WebGLContext::UpdateContextLossStatus()
|
|||
|
||||
// Revival!
|
||||
mContextStatus = ContextNotLost;
|
||||
|
||||
if (mCanvasElement) {
|
||||
nsContentUtils::DispatchTrustedEvent(
|
||||
mCanvasElement->OwnerDoc(),
|
||||
static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement),
|
||||
NS_LITERAL_STRING("webglcontextrestored"),
|
||||
true,
|
||||
true);
|
||||
} else {
|
||||
nsRefPtr<Event> event = new Event(mOffscreenCanvas, nullptr, nullptr);
|
||||
event->InitEvent(NS_LITERAL_STRING("webglcontextrestored"), true, true);
|
||||
event->SetTrusted(true);
|
||||
bool unused;
|
||||
mOffscreenCanvas->DispatchEvent(event, &unused);
|
||||
}
|
||||
|
||||
nsContentUtils::DispatchTrustedEvent(mCanvasElement->OwnerDoc(),
|
||||
static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement),
|
||||
NS_LITERAL_STRING("webglcontextrestored"),
|
||||
true,
|
||||
true);
|
||||
mEmitContextLostErrorOnce = true;
|
||||
return;
|
||||
}
|
||||
|
@ -1722,6 +1772,12 @@ WebGLContext::ForceLoseContext(bool simulateLosing)
|
|||
DestroyResourcesAndContext();
|
||||
mLastLossWasSimulated = simulateLosing;
|
||||
|
||||
// Register visibility change observer to defer the context restoring.
|
||||
// Restore the context when the app is visible.
|
||||
if (mRestoreWhenVisible && !mLastLossWasSimulated) {
|
||||
mContextObserver->RegisterVisibilityChangeEvent();
|
||||
}
|
||||
|
||||
// Queue up a task, since we know the status changed.
|
||||
EnqueueUpdateContextLossStatus();
|
||||
}
|
||||
|
@ -1733,6 +1789,8 @@ WebGLContext::ForceRestoreContext()
|
|||
mContextStatus = ContextLostAwaitingRestore;
|
||||
mAllowContextRestore = true; // Hey, you did say 'force'.
|
||||
|
||||
mContextObserver->UnregisterVisibilityChangeEvent();
|
||||
|
||||
// Queue up a task, since we know the status changed.
|
||||
EnqueueUpdateContextLossStatus();
|
||||
}
|
||||
|
@ -1867,7 +1925,6 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLContext)
|
|||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext,
|
||||
mCanvasElement,
|
||||
mOffscreenCanvas,
|
||||
mExtensions,
|
||||
mBound2DTextures,
|
||||
mBoundCubeMapTextures,
|
||||
|
|
|
@ -40,11 +40,7 @@
|
|||
// Generated
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsIDOMWebGLRenderingContext.h"
|
||||
#include "nsICanvasRenderingContextInternal.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "mozilla/dom/HTMLCanvasElement.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
|
||||
|
||||
class nsIDocShell;
|
||||
|
@ -84,6 +80,7 @@ class WebGLContextLossHandler;
|
|||
class WebGLBuffer;
|
||||
class WebGLExtensionBase;
|
||||
class WebGLFramebuffer;
|
||||
class WebGLObserver;
|
||||
class WebGLProgram;
|
||||
class WebGLQuery;
|
||||
class WebGLRenderbuffer;
|
||||
|
@ -98,7 +95,6 @@ class WebGLVertexArray;
|
|||
namespace dom {
|
||||
class Element;
|
||||
class ImageData;
|
||||
class OwningHTMLCanvasElementOrOffscreenCanvas;
|
||||
struct WebGLContextAttributes;
|
||||
template<typename> struct Nullable;
|
||||
} // namespace dom
|
||||
|
@ -188,6 +184,7 @@ class WebGLContext
|
|||
friend class WebGLExtensionLoseContext;
|
||||
friend class WebGLExtensionVertexArray;
|
||||
friend class WebGLMemoryTracker;
|
||||
friend class WebGLObserver;
|
||||
|
||||
enum {
|
||||
UNPACK_FLIP_Y_WEBGL = 0x9240,
|
||||
|
@ -217,9 +214,6 @@ public:
|
|||
|
||||
NS_DECL_NSIDOMWEBGLRENDERINGCONTEXT
|
||||
|
||||
virtual void OnVisibilityChange() override;
|
||||
virtual void OnMemoryPressure() override;
|
||||
|
||||
// nsICanvasRenderingContextInternal
|
||||
virtual int32_t GetWidth() const override;
|
||||
virtual int32_t GetHeight() const override;
|
||||
|
@ -367,11 +361,8 @@ public:
|
|||
void AssertCachedBindings();
|
||||
void AssertCachedState();
|
||||
|
||||
dom::HTMLCanvasElement* GetCanvas() const { return mCanvasElement; }
|
||||
|
||||
// WebIDL WebGLRenderingContext API
|
||||
void Commit();
|
||||
void GetCanvas(Nullable<dom::OwningHTMLCanvasElementOrOffscreenCanvas>& retval);
|
||||
dom::HTMLCanvasElement* GetCanvas() const { return mCanvasElement; }
|
||||
GLsizei DrawingBufferWidth() const { return IsContextLost() ? 0 : mWidth; }
|
||||
GLsizei DrawingBufferHeight() const {
|
||||
return IsContextLost() ? 0 : mHeight;
|
||||
|
@ -1517,6 +1508,8 @@ protected:
|
|||
ForceDiscreteGPUHelperCGL mForceDiscreteGPUHelper;
|
||||
#endif
|
||||
|
||||
nsRefPtr<WebGLObserver> mContextObserver;
|
||||
|
||||
public:
|
||||
// console logging helpers
|
||||
void GenerateWarning(const char* fmt, ...);
|
||||
|
@ -1621,6 +1614,32 @@ WebGLContext::ValidateObject(const char* info, ObjectType* object)
|
|||
return ValidateObjectAssumeNonNull(info, object);
|
||||
}
|
||||
|
||||
// Listen visibilitychange and memory-pressure event for context lose/restore
|
||||
class WebGLObserver final
|
||||
: public nsIObserver
|
||||
, public nsIDOMEventListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
|
||||
explicit WebGLObserver(WebGLContext* webgl);
|
||||
|
||||
void Destroy();
|
||||
|
||||
void RegisterVisibilityChangeEvent();
|
||||
void UnregisterVisibilityChangeEvent();
|
||||
|
||||
void RegisterMemoryPressureEvent();
|
||||
void UnregisterMemoryPressureEvent();
|
||||
|
||||
private:
|
||||
~WebGLObserver();
|
||||
|
||||
WebGLContext* mWebGL;
|
||||
};
|
||||
|
||||
size_t RoundUpToMultipleOf(size_t value, size_t multiple);
|
||||
|
||||
bool
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "WebGLContext.h"
|
||||
#include "WebGLContextUtils.h"
|
||||
#include "WebGLExtensions.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "GLContext.h"
|
||||
|
||||
#include "nsString.h"
|
||||
|
@ -75,15 +74,12 @@ bool WebGLContext::IsExtensionSupported(JSContext* cx,
|
|||
|
||||
// Chrome contexts need access to debug information even when
|
||||
// webgl.disable-extensions is set. This is used in the graphics
|
||||
// section of about:support
|
||||
if (NS_IsMainThread() &&
|
||||
xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))) {
|
||||
// section of about:support.
|
||||
if (xpc::AccessCheck::isChrome(js::GetContextCompartment(cx)))
|
||||
allowPrivilegedExts = true;
|
||||
}
|
||||
|
||||
if (gfxPrefs::WebGLPrivilegedExtensionsEnabled()) {
|
||||
if (Preferences::GetBool("webgl.enable-privileged-extensions", false))
|
||||
allowPrivilegedExts = true;
|
||||
}
|
||||
|
||||
if (allowPrivilegedExts) {
|
||||
switch (ext) {
|
||||
|
@ -185,7 +181,9 @@ WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
|
|||
break;
|
||||
}
|
||||
|
||||
if (gfxPrefs::WebGLDraftExtensionsEnabled() || IsWebGL2()) {
|
||||
if (Preferences::GetBool("webgl.enable-draft-extensions", false) ||
|
||||
IsWebGL2())
|
||||
{
|
||||
switch (ext) {
|
||||
case WebGLExtensionID::EXT_disjoint_timer_query:
|
||||
return WebGLExtensionDisjointTimerQuery::IsSupported(this);
|
||||
|
|
|
@ -1390,10 +1390,7 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
|||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (mCanvasElement &&
|
||||
mCanvasElement->IsWriteOnly() &&
|
||||
!nsContentUtils::IsCallerChrome())
|
||||
{
|
||||
if (mCanvasElement->IsWriteOnly() && !nsContentUtils::IsCallerChrome()) {
|
||||
GenerateWarning("readPixels: Not allowed");
|
||||
return rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
}
|
||||
|
|
|
@ -8,103 +8,15 @@
|
|||
#include "nsITimer.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "WebGLContext.h"
|
||||
#include "mozilla/dom/WorkerPrivate.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Begin worker specific code
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// On workers we can only dispatch CancelableRunnables, so we have to wrap the
|
||||
// timer's EventTarget to use our own cancelable runnable
|
||||
|
||||
class ContextLossWorkerEventTarget final : public nsIEventTarget
|
||||
{
|
||||
public:
|
||||
explicit ContextLossWorkerEventTarget(nsIEventTarget* aEventTarget)
|
||||
: mEventTarget(aEventTarget)
|
||||
{
|
||||
MOZ_ASSERT(aEventTarget);
|
||||
}
|
||||
|
||||
NS_DECL_NSIEVENTTARGET
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
protected:
|
||||
~ContextLossWorkerEventTarget() {}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIEventTarget> mEventTarget;
|
||||
};
|
||||
|
||||
class ContextLossWorkerRunnable final : public nsICancelableRunnable
|
||||
{
|
||||
public:
|
||||
explicit ContextLossWorkerRunnable(nsIRunnable* aRunnable)
|
||||
: mRunnable(aRunnable)
|
||||
{
|
||||
}
|
||||
|
||||
NS_DECL_NSICANCELABLERUNNABLE
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
NS_FORWARD_NSIRUNNABLE(mRunnable->)
|
||||
|
||||
protected:
|
||||
~ContextLossWorkerRunnable() {}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(ContextLossWorkerEventTarget, nsIEventTarget,
|
||||
nsISupports)
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContextLossWorkerEventTarget::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> event(aEvent);
|
||||
return Dispatch(event.forget(), aFlags);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContextLossWorkerEventTarget::Dispatch(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> eventRef(aEvent);
|
||||
nsRefPtr<ContextLossWorkerRunnable> wrappedEvent =
|
||||
new ContextLossWorkerRunnable(eventRef);
|
||||
return mEventTarget->Dispatch(wrappedEvent, aFlags);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContextLossWorkerEventTarget::IsOnCurrentThread(bool* aResult)
|
||||
{
|
||||
return mEventTarget->IsOnCurrentThread(aResult);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(ContextLossWorkerRunnable, nsICancelableRunnable,
|
||||
nsIRunnable)
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContextLossWorkerRunnable::Cancel()
|
||||
{
|
||||
mRunnable = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// End worker-specific code
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
WebGLContextLossHandler::WebGLContextLossHandler(WebGLContext* webgl)
|
||||
: mWeakWebGL(webgl)
|
||||
, mTimer(do_CreateInstance(NS_TIMER_CONTRACTID))
|
||||
, mIsTimerRunning(false)
|
||||
, mShouldRunTimerAgain(false)
|
||||
, mIsDisabled(false)
|
||||
, mFeatureAdded(false)
|
||||
#ifdef DEBUG
|
||||
, mThread(NS_GetCurrentThread())
|
||||
#endif
|
||||
|
@ -178,17 +90,6 @@ WebGLContextLossHandler::RunTimer()
|
|||
return;
|
||||
}
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
dom::workers::WorkerPrivate* workerPrivate =
|
||||
dom::workers::GetCurrentThreadWorkerPrivate();
|
||||
nsCOMPtr<nsIEventTarget> target = workerPrivate->GetEventTarget();
|
||||
mTimer->SetTarget(new ContextLossWorkerEventTarget(target));
|
||||
if (!mFeatureAdded) {
|
||||
workerPrivate->AddFeature(workerPrivate->GetJSContext(), this);
|
||||
mFeatureAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
StartTimer(1000);
|
||||
|
||||
mIsTimerRunning = true;
|
||||
|
@ -203,14 +104,6 @@ WebGLContextLossHandler::DisableTimer()
|
|||
|
||||
mIsDisabled = true;
|
||||
|
||||
if (mFeatureAdded) {
|
||||
dom::workers::WorkerPrivate* workerPrivate =
|
||||
dom::workers::GetCurrentThreadWorkerPrivate();
|
||||
MOZ_RELEASE_ASSERT(workerPrivate);
|
||||
workerPrivate->RemoveFeature(workerPrivate->GetJSContext(), this);
|
||||
mFeatureAdded = false;
|
||||
}
|
||||
|
||||
// We can't just Cancel() the timer, as sometimes we end up
|
||||
// receiving a callback after calling Cancel(). This could cause us
|
||||
// to receive the callback after object destruction.
|
||||
|
@ -223,16 +116,4 @@ WebGLContextLossHandler::DisableTimer()
|
|||
mTimer->SetDelay(0);
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContextLossHandler::Notify(JSContext* aCx, dom::workers::Status aStatus)
|
||||
{
|
||||
bool isWorkerRunning = aStatus < dom::workers::Closing;
|
||||
if (!isWorkerRunning && mIsTimerRunning) {
|
||||
mIsTimerRunning = false;
|
||||
this->Release();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "mozilla/WeakPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "WorkerFeature.h"
|
||||
|
||||
class nsIThread;
|
||||
class nsITimer;
|
||||
|
@ -18,14 +17,13 @@ class nsITimer;
|
|||
namespace mozilla {
|
||||
class WebGLContext;
|
||||
|
||||
class WebGLContextLossHandler : public dom::workers::WorkerFeature
|
||||
class WebGLContextLossHandler
|
||||
{
|
||||
WeakPtr<WebGLContext> mWeakWebGL;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
bool mIsTimerRunning;
|
||||
bool mShouldRunTimerAgain;
|
||||
bool mIsDisabled;
|
||||
bool mFeatureAdded;
|
||||
DebugOnly<nsIThread*> mThread;
|
||||
|
||||
public:
|
||||
|
@ -35,7 +33,6 @@ public:
|
|||
|
||||
void RunTimer();
|
||||
void DisableTimer();
|
||||
bool Notify(JSContext* aCx, dom::workers::Status aStatus) override;
|
||||
|
||||
protected:
|
||||
~WebGLContextLossHandler();
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
NS_IMPL_ISUPPORTS(WebGLObserver, nsIObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebGLMemoryTracker::CollectReports(nsIHandleReportCallback* handleReport,
|
||||
nsISupports* data, bool)
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include <algorithm>
|
||||
#include "angle/ShaderLang.h"
|
||||
#include "CanvasUtils.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "GLContext.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
|
@ -1666,11 +1665,11 @@ WebGLContext::InitAndValidateGL()
|
|||
return false;
|
||||
}
|
||||
|
||||
mMinCapability = gfxPrefs::WebGLMinCapabilityMode();
|
||||
mDisableExtensions = gfxPrefs::WebGLDisableExtensions();
|
||||
mLoseContextOnMemoryPressure = gfxPrefs::WebGLLoseContextOnMemoryPressure();
|
||||
mCanLoseContextInForeground = gfxPrefs::WebGLCanLoseContextInForeground();
|
||||
mRestoreWhenVisible = gfxPrefs::WebGLRestoreWhenVisible();
|
||||
mMinCapability = Preferences::GetBool("webgl.min_capability_mode", false);
|
||||
mDisableExtensions = Preferences::GetBool("webgl.disable-extensions", false);
|
||||
mLoseContextOnMemoryPressure = Preferences::GetBool("webgl.lose-context-on-memory-pressure", false);
|
||||
mCanLoseContextInForeground = Preferences::GetBool("webgl.can-lose-context-in-foreground", true);
|
||||
mRestoreWhenVisible = Preferences::GetBool("webgl.restore-context-when-visible", true);
|
||||
|
||||
if (MinCapabilityMode())
|
||||
mDisableFragHighP = true;
|
||||
|
@ -1879,7 +1878,10 @@ WebGLContext::InitAndValidateGL()
|
|||
#endif
|
||||
|
||||
// Check the shader validator pref
|
||||
mBypassShaderValidation = gfxPrefs::WebGLBypassShaderValidator();
|
||||
NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
|
||||
|
||||
mBypassShaderValidation = Preferences::GetBool("webgl.bypass-shader-validation",
|
||||
mBypassShaderValidation);
|
||||
|
||||
// initialize shader translator
|
||||
if (!ShInitialize()) {
|
||||
|
@ -1935,6 +1937,9 @@ WebGLContext::InitAndValidateGL()
|
|||
mDefaultVertexArray->BindVertexArray();
|
||||
}
|
||||
|
||||
if (mLoseContextOnMemoryPressure)
|
||||
mContextObserver->RegisterMemoryPressureEvent();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
NS_IMPL_ISUPPORTS(WebGLObserver, nsIObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebGLMemoryTracker::CollectReports(nsIHandleReportCallback* handleReport,
|
||||
nsISupports* data, bool)
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "WebGLShaderValidator.h"
|
||||
|
||||
#include "angle/ShaderLang.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "MurmurHash3.h"
|
||||
|
@ -44,7 +43,7 @@ ChooseValidatorCompileOptions(const ShBuiltInResources& resources,
|
|||
options |= SH_LIMIT_EXPRESSION_COMPLEXITY;
|
||||
}
|
||||
|
||||
if (gfxPrefs::WebGLAllANGLEOptions()) {
|
||||
if (Preferences::GetBool("webgl.all-angle-options", false)) {
|
||||
return options |
|
||||
SH_VALIDATE_LOOP_INDEXING |
|
||||
SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX |
|
||||
|
|
|
@ -28,12 +28,10 @@ EXPORTS.mozilla.dom += [
|
|||
'CanvasPath.h',
|
||||
'CanvasPattern.h',
|
||||
'CanvasRenderingContext2D.h',
|
||||
'CanvasRenderingContextHelper.h',
|
||||
'CanvasUtils.h',
|
||||
'ImageBitmap.h',
|
||||
'ImageBitmapSource.h',
|
||||
'ImageData.h',
|
||||
'OffscreenCanvas.h',
|
||||
'TextMetrics.h',
|
||||
'WebGLVertexArrayObject.h',
|
||||
]
|
||||
|
@ -42,13 +40,11 @@ EXPORTS.mozilla.dom += [
|
|||
UNIFIED_SOURCES += [
|
||||
'CanvasImageCache.cpp',
|
||||
'CanvasRenderingContext2D.cpp',
|
||||
'CanvasRenderingContextHelper.cpp',
|
||||
'CanvasUtils.cpp',
|
||||
'DocumentRendererChild.cpp',
|
||||
'DocumentRendererParent.cpp',
|
||||
'ImageBitmap.cpp',
|
||||
'ImageData.cpp',
|
||||
'OffscreenCanvas.cpp',
|
||||
]
|
||||
|
||||
# WebGL Sources
|
||||
|
@ -154,7 +150,6 @@ LOCAL_INCLUDES += [
|
|||
'/dom/base',
|
||||
'/dom/html',
|
||||
'/dom/svg',
|
||||
'/dom/workers',
|
||||
'/dom/xul',
|
||||
'/gfx/gl',
|
||||
'/image',
|
||||
|
|
|
@ -12,13 +12,12 @@
|
|||
#include "nsIDocShell.h"
|
||||
#include "nsRefreshDriver.h"
|
||||
#include "mozilla/dom/HTMLCanvasElement.h"
|
||||
#include "mozilla/dom/OffscreenCanvas.h"
|
||||
#include "GraphicsFilter.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
#define NS_ICANVASRENDERINGCONTEXTINTERNAL_IID \
|
||||
{ 0xb84f2fed, 0x9d4b, 0x430b, \
|
||||
{ 0xbd, 0xfb, 0x85, 0x57, 0x8a, 0xc2, 0xb4, 0x4b } }
|
||||
{ 0x3cc9e801, 0x1806, 0x4ff6, \
|
||||
{ 0x86, 0x14, 0xf9, 0xd0, 0xf4, 0xfb, 0x3b, 0x08 } }
|
||||
|
||||
class gfxASurface;
|
||||
class nsDisplayListBuilder;
|
||||
|
@ -81,11 +80,6 @@ public:
|
|||
return mCanvasElement;
|
||||
}
|
||||
|
||||
void SetOffscreenCanvas(mozilla::dom::OffscreenCanvas* aOffscreenCanvas)
|
||||
{
|
||||
mOffscreenCanvas = aOffscreenCanvas;
|
||||
}
|
||||
|
||||
// Dimensions of the canvas, in pixels.
|
||||
virtual int32_t GetWidth() const = 0;
|
||||
virtual int32_t GetHeight() const = 0;
|
||||
|
@ -158,10 +152,6 @@ public:
|
|||
// Given a point, return hit region ID if it exists or an empty string if it doesn't
|
||||
virtual nsString GetHitRegion(const mozilla::gfx::Point& point) { return nsString(); }
|
||||
|
||||
virtual void OnVisibilityChange() {}
|
||||
|
||||
virtual void OnMemoryPressure() {}
|
||||
|
||||
//
|
||||
// shmem support
|
||||
//
|
||||
|
@ -174,7 +164,6 @@ public:
|
|||
|
||||
protected:
|
||||
nsRefPtr<mozilla::dom::HTMLCanvasElement> mCanvasElement;
|
||||
nsRefPtr<mozilla::dom::OffscreenCanvas> mOffscreenCanvas;
|
||||
nsRefPtr<nsRefreshDriver> mRefreshDriver;
|
||||
};
|
||||
|
||||
|
|
|
@ -27,10 +27,6 @@ support-files =
|
|||
imagebitmap_on_worker.js
|
||||
imagebitmap_structuredclone.js
|
||||
imagebitmap_structuredclone_iframe.html
|
||||
offscreencanvas.js
|
||||
offscreencanvas_mask.svg
|
||||
offscreencanvas_neuter.js
|
||||
offscreencanvas_serviceworker_inner.html
|
||||
|
||||
[test_2d.clearRect.image.offscreen.html]
|
||||
[test_2d.clip.winding.html]
|
||||
|
@ -265,22 +261,3 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # bug 1040965
|
|||
[test_createPattern_broken.html]
|
||||
[test_setlinedash.html]
|
||||
[test_filter.html]
|
||||
[test_offscreencanvas_basic_webgl.html]
|
||||
tags = offscreencanvas
|
||||
[test_offscreencanvas_dynamic_fallback.html]
|
||||
tags = offscreencanvas
|
||||
[test_offscreencanvas_sharedworker.html]
|
||||
tags = offscreencanvas
|
||||
[test_offscreencanvas_serviceworker.html]
|
||||
tags = offscreencanvas
|
||||
skip-if = buildapp == 'b2g'
|
||||
[test_offscreencanvas_neuter.html]
|
||||
tags = offscreencanvas
|
||||
[test_offscreencanvas_many.html]
|
||||
tags = offscreencanvas
|
||||
skip-if = (toolkit == 'android' || toolkit == 'gonk' || toolkit == 'windows' || toolkit == 'gtk2' || toolkit == 'gtk3')
|
||||
[test_offscreencanvas_sizechange.html]
|
||||
tags = offscreencanvas
|
||||
[test_offscreencanvas_subworker.html]
|
||||
tags = offscreencanvas
|
||||
skip-if = (toolkit == 'android' || toolkit == 'gonk' || toolkit == 'windows' || toolkit == 'gtk2' || toolkit == 'gtk3')
|
||||
|
|
|
@ -1,299 +0,0 @@
|
|||
/* WebWorker for test_offscreencanvas_*.html */
|
||||
var port = null;
|
||||
|
||||
function ok(expect, msg) {
|
||||
if (port) {
|
||||
port.postMessage({type: "test", result: !!expect, name: msg});
|
||||
} else {
|
||||
postMessage({type: "test", result: !!expect, name: msg});
|
||||
}
|
||||
}
|
||||
|
||||
function finish() {
|
||||
if (port) {
|
||||
port.postMessage({type: "finish"});
|
||||
} else {
|
||||
postMessage({type: "finish"});
|
||||
}
|
||||
}
|
||||
|
||||
function drawCount(count) {
|
||||
if (port) {
|
||||
port.postMessage({type: "draw", count: count});
|
||||
} else {
|
||||
postMessage({type: "draw", count: count});
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// WebGL Drawing Functions
|
||||
//--------------------------------------------------------------------
|
||||
function createDrawFunc(canvas) {
|
||||
var gl;
|
||||
|
||||
try {
|
||||
gl = canvas.getContext("experimental-webgl");
|
||||
} catch (e) {}
|
||||
|
||||
if (!gl) {
|
||||
ok(false, "WebGL is unavailable");
|
||||
return null;
|
||||
}
|
||||
|
||||
var vertSrc = "attribute vec2 position; \
|
||||
void main(void) { \
|
||||
gl_Position = vec4(position, 0.0, 1.0); \
|
||||
}";
|
||||
|
||||
var fragSrc = "precision mediump float; \
|
||||
void main(void) { \
|
||||
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); \
|
||||
}";
|
||||
|
||||
// Returns a valid shader, or null on errors.
|
||||
var createShader = function(src, t) {
|
||||
var shader = gl.createShader(t);
|
||||
|
||||
gl.shaderSource(shader, src);
|
||||
gl.compileShader(shader);
|
||||
|
||||
return shader;
|
||||
};
|
||||
|
||||
var createProgram = function(vsSrc, fsSrc) {
|
||||
var vs = createShader(vsSrc, gl.VERTEX_SHADER);
|
||||
var fs = createShader(fsSrc, gl.FRAGMENT_SHADER);
|
||||
|
||||
var prog = gl.createProgram();
|
||||
gl.attachShader(prog, vs);
|
||||
gl.attachShader(prog, fs);
|
||||
gl.linkProgram(prog);
|
||||
|
||||
if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {
|
||||
var str = "Shader program linking failed:";
|
||||
str += "\nShader program info log:\n" + gl.getProgramInfoLog(prog);
|
||||
str += "\n\nVert shader log:\n" + gl.getShaderInfoLog(vs);
|
||||
str += "\n\nFrag shader log:\n" + gl.getShaderInfoLog(fs);
|
||||
console.log(str);
|
||||
ok(false, "Shader program linking failed");
|
||||
return null;
|
||||
}
|
||||
|
||||
return prog;
|
||||
};
|
||||
|
||||
gl.disable(gl.DEPTH_TEST);
|
||||
|
||||
var program = createProgram(vertSrc, fragSrc);
|
||||
ok(program, "Creating shader program");
|
||||
|
||||
program.positionAttr = gl.getAttribLocation(program, "position");
|
||||
ok(program.positionAttr >= 0, "position attribute should be valid");
|
||||
|
||||
var vertCoordArr = new Float32Array([
|
||||
-1, -1,
|
||||
1, -1,
|
||||
-1, 1,
|
||||
1, 1,
|
||||
]);
|
||||
var vertCoordBuff = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, vertCoordBuff);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, vertCoordArr, gl.STATIC_DRAW);
|
||||
|
||||
var checkGLError = function(prefix, refValue) {
|
||||
if (!refValue) {
|
||||
refValue = 0;
|
||||
}
|
||||
|
||||
var error = gl.getError();
|
||||
ok(error == refValue,
|
||||
prefix + 'gl.getError should be 0x' + refValue.toString(16) +
|
||||
', was 0x' + error.toString(16) + '.');
|
||||
};
|
||||
|
||||
var testPixel = function(x, y, refData, infoString) {
|
||||
var pixel = new Uint8Array(4);
|
||||
gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
|
||||
|
||||
var pixelMatches = pixel[0] == refData[0] &&
|
||||
pixel[1] == refData[1] &&
|
||||
pixel[2] == refData[2] &&
|
||||
pixel[3] == refData[3];
|
||||
ok(pixelMatches, infoString);
|
||||
};
|
||||
|
||||
var preDraw = function(prefix) {
|
||||
gl.clearColor(1.0, 0.0, 0.0, 1.0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
testPixel(0, 0, [255, 0, 0, 255], prefix + 'Should be red before drawing.');
|
||||
};
|
||||
|
||||
var postDraw = function(prefix) {
|
||||
testPixel(0, 0, [0, 255, 0, 255], prefix + 'Should be green after drawing.');
|
||||
};
|
||||
|
||||
gl.useProgram(program);
|
||||
gl.enableVertexAttribArray(program.position);
|
||||
gl.vertexAttribPointer(program.position, 2, gl.FLOAT, false, 0, 0);
|
||||
|
||||
// Start drawing
|
||||
checkGLError('after setup');
|
||||
|
||||
return function(prefix) {
|
||||
if (prefix) {
|
||||
prefix = "[" + prefix + "] ";
|
||||
} else {
|
||||
prefix = "";
|
||||
}
|
||||
|
||||
gl.viewport(0, 0, canvas.width, canvas.height);
|
||||
|
||||
preDraw(prefix);
|
||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
||||
postDraw(prefix);
|
||||
gl.commit();
|
||||
checkGLError(prefix);
|
||||
};
|
||||
}
|
||||
|
||||
/* entry point */
|
||||
function entryFunction(testStr, subtests, offscreenCanvas) {
|
||||
var test = testStr;
|
||||
var canvas = offscreenCanvas;
|
||||
|
||||
if (test != "subworker") {
|
||||
ok(canvas, "Canvas successfully transfered to worker");
|
||||
ok(canvas.getContext, "Canvas has getContext");
|
||||
|
||||
ok(canvas.width == 64, "OffscreenCanvas width should be 64");
|
||||
ok(canvas.height == 64, "OffscreenCanvas height should be 64");
|
||||
}
|
||||
|
||||
var draw;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Basic WebGL test
|
||||
//------------------------------------------------------------------------
|
||||
if (test == "webgl") {
|
||||
draw = createDrawFunc(canvas);
|
||||
if (!draw) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var count = 0;
|
||||
var iid = setInterval(function() {
|
||||
if (count++ > 20) {
|
||||
clearInterval(iid);
|
||||
ok(true, "Worker is done");
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
draw("loop " +count);
|
||||
}, 0);
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
// Test dynamic fallback
|
||||
//------------------------------------------------------------------------
|
||||
else if (test == "webgl_fallback") {
|
||||
draw = createDrawFunc(canvas);
|
||||
if (!draw) {
|
||||
return;
|
||||
}
|
||||
|
||||
var count = 0;
|
||||
var iid = setInterval(function() {
|
||||
++count;
|
||||
draw("loop " + count);
|
||||
drawCount(count);
|
||||
}, 0);
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
// Canvas Size Change from Worker
|
||||
//------------------------------------------------------------------------
|
||||
else if (test == "webgl_changesize") {
|
||||
draw = createDrawFunc(canvas);
|
||||
if (!draw) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
draw("64x64");
|
||||
|
||||
setTimeout(function() {
|
||||
canvas.width = 128;
|
||||
canvas.height = 128;
|
||||
draw("Increased to 128x128");
|
||||
|
||||
setTimeout(function() {
|
||||
canvas.width = 32;
|
||||
canvas.width = 32;
|
||||
draw("Decreased to 32x32");
|
||||
|
||||
setTimeout(function() {
|
||||
canvas.width = 64;
|
||||
canvas.height = 64;
|
||||
draw("Increased to 64x64");
|
||||
|
||||
ok(true, "Worker is done");
|
||||
finish();
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
// Using OffscreenCanvas from sub workers
|
||||
//------------------------------------------------------------------------
|
||||
else if (test == "subworker") {
|
||||
/* subworker tests take a list of tests to run on children */
|
||||
var stillRunning = 0;
|
||||
subtests.forEach(function (subtest) {
|
||||
++stillRunning;
|
||||
var subworker = new Worker('offscreencanvas.js');
|
||||
subworker.onmessage = function(evt) {
|
||||
/* report finish to parent when all children are finished */
|
||||
if (evt.data.type == "finish") {
|
||||
subworker.terminate();
|
||||
if (--stillRunning == 0) {
|
||||
ok(true, "Worker is done");
|
||||
finish();
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* relay all other messages to parent */
|
||||
postMessage(evt.data);
|
||||
};
|
||||
|
||||
var findTransferables = function(t) {
|
||||
if (t.test == "subworker") {
|
||||
var result = [];
|
||||
t.subtests.forEach(function(test) {
|
||||
result = result.concat(findTransferables(test));
|
||||
});
|
||||
|
||||
return result;
|
||||
} else {
|
||||
return [t.canvas];
|
||||
}
|
||||
};
|
||||
|
||||
subworker.postMessage(subtest, findTransferables(subtest));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onmessage = function(evt) {
|
||||
port = evt.ports[0];
|
||||
entryFunction(evt.data.test, evt.data.subtests, evt.data.canvas);
|
||||
};
|
||||
|
||||
onconnect = function(evt) {
|
||||
port = evt.ports[0];
|
||||
|
||||
port.addEventListener('message', function(evt) {
|
||||
entryFunction(evt.data.test, evt.data.subtests, evt.data.canvas);
|
||||
});
|
||||
|
||||
port.start();
|
||||
};
|
|
@ -1,11 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
|
||||
<mask id="fade_mask_both" maskUnits="objectBoundingBox" maskContentUnits="objectBoundingBox">
|
||||
<linearGradient id="fade_gradient_both" gradientUnits="objectBoundingBox" x2="0" y2="1">
|
||||
<stop stop-color="white" stop-opacity="0" offset="0"></stop>
|
||||
<stop stop-color="white" stop-opacity="1" offset="0.2"></stop>
|
||||
<stop stop-color="white" stop-opacity="1" offset="0.8"></stop>
|
||||
<stop stop-color="white" stop-opacity="0" offset="1"></stop>
|
||||
</linearGradient>
|
||||
<rect x="0" y="0" width="1" height="1" fill="url(#fade_gradient_both)"></rect>
|
||||
</mask>
|
||||
</svg>
|
До Ширина: | Высота: | Размер: 638 B |
|
@ -1 +0,0 @@
|
|||
/* empty worker for test_offscreencanvas_disable.html */
|
|
@ -1,32 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebGL in OffscreenCanvas</title>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="c" width="64" height="64"></canvas>
|
||||
<script>
|
||||
function ok(expect, msg) {
|
||||
parent.postMessage({type: "test", result: !!expect, name: msg}, "*");
|
||||
}
|
||||
|
||||
var htmlCanvas = document.getElementById("c");
|
||||
|
||||
ok(htmlCanvas, "Should have HTML canvas element");
|
||||
|
||||
var messageChannel = new MessageChannel();
|
||||
messageChannel.port1.onmessage = function(evt) {
|
||||
parent.postMessage(evt.data, "*");
|
||||
}
|
||||
|
||||
ok(htmlCanvas.transferControlToOffscreen, "HTMLCanvasElement has transferControlToOffscreen function");
|
||||
|
||||
var offscreenCanvas = htmlCanvas.transferControlToOffscreen();
|
||||
ok(offscreenCanvas, "Expected transferControlToOffscreen to succeed");
|
||||
|
||||
navigator.serviceWorker.ready.then(function() {
|
||||
navigator.serviceWorker.controller.postMessage({test: 'webgl', canvas: offscreenCanvas}, [offscreenCanvas, messageChannel.port2]);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,62 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebGL in OffscreenCanvas</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="c" width="64" height="64"></canvas>
|
||||
<canvas id="c-ref" width="64" height="64"></canvas>
|
||||
<script>
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function testToDataURL() {
|
||||
// testing toDataURL
|
||||
// Fill c-ref with green color.
|
||||
var c = document.getElementById("c-ref");
|
||||
var ctx = c.getContext("2d");
|
||||
ctx.rect(0, 0, 64, 64);
|
||||
ctx.fillStyle = "#00FF00";
|
||||
ctx.fill();
|
||||
var htmlCanvas = document.getElementById("c");
|
||||
ok(c.toDataURL() == htmlCanvas.toDataURL(), "toDataURL should return a 64x64 green square");
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
|
||||
var htmlCanvas = document.getElementById("c");
|
||||
var worker = new Worker("offscreencanvas.js");
|
||||
|
||||
ok(htmlCanvas, "Should have HTML canvas element");
|
||||
ok(worker, "Web worker successfully created");
|
||||
|
||||
worker.onmessage = function(evt) {
|
||||
var msg = evt.data || {};
|
||||
if (msg.type == "test") {
|
||||
ok(msg.result, msg.name);
|
||||
}
|
||||
if (msg.type == "finish") {
|
||||
testToDataURL();
|
||||
worker.terminate();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
ok(htmlCanvas.transferControlToOffscreen, "HTMLCanvasElement has transferControlToOffscreen function");
|
||||
|
||||
var offscreenCanvas = htmlCanvas.transferControlToOffscreen();
|
||||
ok(offscreenCanvas, "Expected transferControlToOffscreen to succeed");
|
||||
|
||||
worker.postMessage({test: 'webgl', canvas: offscreenCanvas}, [offscreenCanvas]);
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({'set': [
|
||||
['gfx.offscreencanvas.enabled', true],
|
||||
['webgl.force-enabled', true],
|
||||
]}, runTest);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,80 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebGL in OffscreenCanvas</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="/tests/SimpleTest/WindowSnapshot.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function createCanvas(initWithMask) {
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.width = 64;
|
||||
canvas.height = 64;
|
||||
document.body.appendChild(canvas);
|
||||
if (initWithMask) {
|
||||
canvas.style.mask = "url('offscreencanvas_mask.svg#fade_mask_both')";
|
||||
}
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
function getRefSnapshot(initWithMask) {
|
||||
var refCanvas = createCanvas(!initWithMask);
|
||||
var ctx = refCanvas.getContext("2d");
|
||||
ctx.rect(0, 0, 64, 64);
|
||||
ctx.fillStyle = "#00FF00";
|
||||
ctx.fill();
|
||||
var result = snapshotWindow(window);
|
||||
document.body.removeChild(refCanvas);
|
||||
return result;
|
||||
}
|
||||
|
||||
function runTest(initWithMask) {
|
||||
var htmlCanvas = createCanvas(initWithMask);
|
||||
var worker = new Worker("offscreencanvas.js");
|
||||
|
||||
worker.onmessage = function(evt) {
|
||||
var msg = evt.data || {};
|
||||
if (msg.type == "draw") {
|
||||
if (msg.count === 10) {
|
||||
// Change the fallback state dynamically when drawing count reaches 10.
|
||||
if (initWithMask) {
|
||||
htmlCanvas.style.mask = "";
|
||||
} else {
|
||||
htmlCanvas.style.mask = "url('offscreencanvas_mask.svg#fade_mask_both')";
|
||||
}
|
||||
} else if (msg.count === 20) {
|
||||
var snapshotFallback = snapshotWindow(window);
|
||||
worker.terminate();
|
||||
document.body.removeChild(htmlCanvas);
|
||||
|
||||
var results = compareSnapshots(snapshotFallback, getRefSnapshot(initWithMask), true);
|
||||
ok(results[0], "after dynamic fallback, screenshots should be the same");
|
||||
|
||||
if (initWithMask) {
|
||||
SimpleTest.finish();
|
||||
} else {
|
||||
runTest(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var offscreenCanvas = htmlCanvas.transferControlToOffscreen();
|
||||
|
||||
worker.postMessage({test: 'webgl_fallback', canvas: offscreenCanvas}, [offscreenCanvas]);
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({'set': [
|
||||
['gfx.offscreencanvas.enabled', true],
|
||||
['webgl.force-enabled', true],
|
||||
]}, runTest.bind(false));
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,67 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebGL in OffscreenCanvas</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<!--
|
||||
This test needs several workers run offscreen canvas simultaneously.
|
||||
So we choose 8 workers, 4 of them run basic webgl drawing test and
|
||||
others run size changing test.
|
||||
-->
|
||||
<script>
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function createCanvas() {
|
||||
var htmlCanvas = document.createElement('canvas');
|
||||
htmlCanvas.width = 64;
|
||||
htmlCanvas.height = 64;
|
||||
document.body.appendChild(htmlCanvas);
|
||||
return htmlCanvas;
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
var stillRunning = 0;
|
||||
|
||||
var startWorker = function(canvas, test) {
|
||||
stillRunning++;
|
||||
var worker = new Worker("offscreencanvas.js");
|
||||
|
||||
worker.onmessage = function(evt) {
|
||||
var msg = evt.data || {};
|
||||
if (msg.type == "test") {
|
||||
ok(msg.result, msg.name);
|
||||
}
|
||||
if (msg.type == "finish") {
|
||||
worker.terminate();
|
||||
if (--stillRunning == 0)
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
var offscreenCanvas = canvas.transferControlToOffscreen();
|
||||
worker.postMessage({test: test, canvas: offscreenCanvas}, [offscreenCanvas]);
|
||||
}
|
||||
|
||||
/* create 4 workers that do the regular drawing test and 4 workers
|
||||
that do the size change test */
|
||||
for (var i = 0; i < 4; i++) {
|
||||
startWorker(createCanvas(), 'webgl');
|
||||
}
|
||||
|
||||
for (var i = 0; i < 4; i++) {
|
||||
startWorker(createCanvas(), 'webgl_changesize');
|
||||
}
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({'set': [
|
||||
['gfx.offscreencanvas.enabled', true],
|
||||
['webgl.force-enabled', true]
|
||||
]}, runTest);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,78 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>OffscreenCanvas: Test neutering</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="c" width="64" height="64"></canvas>
|
||||
<script>
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function runTest() {
|
||||
|
||||
var htmlCanvas = document.getElementById("c");
|
||||
var worker = new Worker("offscreencanvas_neuter.js");
|
||||
|
||||
ok(htmlCanvas, "Should have HTML canvas element");
|
||||
ok(worker, "Web worker successfully created");
|
||||
|
||||
ok(htmlCanvas.transferControlToOffscreen, "HTMLCanvasElement has transferControlToOffscreen function");
|
||||
|
||||
var offscreenCanvas = htmlCanvas.transferControlToOffscreen();
|
||||
ok(offscreenCanvas, "Expected transferControlToOffscreen to succeed");
|
||||
|
||||
/* check html canvas is neuterd */
|
||||
is(htmlCanvas.width, 64, "HTML canvas has correct width");
|
||||
SimpleTest.doesThrow(
|
||||
function() { htmlCanvas.width = 128; },
|
||||
"Can't change html canvas' width after transferControlToOffscreen");
|
||||
|
||||
SimpleTest.doesThrow(
|
||||
function() { htmlCanvas.height = 128; },
|
||||
"Can't change html canvas' height after transferControlToOffscreen");
|
||||
|
||||
ok(!htmlCanvas.getContext("2d"), "Can't getContext after transferControlToOffscreen");
|
||||
ok(!htmlCanvas.getContext("webgl"), "Can't getContext after transferControlToOffscreen");
|
||||
ok(!htmlCanvas.getContext("webgl2"), "Can't getContext after transferControlToOffscreen");
|
||||
|
||||
worker.postMessage(offscreenCanvas, [offscreenCanvas]);
|
||||
|
||||
/* check parent offscreencanvas is neutered after being transfered */
|
||||
SimpleTest.doesThrow(
|
||||
function() { offscreenCanvas.width = 128; },
|
||||
"Can't change transfered worker canvas width");
|
||||
|
||||
SimpleTest.doesThrow(
|
||||
function() { offscreenCanvas.height = 128; },
|
||||
"Can't change transfered worker canvas height");
|
||||
|
||||
SimpleTest.doesThrow(
|
||||
function() { offscreenCanvas.getContext("2d") },
|
||||
"Can't getContext on transfered worker canvas");
|
||||
|
||||
SimpleTest.doesThrow(
|
||||
function() { offscreenCanvas.getContext("webgl") },
|
||||
"Can't getContext on transfered worker canvas");
|
||||
|
||||
SimpleTest.doesThrow(
|
||||
function() { offscreenCanvas.getContext("webgl2") },
|
||||
"Can't getContext on transfered worker canvas");
|
||||
|
||||
// Transfer a neutered offscreencanvas should be ok.
|
||||
worker.postMessage(offscreenCanvas, [offscreenCanvas]);
|
||||
|
||||
worker.terminate();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({'set': [
|
||||
['gfx.offscreencanvas.enabled', true],
|
||||
['webgl.force-enabled', true],
|
||||
]}, runTest);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,46 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebGL in OffscreenCanvas</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function runTest() {
|
||||
window.onmessage = function(evt) {
|
||||
var msg = evt.data || {};
|
||||
if (msg.type == "test") {
|
||||
ok(msg.result, msg.name);
|
||||
}
|
||||
if (msg.type == "finish") {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
navigator.serviceWorker.register('offscreencanvas.js', { scope: "."})
|
||||
// Wait until the service worker is active.
|
||||
.then(navigator.serviceWorker.ready)
|
||||
// ...and then show the interface for the commands once it's ready.
|
||||
.then(function() {
|
||||
iframe = document.createElement("iframe");
|
||||
iframe.setAttribute('src', "offscreencanvas_serviceworker_inner.html");
|
||||
document.body.appendChild(iframe);
|
||||
})
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({'set': [
|
||||
['gfx.offscreencanvas.enabled', true],
|
||||
['webgl.force-enabled', true],
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.interception.enabled", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true]
|
||||
]}, runTest);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,47 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebGL in OffscreenCanvas</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="c" width="64" height="64"></canvas>
|
||||
<script>
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function runTest() {
|
||||
|
||||
var htmlCanvas = document.getElementById("c");
|
||||
var worker = new SharedWorker("offscreencanvas.js");
|
||||
|
||||
ok(htmlCanvas, "Should have HTML canvas element");
|
||||
ok(worker, "Web worker successfully created");
|
||||
|
||||
ok(htmlCanvas.transferControlToOffscreen, "HTMLCanvasElement has transferControlToOffscreen function");
|
||||
|
||||
var offscreenCanvas = htmlCanvas.transferControlToOffscreen();
|
||||
ok(offscreenCanvas, "Expected transferControlToOffscreen to succeed");
|
||||
|
||||
worker.port.start();
|
||||
|
||||
// We don't support transferring OffscreenCanvas via shared worker.
|
||||
SimpleTest.doesThrow(
|
||||
function() {
|
||||
worker.port.postMessage({test: 'webgl', canvas: offscreenCanvas}, [offscreenCanvas]);
|
||||
},
|
||||
"OffscreenCanvas cannot transfer to shared worker"
|
||||
);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({'set': [
|
||||
['gfx.offscreencanvas.enabled', true],
|
||||
['webgl.force-enabled', true],
|
||||
]}, runTest);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,41 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebGL in OffscreenCanvas</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="c" width="64" height="64"></canvas>
|
||||
<script>
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function runTest() {
|
||||
|
||||
var htmlCanvas = document.getElementById("c");
|
||||
var worker = new Worker("offscreencanvas.js");
|
||||
|
||||
worker.onmessage = function(evt) {
|
||||
var msg = evt.data || {};
|
||||
if (msg.type == "test") {
|
||||
ok(msg.result, msg.name);
|
||||
}
|
||||
if (msg.type == "finish") {
|
||||
worker.terminate();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
var offscreenCanvas = htmlCanvas.transferControlToOffscreen();
|
||||
worker.postMessage({test: 'webgl_changesize', canvas: offscreenCanvas}, [offscreenCanvas]);
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({'set': [
|
||||
['gfx.offscreencanvas.enabled', true],
|
||||
['webgl.force-enabled', true],
|
||||
]}, runTest);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,90 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>OffscreenCanvas: Test subworkers</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<!--
|
||||
We want to test offscreen canvas works well when it running on worker
|
||||
and nested worker simultaneously. So we create 10 canvas and dispatch
|
||||
it to different workers and sub-workers.
|
||||
-->
|
||||
<script>
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function createCanvas() {
|
||||
var htmlCanvas = document.createElement('canvas');
|
||||
htmlCanvas.width = 64;
|
||||
htmlCanvas.height = 64;
|
||||
document.body.appendChild(htmlCanvas);
|
||||
return htmlCanvas.transferControlToOffscreen();
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
|
||||
var worker = new Worker("offscreencanvas.js");
|
||||
|
||||
worker.onmessage = function(evt) {
|
||||
var msg = evt.data || {};
|
||||
if (msg.type == "test") {
|
||||
ok(msg.result, msg.name);
|
||||
}
|
||||
if (msg.type == "finish") {
|
||||
worker.terminate();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
var findTransferables = function(t) {
|
||||
if (t.test == "subworker") {
|
||||
var result = [];
|
||||
t.subtests.forEach(function(test) {
|
||||
result = result.concat(findTransferables(test));
|
||||
});
|
||||
|
||||
return result;
|
||||
} else {
|
||||
return [t.canvas];
|
||||
}
|
||||
};
|
||||
|
||||
var testData =
|
||||
{test: 'subworker', subtests: [
|
||||
{test: 'webgl', canvas: createCanvas()},
|
||||
{test: 'subworker', subtests: [
|
||||
{test: 'webgl', canvas: createCanvas()},
|
||||
{test: 'webgl_changesize', canvas: createCanvas()},
|
||||
{test: 'webgl', canvas: createCanvas()}
|
||||
]},
|
||||
{test: 'subworker', subtests: [
|
||||
{test: 'webgl', canvas: createCanvas()},
|
||||
{test: 'webgl_changesize', canvas: createCanvas()},
|
||||
{test: 'subworker', subtests: [
|
||||
{test: 'webgl_changesize', canvas: createCanvas()},
|
||||
{test: 'webgl', canvas: createCanvas()}
|
||||
]},
|
||||
{test: 'subworker', subtests: [
|
||||
{test: 'webgl_changesize', canvas: createCanvas()},
|
||||
{test: 'subworker', subtests: [
|
||||
{test: 'subworker', subtests: [
|
||||
{test: 'webgl_changesize', canvas: createCanvas()}
|
||||
]}
|
||||
]}
|
||||
]},
|
||||
]}
|
||||
]};
|
||||
|
||||
worker.postMessage(testData, findTransferables(testData));
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({'set': [
|
||||
['gfx.offscreencanvas.enabled', true],
|
||||
['webgl.force-enabled', true],
|
||||
]}, runTest);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -19,10 +19,8 @@
|
|||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/HTMLCanvasElementBinding.h"
|
||||
#include "mozilla/dom/MouseEvent.h"
|
||||
#include "mozilla/dom/OffscreenCanvas.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/gfx/Rect.h"
|
||||
#include "mozilla/layers/AsyncCanvasRenderer.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
@ -241,135 +239,18 @@ HTMLCanvasPrintState::NotifyDone()
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
HTMLCanvasElementObserver::HTMLCanvasElementObserver(HTMLCanvasElement* aElement)
|
||||
: mElement(aElement)
|
||||
{
|
||||
RegisterVisibilityChangeEvent();
|
||||
RegisterMemoryPressureEvent();
|
||||
}
|
||||
|
||||
HTMLCanvasElementObserver::~HTMLCanvasElementObserver()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void
|
||||
HTMLCanvasElementObserver::Destroy()
|
||||
{
|
||||
UnregisterMemoryPressureEvent();
|
||||
UnregisterVisibilityChangeEvent();
|
||||
mElement = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLCanvasElementObserver::RegisterVisibilityChangeEvent()
|
||||
{
|
||||
if (!mElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsIDocument* document = mElement->OwnerDoc();
|
||||
document->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
|
||||
this, true, false);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLCanvasElementObserver::UnregisterVisibilityChangeEvent()
|
||||
{
|
||||
if (!mElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsIDocument* document = mElement->OwnerDoc();
|
||||
document->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
|
||||
this, true);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLCanvasElementObserver::RegisterMemoryPressureEvent()
|
||||
{
|
||||
if (!mElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
|
||||
MOZ_ASSERT(observerService);
|
||||
|
||||
if (observerService)
|
||||
observerService->AddObserver(this, "memory-pressure", false);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLCanvasElementObserver::UnregisterMemoryPressureEvent()
|
||||
{
|
||||
if (!mElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
|
||||
// Do not assert on observerService here. This might be triggered by
|
||||
// the cycle collector at a late enough time, that XPCOM services are
|
||||
// no longer available. See bug 1029504.
|
||||
if (observerService)
|
||||
observerService->RemoveObserver(this, "memory-pressure");
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLCanvasElementObserver::Observe(nsISupports*, const char* aTopic, const char16_t*)
|
||||
{
|
||||
if (!mElement || strcmp(aTopic, "memory-pressure")) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mElement->OnMemoryPressure();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLCanvasElementObserver::HandleEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
nsAutoString type;
|
||||
aEvent->GetType(type);
|
||||
if (!mElement || !type.EqualsLiteral("visibilitychange")) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mElement->OnVisibilityChange();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(HTMLCanvasElementObserver, nsIObserver)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
HTMLCanvasElement::HTMLCanvasElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsGenericHTMLElement(aNodeInfo),
|
||||
mResetLayer(true) ,
|
||||
mWriteOnly(false)
|
||||
{
|
||||
}
|
||||
|
||||
HTMLCanvasElement::~HTMLCanvasElement()
|
||||
{
|
||||
if (mContextObserver) {
|
||||
mContextObserver->Destroy();
|
||||
mContextObserver = nullptr;
|
||||
}
|
||||
|
||||
ResetPrintCallback();
|
||||
if (mRequestedFrameRefreshObserver) {
|
||||
mRequestedFrameRefreshObserver->DetachFromRefreshDriver();
|
||||
}
|
||||
|
||||
if (mAsyncCanvasRenderer) {
|
||||
mAsyncCanvasRenderer->mHTMLCanvasElement = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLCanvasElement, nsGenericHTMLElement,
|
||||
|
@ -391,22 +272,6 @@ HTMLCanvasElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|||
return HTMLCanvasElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
already_AddRefed<nsICanvasRenderingContextInternal>
|
||||
HTMLCanvasElement::CreateContext(CanvasContextType aContextType)
|
||||
{
|
||||
nsRefPtr<nsICanvasRenderingContextInternal> ret =
|
||||
CanvasRenderingContextHelper::CreateContext(aContextType);
|
||||
|
||||
// Add Observer for webgl canvas.
|
||||
if (aContextType == CanvasContextType::WebGL1 ||
|
||||
aContextType == CanvasContextType::WebGL2) {
|
||||
mContextObserver = new HTMLCanvasElementObserver(this);
|
||||
}
|
||||
|
||||
ret->SetCanvasElement(this);
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
nsIntSize
|
||||
HTMLCanvasElement::GetWidthHeight()
|
||||
{
|
||||
|
@ -691,10 +556,51 @@ HTMLCanvasElement::ExtractData(nsAString& aType,
|
|||
aOptions,
|
||||
GetSize(),
|
||||
mCurrentContext,
|
||||
mAsyncCanvasRenderer,
|
||||
aStream);
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLCanvasElement::ParseParams(JSContext* aCx,
|
||||
const nsAString& aType,
|
||||
const JS::Value& aEncoderOptions,
|
||||
nsAString& aParams,
|
||||
bool* usingCustomParseOptions)
|
||||
{
|
||||
// Quality parameter is only valid for the image/jpeg MIME type
|
||||
if (aType.EqualsLiteral("image/jpeg")) {
|
||||
if (aEncoderOptions.isNumber()) {
|
||||
double quality = aEncoderOptions.toNumber();
|
||||
// Quality must be between 0.0 and 1.0, inclusive
|
||||
if (quality >= 0.0 && quality <= 1.0) {
|
||||
aParams.AppendLiteral("quality=");
|
||||
aParams.AppendInt(NS_lround(quality * 100.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we haven't parsed the aParams check for proprietary options.
|
||||
// The proprietary option -moz-parse-options will take a image lib encoder
|
||||
// parse options string as is and pass it to the encoder.
|
||||
*usingCustomParseOptions = false;
|
||||
if (aParams.Length() == 0 && aEncoderOptions.isString()) {
|
||||
NS_NAMED_LITERAL_STRING(mozParseOptions, "-moz-parse-options:");
|
||||
nsAutoJSString paramString;
|
||||
if (!paramString.init(aCx, aEncoderOptions.toString())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (StringBeginsWith(paramString, mozParseOptions)) {
|
||||
nsDependentSubstring parseOptions = Substring(paramString,
|
||||
mozParseOptions.Length(),
|
||||
paramString.Length() -
|
||||
mozParseOptions.Length());
|
||||
aParams.Append(parseOptions);
|
||||
*usingCustomParseOptions = true;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLCanvasElement::ToDataURLImpl(JSContext* aCx,
|
||||
const nsAString& aMimeType,
|
||||
|
@ -753,38 +659,84 @@ HTMLCanvasElement::ToBlob(JSContext* aCx,
|
|||
return;
|
||||
}
|
||||
|
||||
nsAutoString type;
|
||||
nsContentUtils::ASCIIToLower(aType, type);
|
||||
|
||||
nsAutoString params;
|
||||
bool usingCustomParseOptions;
|
||||
aRv = ParseParams(aCx, type, aParams, params, &usingCustomParseOptions);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCurrentContext) {
|
||||
// We disallow canvases of width or height zero, and set them to 1, so
|
||||
// we will have a discrepancy with the sizes of the canvas and the context.
|
||||
// That discrepancy is OK, the rest are not.
|
||||
nsIntSize elementSize = GetWidthHeight();
|
||||
if ((elementSize.width != mCurrentContext->GetWidth() &&
|
||||
(elementSize.width != 0 || mCurrentContext->GetWidth() != 1)) ||
|
||||
(elementSize.height != mCurrentContext->GetHeight() &&
|
||||
(elementSize.height != 0 || mCurrentContext->GetHeight() != 1))) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* imageBuffer = nullptr;
|
||||
int32_t format = 0;
|
||||
if (mCurrentContext) {
|
||||
mCurrentContext->GetImageBuffer(&imageBuffer, &format);
|
||||
}
|
||||
|
||||
// Encoder callback when encoding is complete.
|
||||
class EncodeCallback : public EncodeCompleteCallback
|
||||
{
|
||||
public:
|
||||
EncodeCallback(nsIGlobalObject* aGlobal, FileCallback* aCallback)
|
||||
: mGlobal(aGlobal)
|
||||
, mFileCallback(aCallback) {}
|
||||
|
||||
// This is called on main thread.
|
||||
nsresult ReceiveBlob(already_AddRefed<Blob> aBlob)
|
||||
{
|
||||
nsRefPtr<Blob> blob = aBlob;
|
||||
|
||||
ErrorResult rv;
|
||||
uint64_t size = blob->GetSize(rv);
|
||||
if (rv.Failed()) {
|
||||
rv.SuppressException();
|
||||
} else {
|
||||
AutoJSAPI jsapi;
|
||||
if (jsapi.Init(mGlobal)) {
|
||||
JS_updateMallocCounter(jsapi.cx(), size);
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<Blob> newBlob = Blob::Create(mGlobal, blob->Impl());
|
||||
|
||||
mFileCallback->Call(*newBlob, rv);
|
||||
|
||||
mGlobal = nullptr;
|
||||
mFileCallback = nullptr;
|
||||
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
nsRefPtr<FileCallback> mFileCallback;
|
||||
};
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
|
||||
MOZ_ASSERT(global);
|
||||
|
||||
CanvasRenderingContextHelper::ToBlob(aCx, global, aCallback, aType,
|
||||
aParams, aRv);
|
||||
|
||||
}
|
||||
|
||||
OffscreenCanvas*
|
||||
HTMLCanvasElement::TransferControlToOffscreen(ErrorResult& aRv)
|
||||
{
|
||||
if (mCurrentContext) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mOffscreenCanvas) {
|
||||
nsIntSize sz = GetWidthHeight();
|
||||
nsRefPtr<AsyncCanvasRenderer> renderer = GetAsyncCanvasRenderer();
|
||||
renderer->SetWidth(sz.width);
|
||||
renderer->SetHeight(sz.height);
|
||||
|
||||
mOffscreenCanvas = new OffscreenCanvas(sz.width,
|
||||
sz.height,
|
||||
GetCompositorBackendType(),
|
||||
renderer);
|
||||
mContextObserver = new HTMLCanvasElementObserver(this);
|
||||
} else {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
}
|
||||
|
||||
return mOffscreenCanvas;
|
||||
nsRefPtr<EncodeCompleteCallback> callback = new EncodeCallback(global, &aCallback);
|
||||
aRv = ImageEncoder::ExtractDataAsync(type,
|
||||
params,
|
||||
usingCustomParseOptions,
|
||||
imageBuffer,
|
||||
format,
|
||||
GetSize(),
|
||||
callback);
|
||||
}
|
||||
|
||||
already_AddRefed<File>
|
||||
|
@ -855,6 +807,76 @@ HTMLCanvasElement::MozGetAsBlobImpl(const nsAString& aName,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
static bool
|
||||
GetCanvasContextType(const nsAString& str, CanvasContextType* const out_type)
|
||||
{
|
||||
if (str.EqualsLiteral("2d")) {
|
||||
*out_type = CanvasContextType::Canvas2D;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (str.EqualsLiteral("experimental-webgl")) {
|
||||
*out_type = CanvasContextType::WebGL1;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WEBGL_CONFORMANT
|
||||
if (str.EqualsLiteral("webgl")) {
|
||||
/* WebGL 1.0, $2.1 "Context Creation":
|
||||
* If the user agent supports both the webgl and experimental-webgl
|
||||
* canvas context types, they shall be treated as aliases.
|
||||
*/
|
||||
*out_type = CanvasContextType::WebGL1;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (WebGL2Context::IsSupported()) {
|
||||
if (str.EqualsLiteral("webgl2")) {
|
||||
*out_type = CanvasContextType::WebGL2;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static already_AddRefed<nsICanvasRenderingContextInternal>
|
||||
CreateContextForCanvas(CanvasContextType contextType, HTMLCanvasElement* canvas)
|
||||
{
|
||||
MOZ_ASSERT(contextType != CanvasContextType::NoContext);
|
||||
nsRefPtr<nsICanvasRenderingContextInternal> ret;
|
||||
|
||||
switch (contextType) {
|
||||
case CanvasContextType::NoContext:
|
||||
break;
|
||||
case CanvasContextType::Canvas2D:
|
||||
Telemetry::Accumulate(Telemetry::CANVAS_2D_USED, 1);
|
||||
ret = new CanvasRenderingContext2D();
|
||||
break;
|
||||
|
||||
case CanvasContextType::WebGL1:
|
||||
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
|
||||
|
||||
ret = WebGL1Context::Create();
|
||||
if (!ret)
|
||||
return nullptr;
|
||||
break;
|
||||
|
||||
case CanvasContextType::WebGL2:
|
||||
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
|
||||
|
||||
ret = WebGL2Context::Create();
|
||||
if (!ret)
|
||||
return nullptr;
|
||||
break;
|
||||
}
|
||||
MOZ_ASSERT(ret);
|
||||
|
||||
ret->SetCanvasElement(canvas);
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLCanvasElement::GetContext(const nsAString& aContextId,
|
||||
nsISupports** aContext)
|
||||
|
@ -868,14 +890,45 @@ already_AddRefed<nsISupports>
|
|||
HTMLCanvasElement::GetContext(JSContext* aCx,
|
||||
const nsAString& aContextId,
|
||||
JS::Handle<JS::Value> aContextOptions,
|
||||
ErrorResult& aRv)
|
||||
ErrorResult& rv)
|
||||
{
|
||||
if (mOffscreenCanvas) {
|
||||
CanvasContextType contextType;
|
||||
if (!GetCanvasContextType(aContextId, &contextType))
|
||||
return nullptr;
|
||||
|
||||
if (!mCurrentContext) {
|
||||
// This canvas doesn't have a context yet.
|
||||
|
||||
nsRefPtr<nsICanvasRenderingContextInternal> context;
|
||||
context = CreateContextForCanvas(contextType, this);
|
||||
if (!context)
|
||||
return nullptr;
|
||||
|
||||
// Ensure that the context participates in CC. Note that returning a
|
||||
// CC participant from QI doesn't addref.
|
||||
nsXPCOMCycleCollectionParticipant* cp = nullptr;
|
||||
CallQueryInterface(context, &cp);
|
||||
if (!cp) {
|
||||
rv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mCurrentContext = context.forget();
|
||||
mCurrentContextType = contextType;
|
||||
|
||||
rv = UpdateContext(aCx, aContextOptions);
|
||||
if (rv.Failed()) {
|
||||
rv = NS_OK; // See bug 645792
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
// We already have a context of some type.
|
||||
if (contextType != mCurrentContextType)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return CanvasRenderingContextHelper::GetContext(aCx, aContextId,
|
||||
aContextOptions, aRv);
|
||||
nsCOMPtr<nsICanvasRenderingContextInternal> context = mCurrentContext;
|
||||
return context.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -897,7 +950,7 @@ HTMLCanvasElement::MozGetIPCContext(const nsAString& aContextId,
|
|||
// This canvas doesn't have a context yet.
|
||||
|
||||
nsRefPtr<nsICanvasRenderingContextInternal> context;
|
||||
context = CreateContext(contextType);
|
||||
context = CreateContextForCanvas(contextType, this);
|
||||
if (!context) {
|
||||
*aContext = nullptr;
|
||||
return NS_OK;
|
||||
|
@ -919,6 +972,36 @@ HTMLCanvasElement::MozGetIPCContext(const nsAString& aContextId,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLCanvasElement::UpdateContext(JSContext* aCx, JS::Handle<JS::Value> aNewContextOptions)
|
||||
{
|
||||
if (!mCurrentContext)
|
||||
return NS_OK;
|
||||
|
||||
nsIntSize sz = GetWidthHeight();
|
||||
|
||||
nsCOMPtr<nsICanvasRenderingContextInternal> currentContext = mCurrentContext;
|
||||
|
||||
nsresult rv = currentContext->SetIsOpaque(HasAttr(kNameSpaceID_None, nsGkAtoms::moz_opaque));
|
||||
if (NS_FAILED(rv)) {
|
||||
mCurrentContext = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = currentContext->SetContextOptions(aCx, aNewContextOptions);
|
||||
if (NS_FAILED(rv)) {
|
||||
mCurrentContext = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = currentContext->SetDimensions(sz.width, sz.height);
|
||||
if (NS_FAILED(rv)) {
|
||||
mCurrentContext = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsIntSize
|
||||
HTMLCanvasElement::GetSize()
|
||||
|
@ -1022,12 +1105,6 @@ HTMLCanvasElement::GetIsOpaque()
|
|||
return mCurrentContext->GetIsOpaque();
|
||||
}
|
||||
|
||||
return GetOpaqueAttr();
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLCanvasElement::GetOpaqueAttr()
|
||||
{
|
||||
return HasAttr(kNameSpaceID_None, nsGkAtoms::moz_opaque);
|
||||
}
|
||||
|
||||
|
@ -1036,57 +1113,16 @@ HTMLCanvasElement::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
|||
CanvasLayer *aOldLayer,
|
||||
LayerManager *aManager)
|
||||
{
|
||||
// The address of sOffscreenCanvasLayerUserDataDummy is used as the user
|
||||
// data key for retained LayerManagers managed by FrameLayerBuilder.
|
||||
// We don't much care about what value in it, so just assign a dummy
|
||||
// value for it.
|
||||
static uint8_t sOffscreenCanvasLayerUserDataDummy = 0;
|
||||
if (!mCurrentContext)
|
||||
return nullptr;
|
||||
|
||||
if (mCurrentContext) {
|
||||
return mCurrentContext->GetCanvasLayer(aBuilder, aOldLayer, aManager);
|
||||
}
|
||||
|
||||
if (mOffscreenCanvas) {
|
||||
if (!mResetLayer &&
|
||||
aOldLayer && aOldLayer->HasUserData(&sOffscreenCanvasLayerUserDataDummy)) {
|
||||
nsRefPtr<CanvasLayer> ret = aOldLayer;
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
nsRefPtr<CanvasLayer> layer = aManager->CreateCanvasLayer();
|
||||
if (!layer) {
|
||||
NS_WARNING("CreateCanvasLayer failed!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LayerUserData* userData = nullptr;
|
||||
layer->SetUserData(&sOffscreenCanvasLayerUserDataDummy, userData);
|
||||
|
||||
CanvasLayer::Data data;
|
||||
data.mRenderer = GetAsyncCanvasRenderer();
|
||||
data.mSize = GetWidthHeight();
|
||||
layer->Initialize(data);
|
||||
|
||||
layer->Updated();
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return mCurrentContext->GetCanvasLayer(aBuilder, aOldLayer, aManager);
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLCanvasElement::ShouldForceInactiveLayer(LayerManager* aManager)
|
||||
HTMLCanvasElement::ShouldForceInactiveLayer(LayerManager *aManager)
|
||||
{
|
||||
if (mCurrentContext) {
|
||||
return mCurrentContext->ShouldForceInactiveLayer(aManager);
|
||||
}
|
||||
|
||||
if (mOffscreenCanvas) {
|
||||
// TODO: We should handle offscreen canvas case.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return !mCurrentContext || mCurrentContext->ShouldForceInactiveLayer(aManager);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1201,155 +1237,5 @@ HTMLCanvasElement::GetSurfaceSnapshot(bool* aPremultAlpha)
|
|||
return mCurrentContext->GetSurfaceSnapshot(aPremultAlpha);
|
||||
}
|
||||
|
||||
AsyncCanvasRenderer*
|
||||
HTMLCanvasElement::GetAsyncCanvasRenderer()
|
||||
{
|
||||
if (!mAsyncCanvasRenderer) {
|
||||
mAsyncCanvasRenderer = new AsyncCanvasRenderer();
|
||||
mAsyncCanvasRenderer->mHTMLCanvasElement = this;
|
||||
}
|
||||
|
||||
return mAsyncCanvasRenderer;
|
||||
}
|
||||
|
||||
layers::LayersBackend
|
||||
HTMLCanvasElement::GetCompositorBackendType() const
|
||||
{
|
||||
nsIWidget* docWidget = nsContentUtils::WidgetForDocument(OwnerDoc());
|
||||
if (docWidget) {
|
||||
layers::LayerManager* layerManager = docWidget->GetLayerManager();
|
||||
return layerManager->GetCompositorBackendType();
|
||||
}
|
||||
|
||||
return LayersBackend::LAYERS_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLCanvasElement::OnVisibilityChange()
|
||||
{
|
||||
if (OwnerDoc()->Hidden()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mOffscreenCanvas) {
|
||||
class Runnable final : public nsCancelableRunnable
|
||||
{
|
||||
public:
|
||||
explicit Runnable(AsyncCanvasRenderer* aRenderer)
|
||||
: mRenderer(aRenderer)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
if (mRenderer && mRenderer->mContext) {
|
||||
mRenderer->mContext->OnVisibilityChange();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Revoke()
|
||||
{
|
||||
mRenderer = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<AsyncCanvasRenderer> mRenderer;
|
||||
};
|
||||
|
||||
nsRefPtr<nsIRunnable> runnable = new Runnable(mAsyncCanvasRenderer);
|
||||
nsCOMPtr<nsIThread> activeThread = mAsyncCanvasRenderer->GetActiveThread();
|
||||
if (activeThread) {
|
||||
activeThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCurrentContext) {
|
||||
mCurrentContext->OnVisibilityChange();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLCanvasElement::OnMemoryPressure()
|
||||
{
|
||||
if (mOffscreenCanvas) {
|
||||
class Runnable final : public nsCancelableRunnable
|
||||
{
|
||||
public:
|
||||
explicit Runnable(AsyncCanvasRenderer* aRenderer)
|
||||
: mRenderer(aRenderer)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
if (mRenderer && mRenderer->mContext) {
|
||||
mRenderer->mContext->OnMemoryPressure();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Revoke()
|
||||
{
|
||||
mRenderer = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<AsyncCanvasRenderer> mRenderer;
|
||||
};
|
||||
|
||||
nsRefPtr<nsIRunnable> runnable = new Runnable(mAsyncCanvasRenderer);
|
||||
nsCOMPtr<nsIThread> activeThread = mAsyncCanvasRenderer->GetActiveThread();
|
||||
if (activeThread) {
|
||||
activeThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCurrentContext) {
|
||||
mCurrentContext->OnMemoryPressure();
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
HTMLCanvasElement::SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer)
|
||||
{
|
||||
HTMLCanvasElement *element = aRenderer->mHTMLCanvasElement;
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (element->GetWidthHeight() == aRenderer->GetSize()) {
|
||||
return;
|
||||
}
|
||||
|
||||
gfx::IntSize asyncCanvasSize = aRenderer->GetSize();
|
||||
|
||||
ErrorResult rv;
|
||||
element->SetUnsignedIntAttr(nsGkAtoms::width, asyncCanvasSize.width, rv);
|
||||
if (rv.Failed()) {
|
||||
NS_WARNING("Failed to set width attribute to a canvas element asynchronously.");
|
||||
}
|
||||
|
||||
element->SetUnsignedIntAttr(nsGkAtoms::height, asyncCanvasSize.height, rv);
|
||||
if (rv.Failed()) {
|
||||
NS_WARNING("Failed to set height attribute to a canvas element asynchronously.");
|
||||
}
|
||||
|
||||
element->mResetLayer = true;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
HTMLCanvasElement::InvalidateFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer)
|
||||
{
|
||||
HTMLCanvasElement *element = aRenderer->mHTMLCanvasElement;
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
element->InvalidateCanvasContent(nullptr);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -8,27 +8,20 @@
|
|||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsIDOMHTMLCanvasElement.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsSize.h"
|
||||
#include "nsError.h"
|
||||
|
||||
#include "mozilla/dom/CanvasRenderingContextHelper.h"
|
||||
#include "mozilla/gfx/Rect.h"
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
|
||||
class nsICanvasRenderingContextInternal;
|
||||
class nsITimerCallback;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class WebGLContext;
|
||||
|
||||
namespace layers {
|
||||
class AsyncCanvasRenderer;
|
||||
class CanvasLayer;
|
||||
class Image;
|
||||
class LayerManager;
|
||||
|
@ -42,33 +35,14 @@ class CanvasCaptureMediaStream;
|
|||
class File;
|
||||
class FileCallback;
|
||||
class HTMLCanvasPrintState;
|
||||
class OffscreenCanvas;
|
||||
class PrintCallback;
|
||||
class RequestedFrameRefreshObserver;
|
||||
|
||||
// Listen visibilitychange and memory-pressure event and inform
|
||||
// context when event is fired.
|
||||
class HTMLCanvasElementObserver final : public nsIObserver
|
||||
, public nsIDOMEventListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
|
||||
explicit HTMLCanvasElementObserver(HTMLCanvasElement* aElement);
|
||||
void Destroy();
|
||||
|
||||
void RegisterVisibilityChangeEvent();
|
||||
void UnregisterVisibilityChangeEvent();
|
||||
|
||||
void RegisterMemoryPressureEvent();
|
||||
void UnregisterMemoryPressureEvent();
|
||||
|
||||
private:
|
||||
~HTMLCanvasElementObserver();
|
||||
|
||||
HTMLCanvasElement* mElement;
|
||||
enum class CanvasContextType : uint8_t {
|
||||
NoContext,
|
||||
Canvas2D,
|
||||
WebGL1,
|
||||
WebGL2
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -110,15 +84,13 @@ protected:
|
|||
};
|
||||
|
||||
class HTMLCanvasElement final : public nsGenericHTMLElement,
|
||||
public nsIDOMHTMLCanvasElement,
|
||||
public CanvasRenderingContextHelper
|
||||
public nsIDOMHTMLCanvasElement
|
||||
{
|
||||
enum {
|
||||
DEFAULT_CANVAS_WIDTH = 300,
|
||||
DEFAULT_CANVAS_HEIGHT = 150
|
||||
};
|
||||
|
||||
typedef layers::AsyncCanvasRenderer AsyncCanvasRenderer;
|
||||
typedef layers::CanvasLayer CanvasLayer;
|
||||
typedef layers::LayerManager LayerManager;
|
||||
|
||||
|
@ -144,11 +116,6 @@ public:
|
|||
}
|
||||
void SetHeight(uint32_t aHeight, ErrorResult& aRv)
|
||||
{
|
||||
if (mOffscreenCanvas) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
SetUnsignedIntAttr(nsGkAtoms::height, aHeight, aRv);
|
||||
}
|
||||
uint32_t Width()
|
||||
|
@ -157,45 +124,30 @@ public:
|
|||
}
|
||||
void SetWidth(uint32_t aWidth, ErrorResult& aRv)
|
||||
{
|
||||
if (mOffscreenCanvas) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
SetUnsignedIntAttr(nsGkAtoms::width, aWidth, aRv);
|
||||
}
|
||||
|
||||
virtual already_AddRefed<nsISupports>
|
||||
already_AddRefed<nsISupports>
|
||||
GetContext(JSContext* aCx, const nsAString& aContextId,
|
||||
JS::Handle<JS::Value> aContextOptions,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
ErrorResult& aRv);
|
||||
void ToDataURL(JSContext* aCx, const nsAString& aType,
|
||||
JS::Handle<JS::Value> aParams,
|
||||
nsAString& aDataURL, ErrorResult& aRv)
|
||||
{
|
||||
aRv = ToDataURL(aType, aParams, aCx, aDataURL);
|
||||
}
|
||||
|
||||
void ToBlob(JSContext* aCx,
|
||||
FileCallback& aCallback,
|
||||
const nsAString& aType,
|
||||
JS::Handle<JS::Value> aParams,
|
||||
ErrorResult& aRv);
|
||||
|
||||
OffscreenCanvas* TransferControlToOffscreen(ErrorResult& aRv);
|
||||
|
||||
bool MozOpaque() const
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::moz_opaque);
|
||||
}
|
||||
void SetMozOpaque(bool aValue, ErrorResult& aRv)
|
||||
{
|
||||
if (mOffscreenCanvas) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
SetHTMLBoolAttr(nsGkAtoms::moz_opaque, aValue, aRv);
|
||||
}
|
||||
already_AddRefed<File> MozGetAsFile(const nsAString& aName,
|
||||
|
@ -252,7 +204,6 @@ public:
|
|||
* across its entire area.
|
||||
*/
|
||||
bool GetIsOpaque();
|
||||
virtual bool GetOpaqueAttr() override;
|
||||
|
||||
virtual already_AddRefed<gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha = nullptr);
|
||||
|
||||
|
@ -331,25 +282,19 @@ public:
|
|||
|
||||
nsresult GetContext(const nsAString& aContextId, nsISupports** aContext);
|
||||
|
||||
layers::LayersBackend GetCompositorBackendType() const;
|
||||
|
||||
void OnVisibilityChange();
|
||||
|
||||
void OnMemoryPressure();
|
||||
|
||||
static void SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer);
|
||||
static void InvalidateFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer);
|
||||
|
||||
protected:
|
||||
virtual ~HTMLCanvasElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
virtual nsIntSize GetWidthHeight() override;
|
||||
|
||||
virtual already_AddRefed<nsICanvasRenderingContextInternal>
|
||||
CreateContext(CanvasContextType aContextType) override;
|
||||
nsIntSize GetWidthHeight();
|
||||
|
||||
nsresult UpdateContext(JSContext* aCx, JS::Handle<JS::Value> options);
|
||||
nsresult ParseParams(JSContext* aCx,
|
||||
const nsAString& aType,
|
||||
const JS::Value& aEncoderOptions,
|
||||
nsAString& aParams,
|
||||
bool* usingCustomParseOptions);
|
||||
nsresult ExtractData(nsAString& aType,
|
||||
const nsAString& aOptions,
|
||||
nsIInputStream** aStream);
|
||||
|
@ -362,17 +307,13 @@ protected:
|
|||
nsISupports** aResult);
|
||||
void CallPrintCallback();
|
||||
|
||||
AsyncCanvasRenderer* GetAsyncCanvasRenderer();
|
||||
|
||||
bool mResetLayer;
|
||||
CanvasContextType mCurrentContextType;
|
||||
nsRefPtr<HTMLCanvasElement> mOriginalCanvas;
|
||||
nsRefPtr<PrintCallback> mPrintCallback;
|
||||
nsCOMPtr<nsICanvasRenderingContextInternal> mCurrentContext;
|
||||
nsRefPtr<HTMLCanvasPrintState> mPrintState;
|
||||
nsTArray<WeakPtr<FrameCaptureListener>> mRequestedFrameListeners;
|
||||
nsRefPtr<RequestedFrameRefreshObserver> mRequestedFrameRefreshObserver;
|
||||
nsRefPtr<AsyncCanvasRenderer> mAsyncCanvasRenderer;
|
||||
nsRefPtr<OffscreenCanvas> mOffscreenCanvas;
|
||||
nsRefPtr<HTMLCanvasElementObserver> mContextObserver;
|
||||
|
||||
public:
|
||||
// Record whether this canvas should be write-only or not.
|
||||
|
|
|
@ -872,8 +872,6 @@ var interfaceNamesInGlobalScope =
|
|||
"Notification",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"NotifyPaintEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "OffscreenCanvas", disabled: true},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"OfflineAudioCompletionEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
|
|
@ -46,13 +46,6 @@ partial interface HTMLCanvasElement {
|
|||
CanvasCaptureMediaStream captureStream(optional double frameRate);
|
||||
};
|
||||
|
||||
// For OffscreenCanvas
|
||||
// Reference: https://wiki.whatwg.org/wiki/OffscreenCanvas
|
||||
partial interface HTMLCanvasElement {
|
||||
[Pref="gfx.offscreencanvas.enabled", Throws]
|
||||
OffscreenCanvas transferControlToOffscreen();
|
||||
};
|
||||
|
||||
[ChromeOnly]
|
||||
interface MozCanvasPrintState
|
||||
{
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* For more information on this interface, please see
|
||||
* https://wiki.whatwg.org/wiki/OffscreenCanvas
|
||||
*
|
||||
* Current implementation focus on transfer canvas from main thread to worker.
|
||||
* So there are some spec doesn't implement, such as [Constructor], toBlob() and
|
||||
* transferToImageBitmap in OffscreenCanvas. Bug 1172796 will implement
|
||||
* remaining spec.
|
||||
*/
|
||||
|
||||
[Exposed=(Window,Worker),
|
||||
Func="mozilla::dom::OffscreenCanvas::PrefEnabled"]
|
||||
interface OffscreenCanvas : EventTarget {
|
||||
[Pure, SetterThrows]
|
||||
attribute unsigned long width;
|
||||
[Pure, SetterThrows]
|
||||
attribute unsigned long height;
|
||||
|
||||
[Throws]
|
||||
nsISupports? getContext(DOMString contextId,
|
||||
optional any contextOptions = null);
|
||||
};
|
||||
|
||||
// OffscreenCanvas implements Transferable;
|
|
@ -45,38 +45,24 @@ dictionary WebGLContextAttributes {
|
|||
boolean failIfMajorPerformanceCaveat = false;
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker),
|
||||
Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"]
|
||||
interface WebGLBuffer {
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker),
|
||||
Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"]
|
||||
interface WebGLFramebuffer {
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker),
|
||||
Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"]
|
||||
interface WebGLProgram {
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker),
|
||||
Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"]
|
||||
interface WebGLRenderbuffer {
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker),
|
||||
Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"]
|
||||
interface WebGLShader {
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker),
|
||||
Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"]
|
||||
interface WebGLTexture {
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker),
|
||||
Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"]
|
||||
interface WebGLUniformLocation {
|
||||
};
|
||||
|
||||
|
@ -84,24 +70,18 @@ interface WebGLUniformLocation {
|
|||
interface WebGLVertexArrayObjectOES {
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker),
|
||||
Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"]
|
||||
interface WebGLActiveInfo {
|
||||
readonly attribute GLint size;
|
||||
readonly attribute GLenum type;
|
||||
readonly attribute DOMString name;
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker),
|
||||
Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"]
|
||||
interface WebGLShaderPrecisionFormat {
|
||||
readonly attribute GLint rangeMin;
|
||||
readonly attribute GLint rangeMax;
|
||||
readonly attribute GLint precision;
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker),
|
||||
Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"]
|
||||
interface WebGLRenderingContext {
|
||||
|
||||
/* ClearBufferMask */
|
||||
|
@ -524,7 +504,7 @@ interface WebGLRenderingContext {
|
|||
const GLenum BROWSER_DEFAULT_WEBGL = 0x9244;
|
||||
|
||||
// The canvas might actually be null in some cases, apparently.
|
||||
readonly attribute (HTMLCanvasElement or OffscreenCanvas)? canvas;
|
||||
readonly attribute HTMLCanvasElement? canvas;
|
||||
readonly attribute GLsizei drawingBufferWidth;
|
||||
readonly attribute GLsizei drawingBufferHeight;
|
||||
|
||||
|
@ -786,14 +766,6 @@ interface WebGLRenderingContext {
|
|||
void viewport(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
};
|
||||
|
||||
// For OffscreenCanvas
|
||||
// Reference: https://wiki.whatwg.org/wiki/OffscreenCanvas
|
||||
[Exposed=(Window,Worker)]
|
||||
partial interface WebGLRenderingContext {
|
||||
[Func="mozilla::dom::OffscreenCanvas::PrefEnabled"]
|
||||
void commit();
|
||||
};
|
||||
|
||||
/*[Constructor(DOMString type, optional WebGLContextEventInit eventInit)]
|
||||
interface WebGLContextEvent : Event {
|
||||
readonly attribute DOMString statusMessage;
|
||||
|
|
|
@ -344,7 +344,6 @@ WEBIDL_FILES = [
|
|||
'OfflineAudioCompletionEvent.webidl',
|
||||
'OfflineAudioContext.webidl',
|
||||
'OfflineResourceList.webidl',
|
||||
'OffscreenCanvas.webidl',
|
||||
'OscillatorNode.webidl',
|
||||
'PaintRequest.webidl',
|
||||
'PaintRequestList.webidl',
|
||||
|
|
|
@ -170,7 +170,6 @@ static_assert(MAX_WORKERS_PER_DOMAIN >= 1,
|
|||
#define PREF_INTERCEPTION_OPAQUE_ENABLED "dom.serviceWorkers.interception.opaque.enabled"
|
||||
#define PREF_PUSH_ENABLED "dom.push.enabled"
|
||||
#define PREF_REQUESTCONTEXT_ENABLED "dom.requestcontext.enabled"
|
||||
#define PREF_OFFSCREENCANVAS_ENABLED "gfx.offscreencanvas.enabled"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -1944,10 +1943,6 @@ RuntimeService::Init()
|
|||
WorkerPrefChanged,
|
||||
PREF_REQUESTCONTEXT_ENABLED,
|
||||
reinterpret_cast<void *>(WORKERPREF_REQUESTCONTEXT))) ||
|
||||
NS_FAILED(Preferences::RegisterCallbackAndCall(
|
||||
WorkerPrefChanged,
|
||||
PREF_OFFSCREENCANVAS_ENABLED,
|
||||
reinterpret_cast<void *>(WORKERPREF_OFFSCREENCANVAS))) ||
|
||||
NS_FAILED(Preferences::RegisterCallback(LoadRuntimeOptions,
|
||||
PREF_JS_OPTIONS_PREFIX,
|
||||
nullptr)) ||
|
||||
|
@ -2187,10 +2182,6 @@ RuntimeService::Cleanup()
|
|||
WorkerPrefChanged,
|
||||
PREF_REQUESTCONTEXT_ENABLED,
|
||||
reinterpret_cast<void *>(WORKERPREF_REQUESTCONTEXT))) ||
|
||||
NS_FAILED(Preferences::UnregisterCallback(
|
||||
WorkerPrefChanged,
|
||||
PREF_OFFSCREENCANVAS_ENABLED,
|
||||
reinterpret_cast<void *>(WORKERPREF_OFFSCREENCANVAS))) ||
|
||||
#if DUMP_CONTROLLED_BY_PREF
|
||||
NS_FAILED(Preferences::UnregisterCallback(
|
||||
WorkerPrefChanged,
|
||||
|
@ -2741,7 +2732,6 @@ RuntimeService::WorkerPrefChanged(const char* aPrefName, void* aClosure)
|
|||
case WORKERPREF_SERVICEWORKERS_TESTING:
|
||||
case WORKERPREF_PUSH:
|
||||
case WORKERPREF_REQUESTCONTEXT:
|
||||
case WORKERPREF_OFFSCREENCANVAS:
|
||||
sDefaultPreferences[key] = Preferences::GetBool(aPrefName, false);
|
||||
break;
|
||||
|
||||
|
|
|
@ -1313,13 +1313,6 @@ public:
|
|||
return mPreferences[WORKERPREF_REQUESTCONTEXT];
|
||||
}
|
||||
|
||||
bool
|
||||
OffscreenCanvasEnabled() const
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
return mPreferences[WORKERPREF_OFFSCREENCANVAS];
|
||||
}
|
||||
|
||||
bool
|
||||
OnLine() const
|
||||
{
|
||||
|
|
|
@ -209,7 +209,6 @@ enum WorkerPreference
|
|||
WORKERPREF_PERFORMANCE_LOGGING_ENABLED, // dom.performance.enable_user_timing_logging
|
||||
WORKERPREF_PUSH, // dom.push.enabled
|
||||
WORKERPREF_REQUESTCONTEXT, // dom.requestcontext.enabled
|
||||
WORKERPREF_OFFSCREENCANVAS, // gfx.offscreencanvas.enabled
|
||||
WORKERPREF_COUNT
|
||||
};
|
||||
|
||||
|
|
|
@ -155,8 +155,6 @@ var interfaceNamesInGlobalScope =
|
|||
"MessagePort",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"Notification",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{ name: "OffscreenCanvas", disabled: true },
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"Performance",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -191,26 +189,6 @@ var interfaceNamesInGlobalScope =
|
|||
"URL",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"URLSearchParams",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{ name: "WebGLActiveInfo", disabled: true },
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{ name: "WebGLBuffer", disabled: true },
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{ name: "WebGLFramebuffer", disabled: true },
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{ name: "WebGLProgram", disabled: true },
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{ name: "WebGLRenderbuffer", disabled: true },
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{ name: "WebGLRenderingContext", disabled: true },
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{ name: "WebGLShader", disabled: true },
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{ name: "WebGLShaderPrecisionFormat", disabled: true },
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{ name: "WebGLTexture", disabled: true },
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{ name: "WebGLUniformLocation", disabled: true },
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"WebSocket",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
|
|
@ -2650,7 +2650,6 @@ GLContext::Readback(SharedSurface* src, gfx::DataSourceSurface* dest)
|
|||
}
|
||||
|
||||
GLuint tempFB = 0;
|
||||
GLuint tempTex = 0;
|
||||
|
||||
{
|
||||
ScopedBindFramebuffer autoFB(this);
|
||||
|
@ -2682,24 +2681,6 @@ GLContext::Readback(SharedSurface* src, gfx::DataSourceSurface* dest)
|
|||
MOZ_ASSERT(status == LOCAL_GL_FRAMEBUFFER_COMPLETE);
|
||||
}
|
||||
|
||||
if (src->NeedsIndirectReads()) {
|
||||
fGenTextures(1, &tempTex);
|
||||
{
|
||||
ScopedBindTexture autoTex(this, tempTex);
|
||||
|
||||
GLenum format = src->mHasAlpha ? LOCAL_GL_RGBA
|
||||
: LOCAL_GL_RGB;
|
||||
auto width = src->mSize.width;
|
||||
auto height = src->mSize.height;
|
||||
fCopyTexImage2D(LOCAL_GL_TEXTURE_2D, 0, format, 0, 0, width,
|
||||
height, 0);
|
||||
}
|
||||
|
||||
fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
|
||||
LOCAL_GL_COLOR_ATTACHMENT0,
|
||||
LOCAL_GL_TEXTURE_2D, tempTex, 0);
|
||||
}
|
||||
|
||||
ReadPixelsIntoDataSurface(this, dest);
|
||||
|
||||
src->ProducerReadRelease();
|
||||
|
@ -2708,10 +2689,6 @@ GLContext::Readback(SharedSurface* src, gfx::DataSourceSurface* dest)
|
|||
if (tempFB)
|
||||
fDeleteFramebuffers(1, &tempFB);
|
||||
|
||||
if (tempTex) {
|
||||
fDeleteTextures(1, &tempTex);
|
||||
}
|
||||
|
||||
if (needsSwap) {
|
||||
src->UnlockProd();
|
||||
if (prev)
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#include "GLLibraryEGL.h"
|
||||
|
||||
#include "gfxCrashReporterUtils.h"
|
||||
#include "gfxUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
|
@ -15,17 +14,13 @@
|
|||
#ifdef XP_WIN
|
||||
#include "nsWindowsHelpers.h"
|
||||
#endif
|
||||
#include "OGLShaderProgram.h"
|
||||
#include "prenv.h"
|
||||
#include "GLContext.h"
|
||||
#include "GLContextProvider.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "ScopedGLHelpers.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
|
||||
StaticMutex GLLibraryEGL::sMutex;
|
||||
GLLibraryEGL sEGLLibrary;
|
||||
#ifdef MOZ_B2G
|
||||
ThreadLocal<EGLContext> GLLibraryEGL::sCurrentContext;
|
||||
|
@ -133,9 +128,7 @@ static bool
|
|||
IsAccelAngleSupported(const nsCOMPtr<nsIGfxInfo>& gfxInfo)
|
||||
{
|
||||
int32_t angleSupport;
|
||||
gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
|
||||
nsIGfxInfo::FEATURE_WEBGL_ANGLE,
|
||||
&angleSupport);
|
||||
gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBGL_ANGLE, &angleSupport);
|
||||
return (angleSupport == nsIGfxInfo::FEATURE_STATUS_OK);
|
||||
}
|
||||
|
||||
|
@ -152,32 +145,6 @@ GetAndInitDisplay(GLLibraryEGL& egl, void* displayType)
|
|||
return display;
|
||||
}
|
||||
|
||||
bool
|
||||
GLLibraryEGL::ReadbackEGLImage(EGLImage image, gfx::DataSourceSurface* out_surface)
|
||||
{
|
||||
StaticMutexAutoUnlock lock(sMutex);
|
||||
if (!mReadbackGL) {
|
||||
mReadbackGL = gl::GLContextProvider::CreateHeadless(gl::CreateContextFlags::NONE);
|
||||
}
|
||||
|
||||
ScopedTexture destTex(mReadbackGL);
|
||||
const GLuint target = LOCAL_GL_TEXTURE_EXTERNAL;
|
||||
ScopedBindTexture autoTex(mReadbackGL, destTex.Texture(), target);
|
||||
mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
|
||||
mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
|
||||
mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
|
||||
mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
|
||||
mReadbackGL->fEGLImageTargetTexture2D(target, image);
|
||||
|
||||
ShaderConfigOGL config = ShaderConfigFromTargetAndFormat(target,
|
||||
out_surface->GetFormat());
|
||||
int shaderConfig = config.mFeatures;
|
||||
mReadbackGL->ReadTexImageHelper()->ReadTexImage(out_surface, 0, target,
|
||||
out_surface->GetSize(), shaderConfig);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GLLibraryEGL::EnsureInitialized(bool forceAccel)
|
||||
{
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#endif
|
||||
|
||||
#include "GLLibraryLoader.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "mozilla/ThreadLocal.h"
|
||||
#include "nsIFile.h"
|
||||
#include "GeckoProfiler.h"
|
||||
|
@ -53,11 +52,6 @@
|
|||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace gfx {
|
||||
class DataSourceSurface;
|
||||
}
|
||||
|
||||
namespace gl {
|
||||
|
||||
#undef BEFORE_GL_CALL
|
||||
|
@ -100,8 +94,6 @@ namespace gl {
|
|||
#define AFTER_GL_CALL
|
||||
#endif
|
||||
|
||||
class GLContext;
|
||||
|
||||
class GLLibraryEGL
|
||||
{
|
||||
public:
|
||||
|
@ -486,8 +478,6 @@ public:
|
|||
return IsExtensionSupported(EXT_create_context_robustness);
|
||||
}
|
||||
|
||||
bool ReadbackEGLImage(EGLImage image, gfx::DataSourceSurface* out_surface);
|
||||
|
||||
bool EnsureInitialized(bool forceAccel = false);
|
||||
|
||||
void DumpEGLConfig(EGLConfig cfg);
|
||||
|
@ -613,11 +603,9 @@ private:
|
|||
bool mInitialized;
|
||||
PRLibrary* mEGLLibrary;
|
||||
EGLDisplay mEGLDisplay;
|
||||
RefPtr<GLContext> mReadbackGL;
|
||||
|
||||
bool mIsANGLE;
|
||||
bool mIsWARP;
|
||||
static StaticMutex sMutex;
|
||||
};
|
||||
|
||||
extern GLLibraryEGL sEGLLibrary;
|
||||
|
|
|
@ -214,7 +214,7 @@ GetActualReadFormats(GLContext* gl,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
SwapRAndBComponents(DataSourceSurface* surf)
|
||||
{
|
||||
DataSourceSurface::MappedSurface map;
|
||||
|
@ -533,8 +533,8 @@ ReadPixelsIntoDataSurface(GLContext* gl, DataSourceSurface* dest)
|
|||
#endif
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::DataSourceSurface>
|
||||
YInvertImageSurface(gfx::DataSourceSurface* aSurf)
|
||||
static already_AddRefed<DataSourceSurface>
|
||||
YInvertImageSurface(DataSourceSurface* aSurf)
|
||||
{
|
||||
RefPtr<DataSourceSurface> temp =
|
||||
Factory::CreateDataSourceSurfaceWithStride(aSurf->GetSize(),
|
||||
|
@ -560,8 +560,8 @@ YInvertImageSurface(gfx::DataSourceSurface* aSurf)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
dt->SetTransform(Matrix::Scaling(1.0, -1.0) *
|
||||
Matrix::Translation(0.0, aSurf->GetSize().height));
|
||||
dt->SetTransform(Matrix::Translation(0.0, aSurf->GetSize().height) *
|
||||
Matrix::Scaling(1.0, -1.0));
|
||||
Rect rect(0, 0, aSurf->GetSize().width, aSurf->GetSize().height);
|
||||
dt->DrawSurface(aSurf, rect, rect, DrawSurfaceOptions(),
|
||||
DrawOptions(1.0, CompositionOp::OP_SOURCE, AntialiasMode::NONE));
|
||||
|
@ -614,7 +614,8 @@ ReadBackSurface(GLContext* gl, GLuint aTexture, bool aYInvert, SurfaceFormat aFo
|
|||
|
||||
#define CLEANUP_IF_GLERROR_OCCURRED(x) \
|
||||
if (DidGLErrorOccur(x)) { \
|
||||
return false; \
|
||||
isurf = nullptr; \
|
||||
break; \
|
||||
}
|
||||
|
||||
already_AddRefed<DataSourceSurface>
|
||||
|
@ -623,31 +624,6 @@ GLReadTexImageHelper::ReadTexImage(GLuint aTextureId,
|
|||
const gfx::IntSize& aSize,
|
||||
/* ShaderConfigOGL.mFeature */ int aConfig,
|
||||
bool aYInvert)
|
||||
{
|
||||
/* Allocate resulting image surface */
|
||||
int32_t stride = aSize.width * BytesPerPixel(SurfaceFormat::R8G8B8A8);
|
||||
RefPtr<DataSourceSurface> isurf =
|
||||
Factory::CreateDataSourceSurfaceWithStride(aSize,
|
||||
SurfaceFormat::R8G8B8A8,
|
||||
stride);
|
||||
if (NS_WARN_IF(!isurf)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!ReadTexImage(isurf, aTextureId, aTextureTarget, aSize, aConfig, aYInvert)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return isurf.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
GLReadTexImageHelper::ReadTexImage(DataSourceSurface* aDest,
|
||||
GLuint aTextureId,
|
||||
GLenum aTextureTarget,
|
||||
const gfx::IntSize& aSize,
|
||||
/* ShaderConfigOGL.mFeature */ int aConfig,
|
||||
bool aYInvert)
|
||||
{
|
||||
MOZ_ASSERT(aTextureTarget == LOCAL_GL_TEXTURE_2D ||
|
||||
aTextureTarget == LOCAL_GL_TEXTURE_EXTERNAL ||
|
||||
|
@ -655,6 +631,16 @@ GLReadTexImageHelper::ReadTexImage(DataSourceSurface* aDest,
|
|||
|
||||
mGL->MakeCurrent();
|
||||
|
||||
/* Allocate resulting image surface */
|
||||
int32_t stride = aSize.width * BytesPerPixel(SurfaceFormat::R8G8B8A8);
|
||||
RefPtr<DataSourceSurface> isurf =
|
||||
Factory::CreateDataSourceSurfaceWithStride(aSize,
|
||||
SurfaceFormat::R8G8B8A8,
|
||||
stride);
|
||||
if (NS_WARN_IF(!isurf)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GLint oldrb, oldfb, oldprog, oldTexUnit, oldTex;
|
||||
GLuint rb, fb;
|
||||
|
||||
|
@ -751,7 +737,7 @@ GLReadTexImageHelper::ReadTexImage(DataSourceSurface* aDest,
|
|||
CLEANUP_IF_GLERROR_OCCURRED("when drawing texture");
|
||||
|
||||
/* Read-back draw results */
|
||||
ReadPixelsIntoDataSurface(mGL, aDest);
|
||||
ReadPixelsIntoDataSurface(mGL, isurf);
|
||||
CLEANUP_IF_GLERROR_OCCURRED("when reading pixels into surface");
|
||||
} while (false);
|
||||
|
||||
|
@ -770,7 +756,7 @@ GLReadTexImageHelper::ReadTexImage(DataSourceSurface* aDest,
|
|||
if (oldTexUnit != LOCAL_GL_TEXTURE0)
|
||||
mGL->fActiveTexture(oldTexUnit);
|
||||
|
||||
return true;
|
||||
return isurf.forget();
|
||||
}
|
||||
|
||||
#undef CLEANUP_IF_GLERROR_OCCURRED
|
||||
|
|
|
@ -34,12 +34,6 @@ void ReadPixelsIntoDataSurface(GLContext* aGL,
|
|||
already_AddRefed<gfx::DataSourceSurface>
|
||||
ReadBackSurface(GLContext* gl, GLuint aTexture, bool aYInvert, gfx::SurfaceFormat aFormat);
|
||||
|
||||
already_AddRefed<gfx::DataSourceSurface>
|
||||
YInvertImageSurface(gfx::DataSourceSurface* aSurf);
|
||||
|
||||
void
|
||||
SwapRAndBComponents(gfx::DataSourceSurface* surf);
|
||||
|
||||
class GLReadTexImageHelper final
|
||||
{
|
||||
// The GLContext is the sole owner of the GLBlitHelper.
|
||||
|
@ -71,17 +65,12 @@ public:
|
|||
* passed as int to eliminate including LayerManagerOGLProgram.h here.
|
||||
*/
|
||||
already_AddRefed<gfx::DataSourceSurface> ReadTexImage(GLuint aTextureId,
|
||||
GLenum aTextureTarget,
|
||||
const gfx::IntSize& aSize,
|
||||
/* ShaderProgramType */ int aShaderProgram,
|
||||
bool aYInvert = false);
|
||||
GLenum aTextureTarget,
|
||||
const gfx::IntSize& aSize,
|
||||
/* ShaderProgramType */ int aShaderProgram,
|
||||
bool aYInvert = false);
|
||||
|
||||
|
||||
bool ReadTexImage(gfx::DataSourceSurface* aDest,
|
||||
GLuint aTextureId,
|
||||
GLenum aTextureTarget,
|
||||
const gfx::IntSize& aSize,
|
||||
int aShaderProgram,
|
||||
bool aYInvert = false);
|
||||
};
|
||||
|
||||
} // namespace gl
|
||||
|
|
|
@ -10,32 +10,18 @@
|
|||
#include "GLContext.h"
|
||||
#include "GLBlitHelper.h"
|
||||
#include "GLReadTexImageHelper.h"
|
||||
#include "SharedSurfaceEGL.h"
|
||||
#include "SharedSurfaceGL.h"
|
||||
#include "ScopedGLHelpers.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "../layers/ipc/ShadowLayers.h"
|
||||
#include "mozilla/layers/CompositableForwarder.h"
|
||||
#include "mozilla/layers/TextureClientSharedSurface.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "SharedSurfaceANGLE.h" // for SurfaceFactory_ANGLEShareHandle
|
||||
#include "gfxWindowsPlatform.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include "SharedSurfaceGralloc.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include "SharedSurfaceIO.h"
|
||||
#endif
|
||||
|
||||
#ifdef GL_PROVIDER_GLX
|
||||
#include "GLXLibrary.h"
|
||||
#include "SharedSurfaceGLX.h"
|
||||
#endif
|
||||
#include "ScopedGLHelpers.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "../layers/ipc/ShadowLayers.h"
|
||||
#include "mozilla/layers/TextureClientSharedSurface.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gl {
|
||||
|
@ -65,53 +51,6 @@ GLScreenBuffer::Create(GLContext* gl,
|
|||
return Move(ret);
|
||||
}
|
||||
|
||||
/* static */ UniquePtr<SurfaceFactory>
|
||||
GLScreenBuffer::CreateFactory(GLContext* gl,
|
||||
const SurfaceCaps& caps,
|
||||
const RefPtr<layers::CompositableForwarder>& forwarder,
|
||||
const layers::TextureFlags& flags)
|
||||
{
|
||||
UniquePtr<SurfaceFactory> factory = nullptr;
|
||||
if (!gfxPrefs::WebGLForceLayersReadback()) {
|
||||
switch (forwarder->GetCompositorBackendType()) {
|
||||
case mozilla::layers::LayersBackend::LAYERS_OPENGL: {
|
||||
#if defined(XP_MACOSX)
|
||||
factory = SurfaceFactory_IOSurface::Create(gl, caps, forwarder, flags);
|
||||
#elif defined(MOZ_WIDGET_GONK)
|
||||
factory = MakeUnique<SurfaceFactory_Gralloc>(gl, caps, forwarder, flags);
|
||||
#elif defined(GL_PROVIDER_GLX)
|
||||
if (sGLXLibrary.UseSurfaceSharing())
|
||||
factory = SurfaceFactory_GLXDrawable::Create(gl, caps, forwarder, flags);
|
||||
#else
|
||||
if (gl->GetContextType() == GLContextType::EGL) {
|
||||
if (XRE_IsParentProcess()) {
|
||||
factory = SurfaceFactory_EGLImage::Create(gl, caps, forwarder, flags);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case mozilla::layers::LayersBackend::LAYERS_D3D11: {
|
||||
#ifdef XP_WIN
|
||||
// Enable surface sharing only if ANGLE and compositing devices
|
||||
// are both WARP or both not WARP
|
||||
if (gl->IsANGLE() &&
|
||||
(gl->IsWARP() == gfxWindowsPlatform::GetPlatform()->IsWARP()) &&
|
||||
gfxWindowsPlatform::GetPlatform()->CompositorD3D11TextureSharingWorks())
|
||||
{
|
||||
factory = SurfaceFactory_ANGLEShareHandle::Create(gl, caps, forwarder, flags);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return factory;
|
||||
}
|
||||
|
||||
GLScreenBuffer::GLScreenBuffer(GLContext* gl,
|
||||
const SurfaceCaps& caps,
|
||||
UniquePtr<SurfaceFactory> factory)
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
class CompositableForwarder;
|
||||
class SharedSurfaceTextureClient;
|
||||
} // namespace layers
|
||||
|
||||
|
@ -134,12 +133,6 @@ public:
|
|||
const gfx::IntSize& size,
|
||||
const SurfaceCaps& caps);
|
||||
|
||||
static UniquePtr<SurfaceFactory>
|
||||
CreateFactory(GLContext* gl,
|
||||
const SurfaceCaps& caps,
|
||||
const RefPtr<layers::CompositableForwarder>& forwarder,
|
||||
const layers::TextureFlags& flags);
|
||||
|
||||
protected:
|
||||
GLContext* const mGL; // Owns us.
|
||||
public:
|
||||
|
|
|
@ -311,7 +311,6 @@ SurfaceFactory::SurfaceFactory(SharedSurfaceType type, GLContext* gl,
|
|||
, mAllocator(allocator)
|
||||
, mFlags(flags)
|
||||
, mFormats(gl->ChooseGLFormats(caps))
|
||||
, mMutex("SurfaceFactor::mMutex")
|
||||
{
|
||||
ChooseBufferBits(mCaps, &mDrawCaps, &mReadCaps);
|
||||
}
|
||||
|
@ -369,7 +368,6 @@ SurfaceFactory::StartRecycling(layers::SharedSurfaceTextureClient* tc)
|
|||
void
|
||||
SurfaceFactory::StopRecycling(layers::SharedSurfaceTextureClient* tc)
|
||||
{
|
||||
MutexAutoLock autoLock(mMutex);
|
||||
// Must clear before releasing ref.
|
||||
tc->ClearRecycleCallback();
|
||||
|
||||
|
@ -381,8 +379,11 @@ SurfaceFactory::StopRecycling(layers::SharedSurfaceTextureClient* tc)
|
|||
/*static*/ void
|
||||
SurfaceFactory::RecycleCallback(layers::TextureClient* rawTC, void* rawFactory)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
RefPtr<layers::SharedSurfaceTextureClient> tc;
|
||||
tc = static_cast<layers::SharedSurfaceTextureClient*>(rawTC);
|
||||
|
||||
SurfaceFactory* factory = static_cast<SurfaceFactory*>(rawFactory);
|
||||
|
||||
if (tc->mSurf->mCanRecycle) {
|
||||
|
@ -398,7 +399,6 @@ bool
|
|||
SurfaceFactory::Recycle(layers::SharedSurfaceTextureClient* texClient)
|
||||
{
|
||||
MOZ_ASSERT(texClient);
|
||||
MutexAutoLock autoLock(mMutex);
|
||||
|
||||
if (mRecycleFreePool.size() >= 2) {
|
||||
return false;
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/gfx/Point.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "ScopedGLHelpers.h"
|
||||
|
@ -34,7 +33,6 @@ class nsIThread;
|
|||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
class DataSourceSurface;
|
||||
class DrawTarget;
|
||||
} // namespace gfx
|
||||
|
||||
|
@ -201,10 +199,6 @@ public:
|
|||
}
|
||||
|
||||
virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) = 0;
|
||||
|
||||
virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
@ -304,7 +298,6 @@ public:
|
|||
const RefPtr<layers::ISurfaceAllocator> mAllocator;
|
||||
const layers::TextureFlags mFlags;
|
||||
const GLFormats mFormats;
|
||||
Mutex mMutex;
|
||||
protected:
|
||||
SurfaceCaps mDrawCaps;
|
||||
SurfaceCaps mReadCaps;
|
||||
|
|
|
@ -273,138 +273,6 @@ SharedSurface_ANGLEShareHandle::ToSurfaceDescriptor(layers::SurfaceDescriptor* c
|
|||
return true;
|
||||
}
|
||||
|
||||
class ScopedLockTexture final
|
||||
{
|
||||
public:
|
||||
explicit ScopedLockTexture(ID3D11Texture2D* texture, bool* succeeded)
|
||||
: mIsLocked(false)
|
||||
, mTexture(texture)
|
||||
{
|
||||
MOZ_ASSERT(mTexture);
|
||||
MOZ_ASSERT(succeeded);
|
||||
*succeeded = false;
|
||||
|
||||
HRESULT hr;
|
||||
mTexture->QueryInterface((IDXGIKeyedMutex**)byRef(mMutex));
|
||||
if (mMutex) {
|
||||
hr = mMutex->AcquireSync(0, 10000);
|
||||
if (hr == WAIT_TIMEOUT) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Failed to lock the texture");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ID3D11Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D11Device();
|
||||
device->GetImmediateContext(byRef(mDeviceContext));
|
||||
|
||||
mTexture->GetDesc(&mDesc);
|
||||
mDesc.BindFlags = 0;
|
||||
mDesc.Usage = D3D11_USAGE_STAGING;
|
||||
mDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
mDesc.MiscFlags = 0;
|
||||
|
||||
hr = device->CreateTexture2D(&mDesc, nullptr, byRef(mCopiedTexture));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mDeviceContext->CopyResource(mCopiedTexture, mTexture);
|
||||
|
||||
hr = mDeviceContext->Map(mCopiedTexture, 0, D3D11_MAP_READ, 0, &mSubresource);
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
*succeeded = true;
|
||||
mIsLocked = true;
|
||||
}
|
||||
|
||||
~ScopedLockTexture()
|
||||
{
|
||||
mDeviceContext->Unmap(mCopiedTexture, 0);
|
||||
if (mMutex) {
|
||||
HRESULT hr = mMutex->ReleaseSync(0);
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Failed to unlock the texture");
|
||||
}
|
||||
}
|
||||
mIsLocked = false;
|
||||
}
|
||||
|
||||
bool mIsLocked;
|
||||
RefPtr<ID3D11Texture2D> mTexture;
|
||||
RefPtr<ID3D11Texture2D> mCopiedTexture;
|
||||
RefPtr<IDXGIKeyedMutex> mMutex;
|
||||
RefPtr<ID3D11DeviceContext> mDeviceContext;
|
||||
D3D11_TEXTURE2D_DESC mDesc;
|
||||
D3D11_MAPPED_SUBRESOURCE mSubresource;
|
||||
};
|
||||
|
||||
bool
|
||||
SharedSurface_ANGLEShareHandle::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface)
|
||||
{
|
||||
MOZ_ASSERT(out_surface);
|
||||
RefPtr<ID3D11Texture2D> tex;
|
||||
ID3D11Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D11Device();
|
||||
HRESULT hr = device->OpenSharedResource(mShareHandle,
|
||||
__uuidof(ID3D11Texture2D),
|
||||
(void**)(ID3D11Texture2D**)byRef(tex));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool succeeded = false;
|
||||
ScopedLockTexture scopedLock(tex, &succeeded);
|
||||
if (!succeeded) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t* data = reinterpret_cast<uint8_t*>(scopedLock.mSubresource.pData);
|
||||
uint32_t srcStride = scopedLock.mSubresource.RowPitch;
|
||||
|
||||
gfx::DataSourceSurface::ScopedMap map(out_surface, gfx::DataSourceSurface::WRITE);
|
||||
if (!map.IsMapped()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (map.GetStride() == srcStride) {
|
||||
memcpy(map.GetData(), data, out_surface->GetSize().height * map.GetStride());
|
||||
} else {
|
||||
const uint8_t bytesPerPixel = BytesPerPixel(out_surface->GetFormat());
|
||||
for (int32_t i = 0; i < out_surface->GetSize().height; i++) {
|
||||
memcpy(map.GetData() + i * map.GetStride(),
|
||||
data + i * srcStride,
|
||||
bytesPerPixel * out_surface->GetSize().width);
|
||||
}
|
||||
}
|
||||
|
||||
DXGI_FORMAT srcFormat = scopedLock.mDesc.Format;
|
||||
MOZ_ASSERT(srcFormat == DXGI_FORMAT_B8G8R8A8_UNORM ||
|
||||
srcFormat == DXGI_FORMAT_B8G8R8X8_UNORM ||
|
||||
srcFormat == DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
bool isSrcRGB = srcFormat == DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
|
||||
gfx::SurfaceFormat destFormat = out_surface->GetFormat();
|
||||
MOZ_ASSERT(destFormat == gfx::SurfaceFormat::R8G8B8X8 ||
|
||||
destFormat == gfx::SurfaceFormat::R8G8B8A8 ||
|
||||
destFormat == gfx::SurfaceFormat::B8G8R8X8 ||
|
||||
destFormat == gfx::SurfaceFormat::B8G8R8A8);
|
||||
bool isDestRGB = destFormat == gfx::SurfaceFormat::R8G8B8X8 ||
|
||||
destFormat == gfx::SurfaceFormat::R8G8B8A8;
|
||||
|
||||
if (isSrcRGB != isDestRGB) {
|
||||
SwapRAndBComponents(out_surface);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Factory
|
||||
|
||||
|
|
|
@ -81,8 +81,6 @@ public:
|
|||
}
|
||||
|
||||
virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
|
||||
|
||||
virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) override;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "GLLibraryEGL.h"
|
||||
#include "GLReadTexImageHelper.h"
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
|
||||
#include "ScopedGLHelpers.h"
|
||||
#include "SharedSurface.h"
|
||||
#include "TextureGarbageBin.h"
|
||||
|
||||
|
@ -212,14 +213,6 @@ SharedSurface_EGLImage::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SharedSurface_EGLImage::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface)
|
||||
{
|
||||
MOZ_ASSERT(out_surface);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return sEGLLibrary.ReadbackEGLImage(mImage, out_surface);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*static*/ UniquePtr<SurfaceFactory_EGLImage>
|
||||
|
|
|
@ -79,8 +79,6 @@ public:
|
|||
void AcquireConsumerTexture(GLContext* consGL, GLuint* out_texture, GLuint* out_target);
|
||||
|
||||
virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
|
||||
|
||||
virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) override;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include "GLContextProvider.h"
|
||||
#include "GLContextGLX.h"
|
||||
#include "GLScreenBuffer.h"
|
||||
#include "mozilla/gfx/SourceSurfaceCairo.h"
|
||||
#include "mozilla/layers/LayersSurfaces.h"
|
||||
#include "mozilla/layers/ShadowLayerUtilsX11.h"
|
||||
#include "mozilla/layers/ISurfaceAllocator.h"
|
||||
|
@ -84,38 +83,6 @@ SharedSurface_GLXDrawable::ToSurfaceDescriptor(layers::SurfaceDescriptor* const
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SharedSurface_GLXDrawable::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface)
|
||||
{
|
||||
MOZ_ASSERT(out_surface);
|
||||
RefPtr<gfx::DataSourceSurface> dataSurf =
|
||||
new gfx::DataSourceSurfaceCairo(mXlibSurface->CairoSurface());
|
||||
|
||||
gfx::DataSourceSurface::ScopedMap mapSrc(dataSurf, gfx::DataSourceSurface::READ);
|
||||
if (!mapSrc.IsMapped()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gfx::DataSourceSurface::ScopedMap mapDest(out_surface, gfx::DataSourceSurface::WRITE);
|
||||
if (!mapDest.IsMapped()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mapDest.GetStride() == mapSrc.GetStride()) {
|
||||
memcpy(mapDest.GetData(),
|
||||
mapSrc.GetData(),
|
||||
out_surface->GetSize().height * mapDest.GetStride());
|
||||
} else {
|
||||
for (int32_t i = 0; i < dataSurf->GetSize().height; i++) {
|
||||
memcpy(mapDest.GetData() + i * mapDest.GetStride(),
|
||||
mapSrc.GetData() + i * mapSrc.GetStride(),
|
||||
std::min(mapSrc.GetStride(), mapDest.GetStride()));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
UniquePtr<SurfaceFactory_GLXDrawable>
|
||||
SurfaceFactory_GLXDrawable::Create(GLContext* prodGL,
|
||||
|
|
|
@ -32,8 +32,6 @@ public:
|
|||
virtual void UnlockProdImpl() override;
|
||||
|
||||
virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
|
||||
|
||||
virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) override;
|
||||
private:
|
||||
SharedSurface_GLXDrawable(GLContext* gl,
|
||||
const gfx::IntSize& size,
|
||||
|
|
|
@ -283,58 +283,5 @@ SharedSurface_Gralloc::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_
|
|||
return mTextureClient->ToSurfaceDescriptor(*out_descriptor);
|
||||
}
|
||||
|
||||
bool
|
||||
SharedSurface_Gralloc::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface)
|
||||
{
|
||||
MOZ_ASSERT(out_surface);
|
||||
sp<GraphicBuffer> buffer = mTextureClient->GetGraphicBuffer();
|
||||
|
||||
const uint8_t* grallocData = nullptr;
|
||||
auto result = buffer->lock(
|
||||
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
|
||||
const_cast<void**>(reinterpret_cast<const void**>(&grallocData))
|
||||
);
|
||||
|
||||
if (result == BAD_VALUE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gfx::DataSourceSurface::ScopedMap map(out_surface, gfx::DataSourceSurface::WRITE);
|
||||
if (!map.IsMapped()) {
|
||||
buffer->unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t stride = buffer->getStride() * android::bytesPerPixel(buffer->getPixelFormat());
|
||||
uint32_t height = buffer->getHeight();
|
||||
uint32_t width = buffer->getWidth();
|
||||
for (uint32_t i = 0; i < height; i++) {
|
||||
memcpy(map.GetData() + i * map.GetStride(),
|
||||
grallocData + i * stride, width * 4);
|
||||
}
|
||||
|
||||
buffer->unlock();
|
||||
|
||||
android::PixelFormat srcFormat = buffer->getPixelFormat();
|
||||
MOZ_ASSERT(srcFormat == PIXEL_FORMAT_RGBA_8888 ||
|
||||
srcFormat == PIXEL_FORMAT_BGRA_8888 ||
|
||||
srcFormat == PIXEL_FORMAT_RGBX_8888);
|
||||
bool isSrcRGB = srcFormat == PIXEL_FORMAT_RGBA_8888 ||
|
||||
srcFormat == PIXEL_FORMAT_RGBX_8888;
|
||||
|
||||
gfx::SurfaceFormat destFormat = out_surface->GetFormat();
|
||||
MOZ_ASSERT(destFormat == gfx::SurfaceFormat::R8G8B8X8 ||
|
||||
destFormat == gfx::SurfaceFormat::R8G8B8A8 ||
|
||||
destFormat == gfx::SurfaceFormat::B8G8R8X8 ||
|
||||
destFormat == gfx::SurfaceFormat::B8G8R8A8);
|
||||
bool isDestRGB = destFormat == gfx::SurfaceFormat::R8G8B8X8 ||
|
||||
destFormat == gfx::SurfaceFormat::R8G8B8A8;
|
||||
|
||||
if (isSrcRGB != isDestRGB) {
|
||||
SwapRAndBComponents(out_surface);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace gl
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -75,8 +75,6 @@ public:
|
|||
}
|
||||
|
||||
virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
|
||||
|
||||
virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) override;
|
||||
};
|
||||
|
||||
class SurfaceFactory_Gralloc
|
||||
|
|
|
@ -182,31 +182,6 @@ SharedSurface_IOSurface::ToSurfaceDescriptor(layers::SurfaceDescriptor* const ou
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SharedSurface_IOSurface::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface)
|
||||
{
|
||||
MOZ_ASSERT(out_surface);
|
||||
mIOSurf->Lock();
|
||||
size_t bytesPerRow = mIOSurf->GetBytesPerRow();
|
||||
size_t ioWidth = mIOSurf->GetDevicePixelWidth();
|
||||
size_t ioHeight = mIOSurf->GetDevicePixelHeight();
|
||||
|
||||
const unsigned char* ioData = (unsigned char*)mIOSurf->GetBaseAddress();
|
||||
gfx::DataSourceSurface::ScopedMap map(out_surface, gfx::DataSourceSurface::WRITE);
|
||||
if (!map.IsMapped()) {
|
||||
mIOSurf->Unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ioHeight; i++) {
|
||||
memcpy(map.GetData() + i * map.GetStride(),
|
||||
ioData + i * bytesPerRow, ioWidth * 4);
|
||||
}
|
||||
|
||||
mIOSurf->Unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// SurfaceFactory_IOSurface
|
||||
|
||||
|
|
|
@ -68,8 +68,6 @@ public:
|
|||
}
|
||||
|
||||
virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
|
||||
|
||||
virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) override;
|
||||
};
|
||||
|
||||
class SurfaceFactory_IOSurface : public SurfaceFactory
|
||||
|
|
|
@ -1,279 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "AsyncCanvasRenderer.h"
|
||||
|
||||
#include "gfxUtils.h"
|
||||
#include "GLContext.h"
|
||||
#include "GLReadTexImageHelper.h"
|
||||
#include "GLScreenBuffer.h"
|
||||
#include "mozilla/dom/HTMLCanvasElement.h"
|
||||
#include "mozilla/layers/CanvasClient.h"
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#include "mozilla/layers/TextureClientSharedSurface.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
AsyncCanvasRenderer::AsyncCanvasRenderer()
|
||||
: mHTMLCanvasElement(nullptr)
|
||||
, mContext(nullptr)
|
||||
, mGLContext(nullptr)
|
||||
, mIsAlphaPremultiplied(true)
|
||||
, mWidth(0)
|
||||
, mHeight(0)
|
||||
, mCanvasClientAsyncID(0)
|
||||
, mCanvasClient(nullptr)
|
||||
, mMutex("AsyncCanvasRenderer::mMutex")
|
||||
{
|
||||
MOZ_COUNT_CTOR(AsyncCanvasRenderer);
|
||||
}
|
||||
|
||||
AsyncCanvasRenderer::~AsyncCanvasRenderer()
|
||||
{
|
||||
MOZ_COUNT_DTOR(AsyncCanvasRenderer);
|
||||
}
|
||||
|
||||
void
|
||||
AsyncCanvasRenderer::NotifyElementAboutAttributesChanged()
|
||||
{
|
||||
class Runnable final : public nsRunnable
|
||||
{
|
||||
public:
|
||||
explicit Runnable(AsyncCanvasRenderer* aRenderer)
|
||||
: mRenderer(aRenderer)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
if (mRenderer) {
|
||||
dom::HTMLCanvasElement::SetAttrFromAsyncCanvasRenderer(mRenderer);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Revoke()
|
||||
{
|
||||
mRenderer = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<AsyncCanvasRenderer> mRenderer;
|
||||
};
|
||||
|
||||
nsRefPtr<nsRunnable> runnable = new Runnable(this);
|
||||
nsresult rv = NS_DispatchToMainThread(runnable);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to dispatch a runnable to the main-thread.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AsyncCanvasRenderer::NotifyElementAboutInvalidation()
|
||||
{
|
||||
class Runnable final : public nsRunnable
|
||||
{
|
||||
public:
|
||||
explicit Runnable(AsyncCanvasRenderer* aRenderer)
|
||||
: mRenderer(aRenderer)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
if (mRenderer) {
|
||||
dom::HTMLCanvasElement::InvalidateFromAsyncCanvasRenderer(mRenderer);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Revoke()
|
||||
{
|
||||
mRenderer = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<AsyncCanvasRenderer> mRenderer;
|
||||
};
|
||||
|
||||
nsRefPtr<nsRunnable> runnable = new Runnable(this);
|
||||
nsresult rv = NS_DispatchToMainThread(runnable);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to dispatch a runnable to the main-thread.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AsyncCanvasRenderer::SetCanvasClient(CanvasClient* aClient)
|
||||
{
|
||||
mCanvasClient = aClient;
|
||||
if (aClient) {
|
||||
mCanvasClientAsyncID = aClient->GetAsyncID();
|
||||
} else {
|
||||
mCanvasClientAsyncID = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AsyncCanvasRenderer::SetActiveThread()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mActiveThread = NS_GetCurrentThread();
|
||||
}
|
||||
|
||||
void
|
||||
AsyncCanvasRenderer::ResetActiveThread()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mActiveThread = nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIThread>
|
||||
AsyncCanvasRenderer::GetActiveThread()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
nsCOMPtr<nsIThread> result = mActiveThread;
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
void
|
||||
AsyncCanvasRenderer::CopyFromTextureClient(TextureClient* aTextureClient)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
RefPtr<BufferTextureClient> buffer = static_cast<BufferTextureClient*>(aTextureClient);
|
||||
if (!buffer->Lock(layers::OpenMode::OPEN_READ)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const gfx::IntSize& size = aTextureClient->GetSize();
|
||||
// This buffer would be used later for content rendering. So we choose
|
||||
// B8G8R8A8 format here.
|
||||
const gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8;
|
||||
// Avoid to create buffer every time.
|
||||
if (!mSurfaceForBasic ||
|
||||
size != mSurfaceForBasic->GetSize() ||
|
||||
format != mSurfaceForBasic->GetFormat())
|
||||
{
|
||||
uint32_t stride = gfx::GetAlignedStride<8>(size.width * BytesPerPixel(format));
|
||||
mSurfaceForBasic = gfx::Factory::CreateDataSourceSurfaceWithStride(size, format, stride);
|
||||
}
|
||||
|
||||
const uint8_t* lockedBytes = buffer->GetLockedData();
|
||||
gfx::DataSourceSurface::ScopedMap map(mSurfaceForBasic,
|
||||
gfx::DataSourceSurface::MapType::WRITE);
|
||||
if (!map.IsMapped()) {
|
||||
buffer->Unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(map.GetData(), lockedBytes, map.GetStride() * mSurfaceForBasic->GetSize().height);
|
||||
buffer->Unlock();
|
||||
|
||||
if (mSurfaceForBasic->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 ||
|
||||
mSurfaceForBasic->GetFormat() == gfx::SurfaceFormat::R8G8B8X8) {
|
||||
gl::SwapRAndBComponents(mSurfaceForBasic);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::DataSourceSurface>
|
||||
AsyncCanvasRenderer::UpdateTarget()
|
||||
{
|
||||
if (!mGLContext) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gl::SharedSurface* frontbuffer = nullptr;
|
||||
gl::GLScreenBuffer* screen = mGLContext->Screen();
|
||||
const auto& front = screen->Front();
|
||||
if (front) {
|
||||
frontbuffer = front->Surf();
|
||||
}
|
||||
|
||||
if (!frontbuffer) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (frontbuffer->mType == gl::SharedSurfaceType::Basic) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const gfx::IntSize& size = frontbuffer->mSize;
|
||||
// This buffer would be used later for content rendering. So we choose
|
||||
// B8G8R8A8 format here.
|
||||
const gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8;
|
||||
uint32_t stride = gfx::GetAlignedStride<8>(size.width * BytesPerPixel(format));
|
||||
RefPtr<gfx::DataSourceSurface> surface =
|
||||
gfx::Factory::CreateDataSourceSurfaceWithStride(size, format, stride);
|
||||
|
||||
|
||||
if (NS_WARN_IF(!surface)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!frontbuffer->ReadbackBySharedHandle(surface)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied;
|
||||
if (needsPremult) {
|
||||
gfxUtils::PremultiplyDataSurface(surface, surface);
|
||||
}
|
||||
|
||||
return surface.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::DataSourceSurface>
|
||||
AsyncCanvasRenderer::GetSurface()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (mSurfaceForBasic) {
|
||||
// Since SourceSurface isn't thread-safe, we need copy to a new SourceSurface.
|
||||
RefPtr<gfx::DataSourceSurface> result =
|
||||
gfx::Factory::CreateDataSourceSurfaceWithStride(mSurfaceForBasic->GetSize(),
|
||||
mSurfaceForBasic->GetFormat(),
|
||||
mSurfaceForBasic->Stride());
|
||||
|
||||
gfx::DataSourceSurface::ScopedMap srcMap(mSurfaceForBasic, gfx::DataSourceSurface::READ);
|
||||
gfx::DataSourceSurface::ScopedMap dstMap(result, gfx::DataSourceSurface::WRITE);
|
||||
|
||||
if (NS_WARN_IF(!srcMap.IsMapped()) ||
|
||||
NS_WARN_IF(!dstMap.IsMapped())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
memcpy(dstMap.GetData(),
|
||||
srcMap.GetData(),
|
||||
srcMap.GetStride() * mSurfaceForBasic->GetSize().height);
|
||||
return result.forget();
|
||||
} else {
|
||||
return UpdateTarget();
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
AsyncCanvasRenderer::GetInputStream(const char *aMimeType,
|
||||
const char16_t *aEncoderOptions,
|
||||
nsIInputStream **aStream)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
RefPtr<gfx::DataSourceSurface> surface = GetSurface();
|
||||
if (!surface) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Handle y flip.
|
||||
RefPtr<gfx::DataSourceSurface> dataSurf = gl::YInvertImageSurface(surface);
|
||||
|
||||
return gfxUtils::GetInputStream(dataSurf, false, aMimeType, aEncoderOptions, aStream);
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
|
@ -1,169 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_
|
||||
#define MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_
|
||||
|
||||
#include "LayersTypes.h"
|
||||
#include "mozilla/gfx/Point.h" // for IntSize
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/RefPtr.h" // for nsAutoPtr, nsRefPtr, etc
|
||||
#include "nsCOMPtr.h" // for nsCOMPtr
|
||||
|
||||
class nsICanvasRenderingContextInternal;
|
||||
class nsIInputStream;
|
||||
class nsIThread;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace gfx {
|
||||
class DataSourceSurface;
|
||||
}
|
||||
|
||||
namespace gl {
|
||||
class GLContext;
|
||||
}
|
||||
|
||||
namespace dom {
|
||||
class HTMLCanvasElement;
|
||||
}
|
||||
|
||||
namespace layers {
|
||||
|
||||
class CanvasClient;
|
||||
class TextureClient;
|
||||
|
||||
/**
|
||||
* Since HTMLCanvasElement and OffscreenCanvas are not thread-safe, we create
|
||||
* AsyncCanvasRenderer which is thread-safe wrapper object for communicating
|
||||
* among main, worker and ImageBridgeChild threads.
|
||||
*
|
||||
* Each HTMLCanvasElement object is responsible for creating
|
||||
* AsyncCanvasRenderer object. Once Canvas is transfered to worker,
|
||||
* OffscreenCanvas will keep reference pointer of this object.
|
||||
*
|
||||
* Sometimes main thread needs AsyncCanvasRenderer's result, such as layers
|
||||
* fallback to BasicLayerManager or calling toDataURL in Javascript. Simply call
|
||||
* GetSurface() in main thread will readback the result to mSurface.
|
||||
*
|
||||
* If layers backend is LAYERS_CLIENT, this object will pass to ImageBridgeChild
|
||||
* for submitting frames to Compositor.
|
||||
*/
|
||||
class AsyncCanvasRenderer final
|
||||
{
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncCanvasRenderer)
|
||||
|
||||
public:
|
||||
AsyncCanvasRenderer();
|
||||
|
||||
void NotifyElementAboutAttributesChanged();
|
||||
void NotifyElementAboutInvalidation();
|
||||
|
||||
void SetCanvasClient(CanvasClient* aClient);
|
||||
|
||||
void SetWidth(uint32_t aWidth)
|
||||
{
|
||||
mWidth = aWidth;
|
||||
}
|
||||
|
||||
void SetHeight(uint32_t aHeight)
|
||||
{
|
||||
mHeight = aHeight;
|
||||
}
|
||||
|
||||
void SetIsAlphaPremultiplied(bool aIsAlphaPremultiplied)
|
||||
{
|
||||
mIsAlphaPremultiplied = aIsAlphaPremultiplied;
|
||||
}
|
||||
|
||||
// Active thread means the thread which spawns GLContext.
|
||||
void SetActiveThread();
|
||||
void ResetActiveThread();
|
||||
|
||||
// This will readback surface and return the surface
|
||||
// in the DataSourceSurface.
|
||||
// Can be called in main thread only.
|
||||
already_AddRefed<gfx::DataSourceSurface> GetSurface();
|
||||
|
||||
// For SharedSurface_Basic case, before the frame sending to the compositor,
|
||||
// we readback it to a texture client because SharedSurface_Basic cannot shared.
|
||||
// We don't want to readback it again here, so just copy the content of that
|
||||
// texture client here to avoid readback again.
|
||||
void CopyFromTextureClient(TextureClient *aClient);
|
||||
|
||||
// Readback current WebGL's content and convert it to InputStream. This
|
||||
// function called GetSurface implicitly and GetSurface handles only get
|
||||
// called in the main thread. So this function can be called in main thread.
|
||||
nsresult
|
||||
GetInputStream(const char *aMimeType,
|
||||
const char16_t *aEncoderOptions,
|
||||
nsIInputStream **aStream);
|
||||
|
||||
gfx::IntSize GetSize() const
|
||||
{
|
||||
return gfx::IntSize(mWidth, mHeight);
|
||||
}
|
||||
|
||||
uint64_t GetCanvasClientAsyncID() const
|
||||
{
|
||||
return mCanvasClientAsyncID;
|
||||
}
|
||||
|
||||
CanvasClient* GetCanvasClient() const
|
||||
{
|
||||
return mCanvasClient;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIThread> GetActiveThread();
|
||||
|
||||
// The lifetime is controllered by HTMLCanvasElement.
|
||||
// Only accessed in main thread.
|
||||
dom::HTMLCanvasElement* mHTMLCanvasElement;
|
||||
|
||||
// Only accessed in active thread.
|
||||
nsICanvasRenderingContextInternal* mContext;
|
||||
|
||||
// We need to keep a reference to the context around here, otherwise the
|
||||
// canvas' surface texture destructor will deref and destroy it too early
|
||||
// Only accessed in active thread.
|
||||
RefPtr<gl::GLContext> mGLContext;
|
||||
private:
|
||||
|
||||
virtual ~AsyncCanvasRenderer();
|
||||
|
||||
// Readback current WebGL's content and return it as DataSourceSurface.
|
||||
already_AddRefed<gfx::DataSourceSurface> UpdateTarget();
|
||||
|
||||
bool mIsAlphaPremultiplied;
|
||||
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
uint64_t mCanvasClientAsyncID;
|
||||
|
||||
// The lifetime of this pointer is controlled by OffscreenCanvas
|
||||
// Can be accessed in active thread and ImageBridge thread.
|
||||
// But we never accessed it at the same time on both thread. So no
|
||||
// need to protect this member.
|
||||
CanvasClient* mCanvasClient;
|
||||
|
||||
// When backend is LAYER_BASIC and SharedSurface type is Basic.
|
||||
// CanvasClient will readback the GLContext to a TextureClient
|
||||
// in order to send frame to compositor. To avoid readback again,
|
||||
// we copy from this TextureClient to this mSurfaceForBasic directly
|
||||
// by calling CopyFromTextureClient().
|
||||
RefPtr<gfx::DataSourceSurface> mSurfaceForBasic;
|
||||
|
||||
// Protect non thread-safe objects.
|
||||
Mutex mMutex;
|
||||
|
||||
// Can be accessed in any thread, need protect by mutex.
|
||||
nsCOMPtr<nsIThread> mActiveThread;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_
|
|
@ -64,9 +64,6 @@ CopyableCanvasLayer::Initialize(const Data& aData)
|
|||
}
|
||||
} else if (aData.mBufferProvider) {
|
||||
mBufferProvider = aData.mBufferProvider;
|
||||
} else if (aData.mRenderer) {
|
||||
mAsyncRenderer = aData.mRenderer;
|
||||
mOriginPos = gl::OriginPos::BottomLeft;
|
||||
} else {
|
||||
MOZ_CRASH("CanvasLayer created without mSurface, mDrawTarget or mGLContext?");
|
||||
}
|
||||
|
@ -83,9 +80,7 @@ CopyableCanvasLayer::IsDataValid(const Data& aData)
|
|||
void
|
||||
CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget)
|
||||
{
|
||||
if (mAsyncRenderer) {
|
||||
mSurface = mAsyncRenderer->GetSurface();
|
||||
} else if (mBufferProvider) {
|
||||
if (mBufferProvider) {
|
||||
mSurface = mBufferProvider->GetSnapshot();
|
||||
}
|
||||
|
||||
|
@ -100,7 +95,7 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget)
|
|||
return;
|
||||
}
|
||||
|
||||
if (mBufferProvider || mAsyncRenderer) {
|
||||
if (mBufferProvider) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -385,7 +385,7 @@ struct ColorLayerProperties : public LayerPropertiesBase
|
|||
IntRect mBounds;
|
||||
};
|
||||
|
||||
static ImageHost* GetImageHost(Layer* aLayer)
|
||||
static ImageHost* GetImageHost(ImageLayer* aLayer)
|
||||
{
|
||||
LayerComposite* composite = aLayer->AsLayerComposite();
|
||||
if (composite) {
|
||||
|
@ -465,34 +465,6 @@ struct ImageLayerProperties : public LayerPropertiesBase
|
|||
bool mIsMask;
|
||||
};
|
||||
|
||||
struct CanvasLayerProperties : public LayerPropertiesBase
|
||||
{
|
||||
explicit CanvasLayerProperties(CanvasLayer* aCanvas)
|
||||
: LayerPropertiesBase(aCanvas)
|
||||
, mImageHost(GetImageHost(aCanvas))
|
||||
{
|
||||
mFrameID = mImageHost ? mImageHost->GetFrameID() : -1;
|
||||
}
|
||||
|
||||
virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback,
|
||||
bool& aGeometryChanged)
|
||||
{
|
||||
CanvasLayer* canvasLayer = static_cast<CanvasLayer*>(mLayer.get());
|
||||
|
||||
ImageHost* host = GetImageHost(canvasLayer);
|
||||
if (host && host->GetFrameID() != mFrameID) {
|
||||
aGeometryChanged = true;
|
||||
|
||||
return NewTransformedBounds();
|
||||
}
|
||||
|
||||
return IntRect();
|
||||
}
|
||||
|
||||
nsRefPtr<ImageHost> mImageHost;
|
||||
int32_t mFrameID;
|
||||
};
|
||||
|
||||
UniquePtr<LayerPropertiesBase>
|
||||
CloneLayerTreePropertiesInternal(Layer* aRoot, bool aIsMask /* = false */)
|
||||
{
|
||||
|
@ -511,7 +483,6 @@ CloneLayerTreePropertiesInternal(Layer* aRoot, bool aIsMask /* = false */)
|
|||
case Layer::TYPE_IMAGE:
|
||||
return MakeUnique<ImageLayerProperties>(static_cast<ImageLayer*>(aRoot), aIsMask);
|
||||
case Layer::TYPE_CANVAS:
|
||||
return MakeUnique<CanvasLayerProperties>(static_cast<CanvasLayer*>(aRoot));
|
||||
case Layer::TYPE_READBACK:
|
||||
case Layer::TYPE_SHADOW:
|
||||
case Layer::TYPE_PAINTED:
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include "mozilla/gfx/2D.h" // for DrawTarget
|
||||
#include "mozilla/gfx/BaseSize.h" // for BaseSize
|
||||
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
|
||||
#include "mozilla/layers/AsyncCanvasRenderer.h"
|
||||
#include "mozilla/layers/CompositableClient.h" // for CompositableClient
|
||||
#include "mozilla/layers/Compositor.h" // for Compositor
|
||||
#include "mozilla/layers/CompositorTypes.h"
|
||||
|
@ -2129,19 +2128,6 @@ ColorLayer::DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent)
|
|||
layer->set_color(mColor.ToABGR());
|
||||
}
|
||||
|
||||
CanvasLayer::CanvasLayer(LayerManager* aManager, void* aImplData)
|
||||
: Layer(aManager, aImplData)
|
||||
, mPreTransCallback(nullptr)
|
||||
, mPreTransCallbackData(nullptr)
|
||||
, mPostTransCallback(nullptr)
|
||||
, mPostTransCallbackData(nullptr)
|
||||
, mFilter(GraphicsFilter::FILTER_GOOD)
|
||||
, mDirty(false)
|
||||
{}
|
||||
|
||||
CanvasLayer::~CanvasLayer()
|
||||
{}
|
||||
|
||||
void
|
||||
CanvasLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
||||
{
|
||||
|
|
|
@ -74,7 +74,6 @@ namespace layers {
|
|||
|
||||
class Animation;
|
||||
class AnimationData;
|
||||
class AsyncCanvasRenderer;
|
||||
class AsyncPanZoomController;
|
||||
class ClientLayerManager;
|
||||
class Layer;
|
||||
|
@ -2274,17 +2273,15 @@ public:
|
|||
Data()
|
||||
: mBufferProvider(nullptr)
|
||||
, mGLContext(nullptr)
|
||||
, mRenderer(nullptr)
|
||||
, mFrontbufferGLTex(0)
|
||||
, mSize(0,0)
|
||||
, mHasAlpha(false)
|
||||
, mIsGLAlphaPremult(true)
|
||||
{ }
|
||||
|
||||
// One of these three must be specified for Canvas2D, but never more than one
|
||||
// One of these two must be specified for Canvas2D, but never both
|
||||
PersistentBufferProvider* mBufferProvider; // A BufferProvider for the Canvas contents
|
||||
mozilla::gl::GLContext* mGLContext; // or this, for GL.
|
||||
AsyncCanvasRenderer* mRenderer; // or this, for OffscreenCanvas
|
||||
|
||||
// Frontbuffer override
|
||||
uint32_t mFrontbufferGLTex;
|
||||
|
@ -2400,14 +2397,16 @@ public:
|
|||
ComputeEffectiveTransformForMaskLayers(aTransformToSurface);
|
||||
}
|
||||
|
||||
bool GetIsAsyncRenderer() const
|
||||
{
|
||||
return !!mAsyncRenderer;
|
||||
}
|
||||
|
||||
protected:
|
||||
CanvasLayer(LayerManager* aManager, void* aImplData);
|
||||
virtual ~CanvasLayer();
|
||||
CanvasLayer(LayerManager* aManager, void* aImplData)
|
||||
: Layer(aManager, aImplData)
|
||||
, mPreTransCallback(nullptr)
|
||||
, mPreTransCallbackData(nullptr)
|
||||
, mPostTransCallback(nullptr)
|
||||
, mPostTransCallbackData(nullptr)
|
||||
, mFilter(GraphicsFilter::FILTER_GOOD)
|
||||
, mDirty(false)
|
||||
{}
|
||||
|
||||
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
|
||||
|
||||
|
@ -2429,7 +2428,6 @@ protected:
|
|||
DidTransactionCallback mPostTransCallback;
|
||||
void* mPostTransCallbackData;
|
||||
GraphicsFilter mFilter;
|
||||
nsRefPtr<AsyncCanvasRenderer> mAsyncRenderer;
|
||||
|
||||
private:
|
||||
/**
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "BasicCanvasLayer.h"
|
||||
#include "AsyncCanvasRenderer.h"
|
||||
#include "basic/BasicLayers.h" // for BasicLayerManager
|
||||
#include "basic/BasicLayersImpl.h" // for GetEffectiveOperator
|
||||
#include "mozilla/mozalloc.h" // for operator new
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "gfxPlatform.h" // for gfxPlatform
|
||||
#include "GLReadTexImageHelper.h"
|
||||
#include "mozilla/gfx/BaseSize.h" // for BaseSize
|
||||
#include "mozilla/layers/AsyncCanvasRenderer.h"
|
||||
#include "mozilla/layers/CompositableForwarder.h"
|
||||
#include "mozilla/layers/CompositorChild.h" // for CompositorChild
|
||||
#include "mozilla/layers/GrallocTextureClient.h"
|
||||
|
@ -39,32 +38,14 @@ CanvasClient::CreateCanvasClient(CanvasClientType aType,
|
|||
switch (aType) {
|
||||
case CanvasClientTypeShSurf:
|
||||
return MakeAndAddRef<CanvasClientSharedSurface>(aForwarder, aFlags);
|
||||
case CanvasClientAsync:
|
||||
return MakeAndAddRef<CanvasClientBridge>(aForwarder, aFlags);
|
||||
break;
|
||||
|
||||
default:
|
||||
return MakeAndAddRef<CanvasClient2D>(aForwarder, aFlags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CanvasClientBridge::UpdateAsync(AsyncCanvasRenderer* aRenderer)
|
||||
{
|
||||
if (!GetForwarder() || !mLayer || !aRenderer ||
|
||||
!aRenderer->GetCanvasClient()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t asyncID = aRenderer->GetCanvasClientAsyncID();
|
||||
if (asyncID == 0 || mAsyncID == asyncID) {
|
||||
return;
|
||||
}
|
||||
|
||||
static_cast<ShadowLayerForwarder*>(GetForwarder())
|
||||
->AttachAsyncCompositable(asyncID, mLayer);
|
||||
mAsyncID = asyncID;
|
||||
}
|
||||
|
||||
void
|
||||
CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
|
||||
{
|
||||
|
@ -125,7 +106,6 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
|
|||
CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
|
||||
t->mTextureClient = mBuffer;
|
||||
t->mPictureRect = nsIntRect(nsIntPoint(0, 0), mBuffer->GetSize());
|
||||
t->mFrameID = mFrameID;
|
||||
GetForwarder()->UseTextures(this, textures);
|
||||
mBuffer->SyncWithObject(GetForwarder()->GetSyncObject());
|
||||
}
|
||||
|
@ -341,38 +321,13 @@ CloneSurface(gl::SharedSurface* src, gl::SurfaceFactory* factory)
|
|||
void
|
||||
CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
|
||||
{
|
||||
Renderer renderer;
|
||||
renderer.construct<ClientCanvasLayer*>(aLayer);
|
||||
UpdateRenderer(aSize, renderer);
|
||||
}
|
||||
|
||||
void
|
||||
CanvasClientSharedSurface::UpdateAsync(AsyncCanvasRenderer* aRenderer)
|
||||
{
|
||||
Renderer renderer;
|
||||
renderer.construct<AsyncCanvasRenderer*>(aRenderer);
|
||||
UpdateRenderer(aRenderer->GetSize(), renderer);
|
||||
}
|
||||
|
||||
void
|
||||
CanvasClientSharedSurface::UpdateRenderer(gfx::IntSize aSize, Renderer& aRenderer)
|
||||
{
|
||||
GLContext* gl = nullptr;
|
||||
ClientCanvasLayer* layer = nullptr;
|
||||
AsyncCanvasRenderer* asyncRenderer = nullptr;
|
||||
if (aRenderer.constructed<ClientCanvasLayer*>()) {
|
||||
layer = aRenderer.ref<ClientCanvasLayer*>();
|
||||
gl = layer->mGLContext;
|
||||
} else {
|
||||
asyncRenderer = aRenderer.ref<AsyncCanvasRenderer*>();
|
||||
gl = asyncRenderer->mGLContext;
|
||||
}
|
||||
auto gl = aLayer->mGLContext;
|
||||
gl->MakeCurrent();
|
||||
|
||||
RefPtr<TextureClient> newFront;
|
||||
|
||||
if (layer && layer->mGLFrontbuffer) {
|
||||
mShSurfClient = CloneSurface(layer->mGLFrontbuffer.get(), layer->mFactory.get());
|
||||
if (aLayer->mGLFrontbuffer) {
|
||||
mShSurfClient = CloneSurface(aLayer->mGLFrontbuffer.get(), aLayer->mFactory.get());
|
||||
if (!mShSurfClient) {
|
||||
gfxCriticalError() << "Invalid canvas front buffer";
|
||||
return;
|
||||
|
@ -396,30 +351,14 @@ CanvasClientSharedSurface::UpdateRenderer(gfx::IntSize aSize, Renderer& aRendere
|
|||
|
||||
bool needsReadback = (surf->mType == SharedSurfaceType::Basic);
|
||||
if (needsReadback) {
|
||||
TextureFlags flags = TextureFlags::IMMUTABLE;
|
||||
|
||||
CompositableForwarder* shadowForwarder = nullptr;
|
||||
if (layer) {
|
||||
flags |= layer->Flags();
|
||||
shadowForwarder = layer->ClientManager()->AsShadowForwarder();
|
||||
} else {
|
||||
MOZ_ASSERT(asyncRenderer);
|
||||
flags |= mTextureFlags;
|
||||
shadowForwarder = GetForwarder();
|
||||
}
|
||||
TextureFlags flags = aLayer->Flags() |
|
||||
TextureFlags::IMMUTABLE;
|
||||
|
||||
auto manager = aLayer->ClientManager();
|
||||
auto shadowForwarder = manager->AsShadowForwarder();
|
||||
auto layersBackend = shadowForwarder->GetCompositorBackendType();
|
||||
mReadbackClient = TexClientFromReadback(surf, forwarder, flags, layersBackend);
|
||||
|
||||
if (asyncRenderer) {
|
||||
// Above codes will readback the GLContext to mReadbackClient
|
||||
// in order to send frame to compositor. We copy from this
|
||||
// TextureClient directly by calling CopyFromTextureClient().
|
||||
// Therefore, if main-thread want the content of GLContext,
|
||||
// it don't have to readback it again.
|
||||
asyncRenderer->CopyFromTextureClient(mReadbackClient);
|
||||
}
|
||||
|
||||
newFront = mReadbackClient;
|
||||
} else {
|
||||
mReadbackClient = nullptr;
|
||||
|
@ -432,14 +371,6 @@ CanvasClientSharedSurface::UpdateRenderer(gfx::IntSize aSize, Renderer& aRendere
|
|||
return;
|
||||
}
|
||||
|
||||
mNewFront = newFront;
|
||||
}
|
||||
|
||||
void
|
||||
CanvasClientSharedSurface::Updated()
|
||||
{
|
||||
auto forwarder = GetForwarder();
|
||||
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
if (mFront) {
|
||||
if (mFront->GetFlags() & TextureFlags::RECYCLE) {
|
||||
|
@ -454,13 +385,12 @@ CanvasClientSharedSurface::Updated()
|
|||
// - Call RemoveTexture() after newFront's UseTextures() call.
|
||||
// It could improve performance of Host side's EGL handling on gonk
|
||||
AutoRemoveTexture autoRemove(this);
|
||||
if (mFront && mFront != mNewFront) {
|
||||
if (mFront && mFront != newFront) {
|
||||
autoRemove.mTexture = mFront;
|
||||
}
|
||||
#endif
|
||||
|
||||
mFront = mNewFront;
|
||||
mNewFront = nullptr;
|
||||
mFront = newFront;
|
||||
|
||||
// Add the new TexClient.
|
||||
MOZ_ALWAYS_TRUE( AddTextureClient(mFront) );
|
||||
|
@ -469,7 +399,6 @@ CanvasClientSharedSurface::Updated()
|
|||
CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
|
||||
t->mTextureClient = mFront;
|
||||
t->mPictureRect = nsIntRect(nsIntPoint(0, 0), mFront->GetSize());
|
||||
t->mFrameID = mFrameID;
|
||||
forwarder->UseTextures(this, textures);
|
||||
}
|
||||
|
||||
|
@ -477,7 +406,6 @@ void
|
|||
CanvasClientSharedSurface::ClearSurfaces()
|
||||
{
|
||||
mFront = nullptr;
|
||||
mNewFront = nullptr;
|
||||
mShSurfClient = nullptr;
|
||||
mReadbackClient = nullptr;
|
||||
}
|
||||
|
|
|
@ -13,11 +13,6 @@
|
|||
#include "mozilla/layers/CompositorTypes.h" // for TextureInfo, etc
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
|
||||
#include "mozilla/layers/TextureClient.h" // for TextureClient, etc
|
||||
|
||||
// Fix X11 header brain damage that conflicts with MaybeOneOf::None
|
||||
#undef None
|
||||
#include "mozilla/MaybeOneOf.h"
|
||||
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
|
||||
#include "mozilla/gfx/Point.h" // for IntSize
|
||||
|
@ -26,10 +21,8 @@
|
|||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class AsyncCanvasRenderer;
|
||||
class ClientCanvasLayer;
|
||||
class CompositableForwarder;
|
||||
class ShadowableLayer;
|
||||
class SharedSurfaceTextureClient;
|
||||
|
||||
/**
|
||||
|
@ -38,8 +31,6 @@ class SharedSurfaceTextureClient;
|
|||
class CanvasClient : public CompositableClient
|
||||
{
|
||||
public:
|
||||
typedef MaybeOneOf<ClientCanvasLayer*, AsyncCanvasRenderer*> Renderer;
|
||||
|
||||
/**
|
||||
* Creates, configures, and returns a new canvas client. If necessary, a
|
||||
* message will be sent to the compositor to create a corresponding image
|
||||
|
@ -49,7 +40,6 @@ public:
|
|||
CanvasClientSurface,
|
||||
CanvasClientGLContext,
|
||||
CanvasClientTypeShSurf,
|
||||
CanvasClientAsync, // webgl on workers
|
||||
};
|
||||
static already_AddRefed<CanvasClient> CreateCanvasClient(CanvasClientType aType,
|
||||
CompositableForwarder* aFwd,
|
||||
|
@ -57,7 +47,6 @@ public:
|
|||
|
||||
CanvasClient(CompositableForwarder* aFwd, TextureFlags aFlags)
|
||||
: CompositableClient(aFwd, aFlags)
|
||||
, mFrameID(0)
|
||||
{
|
||||
mTextureFlags = aFlags;
|
||||
}
|
||||
|
@ -68,18 +57,7 @@ public:
|
|||
|
||||
virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) = 0;
|
||||
|
||||
virtual bool AddTextureClient(TextureClient* aTexture) override
|
||||
{
|
||||
++mFrameID;
|
||||
return CompositableClient::AddTextureClient(aTexture);
|
||||
}
|
||||
|
||||
virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) {}
|
||||
|
||||
virtual void Updated() { }
|
||||
|
||||
protected:
|
||||
int32_t mFrameID;
|
||||
};
|
||||
|
||||
// Used for 2D canvases and WebGL canvas on non-GL systems where readback is requried.
|
||||
|
@ -107,7 +85,7 @@ public:
|
|||
virtual bool AddTextureClient(TextureClient* aTexture) override
|
||||
{
|
||||
MOZ_ASSERT((mTextureFlags & aTexture->GetFlags()) == mTextureFlags);
|
||||
return CanvasClient::AddTextureClient(aTexture);
|
||||
return CompositableClient::AddTextureClient(aTexture);
|
||||
}
|
||||
|
||||
virtual void OnDetach() override
|
||||
|
@ -133,7 +111,6 @@ private:
|
|||
RefPtr<SharedSurfaceTextureClient> mShSurfClient;
|
||||
RefPtr<TextureClient> mReadbackClient;
|
||||
RefPtr<TextureClient> mFront;
|
||||
RefPtr<TextureClient> mNewFront;
|
||||
|
||||
void ClearSurfaces();
|
||||
|
||||
|
@ -153,54 +130,12 @@ public:
|
|||
|
||||
virtual void Update(gfx::IntSize aSize,
|
||||
ClientCanvasLayer* aLayer) override;
|
||||
void UpdateRenderer(gfx::IntSize aSize, Renderer& aRenderer);
|
||||
|
||||
virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) override;
|
||||
|
||||
virtual void Updated() override;
|
||||
|
||||
virtual void OnDetach() override {
|
||||
ClearSurfaces();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used for OMT<canvas> uploads using the image bridge protocol.
|
||||
* Actual CanvasClient is on the ImageBridgeChild thread, so we
|
||||
* only forward its AsyncID here
|
||||
*/
|
||||
class CanvasClientBridge final : public CanvasClient
|
||||
{
|
||||
public:
|
||||
CanvasClientBridge(CompositableForwarder* aLayerForwarder,
|
||||
TextureFlags aFlags)
|
||||
: CanvasClient(aLayerForwarder, aFlags)
|
||||
, mAsyncID(0)
|
||||
, mLayer(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
TextureInfo GetTextureInfo() const override
|
||||
{
|
||||
return TextureInfo(CompositableType::IMAGE);
|
||||
}
|
||||
|
||||
virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) override
|
||||
{
|
||||
}
|
||||
|
||||
virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) override;
|
||||
|
||||
void SetLayer(ShadowableLayer* aLayer)
|
||||
{
|
||||
mLayer = aLayer;
|
||||
}
|
||||
|
||||
protected:
|
||||
uint64_t mAsyncID;
|
||||
ShadowableLayer* mLayer;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include "SharedSurfaceGL.h" // for SurfaceFactory_GLTexture, etc
|
||||
#include "ClientLayerManager.h" // for ClientLayerManager, etc
|
||||
#include "mozilla/gfx/Point.h" // for IntSize
|
||||
#include "mozilla/layers/AsyncCanvasRenderer.h"
|
||||
#include "mozilla/layers/CompositorTypes.h"
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
|
@ -20,6 +19,24 @@
|
|||
#include "nsXULAppAPI.h" // for XRE_GetProcessType, etc
|
||||
#include "gfxPrefs.h" // for WebGLForceLayersReadback
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "SharedSurfaceANGLE.h" // for SurfaceFactory_ANGLEShareHandle
|
||||
#include "gfxWindowsPlatform.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include "SharedSurfaceGralloc.h"
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include "SharedSurfaceIO.h"
|
||||
#endif
|
||||
|
||||
#ifdef GL_PROVIDER_GLX
|
||||
#include "GLXLibrary.h"
|
||||
#include "SharedSurfaceGLX.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::gl;
|
||||
|
||||
|
@ -65,7 +82,46 @@ ClientCanvasLayer::Initialize(const Data& aData)
|
|||
mFlags |= TextureFlags::NON_PREMULTIPLIED;
|
||||
}
|
||||
|
||||
UniquePtr<SurfaceFactory> factory = GLScreenBuffer::CreateFactory(mGLContext, caps, forwarder, mFlags);
|
||||
UniquePtr<SurfaceFactory> factory;
|
||||
|
||||
if (!gfxPrefs::WebGLForceLayersReadback()) {
|
||||
switch (forwarder->GetCompositorBackendType()) {
|
||||
case mozilla::layers::LayersBackend::LAYERS_OPENGL: {
|
||||
#if defined(XP_MACOSX)
|
||||
factory = SurfaceFactory_IOSurface::Create(mGLContext, caps, forwarder, mFlags);
|
||||
#elif defined(MOZ_WIDGET_GONK)
|
||||
factory = MakeUnique<SurfaceFactory_Gralloc>(mGLContext, caps, forwarder, mFlags);
|
||||
#elif defined(GL_PROVIDER_GLX)
|
||||
if (sGLXLibrary.UseSurfaceSharing())
|
||||
factory = SurfaceFactory_GLXDrawable::Create(mGLContext, caps, forwarder, mFlags);
|
||||
#else
|
||||
if (mGLContext->GetContextType() == GLContextType::EGL) {
|
||||
if (XRE_IsParentProcess()) {
|
||||
factory = SurfaceFactory_EGLImage::Create(mGLContext, caps, forwarder,
|
||||
mFlags);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case mozilla::layers::LayersBackend::LAYERS_D3D11: {
|
||||
#ifdef XP_WIN
|
||||
// Enable surface sharing only if ANGLE and compositing devices
|
||||
// are both WARP or both not WARP
|
||||
if (mGLContext->IsANGLE() &&
|
||||
(mGLContext->IsWARP() == gfxWindowsPlatform::GetPlatform()->IsWARP()) &&
|
||||
gfxWindowsPlatform::GetPlatform()->CompositorD3D11TextureSharingWorks())
|
||||
{
|
||||
factory = SurfaceFactory_ANGLEShareHandle::Create(mGLContext, caps, forwarder,
|
||||
mFlags);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mGLFrontbuffer) {
|
||||
// We're using a source other than the one in the default screen.
|
||||
|
@ -89,6 +145,11 @@ ClientCanvasLayer::RenderLayer()
|
|||
|
||||
RenderMaskLayers(this);
|
||||
|
||||
if (!IsDirty()) {
|
||||
return;
|
||||
}
|
||||
Painted();
|
||||
|
||||
if (!mCanvasClient) {
|
||||
TextureFlags flags = TextureFlags::IMMEDIATE_UPLOAD;
|
||||
if (mOriginPos == gl::OriginPos::BottomLeft) {
|
||||
|
@ -111,24 +172,11 @@ ClientCanvasLayer::RenderLayer()
|
|||
return;
|
||||
}
|
||||
if (HasShadow()) {
|
||||
if (mAsyncRenderer) {
|
||||
static_cast<CanvasClientBridge*>(mCanvasClient.get())->SetLayer(this);
|
||||
} else {
|
||||
mCanvasClient->Connect();
|
||||
ClientManager()->AsShadowForwarder()->Attach(mCanvasClient, this);
|
||||
}
|
||||
mCanvasClient->Connect();
|
||||
ClientManager()->AsShadowForwarder()->Attach(mCanvasClient, this);
|
||||
}
|
||||
}
|
||||
|
||||
if (mCanvasClient && mAsyncRenderer) {
|
||||
mCanvasClient->UpdateAsync(mAsyncRenderer);
|
||||
}
|
||||
|
||||
if (!IsDirty()) {
|
||||
return;
|
||||
}
|
||||
Painted();
|
||||
|
||||
FirePreTransactionCallback();
|
||||
mCanvasClient->Update(gfx::IntSize(mBounds.width, mBounds.height), this);
|
||||
|
||||
|
@ -141,10 +189,6 @@ ClientCanvasLayer::RenderLayer()
|
|||
CanvasClient::CanvasClientType
|
||||
ClientCanvasLayer::GetCanvasClientType()
|
||||
{
|
||||
if (mAsyncRenderer) {
|
||||
return CanvasClient::CanvasClientAsync;
|
||||
}
|
||||
|
||||
if (mGLContext) {
|
||||
return CanvasClient::CanvasClientTypeShSurf;
|
||||
}
|
||||
|
|
|
@ -97,6 +97,7 @@ protected:
|
|||
|
||||
TextureFlags mFlags;
|
||||
|
||||
friend class DeprecatedCanvasClient2D;
|
||||
friend class CanvasClient2D;
|
||||
friend class CanvasClientSharedSurface;
|
||||
};
|
||||
|
|
|
@ -169,7 +169,6 @@ TextureChild::ActorDestroy(ActorDestroyReason why)
|
|||
{
|
||||
if (mTextureClient) {
|
||||
mTextureClient->mActor = nullptr;
|
||||
mTextureClient->mAllocator = nullptr;
|
||||
}
|
||||
mWaitForRecycle = nullptr;
|
||||
mKeep = nullptr;
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
|
||||
#include "mozilla/ipc/Transport.h" // for Transport
|
||||
#include "mozilla/gfx/Point.h" // for IntSize
|
||||
#include "mozilla/layers/AsyncCanvasRenderer.h"
|
||||
#include "mozilla/media/MediaSystemResourceManager.h" // for MediaSystemResourceManager
|
||||
#include "mozilla/media/MediaSystemResourceManagerChild.h" // for MediaSystemResourceManagerChild
|
||||
#include "mozilla/layers/CompositableClient.h" // for CompositableChild, etc
|
||||
|
@ -237,19 +236,6 @@ static void CreateImageClientSync(RefPtr<ImageClient>* result,
|
|||
barrier->NotifyAll();
|
||||
}
|
||||
|
||||
// dispatched function
|
||||
static void CreateCanvasClientSync(ReentrantMonitor* aBarrier,
|
||||
CanvasClient::CanvasClientType aType,
|
||||
TextureFlags aFlags,
|
||||
RefPtr<CanvasClient>* const outResult,
|
||||
bool* aDone)
|
||||
{
|
||||
ReentrantMonitorAutoEnter autoMon(*aBarrier);
|
||||
*outResult = sImageBridgeChildSingleton->CreateCanvasClientNow(aType, aFlags);
|
||||
*aDone = true;
|
||||
aBarrier->NotifyAll();
|
||||
}
|
||||
|
||||
static void ConnectImageBridge(ImageBridgeChild * child, ImageBridgeParent * parent)
|
||||
{
|
||||
MessageLoop *parentMsgLoop = parent->GetMessageLoop();
|
||||
|
@ -288,14 +274,9 @@ ImageBridgeChild::Connect(CompositableClient* aCompositable,
|
|||
MOZ_ASSERT(aCompositable);
|
||||
MOZ_ASSERT(!mShuttingDown);
|
||||
uint64_t id = 0;
|
||||
|
||||
PImageContainerChild* imageContainerChild = nullptr;
|
||||
if (aImageContainer)
|
||||
imageContainerChild = aImageContainer->GetPImageContainerChild();
|
||||
|
||||
PCompositableChild* child =
|
||||
SendPCompositableConstructor(aCompositable->GetTextureInfo(),
|
||||
imageContainerChild, &id);
|
||||
aImageContainer->GetPImageContainerChild(), &id);
|
||||
MOZ_ASSERT(child);
|
||||
aCompositable->InitIPDLActor(child, id);
|
||||
}
|
||||
|
@ -398,35 +379,6 @@ void ImageBridgeChild::DispatchReleaseImageClient(ImageClient* aClient,
|
|||
NewRunnableFunction(&ReleaseImageClientNow, aClient, aChild));
|
||||
}
|
||||
|
||||
static void ReleaseCanvasClientNow(CanvasClient* aClient)
|
||||
{
|
||||
MOZ_ASSERT(InImageBridgeChildThread());
|
||||
aClient->Release();
|
||||
}
|
||||
|
||||
// static
|
||||
void ImageBridgeChild::DispatchReleaseCanvasClient(CanvasClient* aClient)
|
||||
{
|
||||
if (!aClient) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsCreated()) {
|
||||
// CompositableClient::Release should normally happen in the ImageBridgeChild
|
||||
// thread because it usually generate some IPDL messages.
|
||||
// However, if we take this branch it means that the ImageBridgeChild
|
||||
// has already shut down, along with the CompositableChild, which means no
|
||||
// message will be sent and it is safe to run this code from any thread.
|
||||
MOZ_ASSERT(aClient->GetIPDLActor() == nullptr);
|
||||
aClient->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableFunction(&ReleaseCanvasClientNow, aClient));
|
||||
}
|
||||
|
||||
static void ReleaseTextureClientNow(TextureClient* aClient)
|
||||
{
|
||||
MOZ_ASSERT(InImageBridgeChildThread());
|
||||
|
@ -470,7 +422,7 @@ static void UpdateImageClientNow(ImageClient* aClient, ImageContainer* aContaine
|
|||
sImageBridgeChildSingleton->EndTransaction();
|
||||
}
|
||||
|
||||
// static
|
||||
//static
|
||||
void ImageBridgeChild::DispatchImageClientUpdate(ImageClient* aClient,
|
||||
ImageContainer* aContainer)
|
||||
{
|
||||
|
@ -495,51 +447,6 @@ void ImageBridgeChild::DispatchImageClientUpdate(ImageClient* aClient,
|
|||
nsRefPtr<ImageContainer> >(&UpdateImageClientNow, aClient, aContainer));
|
||||
}
|
||||
|
||||
static void UpdateAsyncCanvasRendererSync(AsyncCanvasRenderer* aWrapper,
|
||||
ReentrantMonitor* aBarrier,
|
||||
bool* const outDone)
|
||||
{
|
||||
ImageBridgeChild::UpdateAsyncCanvasRendererNow(aWrapper);
|
||||
|
||||
ReentrantMonitorAutoEnter autoMon(*aBarrier);
|
||||
*outDone = true;
|
||||
aBarrier->NotifyAll();
|
||||
}
|
||||
|
||||
// static
|
||||
void ImageBridgeChild::UpdateAsyncCanvasRenderer(AsyncCanvasRenderer* aWrapper)
|
||||
{
|
||||
aWrapper->GetCanvasClient()->UpdateAsync(aWrapper);
|
||||
|
||||
if (InImageBridgeChildThread()) {
|
||||
UpdateAsyncCanvasRendererNow(aWrapper);
|
||||
return;
|
||||
}
|
||||
|
||||
ReentrantMonitor barrier("UpdateAsyncCanvasRenderer Lock");
|
||||
ReentrantMonitorAutoEnter autoMon(barrier);
|
||||
bool done = false;
|
||||
|
||||
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableFunction(&UpdateAsyncCanvasRendererSync, aWrapper, &barrier, &done));
|
||||
|
||||
// should stop the thread until the CanvasClient has been created on
|
||||
// the other thread
|
||||
while (!done) {
|
||||
barrier.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void ImageBridgeChild::UpdateAsyncCanvasRendererNow(AsyncCanvasRenderer* aWrapper)
|
||||
{
|
||||
MOZ_ASSERT(aWrapper);
|
||||
sImageBridgeChildSingleton->BeginTransaction();
|
||||
aWrapper->GetCanvasClient()->Updated();
|
||||
sImageBridgeChildSingleton->EndTransaction();
|
||||
}
|
||||
|
||||
static void FlushAllImagesSync(ImageClient* aClient, ImageContainer* aContainer,
|
||||
AsyncTransactionWaiter* aWaiter)
|
||||
{
|
||||
|
@ -568,7 +475,7 @@ static void FlushAllImagesSync(ImageClient* aClient, ImageContainer* aContainer,
|
|||
aWaiter->DecrementWaitCount();
|
||||
}
|
||||
|
||||
// static
|
||||
//static
|
||||
void ImageBridgeChild::FlushAllImages(ImageClient* aClient,
|
||||
ImageContainer* aContainer)
|
||||
{
|
||||
|
@ -824,42 +731,6 @@ ImageBridgeChild::CreateImageClientNow(CompositableType aType,
|
|||
return client.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<CanvasClient>
|
||||
ImageBridgeChild::CreateCanvasClient(CanvasClient::CanvasClientType aType,
|
||||
TextureFlags aFlag)
|
||||
{
|
||||
if (InImageBridgeChildThread()) {
|
||||
return CreateCanvasClientNow(aType, aFlag);
|
||||
}
|
||||
ReentrantMonitor barrier("CreateCanvasClient Lock");
|
||||
ReentrantMonitorAutoEnter autoMon(barrier);
|
||||
bool done = false;
|
||||
|
||||
RefPtr<CanvasClient> result = nullptr;
|
||||
GetMessageLoop()->PostTask(FROM_HERE,
|
||||
NewRunnableFunction(&CreateCanvasClientSync,
|
||||
&barrier, aType, aFlag, &result, &done));
|
||||
// should stop the thread until the CanvasClient has been created on the
|
||||
// other thread
|
||||
while (!done) {
|
||||
barrier.Wait();
|
||||
}
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<CanvasClient>
|
||||
ImageBridgeChild::CreateCanvasClientNow(CanvasClient::CanvasClientType aType,
|
||||
TextureFlags aFlag)
|
||||
{
|
||||
RefPtr<CanvasClient> client
|
||||
= CanvasClient::CreateCanvasClient(aType, this, aFlag);
|
||||
MOZ_ASSERT(client, "failed to create CanvasClient");
|
||||
if (client) {
|
||||
client->Connect();
|
||||
}
|
||||
return client.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
ImageBridgeChild::AllocUnsafeShmem(size_t aSize,
|
||||
ipc::SharedMemory::SharedMemoryType aType,
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include "mozilla/RefPtr.h" // for already_AddRefed
|
||||
#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
|
||||
#include "mozilla/layers/AsyncTransactionTracker.h" // for AsyncTransactionTrackerHolder
|
||||
#include "mozilla/layers/CanvasClient.h"
|
||||
#include "mozilla/layers/CompositableForwarder.h"
|
||||
#include "mozilla/layers/CompositorTypes.h"
|
||||
#include "mozilla/layers/PImageBridgeChild.h"
|
||||
|
@ -33,7 +32,6 @@ class Shmem;
|
|||
|
||||
namespace layers {
|
||||
|
||||
class AsyncCanvasRenderer;
|
||||
class AsyncTransactionTracker;
|
||||
class ImageClient;
|
||||
class ImageContainer;
|
||||
|
@ -212,20 +210,12 @@ public:
|
|||
ImageContainer* aImageContainer);
|
||||
already_AddRefed<ImageClient> CreateImageClientNow(CompositableType aType,
|
||||
ImageContainer* aImageContainer);
|
||||
already_AddRefed<CanvasClient> CreateCanvasClient(CanvasClient::CanvasClientType aType,
|
||||
TextureFlags aFlag);
|
||||
already_AddRefed<CanvasClient> CreateCanvasClientNow(CanvasClient::CanvasClientType aType,
|
||||
TextureFlags aFlag);
|
||||
|
||||
static void DispatchReleaseImageClient(ImageClient* aClient,
|
||||
PImageContainerChild* aChild = nullptr);
|
||||
static void DispatchReleaseCanvasClient(CanvasClient* aClient);
|
||||
static void DispatchReleaseTextureClient(TextureClient* aClient);
|
||||
static void DispatchImageClientUpdate(ImageClient* aClient, ImageContainer* aContainer);
|
||||
|
||||
static void UpdateAsyncCanvasRenderer(AsyncCanvasRenderer* aClient);
|
||||
static void UpdateAsyncCanvasRendererNow(AsyncCanvasRenderer* aClient);
|
||||
|
||||
/**
|
||||
* Flush all Images sent to CompositableHost.
|
||||
*/
|
||||
|
|
|
@ -58,7 +58,7 @@ parent:
|
|||
sync Stop();
|
||||
|
||||
sync PCompositable(TextureInfo aInfo,
|
||||
nullable PImageContainer aImageContainer) returns (uint64_t id);
|
||||
PImageContainer aImageContainer) returns (uint64_t id);
|
||||
async PTexture(SurfaceDescriptor aSharedData, TextureFlags aTextureFlags);
|
||||
async PMediaSystemResourceManager();
|
||||
async PImageContainer();
|
||||
|
|
|
@ -107,7 +107,6 @@ EXPORTS.mozilla.layers += [
|
|||
'apz/util/ChromeProcessController.h',
|
||||
'apz/util/DoubleTapToZoom.h',
|
||||
'apz/util/InputAPZContext.h',
|
||||
'AsyncCanvasRenderer.h',
|
||||
'AtomicRefCountedWithFinalize.h',
|
||||
'AxisPhysicsModel.h',
|
||||
'AxisPhysicsMSDModel.h',
|
||||
|
@ -253,7 +252,6 @@ UNIFIED_SOURCES += [
|
|||
'apz/util/ChromeProcessController.cpp',
|
||||
'apz/util/DoubleTapToZoom.cpp',
|
||||
'apz/util/InputAPZContext.cpp',
|
||||
'AsyncCanvasRenderer.cpp',
|
||||
'AxisPhysicsModel.cpp',
|
||||
'AxisPhysicsMSDModel.cpp',
|
||||
'basic/BasicCanvasLayer.cpp',
|
||||
|
|
|
@ -84,22 +84,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class AppendAppNotesRunnable : public nsCancelableRunnable {
|
||||
public:
|
||||
explicit AppendAppNotesRunnable(nsAutoCString aFeatureStr)
|
||||
: mFeatureString(aFeatureStr)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override {
|
||||
CrashReporter::AppendAppNotesToCrashReport(mFeatureString);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCString mFeatureString;
|
||||
};
|
||||
|
||||
void
|
||||
ScopedGfxFeatureReporter::WriteAppNote(char statusChar)
|
||||
{
|
||||
|
@ -118,8 +102,7 @@ ScopedGfxFeatureReporter::WriteAppNote(char statusChar)
|
|||
|
||||
if (!gFeaturesAlreadyReported->Contains(featureString)) {
|
||||
gFeaturesAlreadyReported->AppendElement(featureString);
|
||||
nsCOMPtr<nsIRunnable> r = new AppendAppNotesRunnable(featureString);
|
||||
NS_DispatchToMainThread(r);
|
||||
CrashReporter::AppendAppNotesToCrashReport(featureString);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -388,32 +388,12 @@ private:
|
|||
DECL_GFX_PREF(Live, "test.mousescroll", MouseScrollTestingEnabled, bool, false);
|
||||
|
||||
DECL_GFX_PREF(Live, "ui.click_hold_context_menus.delay", UiClickHoldContextMenusDelay, int32_t, 500);
|
||||
|
||||
// WebGL (for pref access from Worker threads)
|
||||
DECL_GFX_PREF(Live, "webgl.all-angle-options", WebGLAllANGLEOptions, bool, false);
|
||||
DECL_GFX_PREF(Live, "webgl.angle.force-d3d11", WebGLANGLEForceD3D11, bool, false);
|
||||
DECL_GFX_PREF(Live, "webgl.angle.try-d3d11", WebGLANGLETryD3D11, bool, false);
|
||||
DECL_GFX_PREF(Once, "webgl.angle.force-d3d11", WebGLANGLEForceD3D11, bool, false);
|
||||
DECL_GFX_PREF(Once, "webgl.angle.try-d3d11", WebGLANGLETryD3D11, bool, false);
|
||||
DECL_GFX_PREF(Once, "webgl.angle.force-warp", WebGLANGLEForceWARP, bool, false);
|
||||
DECL_GFX_PREF(Live, "webgl.bypass-shader-validation", WebGLBypassShaderValidator, bool, true);
|
||||
DECL_GFX_PREF(Live, "webgl.can-lose-context-in-foreground", WebGLCanLoseContextInForeground, bool, true);
|
||||
DECL_GFX_PREF(Live, "webgl.default-no-alpha", WebGLDefaultNoAlpha, bool, false);
|
||||
DECL_GFX_PREF(Live, "webgl.disable-angle", WebGLDisableANGLE, bool, false);
|
||||
DECL_GFX_PREF(Live, "webgl.disable-extensions", WebGLDisableExtensions, bool, false);
|
||||
|
||||
DECL_GFX_PREF(Live, "webgl.disable-fail-if-major-performance-caveat",
|
||||
WebGLDisableFailIfMajorPerformanceCaveat, bool, false);
|
||||
DECL_GFX_PREF(Live, "webgl.disabled", WebGLDisabled, bool, false);
|
||||
|
||||
DECL_GFX_PREF(Live, "webgl.enable-draft-extensions", WebGLDraftExtensionsEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "webgl.enable-privileged-extensions", WebGLPrivilegedExtensionsEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "webgl.force-enabled", WebGLForceEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "webgl.force-layers-readback", WebGLForceLayersReadback, bool, false);
|
||||
DECL_GFX_PREF(Live, "webgl.lose-context-on-memory-pressure", WebGLLoseContextOnMemoryPressure, bool, false);
|
||||
DECL_GFX_PREF(Live, "webgl.max-warnings-per-context", WebGLMaxWarningsPerContext, uint32_t, 32);
|
||||
DECL_GFX_PREF(Live, "webgl.min_capability_mode", WebGLMinCapabilityMode, bool, false);
|
||||
DECL_GFX_PREF(Live, "webgl.msaa-force", WebGLForceMSAA, bool, false);
|
||||
DECL_GFX_PREF(Live, "webgl.prefer-16bpp", WebGLPrefer16bpp, bool, false);
|
||||
DECL_GFX_PREF(Live, "webgl.restore-context-when-visible", WebGLRestoreWhenVisible, bool, true);
|
||||
DECL_GFX_PREF(Once, "webgl.force-layers-readback", WebGLForceLayersReadback, bool, false);
|
||||
|
||||
// WARNING:
|
||||
// Please make sure that you've added your new preference to the list above in alphabetical order.
|
||||
|
|
|
@ -12,9 +12,6 @@
|
|||
#include "gfxDrawable.h"
|
||||
#include "imgIEncoder.h"
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/dom/ImageEncoder.h"
|
||||
#include "mozilla/dom/WorkerPrivate.h"
|
||||
#include "mozilla/dom/WorkerRunnable.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/DataSurfaceHelpers.h"
|
||||
#include "mozilla/gfx/Logging.h"
|
||||
|
@ -24,7 +21,6 @@
|
|||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIClipboardHelper.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIGfxInfo.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsRegion.h"
|
||||
|
@ -1547,125 +1543,6 @@ gfxUtils::CopyAsDataURI(DrawTarget* aDT)
|
|||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
gfxUtils::GetImageBuffer(gfx::DataSourceSurface* aSurface,
|
||||
bool aIsAlphaPremultiplied,
|
||||
uint8_t** outImageBuffer,
|
||||
int32_t* outFormat)
|
||||
{
|
||||
*outImageBuffer = nullptr;
|
||||
*outFormat = 0;
|
||||
|
||||
DataSourceSurface::MappedSurface map;
|
||||
if (!aSurface->Map(DataSourceSurface::MapType::READ, &map))
|
||||
return;
|
||||
|
||||
uint32_t bufferSize = aSurface->GetSize().width * aSurface->GetSize().height * 4;
|
||||
uint8_t* imageBuffer = new (fallible) uint8_t[bufferSize];
|
||||
if (!imageBuffer) {
|
||||
aSurface->Unmap();
|
||||
return;
|
||||
}
|
||||
memcpy(imageBuffer, map.mData, bufferSize);
|
||||
|
||||
aSurface->Unmap();
|
||||
|
||||
int32_t format = imgIEncoder::INPUT_FORMAT_HOSTARGB;
|
||||
if (!aIsAlphaPremultiplied) {
|
||||
// We need to convert to INPUT_FORMAT_RGBA, otherwise
|
||||
// we are automatically considered premult, and unpremult'd.
|
||||
// Yes, it is THAT silly.
|
||||
// Except for different lossy conversions by color,
|
||||
// we could probably just change the label, and not change the data.
|
||||
gfxUtils::ConvertBGRAtoRGBA(imageBuffer, bufferSize);
|
||||
format = imgIEncoder::INPUT_FORMAT_RGBA;
|
||||
}
|
||||
|
||||
*outImageBuffer = imageBuffer;
|
||||
*outFormat = format;
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
gfxUtils::GetInputStream(gfx::DataSourceSurface* aSurface,
|
||||
bool aIsAlphaPremultiplied,
|
||||
const char* aMimeType,
|
||||
const char16_t* aEncoderOptions,
|
||||
nsIInputStream** outStream)
|
||||
{
|
||||
nsCString enccid("@mozilla.org/image/encoder;2?type=");
|
||||
enccid += aMimeType;
|
||||
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(enccid.get());
|
||||
if (!encoder)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsAutoArrayPtr<uint8_t> imageBuffer;
|
||||
int32_t format = 0;
|
||||
GetImageBuffer(aSurface, aIsAlphaPremultiplied, getter_Transfers(imageBuffer), &format);
|
||||
if (!imageBuffer)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return dom::ImageEncoder::GetInputStream(aSurface->GetSize().width,
|
||||
aSurface->GetSize().height,
|
||||
imageBuffer, format,
|
||||
encoder, aEncoderOptions, outStream);
|
||||
}
|
||||
|
||||
class GetFeatureStatusRunnable final : public dom::workers::WorkerMainThreadRunnable
|
||||
{
|
||||
public:
|
||||
GetFeatureStatusRunnable(dom::workers::WorkerPrivate* workerPrivate,
|
||||
const nsCOMPtr<nsIGfxInfo>& gfxInfo,
|
||||
int32_t feature,
|
||||
int32_t* status)
|
||||
: WorkerMainThreadRunnable(workerPrivate)
|
||||
, mGfxInfo(gfxInfo)
|
||||
, mFeature(feature)
|
||||
, mStatus(status)
|
||||
, mNSResult(NS_OK)
|
||||
{
|
||||
}
|
||||
|
||||
bool MainThreadRun() override
|
||||
{
|
||||
if (mGfxInfo) {
|
||||
mNSResult = mGfxInfo->GetFeatureStatus(mFeature, mStatus);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult GetNSResult() const
|
||||
{
|
||||
return mNSResult;
|
||||
}
|
||||
|
||||
protected:
|
||||
~GetFeatureStatusRunnable() {}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIGfxInfo> mGfxInfo;
|
||||
int32_t mFeature;
|
||||
int32_t* mStatus;
|
||||
nsresult mNSResult;
|
||||
};
|
||||
|
||||
/* static */ nsresult
|
||||
gfxUtils::ThreadSafeGetFeatureStatus(const nsCOMPtr<nsIGfxInfo>& gfxInfo,
|
||||
int32_t feature, int32_t* status)
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
dom::workers::WorkerPrivate* workerPrivate =
|
||||
dom::workers::GetCurrentThreadWorkerPrivate();
|
||||
nsRefPtr<GetFeatureStatusRunnable> runnable =
|
||||
new GetFeatureStatusRunnable(workerPrivate, gfxInfo, feature, status);
|
||||
|
||||
runnable->Dispatch(workerPrivate->GetJSContext());
|
||||
|
||||
return runnable->GetNSResult();
|
||||
}
|
||||
|
||||
return gfxInfo->GetFeatureStatus(feature, status);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
gfxUtils::DumpDisplayList() {
|
||||
return gfxPrefs::LayoutDumpDisplayList();
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
|
||||
class gfxASurface;
|
||||
class gfxDrawable;
|
||||
class nsIInputStream;
|
||||
class nsIGfxInfo;
|
||||
class nsIntRegion;
|
||||
class nsIPresShell;
|
||||
|
||||
|
@ -283,21 +281,6 @@ public:
|
|||
static nsCString GetAsDataURI(DrawTarget* aDT);
|
||||
static nsCString GetAsLZ4Base64Str(DataSourceSurface* aSourceSurface);
|
||||
|
||||
static void GetImageBuffer(DataSourceSurface* aSurface,
|
||||
bool aIsAlphaPremultiplied,
|
||||
uint8_t** outImageBuffer,
|
||||
int32_t* outFormat);
|
||||
|
||||
static nsresult GetInputStream(DataSourceSurface* aSurface,
|
||||
bool aIsAlphaPremultiplied,
|
||||
const char* aMimeType,
|
||||
const char16_t* aEncoderOptions,
|
||||
nsIInputStream** outStream);
|
||||
|
||||
static nsresult ThreadSafeGetFeatureStatus(const nsCOMPtr<nsIGfxInfo>& gfxInfo,
|
||||
int32_t feature,
|
||||
int32_t* status);
|
||||
|
||||
/**
|
||||
* Copy to the clipboard as a PNG encoded Data URL.
|
||||
*/
|
||||
|
|
|
@ -272,7 +272,6 @@ GENERATED_FILES = [
|
|||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/workers',
|
||||
'/dom/xml',
|
||||
]
|
||||
|
||||
|
|
|
@ -195,20 +195,17 @@ class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
|
|||
void clear(const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr);
|
||||
|
||||
// Copy some memory. It will be automatically freed by the destructor.
|
||||
bool copy(const uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION,
|
||||
const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr);
|
||||
bool copy(const uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION);
|
||||
|
||||
// Adopt some memory. It will be automatically freed by the destructor.
|
||||
// data must have been allocated by the JS engine (e.g., extracted via
|
||||
// JSAutoStructuredCloneBuffer::steal).
|
||||
void adopt(uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION,
|
||||
const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr);
|
||||
void adopt(uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION);
|
||||
|
||||
// Release the buffer and transfer ownership to the caller. The caller is
|
||||
// responsible for calling JS_ClearStructuredClone or feeding the memory
|
||||
// back to JSAutoStructuredCloneBuffer::adopt.
|
||||
void steal(uint64_t** datap, size_t* nbytesp, uint32_t* versionp=nullptr,
|
||||
const JSStructuredCloneCallbacks** callbacks=nullptr, void** closure=nullptr);
|
||||
void steal(uint64_t** datap, size_t* nbytesp, uint32_t* versionp=nullptr);
|
||||
|
||||
// Abandon ownership of any transferable objects stored in the buffer,
|
||||
// without freeing the buffer itself. Useful when copying the data out into
|
||||
|
|
|
@ -2045,7 +2045,7 @@ JS_StructuredClone(JSContext* cx, HandleValue value, MutableHandleValue vp,
|
|||
JSAutoStructuredCloneBuffer::JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other)
|
||||
{
|
||||
ownTransferables_ = other.ownTransferables_;
|
||||
other.steal(&data_, &nbytes_, &version_, &callbacks_, &closure_);
|
||||
other.steal(&data_, &nbytes_, &version_);
|
||||
}
|
||||
|
||||
JSAutoStructuredCloneBuffer&
|
||||
|
@ -2054,7 +2054,7 @@ JSAutoStructuredCloneBuffer::operator=(JSAutoStructuredCloneBuffer&& other)
|
|||
MOZ_ASSERT(&other != this);
|
||||
clear();
|
||||
ownTransferables_ = other.ownTransferables_;
|
||||
other.steal(&data_, &nbytes_, &version_, &callbacks_, &closure_);
|
||||
other.steal(&data_, &nbytes_, &version_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -2079,9 +2079,7 @@ JSAutoStructuredCloneBuffer::clear(const JSStructuredCloneCallbacks* optionalCal
|
|||
}
|
||||
|
||||
bool
|
||||
JSAutoStructuredCloneBuffer::copy(const uint64_t* srcData, size_t nbytes, uint32_t version,
|
||||
const JSStructuredCloneCallbacks* callbacks,
|
||||
void* closure)
|
||||
JSAutoStructuredCloneBuffer::copy(const uint64_t* srcData, size_t nbytes, uint32_t version)
|
||||
{
|
||||
// transferable objects cannot be copied
|
||||
if (StructuredCloneHasTransferObjects(data_, nbytes_))
|
||||
|
@ -2097,45 +2095,31 @@ JSAutoStructuredCloneBuffer::copy(const uint64_t* srcData, size_t nbytes, uint32
|
|||
data_ = newData;
|
||||
nbytes_ = nbytes;
|
||||
version_ = version;
|
||||
callbacks_ = callbacks;
|
||||
closure_ = closure;
|
||||
ownTransferables_ = NoTransferables;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
JSAutoStructuredCloneBuffer::adopt(uint64_t* data, size_t nbytes, uint32_t version,
|
||||
const JSStructuredCloneCallbacks* callbacks,
|
||||
void* closure)
|
||||
JSAutoStructuredCloneBuffer::adopt(uint64_t* data, size_t nbytes, uint32_t version)
|
||||
{
|
||||
clear();
|
||||
data_ = data;
|
||||
nbytes_ = nbytes;
|
||||
version_ = version;
|
||||
callbacks_ = callbacks;
|
||||
closure_ = closure;
|
||||
ownTransferables_ = OwnsTransferablesIfAny;
|
||||
}
|
||||
|
||||
void
|
||||
JSAutoStructuredCloneBuffer::steal(uint64_t** datap, size_t* nbytesp, uint32_t* versionp,
|
||||
const JSStructuredCloneCallbacks** callbacks,
|
||||
void** closure)
|
||||
JSAutoStructuredCloneBuffer::steal(uint64_t** datap, size_t* nbytesp, uint32_t* versionp)
|
||||
{
|
||||
*datap = data_;
|
||||
*nbytesp = nbytes_;
|
||||
if (versionp)
|
||||
*versionp = version_;
|
||||
if (callbacks)
|
||||
*callbacks = callbacks_;
|
||||
if (closure)
|
||||
*closure = closure_;
|
||||
|
||||
data_ = nullptr;
|
||||
nbytes_ = 0;
|
||||
version_ = 0;
|
||||
callbacks_ = 0;
|
||||
closure_ = 0;
|
||||
ownTransferables_ = NoTransferables;
|
||||
}
|
||||
|
||||
|
|
|
@ -4181,8 +4181,6 @@ pref("webgl.angle.force-d3d11", false);
|
|||
pref("webgl.angle.force-warp", false);
|
||||
#endif
|
||||
|
||||
pref("gfx.offscreencanvas.enabled", false);
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
pref("gfx.gralloc.fence-with-readpixels", false);
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче