зеркало из https://github.com/mozilla/gecko-dev.git
Bug 857895 - Run canvas rendering asynchronously on OSX. r=Bas,bholley
This commit is contained in:
Родитель
924056f5e8
Коммит
51ff272372
|
@ -19,6 +19,8 @@
|
||||||
#include "nsSVGEffects.h"
|
#include "nsSVGEffects.h"
|
||||||
#include "nsPresContext.h"
|
#include "nsPresContext.h"
|
||||||
#include "nsIPresShell.h"
|
#include "nsIPresShell.h"
|
||||||
|
#include "nsWidgetsCID.h"
|
||||||
|
#include "nsIAppShell.h"
|
||||||
|
|
||||||
#include "nsIInterfaceRequestorUtils.h"
|
#include "nsIInterfaceRequestorUtils.h"
|
||||||
#include "nsIFrame.h"
|
#include "nsIFrame.h"
|
||||||
|
@ -114,6 +116,7 @@
|
||||||
#include "nsDeviceContext.h"
|
#include "nsDeviceContext.h"
|
||||||
#include "nsFontMetrics.h"
|
#include "nsFontMetrics.h"
|
||||||
#include "Units.h"
|
#include "Units.h"
|
||||||
|
#include "mozilla/Services.h"
|
||||||
|
|
||||||
#undef free // apparently defined by some windows header, clashing with a free()
|
#undef free // apparently defined by some windows header, clashing with a free()
|
||||||
// method in SkTypes.h
|
// method in SkTypes.h
|
||||||
|
@ -179,6 +182,64 @@ public:
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(Canvas2dPixelsReporter, nsIMemoryReporter)
|
NS_IMPL_ISUPPORTS(Canvas2dPixelsReporter, nsIMemoryReporter)
|
||||||
|
|
||||||
|
class CanvasShutdownObserver : public nsIObserver
|
||||||
|
{
|
||||||
|
virtual ~CanvasShutdownObserver() {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
|
||||||
|
explicit CanvasShutdownObserver(CanvasRenderingContext2D* aCanvas)
|
||||||
|
: mCanvas(aCanvas)
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIObserverService> observerService =
|
||||||
|
mozilla::services::GetObserverService();
|
||||||
|
observerService->AddObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shutdown() {
|
||||||
|
nsCOMPtr<nsIObserverService> observerService =
|
||||||
|
mozilla::services::GetObserverService();
|
||||||
|
observerService->RemoveObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHOD Observe(nsISupports* aSubject,
|
||||||
|
const char* aTopic,
|
||||||
|
const char16_t* aData) override
|
||||||
|
{
|
||||||
|
mCanvas->ShutdownTaskQueue();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CanvasRenderingContext2D* mCanvas;
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(CanvasShutdownObserver, nsIObserver);
|
||||||
|
|
||||||
|
|
||||||
|
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
|
||||||
|
|
||||||
|
void
|
||||||
|
CanvasRenderingContext2D::RecordCommand()
|
||||||
|
{
|
||||||
|
static uint32_t kBatchSize = 5;
|
||||||
|
if (++mPendingCommands > kBatchSize) {
|
||||||
|
mPendingCommands = 0;
|
||||||
|
FlushDelayedTarget();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mScheduledFlush) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mScheduledFlush = true;
|
||||||
|
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
|
||||||
|
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(this, &CanvasRenderingContext2D::StableStateReached);
|
||||||
|
appShell->RunInStableState(r);
|
||||||
|
}
|
||||||
|
|
||||||
class CanvasRadialGradient : public CanvasGradient
|
class CanvasRadialGradient : public CanvasGradient
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -393,6 +454,11 @@ public:
|
||||||
mCtx->CurrentState().filterAdditionalImages,
|
mCtx->CurrentState().filterAdditionalImages,
|
||||||
mPostFilterBounds.TopLeft() - mOffset,
|
mPostFilterBounds.TopLeft() - mOffset,
|
||||||
DrawOptions(1.0f, mCompositionOp));
|
DrawOptions(1.0f, mCompositionOp));
|
||||||
|
|
||||||
|
// DrawTargetCapture doesn't properly support filter nodes because they are
|
||||||
|
// mutable. Block until drawing is done to avoid races.
|
||||||
|
mCtx->FlushDelayedTarget();
|
||||||
|
mCtx->FinishDelayedRendering();
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawTarget* DT()
|
DrawTarget* DT()
|
||||||
|
@ -817,6 +883,9 @@ public:
|
||||||
if (!context || !context->mTarget)
|
if (!context || !context->mTarget)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
context->FlushDelayedTarget();
|
||||||
|
context->FinishDelayedRendering();
|
||||||
|
|
||||||
// Since SkiaGL default to store drawing command until flush
|
// Since SkiaGL default to store drawing command until flush
|
||||||
// We will have to flush it before present.
|
// We will have to flush it before present.
|
||||||
context->mTarget->Flush();
|
context->mTarget->Flush();
|
||||||
|
@ -938,6 +1007,8 @@ CanvasRenderingContext2D::CanvasRenderingContext2D()
|
||||||
, mZero(false), mOpaque(false)
|
, mZero(false), mOpaque(false)
|
||||||
, mResetLayer(true)
|
, mResetLayer(true)
|
||||||
, mIPC(false)
|
, mIPC(false)
|
||||||
|
, mPendingCommands(0)
|
||||||
|
, mScheduledFlush(false)
|
||||||
, mDrawObserver(nullptr)
|
, mDrawObserver(nullptr)
|
||||||
, mIsEntireFrameInvalid(false)
|
, mIsEntireFrameInvalid(false)
|
||||||
, mPredictManyRedrawCalls(false), mPathTransformWillUpdate(false)
|
, mPredictManyRedrawCalls(false), mPathTransformWillUpdate(false)
|
||||||
|
@ -945,6 +1016,14 @@ CanvasRenderingContext2D::CanvasRenderingContext2D()
|
||||||
{
|
{
|
||||||
sNumLivingContexts++;
|
sNumLivingContexts++;
|
||||||
|
|
||||||
|
#ifdef XP_MACOSX
|
||||||
|
// Restrict async rendering to OSX for now until the failures on other
|
||||||
|
// platforms get resolved.
|
||||||
|
mTaskQueue = new MediaTaskQueue(SharedThreadPool::Get(NS_LITERAL_CSTRING("Canvas Rendering"),
|
||||||
|
4));
|
||||||
|
mShutdownObserver = new CanvasShutdownObserver(this);
|
||||||
|
#endif
|
||||||
|
|
||||||
// The default is to use OpenGL mode
|
// The default is to use OpenGL mode
|
||||||
if (!gfxPlatform::GetPlatform()->UseAcceleratedSkiaCanvas()) {
|
if (!gfxPlatform::GetPlatform()->UseAcceleratedSkiaCanvas()) {
|
||||||
mRenderingMode = RenderingMode::SoftwareBackendMode;
|
mRenderingMode = RenderingMode::SoftwareBackendMode;
|
||||||
|
@ -957,6 +1036,9 @@ CanvasRenderingContext2D::CanvasRenderingContext2D()
|
||||||
|
|
||||||
CanvasRenderingContext2D::~CanvasRenderingContext2D()
|
CanvasRenderingContext2D::~CanvasRenderingContext2D()
|
||||||
{
|
{
|
||||||
|
if (mTaskQueue) {
|
||||||
|
ShutdownTaskQueue();
|
||||||
|
}
|
||||||
RemoveDrawObserver();
|
RemoveDrawObserver();
|
||||||
RemovePostRefreshObserver();
|
RemovePostRefreshObserver();
|
||||||
Reset();
|
Reset();
|
||||||
|
@ -979,6 +1061,19 @@ CanvasRenderingContext2D::~CanvasRenderingContext2D()
|
||||||
RemoveDemotableContext(this);
|
RemoveDemotableContext(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CanvasRenderingContext2D::ShutdownTaskQueue()
|
||||||
|
{
|
||||||
|
mShutdownObserver->Shutdown();
|
||||||
|
mShutdownObserver = nullptr;
|
||||||
|
FlushDelayedTarget();
|
||||||
|
FinishDelayedRendering();
|
||||||
|
mTaskQueue->BeginShutdown();
|
||||||
|
mTaskQueue = nullptr;
|
||||||
|
mDelayedTarget = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
JSObject*
|
JSObject*
|
||||||
CanvasRenderingContext2D::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
|
CanvasRenderingContext2D::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
|
||||||
{
|
{
|
||||||
|
@ -1034,7 +1129,10 @@ CanvasRenderingContext2D::Reset()
|
||||||
gCanvasAzureMemoryUsed -= mWidth * mHeight * 4;
|
gCanvasAzureMemoryUsed -= mWidth * mHeight * 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FinishDelayedRendering();
|
||||||
mTarget = nullptr;
|
mTarget = nullptr;
|
||||||
|
mDelayedTarget = nullptr;
|
||||||
|
mFinalTarget = nullptr;
|
||||||
|
|
||||||
// reset hit regions
|
// reset hit regions
|
||||||
mHitRegionsOptions.ClearAndRetainStorage();
|
mHitRegionsOptions.ClearAndRetainStorage();
|
||||||
|
@ -1101,6 +1199,8 @@ CanvasRenderingContext2D::StyleColorToString(const nscolor& aColor, nsAString& a
|
||||||
nsresult
|
nsresult
|
||||||
CanvasRenderingContext2D::Redraw()
|
CanvasRenderingContext2D::Redraw()
|
||||||
{
|
{
|
||||||
|
RecordCommand();
|
||||||
|
|
||||||
if (mIsEntireFrameInvalid) {
|
if (mIsEntireFrameInvalid) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -1122,6 +1222,7 @@ CanvasRenderingContext2D::Redraw()
|
||||||
void
|
void
|
||||||
CanvasRenderingContext2D::Redraw(const mgfx::Rect &r)
|
CanvasRenderingContext2D::Redraw(const mgfx::Rect &r)
|
||||||
{
|
{
|
||||||
|
RecordCommand();
|
||||||
++mInvalidateCount;
|
++mInvalidateCount;
|
||||||
|
|
||||||
if (mIsEntireFrameInvalid) {
|
if (mIsEntireFrameInvalid) {
|
||||||
|
@ -1144,6 +1245,18 @@ CanvasRenderingContext2D::Redraw(const mgfx::Rect &r)
|
||||||
mCanvasElement->InvalidateCanvasContent(&r);
|
mCanvasElement->InvalidateCanvasContent(&r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TemporaryRef<SourceSurface>
|
||||||
|
CanvasRenderingContext2D::GetSurfaceSnapshot(bool* aPremultAlpha /* = nullptr */)
|
||||||
|
{
|
||||||
|
EnsureTarget();
|
||||||
|
if (aPremultAlpha) {
|
||||||
|
*aPremultAlpha = true;
|
||||||
|
}
|
||||||
|
FlushDelayedTarget();
|
||||||
|
FinishDelayedRendering();
|
||||||
|
return mFinalTarget->Snapshot();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CanvasRenderingContext2D::DidRefresh()
|
CanvasRenderingContext2D::DidRefresh()
|
||||||
{
|
{
|
||||||
|
@ -1161,6 +1274,7 @@ CanvasRenderingContext2D::RedrawUser(const gfxRect& r)
|
||||||
{
|
{
|
||||||
if (mIsEntireFrameInvalid) {
|
if (mIsEntireFrameInvalid) {
|
||||||
++mInvalidateCount;
|
++mInvalidateCount;
|
||||||
|
RecordCommand();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1186,7 +1300,7 @@ bool CanvasRenderingContext2D::SwitchRenderingMode(RenderingMode aRenderingMode)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
RefPtr<SourceSurface> snapshot = mTarget->Snapshot();
|
RefPtr<SourceSurface> snapshot = GetSurfaceSnapshot();
|
||||||
RefPtr<DrawTarget> oldTarget = mTarget;
|
RefPtr<DrawTarget> oldTarget = mTarget;
|
||||||
mTarget = nullptr;
|
mTarget = nullptr;
|
||||||
mResetLayer = true;
|
mResetLayer = true;
|
||||||
|
@ -1360,7 +1474,7 @@ CanvasRenderingContext2D::EnsureTarget(RenderingMode aRenderingMode)
|
||||||
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
|
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
|
||||||
|
|
||||||
if (glue && glue->GetGrContext() && glue->GetGLContext()) {
|
if (glue && glue->GetGrContext() && glue->GetGLContext()) {
|
||||||
mTarget = Factory::CreateDrawTargetSkiaWithGrContext(glue->GetGrContext(), size, format);
|
mFinalTarget = Factory::CreateDrawTargetSkiaWithGrContext(glue->GetGrContext(), size, format);
|
||||||
if (mTarget) {
|
if (mTarget) {
|
||||||
AddDemotableContext(this);
|
AddDemotableContext(this);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1369,19 +1483,31 @@ CanvasRenderingContext2D::EnsureTarget(RenderingMode aRenderingMode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!mTarget) {
|
if (!mFinalTarget) {
|
||||||
mTarget = layerManager->CreateDrawTarget(size, format);
|
mFinalTarget = layerManager->CreateDrawTarget(size, format);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mTarget = layerManager->CreateDrawTarget(size, format);
|
mFinalTarget = layerManager->CreateDrawTarget(size, format);
|
||||||
mode = RenderingMode::SoftwareBackendMode;
|
mode = RenderingMode::SoftwareBackendMode;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mTarget = gfxPlatform::GetPlatform()->CreateOffscreenCanvasDrawTarget(size, format);
|
mFinalTarget = gfxPlatform::GetPlatform()->CreateOffscreenCanvasDrawTarget(size, format);
|
||||||
mode = RenderingMode::SoftwareBackendMode;
|
mode = RenderingMode::SoftwareBackendMode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restrict async canvas drawing to OSX for now since we get test failures
|
||||||
|
// on other platforms.
|
||||||
|
if (mFinalTarget) {
|
||||||
|
#ifdef XP_MACOSX
|
||||||
|
mTarget = mDelayedTarget = mFinalTarget->CreateCaptureDT(size);
|
||||||
|
#else
|
||||||
|
mTarget = mFinalTarget;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
mPendingCommands = 0;
|
||||||
|
|
||||||
if (mTarget) {
|
if (mTarget) {
|
||||||
static bool registered = false;
|
static bool registered = false;
|
||||||
if (!registered) {
|
if (!registered) {
|
||||||
|
@ -1415,7 +1541,7 @@ CanvasRenderingContext2D::EnsureTarget(RenderingMode aRenderingMode)
|
||||||
Redraw();
|
Redraw();
|
||||||
} else {
|
} else {
|
||||||
EnsureErrorTarget();
|
EnsureErrorTarget();
|
||||||
mTarget = sErrorTarget;
|
mTarget = mFinalTarget = sErrorTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mode;
|
return mode;
|
||||||
|
@ -1435,6 +1561,51 @@ CanvasRenderingContext2D::GetHeight() const
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class DrawCaptureTask : public nsRunnable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DrawCaptureTask(DrawTargetCapture *aReplay, DrawTarget* aDest)
|
||||||
|
: mReplay(aReplay)
|
||||||
|
, mDest(aDest)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHOD Run()
|
||||||
|
{
|
||||||
|
mDest->DrawCapturedDT(mReplay, Matrix());
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
RefPtr<DrawTargetCapture> mReplay;
|
||||||
|
RefPtr<DrawTarget> mDest;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
CanvasRenderingContext2D::FlushDelayedTarget()
|
||||||
|
{
|
||||||
|
if (!mDelayedTarget) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mPendingCommands = 0;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIRunnable> task = new DrawCaptureTask(mDelayedTarget, mFinalTarget);
|
||||||
|
mTaskQueue->Dispatch(task.forget());
|
||||||
|
|
||||||
|
mDelayedTarget = mFinalTarget->CreateCaptureDT(IntSize(mWidth, mHeight));
|
||||||
|
|
||||||
|
mDelayedTarget->SetTransform(mTarget->GetTransform());
|
||||||
|
mTarget = mDelayedTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CanvasRenderingContext2D::FinishDelayedRendering()
|
||||||
|
{
|
||||||
|
if (mTaskQueue) {
|
||||||
|
mTaskQueue->AwaitIdle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CanvasRenderingContext2D::SetDimensions(int32_t width, int32_t height)
|
CanvasRenderingContext2D::SetDimensions(int32_t width, int32_t height)
|
||||||
{
|
{
|
||||||
|
@ -1584,7 +1755,7 @@ CanvasRenderingContext2D::GetImageBuffer(uint8_t** aImageBuffer,
|
||||||
*aFormat = 0;
|
*aFormat = 0;
|
||||||
|
|
||||||
EnsureTarget();
|
EnsureTarget();
|
||||||
RefPtr<SourceSurface> snapshot = mTarget->Snapshot();
|
RefPtr<SourceSurface> snapshot = GetSurfaceSnapshot();
|
||||||
if (!snapshot) {
|
if (!snapshot) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2003,7 +2174,7 @@ CanvasRenderingContext2D::CreatePattern(const HTMLImageOrCanvasOrVideoElement& e
|
||||||
// of animated images
|
// of animated images
|
||||||
nsLayoutUtils::SurfaceFromElementResult res =
|
nsLayoutUtils::SurfaceFromElementResult res =
|
||||||
nsLayoutUtils::SurfaceFromElement(htmlElement,
|
nsLayoutUtils::SurfaceFromElement(htmlElement,
|
||||||
nsLayoutUtils::SFE_WANT_FIRST_FRAME, mTarget);
|
nsLayoutUtils::SFE_WANT_FIRST_FRAME, mFinalTarget);
|
||||||
|
|
||||||
if (!res.mSourceSurface) {
|
if (!res.mSourceSurface) {
|
||||||
error.Throw(NS_ERROR_NOT_AVAILABLE);
|
error.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||||
|
@ -4314,7 +4485,7 @@ CanvasRenderingContext2D::DrawImage(const HTMLImageOrCanvasOrVideoElement& image
|
||||||
nsLayoutUtils::SurfaceFromElementResult res =
|
nsLayoutUtils::SurfaceFromElementResult res =
|
||||||
CachedSurfaceFromElement(element);
|
CachedSurfaceFromElement(element);
|
||||||
if (!res.mSourceSurface)
|
if (!res.mSourceSurface)
|
||||||
res = nsLayoutUtils::SurfaceFromElement(element, sfeFlags, mTarget);
|
res = nsLayoutUtils::SurfaceFromElement(element, sfeFlags, mFinalTarget);
|
||||||
|
|
||||||
if (!res.mSourceSurface && !res.mDrawInfo.mImgContainer) {
|
if (!res.mSourceSurface && !res.mDrawInfo.mImgContainer) {
|
||||||
// The spec says to silently do nothing in the following cases:
|
// The spec says to silently do nothing in the following cases:
|
||||||
|
@ -4658,7 +4829,12 @@ CanvasRenderingContext2D::DrawWindow(nsGlobalWindow& window, double x,
|
||||||
if (gfxPlatform::GetPlatform()->SupportsAzureContentForDrawTarget(mTarget) &&
|
if (gfxPlatform::GetPlatform()->SupportsAzureContentForDrawTarget(mTarget) &&
|
||||||
GlobalAlpha() == 1.0f)
|
GlobalAlpha() == 1.0f)
|
||||||
{
|
{
|
||||||
thebes = new gfxContext(mTarget);
|
// Complete any async rendering and use synchronous rendering for DrawWindow
|
||||||
|
// until we're confident it works for all content.
|
||||||
|
FlushDelayedTarget();
|
||||||
|
FinishDelayedRendering();
|
||||||
|
|
||||||
|
thebes = new gfxContext(mFinalTarget);
|
||||||
thebes->SetMatrix(gfxMatrix(matrix._11, matrix._12, matrix._21,
|
thebes->SetMatrix(gfxMatrix(matrix._11, matrix._12, matrix._21,
|
||||||
matrix._22, matrix._31, matrix._32));
|
matrix._22, matrix._31, matrix._32));
|
||||||
} else {
|
} else {
|
||||||
|
@ -4915,7 +5091,7 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx,
|
||||||
IntRect srcReadRect = srcRect.Intersect(destRect);
|
IntRect srcReadRect = srcRect.Intersect(destRect);
|
||||||
RefPtr<DataSourceSurface> readback;
|
RefPtr<DataSourceSurface> readback;
|
||||||
if (!srcReadRect.IsEmpty() && !mZero) {
|
if (!srcReadRect.IsEmpty() && !mZero) {
|
||||||
RefPtr<SourceSurface> snapshot = mTarget->Snapshot();
|
RefPtr<SourceSurface> snapshot = GetSurfaceSnapshot();
|
||||||
if (snapshot) {
|
if (snapshot) {
|
||||||
readback = snapshot->GetDataSurface();
|
readback = snapshot->GetDataSurface();
|
||||||
}
|
}
|
||||||
|
@ -5301,7 +5477,7 @@ CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
mTarget->Flush();
|
FlushDelayedTarget();
|
||||||
|
|
||||||
if (!mResetLayer && aOldLayer) {
|
if (!mResetLayer && aOldLayer) {
|
||||||
CanvasRenderingContext2DUserData* userData =
|
CanvasRenderingContext2DUserData* userData =
|
||||||
|
@ -5350,6 +5526,8 @@ CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
||||||
userData = new CanvasRenderingContext2DUserData(this);
|
userData = new CanvasRenderingContext2DUserData(this);
|
||||||
canvasLayer->SetDidTransactionCallback(
|
canvasLayer->SetDidTransactionCallback(
|
||||||
CanvasRenderingContext2DUserData::DidTransactionCallback, userData);
|
CanvasRenderingContext2DUserData::DidTransactionCallback, userData);
|
||||||
|
canvasLayer->SetPreTransactionCallback(
|
||||||
|
CanvasRenderingContext2DUserData::PreTransactionCallback, userData);
|
||||||
canvasLayer->SetUserData(&g2DContextLayerUserData, userData);
|
canvasLayer->SetUserData(&g2DContextLayerUserData, userData);
|
||||||
|
|
||||||
CanvasLayer::Data data;
|
CanvasLayer::Data data;
|
||||||
|
@ -5358,16 +5536,13 @@ CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
|
||||||
|
|
||||||
GLuint skiaGLTex = SkiaGLTex();
|
GLuint skiaGLTex = SkiaGLTex();
|
||||||
if (skiaGLTex) {
|
if (skiaGLTex) {
|
||||||
canvasLayer->SetPreTransactionCallback(
|
|
||||||
CanvasRenderingContext2DUserData::PreTransactionCallback, userData);
|
|
||||||
|
|
||||||
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
|
SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
|
||||||
MOZ_ASSERT(glue);
|
MOZ_ASSERT(glue);
|
||||||
|
|
||||||
data.mGLContext = glue->GetGLContext();
|
data.mGLContext = glue->GetGLContext();
|
||||||
data.mFrontbufferGLTex = skiaGLTex;
|
data.mFrontbufferGLTex = skiaGLTex;
|
||||||
} else {
|
} else {
|
||||||
data.mDrawTarget = mTarget;
|
data.mDrawTarget = mFinalTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
canvasLayer->Initialize(data);
|
canvasLayer->Initialize(data);
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "nsIDOMCanvasRenderingContext2D.h"
|
#include "nsIDOMCanvasRenderingContext2D.h"
|
||||||
#include "nsICanvasRenderingContextInternal.h"
|
#include "nsICanvasRenderingContextInternal.h"
|
||||||
#include "mozilla/RefPtr.h"
|
#include "mozilla/RefPtr.h"
|
||||||
|
#include "mozilla/Monitor.h"
|
||||||
#include "nsColor.h"
|
#include "nsColor.h"
|
||||||
#include "mozilla/dom/HTMLCanvasElement.h"
|
#include "mozilla/dom/HTMLCanvasElement.h"
|
||||||
#include "mozilla/dom/HTMLVideoElement.h"
|
#include "mozilla/dom/HTMLVideoElement.h"
|
||||||
|
@ -27,6 +28,7 @@
|
||||||
#include "mozilla/EnumeratedArray.h"
|
#include "mozilla/EnumeratedArray.h"
|
||||||
#include "FilterSupport.h"
|
#include "FilterSupport.h"
|
||||||
#include "nsSVGEffects.h"
|
#include "nsSVGEffects.h"
|
||||||
|
#include "MediaTaskQueue.h"
|
||||||
|
|
||||||
class nsGlobalWindow;
|
class nsGlobalWindow;
|
||||||
class nsXULElement;
|
class nsXULElement;
|
||||||
|
@ -52,6 +54,7 @@ template<typename T> class Optional;
|
||||||
struct CanvasBidiProcessor;
|
struct CanvasBidiProcessor;
|
||||||
class CanvasRenderingContext2DUserData;
|
class CanvasRenderingContext2DUserData;
|
||||||
class CanvasDrawObserver;
|
class CanvasDrawObserver;
|
||||||
|
class CanvasShutdownObserver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** CanvasRenderingContext2D
|
** CanvasRenderingContext2D
|
||||||
|
@ -442,14 +445,7 @@ public:
|
||||||
const char16_t* aEncoderOptions,
|
const char16_t* aEncoderOptions,
|
||||||
nsIInputStream **aStream) override;
|
nsIInputStream **aStream) override;
|
||||||
|
|
||||||
mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha = nullptr) override
|
mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha = nullptr) override;
|
||||||
{
|
|
||||||
EnsureTarget();
|
|
||||||
if (aPremultAlpha) {
|
|
||||||
*aPremultAlpha = true;
|
|
||||||
}
|
|
||||||
return mTarget->Snapshot();
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHOD SetIsOpaque(bool isOpaque) override;
|
NS_IMETHOD SetIsOpaque(bool isOpaque) override;
|
||||||
bool GetIsOpaque() override { return mOpaque; }
|
bool GetIsOpaque() override { return mOpaque; }
|
||||||
|
@ -521,6 +517,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
friend class CanvasRenderingContext2DUserData;
|
friend class CanvasRenderingContext2DUserData;
|
||||||
|
friend class CanvasShutdownObserver;
|
||||||
|
|
||||||
virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat) override;
|
virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat) override;
|
||||||
|
|
||||||
|
@ -532,6 +529,21 @@ public:
|
||||||
// return true and fills in the bound rect if element has a hit region.
|
// return true and fills in the bound rect if element has a hit region.
|
||||||
bool GetHitRegionRect(Element* aElement, nsRect& aRect) override;
|
bool GetHitRegionRect(Element* aElement, nsRect& aRect) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deferred rendering functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the event loop reaches a stable
|
||||||
|
* state, and trigger us to flush any outstanding
|
||||||
|
* commands to the rendering thread.
|
||||||
|
*/
|
||||||
|
void StableStateReached()
|
||||||
|
{
|
||||||
|
mScheduledFlush = false;
|
||||||
|
FlushDelayedTarget();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY,
|
nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY,
|
||||||
uint32_t aWidth, uint32_t aHeight,
|
uint32_t aWidth, uint32_t aHeight,
|
||||||
|
@ -550,6 +562,8 @@ protected:
|
||||||
nsresult InitializeWithTarget(mozilla::gfx::DrawTarget *surface,
|
nsresult InitializeWithTarget(mozilla::gfx::DrawTarget *surface,
|
||||||
int32_t width, int32_t height);
|
int32_t width, int32_t height);
|
||||||
|
|
||||||
|
void ShutdownTaskQueue();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of living nsCanvasRenderingContexts. When this goes down to
|
* The number of living nsCanvasRenderingContexts. When this goes down to
|
||||||
* 0, we free the premultiply and unpremultiply tables, if they exist.
|
* 0, we free the premultiply and unpremultiply tables, if they exist.
|
||||||
|
@ -713,6 +727,54 @@ protected:
|
||||||
// sErrorTarget.
|
// sErrorTarget.
|
||||||
mozilla::RefPtr<mozilla::gfx::DrawTarget> mTarget;
|
mozilla::RefPtr<mozilla::gfx::DrawTarget> mTarget;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deferred rendering implementation
|
||||||
|
*/
|
||||||
|
|
||||||
|
// If we are using deferred rendering, then this is the current
|
||||||
|
// deferred rendering target. It is the same pointer as mTarget.
|
||||||
|
mozilla::RefPtr<mozilla::gfx::DrawTargetCapture> mDelayedTarget;
|
||||||
|
|
||||||
|
// If we are using deferred rendering, then this is the actual destination
|
||||||
|
// buffer.
|
||||||
|
mozilla::RefPtr<mozilla::gfx::DrawTarget> mFinalTarget;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the current DelayedDrawTarget to the rendering queue,
|
||||||
|
* schedule a rendering job if required, and create a new
|
||||||
|
* DelayedDrawTarget.
|
||||||
|
*/
|
||||||
|
void FlushDelayedTarget();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure all commands have been flushed to
|
||||||
|
* the rendering thread, and block until they
|
||||||
|
* are completed.
|
||||||
|
*/
|
||||||
|
void FinishDelayedRendering();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a command is added to the current
|
||||||
|
* delayed draw target.
|
||||||
|
*
|
||||||
|
* Either flushes the current batch of commands to
|
||||||
|
* the rendering thread, or ensures that this happens
|
||||||
|
* the next time the event loop reaches a stable state.
|
||||||
|
*/
|
||||||
|
void RecordCommand();
|
||||||
|
|
||||||
|
// The number of commands currently waiting to be sent
|
||||||
|
// to the rendering thread.
|
||||||
|
uint32_t mPendingCommands;
|
||||||
|
|
||||||
|
// True if we have scheduled FlushDelayedTarget to be
|
||||||
|
// called in the next browser stable state.
|
||||||
|
bool mScheduledFlush;
|
||||||
|
|
||||||
|
nsRefPtr<MediaTaskQueue> mTaskQueue;
|
||||||
|
|
||||||
|
nsRefPtr<CanvasShutdownObserver> mShutdownObserver;
|
||||||
|
|
||||||
uint32_t SkiaGLTex() const;
|
uint32_t SkiaGLTex() const;
|
||||||
|
|
||||||
// This observes our draw calls at the beginning of the canvas
|
// This observes our draw calls at the beginning of the canvas
|
||||||
|
|
|
@ -27,6 +27,7 @@ MediaTaskQueue::~MediaTaskQueue()
|
||||||
{
|
{
|
||||||
MonitorAutoLock mon(mQueueMonitor);
|
MonitorAutoLock mon(mQueueMonitor);
|
||||||
MOZ_ASSERT(mIsShutdown);
|
MOZ_ASSERT(mIsShutdown);
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(mTasks.empty());
|
||||||
MOZ_COUNT_DTOR(MediaTaskQueue);
|
MOZ_COUNT_DTOR(MediaTaskQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
gfx/2d/2D.h
12
gfx/2d/2D.h
|
@ -155,7 +155,7 @@ struct DrawSurfaceOptions {
|
||||||
* matching DrawTarget. Not adhering to this condition will make a draw call
|
* matching DrawTarget. Not adhering to this condition will make a draw call
|
||||||
* fail.
|
* fail.
|
||||||
*/
|
*/
|
||||||
class GradientStops : public RefCounted<GradientStops>
|
class GradientStops : public external::AtomicRefCounted<GradientStops>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStops)
|
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStops)
|
||||||
|
@ -318,7 +318,7 @@ class DrawTargetCaptureImpl;
|
||||||
* which may be used as a source in a SurfacePattern or a DrawSurface call.
|
* which may be used as a source in a SurfacePattern or a DrawSurface call.
|
||||||
* They cannot be drawn to directly.
|
* They cannot be drawn to directly.
|
||||||
*/
|
*/
|
||||||
class SourceSurface : public RefCounted<SourceSurface>
|
class SourceSurface : public external::AtomicRefCounted<SourceSurface>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurface)
|
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurface)
|
||||||
|
@ -476,7 +476,7 @@ class FlattenedPath;
|
||||||
/** The path class is used to create (sets of) figures of any shape that can be
|
/** The path class is used to create (sets of) figures of any shape that can be
|
||||||
* filled or stroked to a DrawTarget
|
* filled or stroked to a DrawTarget
|
||||||
*/
|
*/
|
||||||
class Path : public RefCounted<Path>
|
class Path : public external::AtomicRefCounted<Path>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(Path)
|
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(Path)
|
||||||
|
@ -577,7 +577,7 @@ struct GlyphBuffer
|
||||||
* at a particular size. It is passed into text drawing calls to describe
|
* at a particular size. It is passed into text drawing calls to describe
|
||||||
* the font used for the drawing call.
|
* the font used for the drawing call.
|
||||||
*/
|
*/
|
||||||
class ScaledFont : public RefCounted<ScaledFont>
|
class ScaledFont : public external::AtomicRefCounted<ScaledFont>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFont)
|
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFont)
|
||||||
|
@ -622,7 +622,7 @@ protected:
|
||||||
* parameters. This is because different platforms have unique rendering
|
* parameters. This is because different platforms have unique rendering
|
||||||
* parameters.
|
* parameters.
|
||||||
*/
|
*/
|
||||||
class GlyphRenderingOptions : public RefCounted<GlyphRenderingOptions>
|
class GlyphRenderingOptions : public external::AtomicRefCounted<GlyphRenderingOptions>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GlyphRenderingOptions)
|
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GlyphRenderingOptions)
|
||||||
|
@ -641,7 +641,7 @@ class DrawTargetCapture;
|
||||||
* may be used either through a Snapshot or by flushing the target and directly
|
* may be used either through a Snapshot or by flushing the target and directly
|
||||||
* accessing the backing store a DrawTarget was created with.
|
* accessing the backing store a DrawTarget was created with.
|
||||||
*/
|
*/
|
||||||
class DrawTarget : public RefCounted<DrawTarget>
|
class DrawTarget : public external::AtomicRefCounted<DrawTarget>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTarget)
|
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTarget)
|
||||||
|
|
|
@ -148,7 +148,7 @@ class DrawFilterCommand : public DrawingCommand
|
||||||
public:
|
public:
|
||||||
DrawFilterCommand(FilterNode* aFilter, const Rect& aSourceRect,
|
DrawFilterCommand(FilterNode* aFilter, const Rect& aSourceRect,
|
||||||
const Point& aDestPoint, const DrawOptions& aOptions)
|
const Point& aDestPoint, const DrawOptions& aOptions)
|
||||||
: DrawingCommand(CommandType::DRAWSURFACE)
|
: DrawingCommand(CommandType::DRAWFILTER)
|
||||||
, mFilter(aFilter), mSourceRect(aSourceRect)
|
, mFilter(aFilter), mSourceRect(aSourceRect)
|
||||||
, mDestPoint(aDestPoint), mOptions(aOptions)
|
, mDestPoint(aDestPoint), mOptions(aOptions)
|
||||||
{
|
{
|
||||||
|
@ -166,6 +166,36 @@ private:
|
||||||
DrawOptions mOptions;
|
DrawOptions mOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DrawSurfaceWithShadowCommand : public DrawingCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DrawSurfaceWithShadowCommand(SourceSurface* aSurface, const Point& aDest,
|
||||||
|
const Color& aColor, const Point& aOffset,
|
||||||
|
Float aSigma, CompositionOp aOperator)
|
||||||
|
: DrawingCommand(CommandType::DRAWSURFACEWITHSHADOW)
|
||||||
|
, mSurface(aSurface)
|
||||||
|
, mDest(aDest)
|
||||||
|
, mColor(aColor)
|
||||||
|
, mOffset(aOffset)
|
||||||
|
, mSigma(aSigma)
|
||||||
|
, mOperator(aOperator)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&)
|
||||||
|
{
|
||||||
|
aDT->DrawSurfaceWithShadow(mSurface, mDest, mColor, mOffset, mSigma, mOperator);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
RefPtr<SourceSurface> mSurface;
|
||||||
|
Point mDest;
|
||||||
|
Color mColor;
|
||||||
|
Point mOffset;
|
||||||
|
Float mSigma;
|
||||||
|
CompositionOp mOperator;
|
||||||
|
};
|
||||||
|
|
||||||
class ClearRectCommand : public DrawingCommand
|
class ClearRectCommand : public DrawingCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -30,6 +30,7 @@ DrawTargetCaptureImpl::Init(const IntSize& aSize, DrawTarget* aRefDT)
|
||||||
}
|
}
|
||||||
|
|
||||||
mRefDT = aRefDT;
|
mRefDT = aRefDT;
|
||||||
|
mFormat = mRefDT->GetFormat();
|
||||||
|
|
||||||
mSize = aSize;
|
mSize = aSize;
|
||||||
return true;
|
return true;
|
||||||
|
@ -69,6 +70,18 @@ DrawTargetCaptureImpl::DrawFilter(FilterNode *aNode,
|
||||||
AppendCommand(DrawFilterCommand)(aNode, aSourceRect, aDestPoint, aOptions);
|
AppendCommand(DrawFilterCommand)(aNode, aSourceRect, aDestPoint, aOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DrawTargetCaptureImpl::DrawSurfaceWithShadow(SourceSurface *aSurface,
|
||||||
|
const Point &aDest,
|
||||||
|
const Color &aColor,
|
||||||
|
const Point &aOffset,
|
||||||
|
Float aSigma,
|
||||||
|
CompositionOp aOperator)
|
||||||
|
{
|
||||||
|
aSurface->GuaranteePersistance();
|
||||||
|
AppendCommand(DrawSurfaceWithShadowCommand)(aSurface, aDest, aColor, aOffset, aSigma, aOperator);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DrawTargetCaptureImpl::ClearRect(const Rect &aRect)
|
DrawTargetCaptureImpl::ClearRect(const Rect &aRect)
|
||||||
{
|
{
|
||||||
|
@ -178,6 +191,7 @@ void
|
||||||
DrawTargetCaptureImpl::SetTransform(const Matrix& aTransform)
|
DrawTargetCaptureImpl::SetTransform(const Matrix& aTransform)
|
||||||
{
|
{
|
||||||
AppendCommand(SetTransformCommand)(aTransform);
|
AppendCommand(SetTransformCommand)(aTransform);
|
||||||
|
mTransform = aTransform;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -45,7 +45,7 @@ public:
|
||||||
const Color &aColor,
|
const Color &aColor,
|
||||||
const Point &aOffset,
|
const Point &aOffset,
|
||||||
Float aSigma,
|
Float aSigma,
|
||||||
CompositionOp aOperator) { /* Not implemented */ }
|
CompositionOp aOperator);
|
||||||
|
|
||||||
virtual void ClearRect(const Rect &aRect);
|
virtual void ClearRect(const Rect &aRect);
|
||||||
virtual void MaskSurface(const Pattern &aSource,
|
virtual void MaskSurface(const Pattern &aSource,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче