mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-02 15:15:23 +00:00
Merging changes
This commit is contained in:
commit
b03fa69756
@ -50,6 +50,7 @@ MOCHITEST_FILES = \
|
||||
test_2d.composite.uncovered.image.source-out.html \
|
||||
test_2d.drawImage.zerocanvas.html \
|
||||
test_2d.strokeRect.zero.5.html \
|
||||
test_toBlob.html \
|
||||
test_toDataURL_alpha.html \
|
||||
test_toDataURL_lowercase_ascii.html \
|
||||
test_toDataURL_parameters.html \
|
||||
|
42
content/canvas/test/test_toBlob.html
Normal file
42
content/canvas/test/test_toBlob.html
Normal file
@ -0,0 +1,42 @@
|
||||
<!DOCTYPE HTML>
|
||||
<title>Canvas test: mozGetAsFile</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>
|
||||
|
||||
var gCompares = 2;
|
||||
|
||||
function BlobListener(type, canvas, file)
|
||||
{
|
||||
is(file.type, type,
|
||||
"When a valid type is specified that should be returned");
|
||||
var reader = new FileReader();
|
||||
reader.onload =
|
||||
function(e) {
|
||||
is(e.target.result, canvas.toDataURL(type),
|
||||
"<canvas>.mozGetAsFile().getAsDataURL() should equal <canvas>.toDataURL()");
|
||||
if (--gCompares == 0) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(function () {
|
||||
|
||||
var canvas = document.getElementById('c');
|
||||
var ctx = canvas.getContext('2d');
|
||||
|
||||
ctx.drawImage(document.getElementById('yellow75.png'), 0, 0);
|
||||
|
||||
canvas.toBlob(BlobListener.bind(undefined, "image/png", canvas));
|
||||
canvas.toBlob(BlobListener.bind(undefined, "image/jpeg", canvas), "image/jpeg");
|
||||
|
||||
});
|
||||
</script>
|
||||
<img src="image_yellow75.png" id="yellow75.png" class="resource">
|
||||
|
@ -40,6 +40,32 @@ using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::layers;
|
||||
|
||||
namespace {
|
||||
|
||||
class ToBlobRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ToBlobRunnable(nsIFileCallback* aCallback,
|
||||
nsIDOMBlob* aBlob)
|
||||
: mCallback(aCallback),
|
||||
mBlob(aBlob)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
mCallback->Receive(mBlob);
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
nsCOMPtr<nsIFileCallback> mCallback;
|
||||
nsCOMPtr<nsIDOMBlob> mBlob;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class nsHTMLCanvasPrintState : public nsIDOMMozCanvasPrintState
|
||||
{
|
||||
public:
|
||||
@ -550,6 +576,52 @@ nsHTMLCanvasElement::ToDataURLImpl(const nsAString& aMimeType,
|
||||
return Base64EncodeInputStream(stream, aDataURL, (uint32_t)count, aDataURL.Length());
|
||||
}
|
||||
|
||||
// XXXkhuey the encoding should be off the main thread, but we're lazy.
|
||||
NS_IMETHODIMP
|
||||
nsHTMLCanvasElement::ToBlob(nsIFileCallback* aCallback,
|
||||
const nsAString& aType,
|
||||
nsIVariant* aParams,
|
||||
uint8_t optional_argc)
|
||||
{
|
||||
// do a trust check if this is a write-only canvas
|
||||
if (mWriteOnly && !nsContentUtils::IsCallerTrustedForRead()) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
nsAutoString type;
|
||||
nsresult rv = nsContentUtils::ASCIIToLower(aType, type);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool fallbackToPNG = false;
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
nsresult rv = ExtractData(type, EmptyString(), getter_AddRefs(stream),
|
||||
fallbackToPNG);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (fallbackToPNG) {
|
||||
type.AssignLiteral("image/png");
|
||||
}
|
||||
|
||||
uint64_t imgSize;
|
||||
rv = stream->Available(&imgSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(imgSize <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
|
||||
|
||||
void* imgData = nullptr;
|
||||
rv = NS_ReadInputStreamToBuffer(stream, &imgData, imgSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// The DOMFile takes ownership of the buffer
|
||||
nsRefPtr<nsDOMMemoryFile> blob =
|
||||
new nsDOMMemoryFile(imgData, imgSize, type);
|
||||
|
||||
nsRefPtr<ToBlobRunnable> runnable = new ToBlobRunnable(aCallback, blob);
|
||||
return NS_DispatchToCurrentThread(runnable);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLCanvasElement::MozGetAsFile(const nsAString& aName,
|
||||
const nsAString& aType,
|
||||
|
@ -20,6 +20,7 @@
|
||||
* @status UNDER_DEVELOPMENT
|
||||
*/
|
||||
|
||||
interface nsIDOMBlob;
|
||||
interface nsIDOMFile;
|
||||
interface nsIVariant;
|
||||
interface nsIInputStreamCallback;
|
||||
@ -40,6 +41,11 @@ interface nsIPrintCallback : nsISupports
|
||||
void render(in nsIDOMMozCanvasPrintState ctx);
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(6e9ffb59-2067-4aef-a51c-65e65a3e0d81)]
|
||||
interface nsIFileCallback : nsISupports {
|
||||
void receive(in nsIDOMBlob file);
|
||||
};
|
||||
|
||||
[scriptable, uuid(a7062fca-41c6-4520-b777-3bb30fd77273)]
|
||||
interface nsIDOMHTMLCanvasElement : nsIDOMHTMLElement
|
||||
{
|
||||
@ -64,6 +70,10 @@ interface nsIDOMHTMLCanvasElement : nsIDOMHTMLElement
|
||||
[optional_argc] nsIDOMFile mozGetAsFile(in DOMString name,
|
||||
[optional] in DOMString type);
|
||||
|
||||
[optional_argc] void toBlob(in nsIFileCallback callback,
|
||||
[optional] in DOMString type,
|
||||
[optional] in nsIVariant params);
|
||||
|
||||
// A Mozilla-only extension to get a canvas context backed by double-buffered
|
||||
// shared memory. Only privileged callers can call this.
|
||||
nsISupports MozGetIPCContext(in DOMString contextId);
|
||||
|
@ -263,12 +263,6 @@ BasicTiledThebesLayer::PaintThebes(gfxContext* aContext,
|
||||
resolution.height *= metrics.mResolution.height;
|
||||
}
|
||||
|
||||
// If the resolution has changed, discard all the old tiles.
|
||||
// They will end up being retained on the shadow side by ReusableTileStoreOGL
|
||||
if (mTiledBuffer.GetResolution() != resolution) {
|
||||
mValidRegion = nsIntRegion();
|
||||
}
|
||||
|
||||
// Calculate the scroll offset since the last transaction. Progressive tile
|
||||
// painting is only used when scrolling.
|
||||
gfx::Point scrollOffset(0, 0);
|
||||
|
@ -59,19 +59,33 @@ ReusableTileStoreOGL::InvalidateTiles(TiledThebesLayerOGL* aLayer,
|
||||
mContext->MakeCurrent();
|
||||
for (uint32_t i = 0; i < mTiles.Length();) {
|
||||
ReusableTiledTextureOGL* tile = mTiles[i];
|
||||
bool release = false;
|
||||
|
||||
nsIntRect tileRect = tile->mTileRegion.GetBounds();
|
||||
if (tile->mResolution != aResolution) {
|
||||
// Check if the tile region is contained within the new valid region.
|
||||
nsIntRect tileRect;
|
||||
bool release = false;
|
||||
if (tile->mResolution == aResolution) {
|
||||
if (aValidRegion.Contains(tile->mTileRegion)) {
|
||||
release = true;
|
||||
} else {
|
||||
tileRect = tile->mTileRegion.GetBounds();
|
||||
}
|
||||
} else {
|
||||
nsIntRegion transformedTileRegion(tile->mTileRegion);
|
||||
transformedTileRegion.ScaleRoundOut(tile->mResolution.width / aResolution.width,
|
||||
tile->mResolution.height / aResolution.height);
|
||||
tileRect = transformedTileRegion.GetBounds();
|
||||
if (aValidRegion.Contains(transformedTileRegion))
|
||||
release = true;
|
||||
else
|
||||
tileRect = transformedTileRegion.GetBounds();
|
||||
}
|
||||
|
||||
// Check if the tile region is contained within the new valid region.
|
||||
if (aValidRegion.Contains(tileRect)) {
|
||||
release = true;
|
||||
// If the tile region wasn't contained within the valid region, check if
|
||||
// it intersects with the currently rendered region.
|
||||
if (!release) {
|
||||
// Transform the tile region to see if it falls inside the rendered bounds
|
||||
gfxRect tileBounds = aLayer->GetEffectiveTransform().TransformBounds(gfxRect(tileRect));
|
||||
if (renderBounds.Contains(tileBounds))
|
||||
release = true;
|
||||
}
|
||||
|
||||
if (release) {
|
||||
@ -117,24 +131,11 @@ ReusableTileStoreOGL::HarvestTiles(TiledThebesLayerOGL* aLayer,
|
||||
if (x + w > validBounds.x + validBounds.width)
|
||||
w = validBounds.x + validBounds.width - x;
|
||||
|
||||
// A tile will consume 256^2 of memory, don't retain small tile trims.
|
||||
// This works around the display port sometimes creating a small 1 pixel wide
|
||||
// tile because of rounding error.
|
||||
if (w < 16) {
|
||||
x += w;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int y = validBounds.y; y < validBounds.YMost();) {
|
||||
int h = tileSize - aVideoMemoryTiledBuffer->GetTileStart(y);
|
||||
if (y + h > validBounds.y + validBounds.height)
|
||||
h = validBounds.y + validBounds.height - y;
|
||||
|
||||
if (h < 16) {
|
||||
y += h;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the new valid region doesn't contain this tile region,
|
||||
// harvest the tile.
|
||||
nsIntRegion tileRegion;
|
||||
@ -156,40 +157,15 @@ ReusableTileStoreOGL::HarvestTiles(TiledThebesLayerOGL* aLayer,
|
||||
}
|
||||
|
||||
if (retainTile) {
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
printf_stderr("Retaining tile at %d,%d, x%f for reuse\n", x, y, aOldResolution.width);
|
||||
#endif
|
||||
TiledTexture removedTile;
|
||||
if (aVideoMemoryTiledBuffer->RemoveTile(nsIntPoint(x, y), removedTile)) {
|
||||
ReusableTiledTextureOGL* reusedTile =
|
||||
new ReusableTiledTextureOGL(removedTile, nsIntPoint(x, y), tileRegion,
|
||||
tileSize, aOldResolution);
|
||||
mTiles.AppendElement(reusedTile);
|
||||
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
bool replacedATile = false;
|
||||
#endif
|
||||
// Remove any tile that is superseded by this new tile.
|
||||
// (same resolution, same area)
|
||||
for (int i = 0; i < mTiles.Length() - 1; i++) {
|
||||
// XXX Perhaps we should check the region instead of the origin
|
||||
// so a partial tile doesn't replace a full older tile?
|
||||
if (aVideoMemoryTiledBuffer->RoundDownToTileEdge(mTiles[i]->mTileOrigin.x) == aVideoMemoryTiledBuffer->RoundDownToTileEdge(x) &&
|
||||
aVideoMemoryTiledBuffer->RoundDownToTileEdge(mTiles[i]->mTileOrigin.y) == aVideoMemoryTiledBuffer->RoundDownToTileEdge(y) &&
|
||||
mTiles[i]->mResolution == aOldResolution) {
|
||||
mContext->fDeleteTextures(1, &mTiles[i]->mTexture.mTextureHandle);
|
||||
mTiles.RemoveElementAt(i);
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
replacedATile = true;
|
||||
#endif
|
||||
// There should only be one similar tile
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
if (replacedATile) {
|
||||
printf_stderr("Replaced tile at %d,%d, x%f for reuse\n", x, y, aOldResolution.width);
|
||||
} else {
|
||||
printf_stderr("New tile at %d,%d, x%f for reuse\n", x, y, aOldResolution.width);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
else
|
||||
@ -218,7 +194,6 @@ ReusableTileStoreOGL::HarvestTiles(TiledThebesLayerOGL* aLayer,
|
||||
}
|
||||
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
printf_stderr("Retained tile limit: %f\n", aVideoMemoryTiledBuffer->GetTileCount() * mSizeLimit);
|
||||
printf_stderr("Retained %d tiles\n", mTiles.Length());
|
||||
#endif
|
||||
}
|
||||
@ -275,7 +250,6 @@ ReusableTileStoreOGL::DrawTiles(TiledThebesLayerOGL* aLayer,
|
||||
transform.Scale(scaleFactor.width, scaleFactor.height, 1);
|
||||
|
||||
// Subtract the layer's valid region from the tile region.
|
||||
// This region will be drawn by the layer itself.
|
||||
nsIntRegion transformedValidRegion(aValidRegion);
|
||||
if (aResolution != tile->mResolution)
|
||||
transformedValidRegion.ScaleRoundOut(1.0f/scaleFactor.width,
|
||||
|
@ -10,6 +10,8 @@ function testRunOptionStrictMode(str, arg, result) {
|
||||
}
|
||||
assertEq(eval(uneval(testRunOptionStrictMode()))(), true);
|
||||
|
||||
assertEq(decompileBody(new Function('x', 'return x*2;')).contains('\n"use strict"'), true)
|
||||
if (typeof decompileBody !== "undefined") {
|
||||
assertEq(decompileBody(new Function('x', 'return x*2;')).contains('\n"use strict"'), true);
|
||||
}
|
||||
|
||||
reportCompare(true, true);
|
||||
|
@ -28,7 +28,7 @@ nsresult auxLoad(char *uriBuf);
|
||||
#define RETURN_IF_FAILED(rv, ret, step) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (NS_FAILED(rv)) { \
|
||||
printf(">>> %s failed: rv=%x\n", step, rv); \
|
||||
printf(">>> %s failed: rv=%x\n", step, static_cast<uint32_t>(rv)); \
|
||||
return ret;\
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
@ -47,7 +47,7 @@ static NS_DEFINE_CID(kRDFXMLDataSourceCID, NS_RDFXMLDATASOURCE_CID);
|
||||
#define RETURN_IF_FAILED(rv, step) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (NS_FAILED(rv)) { \
|
||||
printf(">>> %s failed: rv=%x\n", step, rv); \
|
||||
printf(">>> %s failed: rv=%x\n", step, static_cast<uint32_t>(rv)); \
|
||||
return 1;\
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
@ -45,7 +45,7 @@
|
||||
#define RETURN_IF_FAILED(rv, step) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (NS_FAILED(rv)) { \
|
||||
printf(">>> %s failed: rv=%x\n", step, rv); \
|
||||
printf(">>> %s failed: rv=%x\n", step, static_cast<uint32_t>(rv)); \
|
||||
return 1;\
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
@ -1573,7 +1573,8 @@ function updateAboutCompartments()
|
||||
let ghostWindowsByProcess = getGhostWindowsByProcess();
|
||||
|
||||
function handleProcess(aProcess) {
|
||||
appendProcessAboutCompartmentsElements(body, aProcess,
|
||||
let section = appendElement(body, 'div', 'section');
|
||||
appendProcessAboutCompartmentsElements(section, aProcess,
|
||||
compartmentsByProcess[aProcess],
|
||||
ghostWindowsByProcess[aProcess]);
|
||||
}
|
||||
@ -1587,15 +1588,12 @@ function updateAboutCompartments()
|
||||
}
|
||||
}
|
||||
|
||||
appendElement(body, "hr");
|
||||
|
||||
let div1 = appendElement(body, "div");
|
||||
let a;
|
||||
let section = appendElement(body, 'div', 'footer');
|
||||
if (gVerbose) {
|
||||
let a = appendElementWithText(div1, "a", "option", "Less verbose");
|
||||
let a = appendElementWithText(section, "a", "option", "Less verbose");
|
||||
a.href = "about:compartments";
|
||||
} else {
|
||||
let a = appendElementWithText(div1, "a", "option", "More verbose");
|
||||
let a = appendElementWithText(section, "a", "option", "More verbose");
|
||||
a.href = "about:compartments?verbose";
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user