mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1127885 - Console API should display blobs when used in workers, r=smaug
This commit is contained in:
parent
22c09069b1
commit
ffb8a11eea
@ -6,7 +6,9 @@
|
|||||||
#include "mozilla/dom/Console.h"
|
#include "mozilla/dom/Console.h"
|
||||||
#include "mozilla/dom/ConsoleBinding.h"
|
#include "mozilla/dom/ConsoleBinding.h"
|
||||||
|
|
||||||
|
#include "mozilla/dom/BlobBinding.h"
|
||||||
#include "mozilla/dom/Exceptions.h"
|
#include "mozilla/dom/Exceptions.h"
|
||||||
|
#include "mozilla/dom/File.h"
|
||||||
#include "mozilla/dom/ToJSValue.h"
|
#include "mozilla/dom/ToJSValue.h"
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
#include "nsCycleCollectionParticipant.h"
|
#include "nsCycleCollectionParticipant.h"
|
||||||
@ -41,9 +43,10 @@
|
|||||||
// console.trace().
|
// console.trace().
|
||||||
#define DEFAULT_MAX_STACKTRACE_DEPTH 200
|
#define DEFAULT_MAX_STACKTRACE_DEPTH 200
|
||||||
|
|
||||||
// This tag is used in the Structured Clone Algorithm to move js values from
|
// This tags are used in the Structured Clone Algorithm to move js values from
|
||||||
// worker thread to main thread
|
// worker thread to main thread
|
||||||
#define CONSOLE_TAG JS_SCTAG_USER_MIN
|
#define CONSOLE_TAG_STRING JS_SCTAG_USER_MIN
|
||||||
|
#define CONSOLE_TAG_BLOB JS_SCTAG_USER_MIN + 1
|
||||||
|
|
||||||
using namespace mozilla::dom::exceptions;
|
using namespace mozilla::dom::exceptions;
|
||||||
using namespace mozilla::dom::workers;
|
using namespace mozilla::dom::workers;
|
||||||
@ -51,6 +54,14 @@ using namespace mozilla::dom::workers;
|
|||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
|
struct
|
||||||
|
ConsoleStructuredCloneData
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsISupports> mParent;
|
||||||
|
nsTArray<nsString> mStrings;
|
||||||
|
nsTArray<nsRefPtr<FileImpl>> mFiles;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Console API in workers uses the Structured Clone Algorithm to move any value
|
* Console API in workers uses the Structured Clone Algorithm to move any value
|
||||||
* from the worker thread to the main-thread. Some object cannot be moved and,
|
* from the worker thread to the main-thread. Some object cannot be moved and,
|
||||||
@ -63,29 +74,41 @@ namespace dom {
|
|||||||
static JSObject*
|
static JSObject*
|
||||||
ConsoleStructuredCloneCallbacksRead(JSContext* aCx,
|
ConsoleStructuredCloneCallbacksRead(JSContext* aCx,
|
||||||
JSStructuredCloneReader* /* unused */,
|
JSStructuredCloneReader* /* unused */,
|
||||||
uint32_t aTag, uint32_t aData,
|
uint32_t aTag, uint32_t aIndex,
|
||||||
void* aClosure)
|
void* aClosure)
|
||||||
{
|
{
|
||||||
AssertIsOnMainThread();
|
AssertIsOnMainThread();
|
||||||
|
ConsoleStructuredCloneData* data =
|
||||||
|
static_cast<ConsoleStructuredCloneData*>(aClosure);
|
||||||
|
MOZ_ASSERT(data);
|
||||||
|
MOZ_ASSERT(data->mParent);
|
||||||
|
|
||||||
if (aTag != CONSOLE_TAG) {
|
if (aTag == CONSOLE_TAG_STRING) {
|
||||||
return nullptr;
|
MOZ_ASSERT(data->mStrings.Length() > aIndex);
|
||||||
|
|
||||||
|
JS::Rooted<JS::Value> value(aCx);
|
||||||
|
if (!xpc::StringToJsval(aCx, data->mStrings.ElementAt(aIndex), &value)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS::Rooted<JSObject*> obj(aCx);
|
||||||
|
if (!JS_ValueToObject(aCx, value, &obj)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsTArray<nsString>* strings = static_cast<nsTArray<nsString>*>(aClosure);
|
if (aTag == CONSOLE_TAG_BLOB) {
|
||||||
MOZ_ASSERT(strings->Length() > aData);
|
MOZ_ASSERT(data->mFiles.Length() > aIndex);
|
||||||
|
|
||||||
JS::Rooted<JS::Value> value(aCx);
|
nsRefPtr<File> file =
|
||||||
if (!xpc::StringToJsval(aCx, strings->ElementAt(aData), &value)) {
|
new File(data->mParent, data->mFiles.ElementAt(aIndex));
|
||||||
return nullptr;
|
return file->WrapObject(aCx);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::Rooted<JSObject*> obj(aCx);
|
MOZ_CRASH("No other tags are supported.");
|
||||||
if (!JS_ValueToObject(aCx, value, &obj)) {
|
return nullptr;
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method is called by the Structured Clone Algorithm when some data has
|
// This method is called by the Structured Clone Algorithm when some data has
|
||||||
@ -96,6 +119,21 @@ ConsoleStructuredCloneCallbacksWrite(JSContext* aCx,
|
|||||||
JS::Handle<JSObject*> aObj,
|
JS::Handle<JSObject*> aObj,
|
||||||
void* aClosure)
|
void* aClosure)
|
||||||
{
|
{
|
||||||
|
ConsoleStructuredCloneData* data =
|
||||||
|
static_cast<ConsoleStructuredCloneData*>(aClosure);
|
||||||
|
MOZ_ASSERT(data);
|
||||||
|
|
||||||
|
nsRefPtr<File> file;
|
||||||
|
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, file)) &&
|
||||||
|
file->Impl()->MayBeClonedToOtherThreads()) {
|
||||||
|
if (!JS_WriteUint32Pair(aWriter, CONSOLE_TAG_BLOB, data->mFiles.Length())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->mFiles.AppendElement(file->Impl());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
JS::Rooted<JS::Value> value(aCx, JS::ObjectOrNullValue(aObj));
|
JS::Rooted<JS::Value> value(aCx, JS::ObjectOrNullValue(aObj));
|
||||||
JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
|
JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
|
||||||
if (!jsString) {
|
if (!jsString) {
|
||||||
@ -107,14 +145,12 @@ ConsoleStructuredCloneCallbacksWrite(JSContext* aCx,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsTArray<nsString>* strings = static_cast<nsTArray<nsString>*>(aClosure);
|
if (!JS_WriteUint32Pair(aWriter, CONSOLE_TAG_STRING,
|
||||||
|
data->mStrings.Length())) {
|
||||||
if (!JS_WriteUint32Pair(aWriter, CONSOLE_TAG, strings->Length())) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
strings->AppendElement(string);
|
data->mStrings.AppendElement(string);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,7 +450,7 @@ private:
|
|||||||
|
|
||||||
JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*arguments));
|
JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*arguments));
|
||||||
|
|
||||||
if (!mArguments.write(aCx, value, &gConsoleCallbacks, &mStrings)) {
|
if (!mArguments.write(aCx, value, &gConsoleCallbacks, &mData)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -451,8 +487,13 @@ private:
|
|||||||
mCallData->SetIDs(id, frame.mFilename);
|
mCallData->SetIDs(id, frame.mFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now we could have the correct window (if we are not window-less).
|
||||||
|
mData.mParent = aInnerWindow;
|
||||||
|
|
||||||
ProcessCallData(aCx);
|
ProcessCallData(aCx);
|
||||||
mCallData->CleanupJSObjects();
|
mCallData->CleanupJSObjects();
|
||||||
|
|
||||||
|
mData.mParent = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -462,7 +503,7 @@ private:
|
|||||||
ClearException ce(aCx);
|
ClearException ce(aCx);
|
||||||
|
|
||||||
JS::Rooted<JS::Value> argumentsValue(aCx);
|
JS::Rooted<JS::Value> argumentsValue(aCx);
|
||||||
if (!mArguments.read(aCx, &argumentsValue, &gConsoleCallbacks, &mStrings)) {
|
if (!mArguments.read(aCx, &argumentsValue, &gConsoleCallbacks, &mData)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,7 +535,7 @@ private:
|
|||||||
ConsoleCallData* mCallData;
|
ConsoleCallData* mCallData;
|
||||||
|
|
||||||
JSAutoStructuredCloneBuffer mArguments;
|
JSAutoStructuredCloneBuffer mArguments;
|
||||||
nsTArray<nsString> mStrings;
|
ConsoleStructuredCloneData mData;
|
||||||
};
|
};
|
||||||
|
|
||||||
// This runnable calls ProfileMethod() on the console on the main-thread.
|
// This runnable calls ProfileMethod() on the console on the main-thread.
|
||||||
@ -539,7 +580,7 @@ private:
|
|||||||
|
|
||||||
JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*arguments));
|
JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*arguments));
|
||||||
|
|
||||||
if (!mBuffer.write(aCx, value, &gConsoleCallbacks, &mStrings)) {
|
if (!mBuffer.write(aCx, value, &gConsoleCallbacks, &mData)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -552,8 +593,14 @@ private:
|
|||||||
{
|
{
|
||||||
ClearException ce(aCx);
|
ClearException ce(aCx);
|
||||||
|
|
||||||
|
// Now we could have the correct window (if we are not window-less).
|
||||||
|
mData.mParent = aInnerWindow;
|
||||||
|
|
||||||
JS::Rooted<JS::Value> argumentsValue(aCx);
|
JS::Rooted<JS::Value> argumentsValue(aCx);
|
||||||
if (!mBuffer.read(aCx, &argumentsValue, &gConsoleCallbacks, &mStrings)) {
|
bool ok = mBuffer.read(aCx, &argumentsValue, &gConsoleCallbacks, &mData);
|
||||||
|
mData.mParent = nullptr;
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -585,7 +632,7 @@ private:
|
|||||||
Sequence<JS::Value> mArguments;
|
Sequence<JS::Value> mArguments;
|
||||||
|
|
||||||
JSAutoStructuredCloneBuffer mBuffer;
|
JSAutoStructuredCloneBuffer mBuffer;
|
||||||
nsTArray<nsString> mStrings;
|
ConsoleStructuredCloneData mData;
|
||||||
};
|
};
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_CLASS(Console)
|
NS_IMPL_CYCLE_COLLECTION_CLASS(Console)
|
||||||
|
@ -97,6 +97,7 @@ support-files =
|
|||||||
bug1062920_worker.js
|
bug1062920_worker.js
|
||||||
webSocket_sharedWorker.js
|
webSocket_sharedWorker.js
|
||||||
bug1104064_worker.js
|
bug1104064_worker.js
|
||||||
|
worker_consoleAndBlobs.js
|
||||||
|
|
||||||
[test_404.html]
|
[test_404.html]
|
||||||
[test_atob.html]
|
[test_atob.html]
|
||||||
@ -197,3 +198,4 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #bug 982828
|
|||||||
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #bug 982828
|
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #bug 982828
|
||||||
[test_websocket_pref.html]
|
[test_websocket_pref.html]
|
||||||
[test_bug1104064.html]
|
[test_bug1104064.html]
|
||||||
|
[test_consoleAndBlobs.html]
|
||||||
|
41
dom/workers/test/test_consoleAndBlobs.html
Normal file
41
dom/workers/test/test_consoleAndBlobs.html
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<!--
|
||||||
|
Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
-->
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Test for console API and blobs</title>
|
||||||
|
<script src="/tests/SimpleTest/SimpleTest.js">
|
||||||
|
</script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
function consoleListener() {
|
||||||
|
SpecialPowers.addObserver(this, "console-api-log-event", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var order = 0;
|
||||||
|
consoleListener.prototype = {
|
||||||
|
observe: function(aSubject, aTopic, aData) {
|
||||||
|
ok(true, "Something has been received");
|
||||||
|
is(aTopic, "console-api-log-event");
|
||||||
|
SpecialPowers.removeObserver(this, "console-api-log-event");
|
||||||
|
|
||||||
|
var obj = aSubject.wrappedJSObject;
|
||||||
|
is(obj.arguments[0].size, 3, "The size is correct");
|
||||||
|
is(obj.arguments[0].type, 'foo/bar', "The type is correct");
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var cl = new consoleListener();
|
||||||
|
|
||||||
|
new Worker('worker_consoleAndBlobs.js');
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
8
dom/workers/test/worker_consoleAndBlobs.js
Normal file
8
dom/workers/test/worker_consoleAndBlobs.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
*/
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var b = new Blob(['123'], { type: 'foo/bar'});
|
||||||
|
console.log(b);
|
Loading…
Reference in New Issue
Block a user