Bug 1362321 - Do not crash in gfxPlatform:Init if there is a TDR happening; r?bas
MozReview-Commit-ID: 9gJCErHosg1
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -6376,18 +6376,19 @@ CanvasPath::Constructor(const GlobalObje
{
RefPtr<CanvasPath> path = new CanvasPath(aGlobal.GetAsSupports());
return path.forget();
}
already_AddRefed<CanvasPath>
CanvasPath::Constructor(const GlobalObject& aGlobal, CanvasPath& aCanvasPath, ErrorResult& aRv)
{
- RefPtr<gfx::Path> tempPath = aCanvasPath.GetPath(CanvasWindingRule::Nonzero,
- gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget());
+ RefPtr<gfx::Path> tempPath = aCanvasPath.GetPath(
+ CanvasWindingRule::Nonzero,
+ gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget().get());
RefPtr<CanvasPath> path = new CanvasPath(aGlobal.GetAsSupports(), tempPath->CopyToBuilder());
return path.forget();
}
already_AddRefed<CanvasPath>
CanvasPath::Constructor(const GlobalObject& aGlobal, const nsAString& aPathString, ErrorResult& aRv)
{
@@ -6566,18 +6567,19 @@ CanvasPath::BezierTo(const gfx::Point& a
EnsurePathBuilder();
mPathBuilder->BezierTo(aCP1, aCP2, aCP3);
}
void
CanvasPath::AddPath(CanvasPath& aCanvasPath, const Optional<NonNull<SVGMatrix>>& aMatrix)
{
- RefPtr<gfx::Path> tempPath = aCanvasPath.GetPath(CanvasWindingRule::Nonzero,
- gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget());
+ RefPtr<gfx::Path> tempPath = aCanvasPath.GetPath(
+ CanvasWindingRule::Nonzero,
+ gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget().get());
if (aMatrix.WasPassed()) {
const SVGMatrix& m = aMatrix.Value();
Matrix transform(m.A(), m.B(), m.C(), m.D(), m.E(), m.F());
if (!transform.IsIdentity()) {
RefPtr<PathBuilder> tempBuilder = tempPath->TransformedCopyToBuilder(transform, FillRule::FILL_WINDING);
tempPath = tempBuilder->Finish();
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -762,17 +762,22 @@ gfxPlatform::Init()
MOZ_CRASH("Could not initialize mScreenReferenceSurface");
}
gPlatform->mScreenReferenceDrawTarget =
gPlatform->CreateOffscreenContentDrawTarget(IntSize(1, 1),
SurfaceFormat::B8G8R8A8);
if (!gPlatform->mScreenReferenceDrawTarget ||
!gPlatform->mScreenReferenceDrawTarget->IsValid()) {
- MOZ_CRASH("Could not initialize mScreenReferenceDrawTarget");
+ // If TDR is detected, create a draw target with software backend
+ // and it should be replaced later when the process gets the device
+ // reset notification.
+ if (!gPlatform->DidRenderingDeviceReset()) {
+ gfxCriticalError() << "Could not initialize mScreenReferenceDrawTarget";
+ }
}
rv = gfxFontCache::Init();
if (NS_FAILED(rv)) {
MOZ_CRASH("Could not initialize gfxFontCache");
}
#ifdef MOZ_ENABLE_FREETYPE
@@ -1124,18 +1129,18 @@ void SourceSurfaceDestroyed(void *aData)
void
gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface *aSurface)
{
aSurface->SetData(&kSourceSurface, nullptr, nullptr);
}
/* static */ already_AddRefed<SourceSurface>
-gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget,
- gfxASurface *aSurface,
+gfxPlatform::GetSourceSurfaceForSurface(RefPtr<DrawTarget> aTarget,
+ gfxASurface* aSurface,
bool aIsPlugin)
{
if (!aSurface->CairoSurface() || aSurface->CairoStatus()) {
return nullptr;
}
if (!aTarget) {
aTarget = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
@@ -1507,20 +1512,23 @@ gfxPlatform::CreateOffscreenCanvasDrawTa
// On Windows, the fallback backend (Cairo) should use its image backend.
return Factory::CreateDrawTarget(mFallbackCanvasBackend, aSize, aFormat);
#else
return CreateDrawTargetForBackend(mFallbackCanvasBackend, aSize, aFormat);
#endif
}
already_AddRefed<DrawTarget>
-gfxPlatform::CreateOffscreenContentDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
+gfxPlatform::CreateOffscreenContentDrawTarget(const IntSize& aSize,
+ SurfaceFormat aFormat,
+ bool aFallback)
{
- NS_ASSERTION(mContentBackend != BackendType::NONE, "No backend.");
- return CreateDrawTargetForBackend(mContentBackend, aSize, aFormat);
+ BackendType backend = (aFallback) ? mSoftwareBackend : mContentBackend;
+ NS_ASSERTION(backend != BackendType::NONE, "No backend.");
+ return CreateDrawTargetForBackend(backend, aSize, aFormat);
}
already_AddRefed<DrawTarget>
gfxPlatform::CreateSimilarSoftwareDrawTarget(DrawTarget* aDT,
const IntSize& aSize,
SurfaceFormat aFormat)
{
RefPtr<DrawTarget> dt;
@@ -2188,16 +2196,25 @@ gfxPlatform::GetLog(eGfxLog aWhichLog)
case eGfxLog_textperf:
return sTextPerfLog;
}
MOZ_ASSERT_UNREACHABLE("Unexpected log type");
return nullptr;
}
+RefPtr<mozilla::gfx::DrawTarget>
+gfxPlatform::ScreenReferenceDrawTarget()
+{
+ return (mScreenReferenceDrawTarget)
+ ? mScreenReferenceDrawTarget
+ : gPlatform->CreateOffscreenContentDrawTarget(
+ IntSize(1, 1), SurfaceFormat::B8G8R8A8, true);
+}
+
mozilla::gfx::SurfaceFormat
gfxPlatform::Optimal2DFormatForContent(gfxContentType aContent)
{
switch (aContent) {
case gfxContentType::COLOR:
switch (GetOffscreenFormat()) {
case SurfaceFormat::A8R8G8B8_UINT32:
return mozilla::gfx::SurfaceFormat::B8G8R8A8;
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -224,28 +224,30 @@ public:
*
* This function is static so that it can be accessed from
* PluginInstanceChild (where we can't call gfxPlatform::GetPlatform()
* because the prefs service can only be accessed from the main process).
*
* aIsPlugin is used to tell the backend that they can optimize this surface
* specifically because it's used for a plugin. This is mostly for Skia.
*/
- static already_AddRefed<SourceSurface>
- GetSourceSurfaceForSurface(mozilla::gfx::DrawTarget *aTarget,
- gfxASurface *aSurface,
- bool aIsPlugin = false);
+ static already_AddRefed<SourceSurface> GetSourceSurfaceForSurface(
+ RefPtr<mozilla::gfx::DrawTarget> aTarget,
+ gfxASurface* aSurface,
+ bool aIsPlugin = false);
static void ClearSourceSurfaceForSurface(gfxASurface *aSurface);
static already_AddRefed<DataSourceSurface>
GetWrappedDataSourceSurface(gfxASurface *aSurface);
- already_AddRefed<DrawTarget>
- CreateOffscreenContentDrawTarget(const mozilla::gfx::IntSize& aSize, mozilla::gfx::SurfaceFormat aFormat);
+ already_AddRefed<DrawTarget> CreateOffscreenContentDrawTarget(
+ const mozilla::gfx::IntSize& aSize,
+ mozilla::gfx::SurfaceFormat aFormat,
+ bool aFallback = false);
already_AddRefed<DrawTarget>
CreateOffscreenCanvasDrawTarget(const mozilla::gfx::IntSize& aSize, mozilla::gfx::SurfaceFormat aFormat);
already_AddRefed<DrawTarget>
CreateSimilarSoftwareDrawTarget(DrawTarget* aDT, const IntSize &aSize, mozilla::gfx::SurfaceFormat aFormat);
static already_AddRefed<DrawTarget>
@@ -564,17 +566,17 @@ public:
*/
gfxASurface* ScreenReferenceSurface() { return mScreenReferenceSurface; }
/**
* Returns a 1x1 DrawTarget that can be used for measuring text etc. as
* it would measure if rendered on-screen. Guaranteed to return a
* non-null and valid DrawTarget.
*/
- mozilla::gfx::DrawTarget* ScreenReferenceDrawTarget() { return mScreenReferenceDrawTarget; }
+ RefPtr<mozilla::gfx::DrawTarget> ScreenReferenceDrawTarget();
virtual mozilla::gfx::SurfaceFormat Optimal2DFormatForContent(gfxContentType aContent);
virtual gfxImageFormat OptimalFormatForContent(gfxContentType aContent);
virtual gfxImageFormat GetOffscreenFormat()
{ return mozilla::gfx::SurfaceFormat::X8R8G8B8_UINT32; }
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -3032,17 +3032,18 @@ PresShell::ClearFrameRefs(nsIFrame* aFra
}
already_AddRefed<gfxContext>
PresShell::CreateReferenceRenderingContext()
{
nsDeviceContext* devCtx = mPresContext->DeviceContext();
RefPtr<gfxContext> rc;
if (mPresContext->IsScreen()) {
- rc = gfxContext::CreateOrNull(gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget());
+ rc = gfxContext::CreateOrNull(
+ gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget().get());
} else {
// We assume the devCtx has positive width and height for this call.
// However, width and height, may be outside of the reasonable range
// so rc may still be null.
rc = devCtx->CreateReferenceRenderingContext();
}
return rc ? rc.forget() : nullptr;
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -7300,17 +7300,19 @@ nsLayoutUtils::SurfaceFromOffscreenCanva
nsIntSize size = aOffscreenCanvas->GetWidthHeight();
result.mSourceSurface = aOffscreenCanvas->GetSurfaceSnapshot(&result.mAlphaType);
if (!result.mSourceSurface) {
// If the element doesn't have a context then we won't get a snapshot. The canvas spec wants us to not error and just
// draw nothing, so return an empty surface.
result.mAlphaType = gfxAlphaType::Opaque;
- DrawTarget *ref = aTarget ? aTarget.get() : gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
+ RefPtr<DrawTarget> ref =
+ aTarget ? aTarget
+ : gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
RefPtr<DrawTarget> dt = ref->CreateSimilarDrawTarget(IntSize(size.width, size.height),
SurfaceFormat::B8G8R8A8);
if (dt) {
result.mSourceSurface = dt->Snapshot();
}
} else if (aTarget) {
RefPtr<SourceSurface> opt = aTarget->OptimizeSourceSurface(result.mSourceSurface);
if (opt) {
@@ -7468,17 +7470,19 @@ nsLayoutUtils::SurfaceFromElement(HTMLCa
IntSize size = aElement->GetSize();
result.mSourceSurface = aElement->GetSurfaceSnapshot(&result.mAlphaType);
if (!result.mSourceSurface) {
// If the element doesn't have a context then we won't get a snapshot. The canvas spec wants us to not error and just
// draw nothing, so return an empty surface.
result.mAlphaType = gfxAlphaType::Opaque;
- DrawTarget *ref = aTarget ? aTarget.get() : gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
+ RefPtr<DrawTarget> ref =
+ aTarget ? aTarget
+ : gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
RefPtr<DrawTarget> dt = ref->CreateSimilarDrawTarget(IntSize(size.width, size.height),
SurfaceFormat::B8G8R8A8);
if (dt) {
result.mSourceSurface = dt->Snapshot();
}
} else if (aTarget) {
RefPtr<SourceSurface> opt = aTarget->OptimizeSourceSurface(result.mSourceSurface);
if (opt) {
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -612,19 +612,18 @@ protected:
LayerState
nsDisplayBullet::GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aParameters)
{
if (!ShouldUseAdvancedLayer(aManager, gfxPrefs::LayersAllowBulletLayers)) {
return LAYER_NONE;
}
-
- RefPtr<gfxContext> screenRefCtx =
- gfxContext::CreateOrNull(gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget());
+ RefPtr<gfxContext> screenRefCtx = gfxContext::CreateOrNull(
+ gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget().get());
Maybe<BulletRenderer> br = static_cast<nsBulletFrame*>(mFrame)->
CreateBulletRenderer(*screenRefCtx, ToReferenceFrame());
if (!br) {
return LAYER_NONE;
}
--- a/layout/generic/nsColumnSetFrame.cpp
+++ b/layout/generic/nsColumnSetFrame.cpp
@@ -71,19 +71,18 @@ nsDisplayColumnRule::Paint(nsDisplayList
LayerState
nsDisplayColumnRule::GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aParameters)
{
if (!gfxPrefs::LayersAllowColumnRuleLayers()) {
return LAYER_NONE;
}
-
- RefPtr<gfxContext> screenRefCtx =
- gfxContext::CreateOrNull(gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget());
+ RefPtr<gfxContext> screenRefCtx = gfxContext::CreateOrNull(
+ gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget().get());
static_cast<nsColumnSetFrame*>(mFrame)->
CreateBorderRenderers(mBorderRenderers, screenRefCtx, mVisibleRect, ToReferenceFrame());
if (mBorderRenderers.IsEmpty()) {
return LAYER_NONE;
}
@@ -107,18 +106,18 @@ nsDisplayColumnRule::BuildLayer(nsDispla
bool
nsDisplayColumnRule::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
const StackingContextHelper& aSc,
nsTArray<WebRenderParentCommand>& aParentCommands,
mozilla::layers::WebRenderLayerManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder)
{
if (aManager->IsLayersFreeTransaction()) {
- RefPtr<gfxContext> screenRefCtx =
- gfxContext::CreateOrNull(gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget());
+ RefPtr<gfxContext> screenRefCtx = gfxContext::CreateOrNull(
+ gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget().get());
static_cast<nsColumnSetFrame*>(mFrame)->
CreateBorderRenderers(mBorderRenderers, screenRefCtx, mVisibleRect, ToReferenceFrame());
if (mBorderRenderers.IsEmpty()) {
return false;
}