Bug 902651 - Restore the DrawTarget transform and clip when demoting r=mattwoodrow,bz

--HG--
rename : browser/config/mozconfigs/win64/common-opt => browser/config/mozconfigs/win64/nightly
extra : rebase_source : 1f1438d54fb97935c9186b69afc37a5d17028dbb
This commit is contained in:
James Willcox 2013-08-23 09:52:32 -04:00
parent acc11a83aa
commit 4ffb1a14bf
5 changed files with 80 additions and 14 deletions

View File

@ -547,7 +547,7 @@ CanvasRenderingContext2D::CanvasRenderingContext2D()
sNumLivingContexts++;
SetIsDOMBinding();
#if USE_SKIA_GPU
#ifdef USE_SKIA_GPU
mForceSoftware = false;
#endif
}
@ -564,10 +564,8 @@ CanvasRenderingContext2D::~CanvasRenderingContext2D()
NS_IF_RELEASE(sErrorTarget);
}
#if USE_SKIA_GPU
std::vector<CanvasRenderingContext2D*>::iterator iter = std::find(DemotableContexts().begin(), DemotableContexts().end(), this);
if (iter != DemotableContexts().end())
DemotableContexts().erase(iter);
#ifdef USE_SKIA_GPU
RemoveDemotableContext(this);
#endif
}
@ -746,13 +744,14 @@ CanvasRenderingContext2D::RedrawUser(const gfxRect& r)
Redraw(newr);
}
#if USE_SKIA_GPU
void CanvasRenderingContext2D::Demote()
{
#ifdef USE_SKIA_GPU
if (!IsTargetValid() || mForceSoftware)
return;
RemoveDemotableContext(this);
RefPtr<SourceSurface> snapshot = mTarget->Snapshot();
RefPtr<DrawTarget> oldTarget = mTarget;
mTarget = nullptr;
@ -764,11 +763,21 @@ void CanvasRenderingContext2D::Demote()
if (!IsTargetValid())
return;
// Put back the content from the old DrawTarget
// Restore the content from the old DrawTarget
mgfx::Rect r(0, 0, mWidth, mHeight);
mTarget->DrawSurface(snapshot, r, r);
// Restore the clips and transform
for (uint32_t i = 0; i < CurrentState().clipsPushed.size(); i++) {
mTarget->PushClip(CurrentState().clipsPushed[i]);
}
mTarget->SetTransform(oldTarget->GetTransform());
#endif
}
#ifdef USE_SKIA_GPU
std::vector<CanvasRenderingContext2D*>&
CanvasRenderingContext2D::DemotableContexts()
{
@ -790,8 +799,6 @@ CanvasRenderingContext2D::DemoteOldestContextIfNecessary()
return;
CanvasRenderingContext2D* oldest = contexts.front();
contexts.erase(contexts.begin());
oldest->Demote();
}
@ -805,6 +812,14 @@ CanvasRenderingContext2D::AddDemotableContext(CanvasRenderingContext2D* context)
DemotableContexts().push_back(context);
}
void
CanvasRenderingContext2D::RemoveDemotableContext(CanvasRenderingContext2D* context)
{
std::vector<CanvasRenderingContext2D*>::iterator iter = std::find(DemotableContexts().begin(), DemotableContexts().end(), context);
if (iter != DemotableContexts().end())
DemotableContexts().erase(iter);
}
#define MIN_SKIA_GL_DIMENSION 16
bool

View File

@ -367,6 +367,8 @@ public:
double h, const nsAString& bgColor, uint32_t flags,
mozilla::ErrorResult& error);
void Demote();
nsresult Redraw();
// nsICanvasRenderingContextInternal
@ -567,13 +569,11 @@ protected:
}
#if USE_SKIA_GPU
// Recreate the DrawTarget in software mode
void Demote();
static std::vector<CanvasRenderingContext2D*>& DemotableContexts();
static void DemoteOldestContextIfNecessary();
static void AddDemotableContext(CanvasRenderingContext2D* context);
static void RemoveDemotableContext(CanvasRenderingContext2D* context);
// Do not use GL
bool mForceSoftware;

View File

@ -88,6 +88,7 @@ MOCHITEST_FILES = \
file_drawImage_document_domain.html \
test_windingRuleUndefined.html \
test_strokeText_throw.html \
test_bug902651.html \
$(NULL)
# SkiaGL on Android/Gonk does not implement these composite ops yet

View File

@ -0,0 +1,44 @@
<!DOCTYPE HTML>
<title>Canvas test: canvas demotion</title>
<script src="/MochiKit/MochiKit.js"></script>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
<body>
<canvas id="c" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
<script>
SimpleTest.waitForExplicitFinish();
addLoadEvent(function () {
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgb(50, 50, 50)';
ctx.fillRect(0, 0, 100, 50);
ctx.translate(25, 25);
SpecialPowers.wrap(ctx).demote();
setTimeout(function() {
ctx.fillStyle = 'rgb(127, 127, 127)';
ctx.fillRect(0, 0, 10, 10);
var pixels = ctx.getImageData(0, 0, 1, 1);
ok(pixels.data[0] === 50, "pixels.data[0] expected 50, got " + pixels.data[0]);
ok(pixels.data[1] === 50, "pixels.data[1] expected 50, got " + pixels.data[1]);
ok(pixels.data[2] === 50, "pixels.data[2] expected 50, got " + pixels.data[2]);
pixels = ctx.getImageData(25, 25, 1, 1);
ok(pixels.data[0] === 127, "pixels.data[0] expected 127, got " + pixels.data[0]);
ok(pixels.data[1] === 127, "pixels.data[1] expected 127, got " + pixels.data[1]);
ok(pixels.data[2] === 127, "pixels.data[2] expected 127, got " + pixels.data[2]);
SimpleTest.finish();
}, 50);
});
</script>

View File

@ -207,6 +207,12 @@ interface CanvasRenderingContext2D {
void asyncDrawXULElement(XULElement elem, double x, double y, double w,
double h, DOMString bgColor,
optional unsigned long flags = 0);
/**
* This causes a context that is currently using a hardware-accelerated
* backend to fallback to a software one. All state should be preserved.
*/
[ChromeOnly]
void demote();
};
CanvasRenderingContext2D implements CanvasDrawingStyles;
CanvasRenderingContext2D implements CanvasPathMethods;