Bug 673569 - Let each frame script have its own scope (r=smaug)

This commit is contained in:
Tom Schuster 2014-06-13 19:56:38 +02:00
parent 2a6d95d789
commit 4e27ccd62e
17 changed files with 130 additions and 86 deletions

View File

@ -29,8 +29,9 @@ XPCOMUtils.defineLazyModuleGetter(this, 'States',
this.EXPORTED_SYMBOLS = ['EventManager'];
this.EventManager = function EventManager(aContentScope) {
this.EventManager = function EventManager(aContentScope, aContentControl) {
this.contentScope = aContentScope;
this.contentControl = aContentControl;
this.addEventListener = this.contentScope.addEventListener.bind(
this.contentScope);
this.removeEventListener = this.contentScope.removeEventListener.bind(
@ -99,7 +100,7 @@ this.EventManager.prototype = {
{
let attempts = 0;
let delta = aEvent.deltaX || aEvent.deltaY;
this.contentScope.contentControl.autoMove(
this.contentControl.autoMove(
null,
{ moveMethod: delta > 0 ? 'moveNext' : 'movePrevious',
onScreenOnly: true, noOpIfOnScreen: true, delay: 500 });
@ -183,7 +184,7 @@ this.EventManager.prototype = {
}
case Events.SCROLLING_START:
{
this.contentScope.contentControl.autoMove(aEvent.accessible);
this.contentControl.autoMove(aEvent.accessible);
break;
}
case Events.TEXT_CARET_MOVED:
@ -254,7 +255,7 @@ this.EventManager.prototype = {
if (vc.position &&
(Utils.getState(vc.position).contains(States.DEFUNCT) ||
Utils.isInSubtree(vc.position, aEvent.accessible))) {
this.contentScope.contentControl.autoMove(
this.contentControl.autoMove(
evt.targetPrevSibling || evt.targetParent,
{ moveToFocused: true, delay: 500 });
}
@ -279,19 +280,19 @@ this.EventManager.prototype = {
let acc = aEvent.accessible;
let doc = aEvent.accessibleDocument;
if (acc.role != Roles.DOCUMENT && doc.role != Roles.CHROME_WINDOW) {
this.contentScope.contentControl.autoMove(acc);
this.contentControl.autoMove(acc);
}
break;
}
case Events.DOCUMENT_LOAD_COMPLETE:
{
this.contentScope.contentControl.autoMove(
this.contentControl.autoMove(
aEvent.accessible, { delay: 500 });
break;
}
case Events.VALUE_CHANGE:
{
let position = this.contentScope.contentControl.vc.position;
let position = this.contentControl.vc.position;
let target = aEvent.accessible;
if (position === target ||
Utils.getEmbeddedControl(position) === target) {

View File

@ -140,16 +140,16 @@ addMessageListener(
addMessageListener('AccessFu:Scroll', scroll);
addMessageListener('AccessFu:AdjustRange', adjustRange);
if (!eventManager) {
eventManager = new EventManager(this);
}
eventManager.start();
if (!contentControl) {
contentControl = new ContentControl(this);
}
contentControl.start();
if (!eventManager) {
eventManager = new EventManager(this, contentControl);
}
eventManager.start();
sendAsyncMessage('AccessFu:ContentStarted');
});

View File

@ -13,7 +13,7 @@ let crash = function() { // this will crash when called.
};
TestHelper = {
let TestHelper = {
init: function() {
addMessageListener("social-test:crash", this);
},

View File

@ -65,7 +65,7 @@ add_task(function() {
add_task(function () {
const FRAME_SCRIPT = "data:," +
"docShell.QueryInterface%28Ci.nsILoadContext%29.usePrivateBrowsing%3Dtrue";
"docShell.QueryInterface%28Components.interfaces.nsILoadContext%29.usePrivateBrowsing%3Dtrue";
// Clear the list of closed windows.
while (ss.getClosedWindowCount()) {

View File

@ -4,6 +4,8 @@
"use strict";
let {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
/**
* This frame script is only loaded for sessionstore mochitests. It contains
* a bunch of utility functions used to test form data collection and

View File

@ -14,6 +14,7 @@
#include "nsError.h"
#include "nsIXPConnect.h"
#include "jsapi.h"
#include "jsfriendapi.h"
#include "nsJSUtils.h"
#include "nsJSPrincipals.h"
#include "nsNetUtil.h"
@ -429,9 +430,6 @@ nsFrameMessageManager::LoadFrameScript(const nsAString& aURL,
bool aAllowDelayedLoad,
bool aRunInGlobalScope)
{
// FIXME: Bug 673569 is currently disabled.
aRunInGlobalScope = true;
if (aAllowDelayedLoad) {
if (IsGlobal() || IsBroadcaster()) {
// Cache for future windows or frames
@ -1435,35 +1433,33 @@ nsFrameScriptExecutor::LoadFrameScriptInternal(const nsAString& aURL,
AutoSafeJSContext cx;
JS::Rooted<JSScript*> script(cx);
JS::Rooted<JSObject*> funobj(cx);
nsFrameScriptObjectExecutorHolder* holder = sCachedScripts->Get(aURL);
if (holder && holder->WillRunInGlobalScope() == aRunInGlobalScope) {
script = holder->mScript;
funobj = holder->mFunction;
} else {
// Don't put anything in the cache if we already have an entry
// with a different WillRunInGlobalScope() value.
bool shouldCache = !holder;
TryCacheLoadAndCompileScript(aURL, aRunInGlobalScope,
shouldCache, &script, &funobj);
shouldCache, &script);
}
JS::Rooted<JSObject*> global(cx, mGlobal->GetJSObject());
if (global) {
JSAutoCompartment ac(cx, global);
bool ok = true;
if (funobj) {
JS::Rooted<JSObject*> method(cx, JS_CloneFunctionObject(cx, funobj, global));
if (!method) {
return;
if (script) {
if (aRunInGlobalScope) {
ok = JS::CloneAndExecuteScript(cx, global, script);
} else {
JS::Rooted<JSObject*> scope(cx);
ok = js::ExecuteInGlobalAndReturnScope(cx, global, script, &scope);
if (ok){
// Force the scope to stay alive.
mAnonymousGlobalScopes.AppendElement(scope);
}
}
JS::Rooted<JS::Value> rval(cx);
JS::Rooted<JS::Value> methodVal(cx, JS::ObjectValue(*method));
ok = JS_CallFunctionValue(cx, global, methodVal,
JS::HandleValueArray::empty(), &rval);
} else if (script) {
ok = JS::CloneAndExecuteScript(cx, global, script);
}
if (!ok) {
@ -1476,8 +1472,7 @@ void
nsFrameScriptExecutor::TryCacheLoadAndCompileScript(const nsAString& aURL,
bool aRunInGlobalScope,
bool aShouldCache,
JS::MutableHandle<JSScript*> aScriptp,
JS::MutableHandle<JSObject*> aFunp)
JS::MutableHandle<JSScript*> aScriptp)
{
nsCString url = NS_ConvertUTF16toUTF8(aURL);
nsCOMPtr<nsIURI> uri;
@ -1531,30 +1526,22 @@ nsFrameScriptExecutor::TryCacheLoadAndCompileScript(const nsAString& aURL,
JSAutoCompartment ac(cx, global);
JS::CompileOptions options(cx);
options.setFileAndLine(url.get(), 1);
options.setNoScriptRval(true);
JS::Rooted<JSScript*> script(cx);
JS::Rooted<JSObject*> funobj(cx);
if (aRunInGlobalScope) {
options.setNoScriptRval(true);
if (!JS::Compile(cx, JS::NullPtr(), options, srcBuf, &script)) {
return;
}
} else {
JS::Rooted<JSFunction *> fun(cx);
if (!JS::CompileFunction(cx, JS::NullPtr(), options,
nullptr, 0, nullptr, /* name, nargs, args */
srcBuf, &fun))
{
// We can't clone compile-and-go scripts.
options.setCompileAndGo(false);
if (!JS::Compile(cx, JS::NullPtr(), options, srcBuf, &script)) {
return;
}
funobj = JS_GetFunctionObject(fun);
}
if (!script && !funobj) {
return;
}
aScriptp.set(script);
aFunp.set(funobj);
nsAutoCString scheme;
uri->GetScheme(scheme);
@ -1564,9 +1551,7 @@ nsFrameScriptExecutor::TryCacheLoadAndCompileScript(const nsAString& aURL,
// Root the object also for caching.
if (script) {
holder = new nsFrameScriptObjectExecutorHolder(cx, script);
} else {
holder = new nsFrameScriptObjectExecutorHolder(cx, funobj);
holder = new nsFrameScriptObjectExecutorHolder(cx, script, aRunInGlobalScope);
}
sCachedScripts->Put(aURL, holder);
}
@ -1580,8 +1565,7 @@ nsFrameScriptExecutor::TryCacheLoadAndCompileScript(const nsAString& aURL,
{
AutoSafeJSContext cx;
JS::Rooted<JSScript*> script(cx);
JS::Rooted<JSObject*> funobj(cx);
TryCacheLoadAndCompileScript(aURL, aRunInGlobalScope, true, &script, &funobj);
TryCacheLoadAndCompileScript(aURL, aRunInGlobalScope, true, &script);
}
bool

View File

@ -360,21 +360,17 @@ class nsScriptCacheCleaner;
struct nsFrameScriptObjectExecutorHolder
{
nsFrameScriptObjectExecutorHolder(JSContext* aCx, JSScript* aScript)
: mScript(aCx, aScript), mFunction(aCx, nullptr)
{ MOZ_COUNT_CTOR(nsFrameScriptObjectExecutorHolder); }
nsFrameScriptObjectExecutorHolder(JSContext* aCx, JSObject* aFunction)
: mScript(aCx, nullptr), mFunction(aCx, aFunction)
nsFrameScriptObjectExecutorHolder(JSContext* aCx, JSScript* aScript, bool aRunInGlobalScope)
: mScript(aCx, aScript), mRunInGlobalScope(aRunInGlobalScope)
{ MOZ_COUNT_CTOR(nsFrameScriptObjectExecutorHolder); }
~nsFrameScriptObjectExecutorHolder()
{ MOZ_COUNT_DTOR(nsFrameScriptObjectExecutorHolder); }
bool WillRunInGlobalScope() { return mScript; }
bool WillRunInGlobalScope() { return mRunInGlobalScope; }
JS::PersistentRooted<JSScript*> mScript;
JS::PersistentRooted<JSObject*> mFunction;
bool mRunInGlobalScope;
};
class nsFrameScriptObjectExecutorStackHolder;
@ -390,22 +386,22 @@ public:
}
protected:
friend class nsFrameScriptCx;
nsFrameScriptExecutor()
{ MOZ_COUNT_CTOR(nsFrameScriptExecutor); }
~nsFrameScriptExecutor()
{ MOZ_COUNT_DTOR(nsFrameScriptExecutor); }
nsFrameScriptExecutor() { MOZ_COUNT_CTOR(nsFrameScriptExecutor); }
~nsFrameScriptExecutor() { MOZ_COUNT_DTOR(nsFrameScriptExecutor); }
void DidCreateGlobal();
void LoadFrameScriptInternal(const nsAString& aURL, bool aRunInGlobalScope);
void TryCacheLoadAndCompileScript(const nsAString& aURL,
bool aRunInGlobalScope,
bool aShouldCache,
JS::MutableHandle<JSScript*> aScriptp,
JS::MutableHandle<JSObject*> aFunp);
JS::MutableHandle<JSScript*> aScriptp);
void TryCacheLoadAndCompileScript(const nsAString& aURL,
bool aRunInGlobalScope);
bool InitTabChildGlobalInternal(nsISupports* aScope, const nsACString& aID);
nsCOMPtr<nsIXPConnectJSObjectHolder> mGlobal;
nsCOMPtr<nsIPrincipal> mPrincipal;
nsAutoTArray<JS::Heap<JSObject*>, 2> mAnonymousGlobalScopes;
static nsDataHashtable<nsStringHashKey, nsFrameScriptObjectExecutorHolder*>* sCachedScripts;
static nsScriptCacheCleaner* sScriptCacheCleaner;
};

View File

@ -103,6 +103,7 @@ nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell* aShell,
: mDocShell(aShell), mInitialized(false), mLoadingScript(false),
mOwner(aOwner), mChromeMessageManager(aChrome)
{
mozilla::HoldJSObjects(this);
// If owner corresponds to an <iframe mozbrowser> or <iframe mozapp>, we'll
// have to tweak our PreHandleEvent implementation.
@ -117,6 +118,8 @@ nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell* aShell,
nsInProcessTabChildGlobal::~nsInProcessTabChildGlobal()
{
mAnonymousGlobalScopes.Clear();
mozilla::DropJSObjects(this);
}
/* [notxpcom] boolean markForCC (); */
@ -143,10 +146,28 @@ nsInProcessTabChildGlobal::Init()
return NS_OK;
}
NS_IMPL_CYCLE_COLLECTION_INHERITED(nsInProcessTabChildGlobal,
DOMEventTargetHelper,
mMessageManager,
mGlobal)
NS_IMPL_CYCLE_COLLECTION_CLASS(nsInProcessTabChildGlobal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsInProcessTabChildGlobal,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsInProcessTabChildGlobal,
DOMEventTargetHelper)
for (uint32_t i = 0; i < tmp->mAnonymousGlobalScopes.Length(); ++i) {
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mAnonymousGlobalScopes[i])
}
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsInProcessTabChildGlobal,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnonymousGlobalScopes)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsInProcessTabChildGlobal)
NS_INTERFACE_MAP_ENTRY(nsIMessageListenerManager)

View File

@ -39,8 +39,9 @@ public:
nsInProcessTabChildGlobal(nsIDocShell* aShell, nsIContent* aOwner,
nsFrameMessageManager* aChrome);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsInProcessTabChildGlobal,
mozilla::DOMEventTargetHelper)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsInProcessTabChildGlobal,
mozilla::DOMEventTargetHelper)
NS_FORWARD_SAFE_NSIMESSAGELISTENERMANAGER(mMessageManager)
NS_FORWARD_SAFE_NSIMESSAGESENDER(mMessageManager)
NS_IMETHOD SendSyncMessage(const nsAString& aMessageName,

View File

@ -125,6 +125,8 @@ function async_test()
async_obj);
}
var rpc_obj;
function rpc_test()
{
dump('beginning cpow rpc test\n');

View File

@ -47,9 +47,9 @@ function test1() {
// Do window.alert within the iframe, then modify the global |testState|
// after the alert.
var script = 'data:,\
testState = 0; \
this.testState = 0; \
content.alert("Hello, world!"); \
testState = 1; \
this.testState = 1; \
';
mm.loadFrameScript(script, /* allowDelayedLoad = */ false);
@ -71,11 +71,11 @@ function test2a(e) {
// The iframe should be blocked on the alert call at the moment, so testState
// should still be 0.
var script = 'data:,\
if (testState === 0) { \
if (this.testState === 0) { \
sendAsyncMessage("test-success", "1: Correct testState"); \
} \
else { \
sendAsyncMessage("test-fail", "1: Wrong testState: " + testState); \
sendAsyncMessage("test-fail", "1: Wrong testState: " + this.testState); \
}';
mm.loadFrameScript(script, /* allowDelayedLoad = */ false);
@ -89,11 +89,11 @@ function test3(e) {
e.detail.unblock();
var script2 = 'data:,\
if (testState === 1) { \
if (this.testState === 1) { \
sendAsyncMessage("test-success", "2: Correct testState"); \
} \
else { \
sendAsyncMessage("test-try-again", "2: Wrong testState (for now): " + testState); \
sendAsyncMessage("test-try-again", "2: Wrong testState (for now): " + this.testState); \
}';
// Urgh. e.unblock() didn't necessarily unblock us immediately, so we have

View File

@ -118,15 +118,41 @@ TabChildBase::TabChildBase()
, mTabChildGlobal(nullptr)
, mInnerSize(0, 0)
{
mozilla::HoldJSObjects(this);
}
NS_IMPL_CYCLE_COLLECTING_ADDREF(TabChildBase)
NS_IMPL_CYCLE_COLLECTING_RELEASE(TabChildBase)
TabChildBase::~TabChildBase()
{
mAnonymousGlobalScopes.Clear();
mozilla::DropJSObjects(this);
}
NS_IMPL_CYCLE_COLLECTION_CLASS(TabChildBase)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(TabChildBase)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTabChildGlobal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnonymousGlobalScopes)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(TabChildBase)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTabChildGlobal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(TabChildBase)
for (uint32_t i = 0; i < tmp->mAnonymousGlobalScopes.Length(); ++i) {
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mAnonymousGlobalScopes[i])
}
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TabChildBase)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION(TabChildBase, mTabChildGlobal, mGlobal)
NS_IMPL_CYCLE_COLLECTING_ADDREF(TabChildBase)
NS_IMPL_CYCLE_COLLECTING_RELEASE(TabChildBase)
void
TabChildBase::InitializeRootMetrics()

View File

@ -165,8 +165,9 @@ class TabChildBase : public nsISupports,
{
public:
TabChildBase();
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(TabChildBase)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TabChildBase)
virtual nsIWebNavigation* WebNavigation() = 0;
virtual nsIWidget* WebWidget() = 0;
@ -188,7 +189,7 @@ public:
nsIWidget* aWidget);
protected:
~TabChildBase() {}
virtual ~TabChildBase();
CSSSize GetPageSize(nsCOMPtr<nsIDocument> aDocument, const CSSSize& aViewport);
// Get the DOMWindowUtils for the top-level window in this tab.

View File

@ -59,7 +59,7 @@ function openWindow(aEvent) {
mm.loadFrameScript(CHILD_LOGGER_SCRIPT, true);
mm.loadFrameScript(CHILD_SCRIPT_API, true);
mm.loadFrameScript(CHILD_SCRIPT, true);
mm.loadFrameScript('data:,attachSpecialPowersToWindow%28content%29%3B', true);
mm.loadFrameScript('data:,attachSpecialPowersToWindow(content);', true);
});
container.parentNode.appendChild(popupIframe);
@ -87,8 +87,16 @@ if (outOfProcess) {
mm.loadFrameScript(CHILD_LOGGER_SCRIPT, true);
mm.loadFrameScript(CHILD_SCRIPT_API, true);
mm.loadFrameScript(CHILD_SCRIPT, true);
//Workaround for bug 848411, once that bug is fixed, the following line can be removed
mm.loadFrameScript('data:,addEventListener%28%22DOMWindowCreated%22%2C%20function%28e%29%20%7B%0A%20%20removeEventListener%28%22DOMWindowCreated%22%2C%20arguments.callee%2C%20false%29%3B%0A%20%20var%20window%20%3D%20e.target.defaultView%3B%0A%20%20window.wrappedJSObject.SpecialPowers.addPermission%28%22allowXULXBL%22%2C%20true%2C%20window.document%29%3B%0A%7D%0A%29%3B', true);
function contentScript() {
addEventListener("DOMWindowCreated", function listener(e) {
removeEventListener("DOMWindowCreated", listener, false);
var window = e.target.defaultView;
window.wrappedJSObject.SpecialPowers.addPermission("allowXULXBL", true, window.document);
});
}
mm.loadFrameScript("data:,(" + encodeURI(contentScript.toSource()) + ")();", true);
specialPowersObserver._isFrameScriptLoaded = true;
}

View File

@ -2,6 +2,8 @@
* MozillaLogger, a base class logger that just logs to stdout.
*/
"use strict";
function MozillaLogger(aPath) {
}
@ -87,7 +89,7 @@ MozillaFileLogger.prototype = {
this._foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].
createInstance(Components.interfaces.nsIFileOutputStream);
this._foStream.init(this._file, PR_WRITE_ONLY | PR_CREATE_FILE | PR_APPEND,
0664, 0);
436 /* 0664 */, 0);
},
getLogCallback : function() {

View File

@ -1480,7 +1480,7 @@ SpecialPowersAPI.prototype = {
var res = { __exposedProps__: {} };
var props = ["createRequest", "createCursor", "fireError", "fireSuccess",
"fireDone", "fireDetailedError"];
for (i in props) {
for (var i in props) {
let prop = props[i];
res[prop] = function() { return serv[prop].apply(serv, arguments) };
res.__exposedProps__[prop] = "r";

View File

@ -13,7 +13,7 @@ let crash = function() { // this will crash when called.
};
TestHelper = {
let TestHelper = {
init: function() {
addMessageListener("thumbnails-test:crash", this);
},