From a8e78af6d5e158bb73ef5d0066209e7e8bc068f1 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Wed, 17 Oct 2012 14:37:09 -0700 Subject: [PATCH 01/46] Bug 800878 - EvalInFrame, Check debug mode before iterating the stack. r=luke,decoder --- js/src/shell/js.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 1f666b68778..f44149bc458 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -2523,6 +2523,13 @@ EvalInFrame(JSContext *cx, unsigned argc, jsval *vp) JS_ASSERT(cx->hasfp()); + /* This is a copy of CheckDebugMode. */ + if (!JS_GetDebugMode(cx)) { + JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, + NULL, JSMSG_NEED_DEBUG_MODE); + return false; + } + /* Debug-mode currently disables Ion compilation. */ ScriptFrameIter fi(cx); for (uint32_t i = 0; i < upCount; ++i, ++fi) { From b8e096cc2b14cb6ffec03fab49873af1443c5827 Mon Sep 17 00:00:00 2001 From: Jonathan Griffin Date: Wed, 17 Oct 2012 15:12:41 -0700 Subject: [PATCH 02/46] Bug 790677 - Fix xpcshell test packaging for B2G, r=ted --- testing/xpcshell/Makefile.in | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/testing/xpcshell/Makefile.in b/testing/xpcshell/Makefile.in index f4daa44e5c2..77f0bd21fa8 100644 --- a/testing/xpcshell/Makefile.in +++ b/testing/xpcshell/Makefile.in @@ -22,6 +22,7 @@ include $(topsrcdir)/config/rules.mk TEST_HARNESS_FILES := \ runxpcshelltests.py \ remotexpcshelltests.py \ + runtestsb2g.py \ head.js \ node-spdy \ moz-spdy \ @@ -33,9 +34,10 @@ EXTRA_BUILD_FILES := \ manifestparser.py \ $(NULL) -# And files for running xpcshell remotely from $(topsrcdir)/build/mobile -MOBILE_BUILD_FILES := \ +MOZDEVICE_FILES := \ devicemanager.py \ + devicemanagerADB.py \ + devicemanagerSUT.py \ $(NULL) # Components / typelibs that don't get packaged with @@ -66,6 +68,6 @@ stage-package: @(cd $(srcdir) && tar $(TAR_CREATE_FLAGS) - $(TEST_HARNESS_FILES)) | (cd $(PKG_STAGE)/xpcshell && tar -xf -) @(cd $(topsrcdir)/build && tar $(TAR_CREATE_FLAGS) - $(EXTRA_BUILD_FILES)) | (cd $(PKG_STAGE)/xpcshell && tar -xf -) @cp $(DEPTH)/mozinfo.json $(PKG_STAGE)/xpcshell - @(cd $(topsrcdir)/build/mobile && tar $(TAR_CREATE_FLAGS) - $(MOBILE_BUILD_FILES)) | (cd $(PKG_STAGE)/xpcshell && tar -xf -) + @(cd $(topsrcdir)/testing/mozbase/mozdevice/mozdevice && tar $(TAR_CREATE_FLAGS) - $(MOZDEVICE_FILES)) | (cd $(PKG_STAGE)/xpcshell && tar -xf -) (cd $(DEPTH)/_tests/xpcshell/ && tar $(TAR_CREATE_FLAGS_QUIET) - *) | (cd $(PKG_STAGE)/xpcshell/tests && tar -xf -) @(cd $(DIST)/bin/components && tar $(TAR_CREATE_FLAGS) - $(TEST_HARNESS_COMPONENTS)) | (cd $(PKG_STAGE)/bin/components && tar -xf -) From 839fad008d21667a135b3d4a3e839a5bd36c2e21 Mon Sep 17 00:00:00 2001 From: Anant Narayanan Date: Wed, 17 Oct 2012 15:16:03 -0700 Subject: [PATCH 03/46] Bug 801801: Fix runapp argument for B2G Desktop; r=fabrice --- b2g/chrome/content/runapp.js | 65 ++++++++++++++++++++++++++---------- b2g/chrome/content/shell.xul | 2 +- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/b2g/chrome/content/runapp.js b/b2g/chrome/content/runapp.js index d126cdd2530..03ed80b74fd 100644 --- a/b2g/chrome/content/runapp.js +++ b/b2g/chrome/content/runapp.js @@ -1,6 +1,9 @@ +"use strict"; + // runapp.js: // Provide a --runapp APPNAME command-line option. +let runAppObj; window.addEventListener('load', function() { // Get the command line arguments that were passed to the b2g client let args = window.arguments[0].QueryInterface(Ci.nsICommandLine); @@ -13,27 +16,52 @@ window.addEventListener('load', function() { // it was the last argument or the next argument starts with '-'). // However, someone could still explicitly pass an empty argument! appname = args.handleFlagWithParam('runapp', false); - } - catch(e) { + } catch(e) { // treat a missing parameter like an empty parameter (=> show usage) appname = ''; } // not specified, bail. - if (appname === null) + if (appname === null) { return; + } + + runAppObj = new AppRunner(appname); + Services.obs.addObserver(runAppObj, 'webapps-registry-ready', false); +}); + +window.addEventListener('unload', function() { + Services.obs.removeObserver(runAppObj, 'webapps-registry-ready'); +}); + +function AppRunner(aName) { + this._req = null; + this._appName = aName; +} +AppRunner.prototype = { + observe: function(aSubject, aTopic, aData) { + if (aTopic == 'webapps-registry-ready') { + this.doRunApp(); + } + }, + + doRunApp: function() { + // - Get the list of apps since the parameter was specified + this._req = navigator.mozApps.mgmt.getAll(); + this._req.onsuccess = this.getAllSuccess.bind(this); + this._req.onerror = this.getAllError.bind(this); + }, + + getAllSuccess: function() { + let apps = this._req.result; - // - Get the list of apps since the parameter was specified - let appsReq = navigator.mozApps.mgmt.getAll(); - appsReq.onsuccess = function() { - let apps = appsReq.result; function findAppWithName(name) { let normalizedSearchName = name.replace(/[- ]+/g, '').toLowerCase(); for (let i = 0; i < apps.length; i++) { let app = apps[i]; let normalizedAppName = - app.manifest.name.replace(/[- ]+/g, '').toLowerCase(); + app.manifest.name.replace(/[- ]+/g, '').toLowerCase(); if (normalizedSearchName === normalizedAppName) { return app; } @@ -59,14 +87,14 @@ window.addEventListener('load', function() { Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit); } - if (appname === '') { + if (this._appName === '') { usageAndDie(); return; } - let app = findAppWithName(appname); + let app = findAppWithName(this._appName); if (!app) { - dump('Could not find app: "' + appname + '". Maybe you meant one of:\n'); + dump('Could not find app: "' + this._appName + '". Maybe you meant one of:\n'); usageAndDie(true); return; } @@ -74,11 +102,11 @@ window.addEventListener('load', function() { let setReq = navigator.mozSettings.createLock().set({'lockscreen.enabled': false}); setReq.onsuccess = function() { - // give the event loop another turn to disable the lock screen + // give the event loop 100ms to disable the lock screen window.setTimeout(function() { dump('--runapp launching app: ' + app.manifest.name + '\n'); app.launch(); - }, 0); + }, 100); }; setReq.onerror = function() { dump('--runapp failed to disable lock-screen. Giving up.\n'); @@ -86,8 +114,9 @@ window.addEventListener('load', function() { dump('--runapp found app: ' + app.manifest.name + ', disabling lock screen...\n'); - }; - appsReq.onerror = function() { - dump('Problem getting the list of all apps!'); - }; -}); + }, + + getAllError: function() { + dump('Problem getting the list of all apps!'); + } +}; \ No newline at end of file diff --git a/b2g/chrome/content/shell.xul b/b2g/chrome/content/shell.xul index b74c40cf1e4..882e5426783 100644 --- a/b2g/chrome/content/shell.xul +++ b/b2g/chrome/content/shell.xul @@ -17,7 +17,7 @@ + From 0a9fd297dac40b973284775808880f9b50156d8b Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Wed, 17 Oct 2012 18:22:46 -0700 Subject: [PATCH 17/46] Bug 798678 - Add weakmap key preservation support to cycle collector (r=mccr8) --- content/base/src/nsContentUtils.cpp | 2 +- js/src/jsfriendapi.cpp | 8 ++++++++ js/src/jsfriendapi.h | 3 +++ js/xpconnect/src/nsXPConnect.cpp | 10 ++++++++-- xpcom/base/nsCycleCollector.cpp | 23 ++++++++++++++++------- xpcom/glue/nsCycleCollectionParticipant.h | 2 +- 6 files changed, 37 insertions(+), 11 deletions(-) diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index 783fa5cfc51..d3b3dd7f820 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -6358,7 +6358,7 @@ public: { } - NS_IMETHOD_(void) NoteWeakMapping(void* map, void* key, void* val) + NS_IMETHOD_(void) NoteWeakMapping(void* map, void* key, void* kdelegate, void* val) { } diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 1d985a0098f..0cdcd64d9e7 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -532,6 +532,14 @@ js::VisitGrayWrapperTargets(JSCompartment *comp, GCThingCallback *callback, void } } +JS_FRIEND_API(JSObject *) +js::GetWeakmapKeyDelegate(JSObject *key) +{ + if (JSWeakmapKeyDelegateOp op = key->getClass()->ext.weakmapKeyDelegateOp) + return op(key); + return NULL; +} + JS_FRIEND_API(void) JS_SetAccumulateTelemetryCallback(JSRuntime *rt, JSAccumulateTelemetryDataCallback callback) { diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 6aa0c8fcdce..a5933eeb44b 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -265,6 +265,9 @@ typedef void extern JS_FRIEND_API(void) VisitGrayWrapperTargets(JSCompartment *comp, GCThingCallback *callback, void *closure); +extern JS_FRIEND_API(JSObject *) +GetWeakmapKeyDelegate(JSObject *key); + /* * Shadow declarations of JS internal structures, for access by inline access * functions below. Do not use these structures in any other way. When adding diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index 45db61ba67b..feaf1bc8853 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -398,6 +398,7 @@ struct NoteWeakMapChildrenTracer : public JSTracer nsCycleCollectionTraversalCallback &mCb; JSObject *mMap; void *mKey; + void *mKeyDelegate; }; static void @@ -412,7 +413,7 @@ TraceWeakMappingChild(JSTracer *trc, void **thingp, JSGCTraceKind kind) if (!xpc_IsGrayGCThing(thing) && !tracer->mCb.WantAllTraces()) return; if (AddToCCKind(kind)) { - tracer->mCb.NoteWeakMapping(tracer->mMap, tracer->mKey, thing); + tracer->mCb.NoteWeakMapping(tracer->mMap, tracer->mKey, tracer->mKeyDelegate, thing); } else { JS_TraceChildren(trc, thing, kind); } @@ -455,11 +456,16 @@ TraceWeakMapping(js::WeakMapTracer *trc, JSObject *m, if (!AddToCCKind(kkind)) k = nullptr; + JSObject *kdelegate = NULL; + if (kkind == JSTRACE_OBJECT) + kdelegate = js::GetWeakmapKeyDelegate((JSObject *)k); + if (AddToCCKind(vkind)) { - tracer->mCb.NoteWeakMapping(m, k, v); + tracer->mCb.NoteWeakMapping(m, k, kdelegate, v); } else { tracer->mChildTracer.mMap = m; tracer->mChildTracer.mKey = k; + tracer->mChildTracer.mKeyDelegate = kdelegate; JS_TraceChildren(&tracer->mChildTracer, v, vkind); } } diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index ff571bb0b96..ef97b3929ae 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -669,6 +669,7 @@ struct WeakMapping // map and key will be null if the corresponding objects are GC marked PtrInfo *mMap; PtrInfo *mKey; + PtrInfo *mKeyDelegate; PtrInfo *mVal; }; @@ -1678,7 +1679,7 @@ public: nsCycleCollectionParticipant *participant); NS_IMETHOD_(void) NoteNextEdgeName(const char* name); - NS_IMETHOD_(void) NoteWeakMapping(void *map, void *key, void *val); + NS_IMETHOD_(void) NoteWeakMapping(void *map, void *key, void *kdelegate, void *val); private: NS_IMETHOD_(void) NoteRoot(void *root, @@ -1968,7 +1969,7 @@ GCGraphBuilder::AddWeakMapNode(void *node) } NS_IMETHODIMP_(void) -GCGraphBuilder::NoteWeakMapping(void *map, void *key, void *val) +GCGraphBuilder::NoteWeakMapping(void *map, void *key, void *kdelegate, void *val) { PtrInfo *valNode = AddWeakMapNode(val); @@ -1978,6 +1979,7 @@ GCGraphBuilder::NoteWeakMapping(void *map, void *key, void *val) WeakMapping *mapping = mWeakMaps.AppendElement(); mapping->mMap = map ? AddWeakMapNode(map) : nullptr; mapping->mKey = key ? AddWeakMapNode(key) : nullptr; + mapping->mKeyDelegate = kdelegate ? AddWeakMapNode(kdelegate) : mapping->mKey; mapping->mVal = valNode; } @@ -2021,7 +2023,7 @@ public: NS_IMETHOD_(void) NoteNativeRoot(void *root, nsCycleCollectionParticipant *helper) {} NS_IMETHOD_(void) NoteNextEdgeName(const char* name) {} - NS_IMETHOD_(void) NoteWeakMapping(void *map, void *key, void *val) {} + NS_IMETHOD_(void) NoteWeakMapping(void *map, void *key, void *kdelegate, void *val) {} bool MayHaveChild() { return mMayHaveChild; } @@ -2206,15 +2208,22 @@ nsCycleCollector::ScanWeakMaps() // If mMap or mKey are null, the original object was marked black. uint32_t mColor = wm->mMap ? wm->mMap->mColor : black; uint32_t kColor = wm->mKey ? wm->mKey->mColor : black; + uint32_t kdColor = wm->mKeyDelegate ? wm->mKeyDelegate->mColor : black; PtrInfo *v = wm->mVal; // All non-null weak mapping maps, keys and values are // roots (in the sense of WalkFromRoots) in the cycle // collector graph, and thus should have been colored // either black or white in ScanRoots(). - NS_ASSERTION(mColor != grey, "Uncolored weak map"); - NS_ASSERTION(kColor != grey, "Uncolored weak map key"); - NS_ASSERTION(v->mColor != grey, "Uncolored weak map value"); + MOZ_ASSERT(mColor != grey, "Uncolored weak map"); + MOZ_ASSERT(kColor != grey, "Uncolored weak map key"); + MOZ_ASSERT(kdColor != grey, "Uncolored weak map key delegate"); + MOZ_ASSERT(v->mColor != grey, "Uncolored weak map value"); + + if (mColor == black && kColor != black && kdColor == black) { + GraphWalker(ScanBlackVisitor(mWhiteNodeCount)).Walk(wm->mKey); + anyChanged = true; + } if (mColor == black && kColor == black && v->mColor != black) { GraphWalker(ScanBlackVisitor(mWhiteNodeCount)).Walk(v); @@ -2471,7 +2480,7 @@ public: NS_IMETHOD_(void) NoteNativeChild(void *child, nsCycleCollectionParticipant *participant) {} NS_IMETHOD_(void) NoteNextEdgeName(const char* name) {} - NS_IMETHOD_(void) NoteWeakMapping(void *map, void *key, void *val) {} + NS_IMETHOD_(void) NoteWeakMapping(void *map, void *key, void *kdelegate, void *val) {} }; char *Suppressor::sSuppressionList = nullptr; diff --git a/xpcom/glue/nsCycleCollectionParticipant.h b/xpcom/glue/nsCycleCollectionParticipant.h index b4ac1843e5b..28c5855683b 100644 --- a/xpcom/glue/nsCycleCollectionParticipant.h +++ b/xpcom/glue/nsCycleCollectionParticipant.h @@ -84,7 +84,7 @@ public: // flags. NS_IMETHOD_(void) NoteNextEdgeName(const char* name) = 0; - NS_IMETHOD_(void) NoteWeakMapping(void *map, void *key, void *val) = 0; + NS_IMETHOD_(void) NoteWeakMapping(void *map, void *key, void *kdelegate, void *val) = 0; enum { // Values for flags: From 17957fa850ce6e986fc2eefe931fe4d238527e98 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Wed, 17 Oct 2012 18:22:54 -0700 Subject: [PATCH 18/46] Bug 798678 - Weakmap key preservation test (r=mccr8) --- js/src/jsweakmap.cpp | 6 +- js/xpconnect/tests/chrome/Makefile.in | 1 + .../chrome/test_weakmap_keys_preserved2.xul | 84 +++++++++++++++++++ 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 js/xpconnect/tests/chrome/test_weakmap_keys_preserved2.xul diff --git a/js/src/jsweakmap.cpp b/js/src/jsweakmap.cpp index 1f42e691d4d..94c6bd0997c 100644 --- a/js/src/jsweakmap.cpp +++ b/js/src/jsweakmap.cpp @@ -271,6 +271,7 @@ WeakMap_set(JSContext *cx, unsigned argc, Value *vp) JS_FRIEND_API(JSBool) JS_NondeterministicGetWeakMapKeys(JSContext *cx, JSObject *obj, JSObject **ret) { + obj = UnwrapObject(obj); if (!obj || !obj->isWeakMap()) { *ret = NULL; return true; @@ -281,7 +282,10 @@ JS_NondeterministicGetWeakMapKeys(JSContext *cx, JSObject *obj, JSObject **ret) ObjectValueMap *map = GetObjectMap(obj); if (map) { for (ObjectValueMap::Base::Range r = map->all(); !r.empty(); r.popFront()) { - if (!js_NewbornArrayPush(cx, arr, ObjectValue(*r.front().key))) + RootedObject key(cx, r.front().key); + if (!JS_WrapObject(cx, key.address())) + return false; + if (!js_NewbornArrayPush(cx, arr, ObjectValue(*key))) return false; } } diff --git a/js/xpconnect/tests/chrome/Makefile.in b/js/xpconnect/tests/chrome/Makefile.in index d93873c26ff..6787ef6f7aa 100644 --- a/js/xpconnect/tests/chrome/Makefile.in +++ b/js/xpconnect/tests/chrome/Makefile.in @@ -63,6 +63,7 @@ MOCHITEST_CHROME_FILES = \ test_sandboxImport.xul \ test_weakmaps.xul \ test_weakmap_keys_preserved.xul \ + test_weakmap_keys_preserved2.xul \ test_weakref.xul \ test_wrappers.xul \ $(NULL) diff --git a/js/xpconnect/tests/chrome/test_weakmap_keys_preserved2.xul b/js/xpconnect/tests/chrome/test_weakmap_keys_preserved2.xul new file mode 100644 index 00000000000..349dd2d18b6 --- /dev/null +++ b/js/xpconnect/tests/chrome/test_weakmap_keys_preserved2.xul @@ -0,0 +1,84 @@ + + + + + + + From 7a9c77d810bf6cf31cb6a91f2c7fedc6d31b2068 Mon Sep 17 00:00:00 2001 From: Shane Caraveo Date: Tue, 16 Oct 2012 16:47:42 -0700 Subject: [PATCH 19/46] Bug 802395: fix parse error caused by messages being sent when the port isn't yet fully initialized, r=gavin --- toolkit/components/social/MessagePortBase.jsm | 2 +- .../social/test/browser/browser_workerAPI.js | 23 +++++++++++-------- .../social/test/browser/worker_social.js | 3 +++ 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/toolkit/components/social/MessagePortBase.jsm b/toolkit/components/social/MessagePortBase.jsm index 6b2b2397a3b..7a24c4e67f9 100644 --- a/toolkit/components/social/MessagePortBase.jsm +++ b/toolkit/components/social/MessagePortBase.jsm @@ -44,10 +44,10 @@ AbstractPort.prototype = { // Further, we allow the workers to override exactly how the JSON parsing // is done - we try and do such parsing in the client window so things // like prototype overrides on Array work as expected. - data = this._JSONParse(data); if (!this._handler) { this._pendingMessagesIncoming.push(data); } else { + data = this._JSONParse(data); try { this._handler({ data: data, diff --git a/toolkit/components/social/test/browser/browser_workerAPI.js b/toolkit/components/social/test/browser/browser_workerAPI.js index 6079bc3347d..d8560de4e23 100644 --- a/toolkit/components/social/test/browser/browser_workerAPI.js +++ b/toolkit/components/social/test/browser/browser_workerAPI.js @@ -114,13 +114,20 @@ let tests = { // the worker was loaded again and ports reconnected let reloading = false; let worker = fw.getFrameWorkerHandle(provider.workerURL, undefined, "testWorkerReload"); - let win = worker._worker.frame.contentWindow; + let frame = worker._worker.frame; + let win = frame.contentWindow; + let port = provider.getWorkerPort(); win.addEventListener("unload", function workerUnload(e) { win.removeEventListener("unload", workerUnload); ok(true, "worker unload event has fired"); - reloading = true; + is(port._pendingMessagesOutgoing.length, 0, "port has no pending outgoing message"); + }); + frame.addEventListener("DOMWindowCreated", function workerLoaded(e) { + frame.removeEventListener("DOMWindowCreated", workerLoaded); + // send a message which should end up pending + port.postMessage({topic: "test-pending-msg"}); + ok(port._pendingMessagesOutgoing.length > 0, "port has pending outgoing message"); }); - let port = provider.getWorkerPort(); ok(port, "provider has a port"); port.onmessage = function (e) { let topic = e.data.topic; @@ -129,13 +136,9 @@ let tests = { // tell the worker to send the reload msg port.postMessage({topic: "test-reload-init"}); break; - case "worker.connected": - // we'll get this message from the worker on every load of the worker, - // so we need to ignore it unless we have requested the reload. - if (reloading) { - ok(true, "worker reloaded and testPort was reconnected"); - next(); - } + case "test-pending-response": + ok(true, "worker reloaded and testPort was reconnected"); + next(); break; } } diff --git a/toolkit/components/social/test/browser/worker_social.js b/toolkit/components/social/test/browser/worker_social.js index da2ff34f4fd..700bc27e8c3 100644 --- a/toolkit/components/social/test/browser/worker_social.js +++ b/toolkit/components/social/test/browser/worker_social.js @@ -25,6 +25,9 @@ onconnect = function(e) { case "test-profile": apiPort.postMessage({topic: "social.user-profile", data: data}); break; + case "test-pending-msg": + port.postMessage({topic: "test-pending-response"}) + break; case "test-ambient": apiPort.postMessage({topic: "social.ambient-notification", data: data}); break; From 987adce89701557f16011c32b1522d53e1dbb508 Mon Sep 17 00:00:00 2001 From: Donovan Preston Date: Wed, 17 Oct 2012 22:29:58 -0400 Subject: [PATCH 20/46] Bug 784893 - Rename the event's .socket attribute to .target; remove "on" prefix from event names. r=jonas --- dom/network/interfaces/nsIDOMTCPSocket.idl | 12 +++---- dom/network/src/TCPSocket.js | 34 +++++++++---------- .../src/TCPSocketParentIntermediary.js | 4 +-- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/dom/network/interfaces/nsIDOMTCPSocket.idl b/dom/network/interfaces/nsIDOMTCPSocket.idl index 8f07af2e71a..1e9e03a8827 100644 --- a/dom/network/interfaces/nsIDOMTCPSocket.idl +++ b/dom/network/interfaces/nsIDOMTCPSocket.idl @@ -210,16 +210,16 @@ interface nsITCPSocketEvent : nsISupports { /** * The socket object which produced this event. */ - readonly attribute nsIDOMTCPSocket socket; + readonly attribute nsIDOMTCPSocket target; /** * The type of this event. One of: * - * onopen - * onerror - * ondata - * ondrain - * onclose + * open + * error + * data + * drain + * close */ readonly attribute DOMString type; diff --git a/dom/network/src/TCPSocket.js b/dom/network/src/TCPSocket.js index 2f8b08c13db..74587bf5ef8 100644 --- a/dom/network/src/TCPSocket.js +++ b/dom/network/src/TCPSocket.js @@ -49,21 +49,21 @@ function LOG(msg) { function TCPSocketEvent(type, sock, data) { this._type = type; - this._socket = sock; + this._target = sock; this._data = data; } TCPSocketEvent.prototype = { __exposedProps__: { type: 'r', - socket: 'r', + target: 'r', data: 'r' }, get type() { return this._type; }, - get socket() { - return this._socket; + get target() { + return this._target; }, get data() { return this._data; @@ -233,8 +233,8 @@ TCPSocket.prototype = { self._readyState = kCLOSED; let err = new Error("Connection closed while writing: " + status); err.status = status; - self.callListener("onerror", err); - self.callListener("onclose"); + self.callListener("error", err); + self.callListener("close"); return; } @@ -243,12 +243,12 @@ TCPSocket.prototype = { } else { if (self._waitingForDrain) { self._waitingForDrain = false; - self.callListener("ondrain"); + self.callListener("drain"); } if (self._readyState === kCLOSING) { self._socketOutputStream.close(); self._readyState = kCLOSED; - self.callListener("onclose"); + self.callListener("close"); } } } @@ -256,10 +256,10 @@ TCPSocket.prototype = { }, callListener: function ts_callListener(type, data) { - if (!this[type]) + if (!this["on" + type]) return; - this[type].call(null, new TCPSocketEvent(type, this, data || "")); + this["on" + type].call(null, new TCPSocketEvent(type, this, data || "")); }, /* nsITCPSocketInternal methods */ @@ -519,7 +519,7 @@ TCPSocket.prototype = { transport, status, progress, max) { if (status === Ci.nsISocketTransport.STATUS_CONNECTED_TO) { this._readyState = kOPEN; - this.callListener("onopen"); + this.callListener("open"); this._inputStreamPump = new InputStreamPump( this._socketInputStream, -1, -1, 0, 0, false @@ -539,7 +539,7 @@ TCPSocket.prototype = { try { input.available(); } catch (e) { - this.callListener("onerror", new Error("Connection refused")); + this.callListener("error", new Error("Connection refused")); } }, @@ -567,10 +567,10 @@ TCPSocket.prototype = { if (status) { let err = new Error("Connection closed: " + status); err.status = status; - this.callListener("onerror", err); + this.callListener("error", err); } - this.callListener("onclose"); + this.callListener("close"); }, // nsIStreamListener (Triggered by _inputStreamPump.asyncRead) @@ -579,9 +579,9 @@ TCPSocket.prototype = { let ua = this.useWin ? new this.useWin.Uint8Array(count) : new Uint8Array(count); ua.set(this._inputStreamBinary.readByteArray(count)); - this.callListener("ondata", ua); + this.callListener("data", ua); } else { - this.callListener("ondata", this._inputStreamScriptable.read(count)); + this.callListener("data", this._inputStreamScriptable.read(count)); } }, @@ -617,7 +617,7 @@ function SecurityCallbacks(socket) { SecurityCallbacks.prototype = { notifyCertProblem: function sc_notifyCertProblem(socketInfo, status, targetSite) { - this._socket.callListener("onerror", status); + this._socket.callListener("error", status); this._socket.close(); return true; }, diff --git a/dom/network/src/TCPSocketParentIntermediary.js b/dom/network/src/TCPSocketParentIntermediary.js index 719fadf4e8b..b70034abaf8 100644 --- a/dom/network/src/TCPSocketParentIntermediary.js +++ b/dom/network/src/TCPSocketParentIntermediary.js @@ -26,9 +26,9 @@ TCPSocketParentIntermediary.prototype = { // Create handlers for every possible callback that attempt to trigger // corresponding callbacks on the child object. - ["onopen", "ondrain", "ondata", "onerror", "onclose"].forEach( + ["open", "drain", "data", "error", "close"].forEach( function(p) { - socket[p] = function(data) { + socket["on" + p] = function(data) { aParentSide.sendCallback(p, data.data, socket.readyState, socket.bufferedAmount); }; From 8c26b9b1d74ed656c10c17f9825eb4cc21e81e8b Mon Sep 17 00:00:00 2001 From: pushkarsingh Date: Wed, 17 Oct 2012 23:53:40 -0400 Subject: [PATCH 21/46] Bug 779511 - Freeing buffers should be moved out of finalize functions. r=kats --- mobile/android/base/gfx/BufferedCairoImage.java | 12 ++++++++++++ mobile/android/base/gfx/CairoImage.java | 2 ++ mobile/android/base/gfx/CheckerboardImage.java | 13 +++++++++++++ mobile/android/base/gfx/LayerRenderer.java | 14 ++++++++++++++ mobile/android/base/gfx/LayerView.java | 3 +++ mobile/android/base/gfx/ScreenshotLayer.java | 10 ++++++++++ mobile/android/base/gfx/TileLayer.java | 11 +++++++++++ 7 files changed, 65 insertions(+) diff --git a/mobile/android/base/gfx/BufferedCairoImage.java b/mobile/android/base/gfx/BufferedCairoImage.java index 59ca707e9d6..cc5fdfb333b 100644 --- a/mobile/android/base/gfx/BufferedCairoImage.java +++ b/mobile/android/base/gfx/BufferedCairoImage.java @@ -8,6 +8,7 @@ package org.mozilla.gecko.gfx; import org.mozilla.gecko.mozglue.DirectBufferAllocator; import android.graphics.Bitmap; +import android.util.Log; import java.nio.ByteBuffer; @@ -17,6 +18,8 @@ public class BufferedCairoImage extends CairoImage { private IntSize mSize; private int mFormat; + private static String LOGTAG = "GeckoBufferedCairoImage"; + /** Creates a buffered Cairo image from a byte buffer. */ public BufferedCairoImage(ByteBuffer inBuffer, int inWidth, int inHeight, int inFormat) { setBuffer(inBuffer, inWidth, inHeight, inFormat); @@ -40,6 +43,15 @@ public class BufferedCairoImage extends CairoImage { } } + @Override + public void destroy() { + try { + freeBuffer(); + } catch (Exception ex) { + Log.e(LOGTAG, "error clearing buffer: ", ex); + } + } + @Override public ByteBuffer getBuffer() { return mBuffer; } @Override diff --git a/mobile/android/base/gfx/CairoImage.java b/mobile/android/base/gfx/CairoImage.java index 075090117e5..5a18a4bb199 100644 --- a/mobile/android/base/gfx/CairoImage.java +++ b/mobile/android/base/gfx/CairoImage.java @@ -13,6 +13,8 @@ import java.nio.ByteBuffer; public abstract class CairoImage { public abstract ByteBuffer getBuffer(); + public abstract void destroy(); + public abstract IntSize getSize(); public abstract int getFormat(); diff --git a/mobile/android/base/gfx/CheckerboardImage.java b/mobile/android/base/gfx/CheckerboardImage.java index 48655c99a6c..1f336e9952a 100644 --- a/mobile/android/base/gfx/CheckerboardImage.java +++ b/mobile/android/base/gfx/CheckerboardImage.java @@ -8,6 +8,7 @@ package org.mozilla.gecko.gfx; import org.mozilla.gecko.mozglue.DirectBufferAllocator; import android.graphics.Color; +import android.util.Log; import java.nio.ByteBuffer; import java.nio.ShortBuffer; @@ -24,6 +25,8 @@ public class CheckerboardImage extends CairoImage { // The amount to mix in. private static final float TINT_OPACITY = 0.4f; + private static String LOGTAG = "GeckoCheckerboardImage"; + private ByteBuffer mBuffer; private int mMainColor; private boolean mShowChecks; @@ -121,6 +124,16 @@ public class CheckerboardImage extends CairoImage { } } + @Override + public void destroy() { + try { + DirectBufferAllocator.free(mBuffer); + mBuffer = null; + } catch (Exception ex) { + Log.e(LOGTAG, "error clearing buffer: ", ex); + } + } + @Override public ByteBuffer getBuffer() { return mBuffer; diff --git a/mobile/android/base/gfx/LayerRenderer.java b/mobile/android/base/gfx/LayerRenderer.java index 029380d72c7..dfe5b1e50a3 100644 --- a/mobile/android/base/gfx/LayerRenderer.java +++ b/mobile/android/base/gfx/LayerRenderer.java @@ -179,6 +179,20 @@ public class LayerRenderer { } } + public void destroy() { + DirectBufferAllocator.free(mCoordByteBuffer); + mCoordByteBuffer = null; + mCoordBuffer = null; + mScreenshotLayer.destroy(); + mBackgroundLayer.destroy(); + mShadowLayer.destroy(); + mHorizScrollLayer.destroy(); + mVertScrollLayer.destroy(); + if (mFrameRateLayer != null) { + mFrameRateLayer.destroy(); + } + } + void onSurfaceCreated(EGLConfig config) { checkMonitoringEnabled(); createDefaultProgram(); diff --git a/mobile/android/base/gfx/LayerView.java b/mobile/android/base/gfx/LayerView.java index 0f8dbd43154..ab3ab78c6f1 100644 --- a/mobile/android/base/gfx/LayerView.java +++ b/mobile/android/base/gfx/LayerView.java @@ -112,6 +112,9 @@ public class LayerView extends FrameLayout { if (mLayerClient != null) { mLayerClient.destroy(); } + if (mRenderer != null) { + mRenderer.destroy(); + } } @Override diff --git a/mobile/android/base/gfx/ScreenshotLayer.java b/mobile/android/base/gfx/ScreenshotLayer.java index b43ffd2a373..c9c2c43f15b 100644 --- a/mobile/android/base/gfx/ScreenshotLayer.java +++ b/mobile/android/base/gfx/ScreenshotLayer.java @@ -115,6 +115,16 @@ public class ScreenshotLayer extends SingleTileLayer { } } + @Override + public void destroy() { + try { + DirectBufferAllocator.free(mBuffer); + mBuffer = null; + } catch (Exception ex) { + Log.e(LOGTAG, "error clearing buffers: ", ex); + } + } + void copyBuffer(ByteBuffer src, ByteBuffer dst, Rect rect, int stride) { int start = (rect.top * stride) + (rect.left * BYTES_FOR_16BPP); int end = ((rect.bottom - 1) * stride) + (rect.right * BYTES_FOR_16BPP); diff --git a/mobile/android/base/gfx/TileLayer.java b/mobile/android/base/gfx/TileLayer.java index 73d4b9d317e..e860ff91b8f 100644 --- a/mobile/android/base/gfx/TileLayer.java +++ b/mobile/android/base/gfx/TileLayer.java @@ -7,6 +7,7 @@ package org.mozilla.gecko.gfx; import android.graphics.Rect; import android.opengl.GLES20; +import android.util.Log; import java.nio.ByteBuffer; @@ -50,6 +51,16 @@ public abstract class TileLayer extends Layer { } } + public void destroy() { + try { + if (mImage != null) { + mImage.destroy(); + } + } catch (Exception ex) { + Log.e(LOGTAG, "error clearing buffers: ", ex); + } + } + public void setPaintMode(PaintMode mode) { mPaintMode = mode; } From 37264f7176bc1660cfbafaa01ebd4fbec03cf6de Mon Sep 17 00:00:00 2001 From: Jason Duell Date: Wed, 17 Oct 2012 22:00:16 -0700 Subject: [PATCH 22/46] Bug 802885 - Disable offline cache entries for private channels under e10s r=jdm --- docshell/base/nsDocShell.cpp | 40 +++++++-------------- docshell/base/nsDocShell.h | 4 --- netwerk/base/public/nsNetUtil.h | 24 +++++++++++++ netwerk/protocol/http/HttpChannelParent.cpp | 16 +++------ 4 files changed, 41 insertions(+), 43 deletions(-) diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 09c7afaae23..e1dfc24a863 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -6425,11 +6425,14 @@ nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel, nsCOMPtr appCacheChannel = do_QueryInterface(aNewChannel); if (appCacheChannel) { - // Permission will be checked in the parent process. - if (GeckoProcessType_Default != XRE_GetProcessType()) + if (GeckoProcessType_Default != XRE_GetProcessType()) { + // Permission will be checked in the parent process. appCacheChannel->SetChooseApplicationCache(true); - else - appCacheChannel->SetChooseApplicationCache(ShouldCheckAppCache(newURI)); + } else { + appCacheChannel->SetChooseApplicationCache( + NS_ShouldCheckAppCache(newURI, + mInPrivateBrowsing)); + } } if (!(aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) && @@ -9169,26 +9172,6 @@ nsDocShell::GetInheritedPrincipal(bool aConsiderCurrentDocument) return nullptr; } -bool -nsDocShell::ShouldCheckAppCache(nsIURI *aURI) -{ - if (mInPrivateBrowsing) { - return false; - } - - nsCOMPtr offlineService = - do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID); - if (!offlineService) { - return false; - } - - bool allowed; - nsresult rv = offlineService->OfflineAppAllowedForURI(aURI, - nullptr, - &allowed); - return NS_SUCCEEDED(rv) && allowed; -} - nsresult nsDocShell::DoURILoad(nsIURI * aURI, nsIURI * aReferrerURI, @@ -9276,12 +9259,13 @@ nsDocShell::DoURILoad(nsIURI * aURI, // Loads with the correct permissions should check for a matching // application cache. - // Permission will be checked in the parent process - if (GeckoProcessType_Default != XRE_GetProcessType()) + if (GeckoProcessType_Default != XRE_GetProcessType()) { + // Permission will be checked in the parent process appCacheChannel->SetChooseApplicationCache(true); - else + } else { appCacheChannel->SetChooseApplicationCache( - ShouldCheckAppCache(aURI)); + NS_ShouldCheckAppCache(aURI, mInPrivateBrowsing)); + } } // Make sure to give the caller a channel if we managed to create one diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index 4916c98d0a8..6e40493b934 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -282,10 +282,6 @@ protected: // at the parent. nsIPrincipal* GetInheritedPrincipal(bool aConsiderCurrentDocument); - // True if when loading aURI into this docshell, the channel should look - // for an appropriate application cache. - bool ShouldCheckAppCache(nsIURI * aURI); - // Actually open a channel and perform a URI load. Note: whatever owner is // passed to this function will be set on the channel. Callers who wish to // not have an owner on the channel should just pass null. diff --git a/netwerk/base/public/nsNetUtil.h b/netwerk/base/public/nsNetUtil.h index 60277494682..d4778fbdf09 100644 --- a/netwerk/base/public/nsNetUtil.h +++ b/netwerk/base/public/nsNetUtil.h @@ -78,6 +78,7 @@ #include "mozilla/Services.h" #include "nsIPrivateBrowsingChannel.h" #include "mozIApplicationClearPrivateDataParams.h" +#include "nsIOfflineCacheUpdate.h" #include @@ -1375,6 +1376,29 @@ NS_GetAppInfoFromClearDataNotification(nsISupports *aSubject, return NS_OK; } +/** + * Determines whether appcache should be checked for a given URI. + */ +inline bool +NS_ShouldCheckAppCache(nsIURI *aURI, bool usePrivateBrowsing) +{ + if (usePrivateBrowsing) { + return false; + } + + nsCOMPtr offlineService = + do_GetService("@mozilla.org/offlinecacheupdate-service;1"); + if (!offlineService) { + return false; + } + + bool allowed; + nsresult rv = offlineService->OfflineAppAllowedForURI(aURI, + nullptr, + &allowed); + return NS_SUCCEEDED(rv) && allowed; +} + /** * Wraps an nsIAuthPrompt so that it can be used as an nsIAuthPrompt2. This * method is provided mainly for use by other methods in this file. diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index 89e38e64d3d..39f2f9b56ff 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -211,7 +211,7 @@ HttpChannelParent::RecvAsyncOpen(const URIParams& aURI, bool setChooseApplicationCache = chooseApplicationCache; if (appCacheChan && appCacheService) { // We might potentially want to drop this flag (that is TRUE by default) - // after we succefully associate the channel with an application cache + // after we successfully associate the channel with an application cache // reported by the channel child. Dropping it here may be too early. appCacheChan->SetInheritApplicationCache(false); if (!appCacheClientID.IsEmpty()) { @@ -225,16 +225,10 @@ HttpChannelParent::RecvAsyncOpen(const URIParams& aURI, } if (setChooseApplicationCache) { - nsCOMPtr offlineUpdateService = - do_GetService("@mozilla.org/offlinecacheupdate-service;1", &rv); - if (NS_SUCCEEDED(rv)) { - rv = offlineUpdateService->OfflineAppAllowedForURI(uri, - nullptr, - &setChooseApplicationCache); - - if (setChooseApplicationCache && NS_SUCCEEDED(rv)) - appCacheChan->SetChooseApplicationCache(true); - } + // This works because we've already called SetNotificationCallbacks and + // done mPBOverride logic by this point. + appCacheChan->SetChooseApplicationCache( + NS_ShouldCheckAppCache(uri, NS_UsePrivateBrowsing(mChannel))); } } From 31bcc858c290ff8e60335678b8b30217e8ae7e32 Mon Sep 17 00:00:00 2001 From: Timothy Nikkel Date: Thu, 18 Oct 2012 00:34:58 -0500 Subject: [PATCH 23/46] Bug 642257. If there are no plugins in the display list skip a potentially expensive compute visibility pass with accurate visible regions to determine plugin geometry because it is not needed. r=roc If there is a plugin in a background tab and a complex scene in a foreground tab the accurate visible regions can cause us to bog down, for no good reason. --- layout/base/nsDisplayList.cpp | 3 ++- layout/base/nsDisplayList.h | 4 ++++ layout/base/nsPresContext.cpp | 25 ++++++++++++------------- layout/generic/nsObjectFrame.h | 1 + 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 62b0e474cbe..1e33cde9833 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -448,7 +448,8 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame, mHasDisplayPort(false), mHasFixedItems(false), mIsInFixedPosition(false), - mIsCompositingCheap(false) + mIsCompositingCheap(false), + mContainsPluginItem(false) { MOZ_COUNT_CTOR(nsDisplayListBuilder); PL_InitArenaPool(&mPool, "displayListArena", 1024, diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index acbcc7e1253..81dc3acec96 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -582,6 +582,9 @@ public: return aItem == mGlassDisplayItem; } + void SetContainsPluginItem() { mContainsPluginItem = true; } + bool ContainsPluginItem() { return mContainsPluginItem; } + private: void MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, nsIFrame* aFrame, const nsRect& aDirtyRect); @@ -635,6 +638,7 @@ private: bool mHasFixedItems; bool mIsInFixedPosition; bool mIsCompositingCheap; + bool mContainsPluginItem; }; class nsDisplayItem; diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 825be762346..d8c8313f9ff 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -2544,20 +2544,19 @@ nsRootPresContext::ComputePluginGeometryUpdates(nsIFrame* aFrame, mRegisteredPlugins.EnumerateEntries(SetPluginHidden, aFrame); nsIFrame* rootFrame = FrameManager()->GetRootFrame(); - if (!rootFrame) { - return; - } - aBuilder->SetForPluginGeometry(); - aBuilder->SetAccurateVisibleRegions(); - // Merging and flattening has already been done and we should not do it - // again. nsDisplayScroll(Info)Layer doesn't support trying to flatten - // again. - aBuilder->SetAllowMergingAndFlattening(false); - nsRegion region = rootFrame->GetVisualOverflowRectRelativeToSelf(); - // nsDisplayPlugin::ComputeVisibility will automatically set a non-hidden - // widget configuration for the plugin, if it's visible. - aList->ComputeVisibilityForRoot(aBuilder, ®ion); + if (rootFrame && aBuilder->ContainsPluginItem()) { + aBuilder->SetForPluginGeometry(); + aBuilder->SetAccurateVisibleRegions(); + // Merging and flattening has already been done and we should not do it + // again. nsDisplayScroll(Info)Layer doesn't support trying to flatten + // again. + aBuilder->SetAllowMergingAndFlattening(false); + nsRegion region = rootFrame->GetVisualOverflowRectRelativeToSelf(); + // nsDisplayPlugin::ComputeVisibility will automatically set a non-hidden + // widget configuration for the plugin, if it's visible. + aList->ComputeVisibilityForRoot(aBuilder, ®ion); + } InitApplyPluginGeometryTimer(); } diff --git a/layout/generic/nsObjectFrame.h b/layout/generic/nsObjectFrame.h index c6aec787307..4eb86922aa9 100644 --- a/layout/generic/nsObjectFrame.h +++ b/layout/generic/nsObjectFrame.h @@ -299,6 +299,7 @@ public: : nsDisplayItem(aBuilder, aFrame) { MOZ_COUNT_CTOR(nsDisplayPlugin); + aBuilder->SetContainsPluginItem(); } #ifdef NS_BUILD_REFCNT_LOGGING virtual ~nsDisplayPlugin() { From 6c076e658875fb2272b132093cde04cc2dc7a82d Mon Sep 17 00:00:00 2001 From: Felipe Gomes Date: Thu, 18 Oct 2012 16:40:12 +1100 Subject: [PATCH 24/46] Bug 802929 - use existing port handle for socialcookies-get message. r=jaws,mixedpuppy --- toolkit/components/social/WorkerAPI.jsm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/toolkit/components/social/WorkerAPI.jsm b/toolkit/components/social/WorkerAPI.jsm index 398d69c846e..c09d9e4712f 100644 --- a/toolkit/components/social/WorkerAPI.jsm +++ b/toolkit/components/social/WorkerAPI.jsm @@ -63,8 +63,7 @@ WorkerAPI.prototype = { this._provider.setAmbientNotification(data); }, "social.cookies-get": function(data) { - let document = getFrameWorkerHandle(this._provider.workerURL, null). - _worker.frame.contentDocument; + let document = this._port._window.document; let cookies = document.cookie.split(";"); let results = []; cookies.forEach(function(aCookie) { From c23ff0430c5533e9f4403959f7d47fd16a093d10 Mon Sep 17 00:00:00 2001 From: Mark Hammond Date: Thu, 18 Oct 2012 16:42:40 +1100 Subject: [PATCH 25/46] Bug 790201 - better cleanup of social worker sandbox. r=felipe --- toolkit/components/social/FrameWorker.jsm | 91 +++++++++++++++---- .../social/test/browser/worker_relative.js | 1 + 2 files changed, 72 insertions(+), 20 deletions(-) diff --git a/toolkit/components/social/FrameWorker.jsm b/toolkit/components/social/FrameWorker.jsm index 6ec2623870a..fd98efc1b3c 100644 --- a/toolkit/components/social/FrameWorker.jsm +++ b/toolkit/components/social/FrameWorker.jsm @@ -69,6 +69,7 @@ function FrameWorker(url, name) { this.ports = {}; this.pendingPorts = []; this.loaded = false; + this.reloading = false; this.frame = makeHiddenFrame(); this.load(); @@ -81,7 +82,7 @@ FrameWorker.prototype = { if (!doc.defaultView || doc.defaultView != self.frame.contentWindow) { return; } - Services.obs.removeObserver(injectController, "document-element-inserted", false); + Services.obs.removeObserver(injectController, "document-element-inserted"); try { self.createSandbox(); } catch (e) { @@ -100,8 +101,12 @@ FrameWorker.prototype = { this.pendingPorts.push(port); } this.ports = {}; - this.loaded = false; - this.load(); + // reset the iframe to about:blank - this will fire the unload event + // but not remove the iframe from the DOM. Our unload handler will + // (a) set this.loaded to false then (b) see this.reloading is true and + // reload for us. + this.reloading = true; + this.frame.setAttribute("src", "about:blank"); }, createSandbox: function createSandbox() { @@ -118,8 +123,12 @@ FrameWorker.prototype = { 'location']; workerAPI.forEach(function(fn) { try { - // XXX Need to unwrap for this to work - find out why! - sandbox[fn] = XPCNativeWrapper.unwrap(workerWindow)[fn]; + // Bug 798660 - XHR and WebSocket have issues in a sandbox and need + // to be unwrapped to work + if (fn == "XMLHttpRequest" || fn == "WebSocket") + sandbox[fn] = XPCNativeWrapper.unwrap(workerWindow)[fn]; + else + sandbox[fn] = workerWindow[fn]; } catch(e) { Cu.reportError("FrameWorker: failed to import API "+fn+"\n"+e+"\n"); @@ -168,8 +177,9 @@ FrameWorker.prototype = { workerWindow.addEventListener(t, l, c) }; - this.sandbox = sandbox; - + // Note we don't need to stash |sandbox| in |this| as the unload handler + // has a reference in its closure, so it can't die until that handler is + // removed - at which time we've explicitly killed it anyway. let worker = this; workerWindow.addEventListener("load", function loadListener() { @@ -219,24 +229,65 @@ FrameWorker.prototype = { } } }); + + // the 'unload' listener cleans up the worker and the sandbox. This + // will be triggered via either our 'terminate' function or by the + // window unloading as part of shutdown. + workerWindow.addEventListener("unload", function unloadListener() { + workerWindow.removeEventListener("unload", unloadListener); + delete workerCache[worker.url]; + // closing the port also removes it from this.ports via port-close + for (let [portid, port] in Iterator(worker.ports)) { + // port may have been closed as a side-effect from closing another port + if (!port) + continue; + try { + port.close(); + } catch (ex) { + Cu.reportError("FrameWorker: failed to close port. " + ex); + } + } + // Must reset this to an array incase we are being reloaded. + worker.ports = []; + // The worker window may not have fired a load event yet, so pendingPorts + // might still have items in it - close them too. + worker.loaded = false; + // If the worker is reloading, when we don't actually close the pending + // ports as they are the ports which need to be re-entangled. + if (!worker.reloading) { + for (let port of worker.pendingPorts) { + try { + port.close(); + } catch (ex) { + Cu.reportError("FrameWorker: failed to close pending port. " + ex); + } + } + worker.pendingPorts = []; + } + + if (sandbox) { + Cu.nukeSandbox(sandbox); + sandbox = null; + } + if (worker.reloading) { + Services.tm.mainThread.dispatch(function doReload() { + worker.reloading = false; + worker.load(); + }, Ci.nsIThread.DISPATCH_NORMAL); + } + }); }, terminate: function terminate() { - // closing the port also removes it from this.ports via port-close - for (let [portid, port] in Iterator(this.ports)) { - // port may have been closed as a side-effect from closing another port - if (!port) - continue; - try { - port.close(); - } catch (ex) { - Cu.reportError("FrameWorker: failed to close port. " + ex); - } + if (!(this.url in workerCache)) { + // terminating an already terminated worker - ignore it + return; } - + // we want to "forget" about this worker now even though the termination + // may not be complete for a little while... delete workerCache[this.url]; - - // let pending events get delivered before actually removing the frame + // let pending events get delivered before actually removing the frame, + // then we perform the actual cleanup in the unload handler. Services.tm.mainThread.dispatch(function deleteWorkerFrame() { // now nuke the iframe itself and forget everything about this worker. this.frame.parentNode.removeChild(this.frame); diff --git a/toolkit/components/social/test/browser/worker_relative.js b/toolkit/components/social/test/browser/worker_relative.js index 9b50b132f3e..91bce315a52 100644 --- a/toolkit/components/social/test/browser/worker_relative.js +++ b/toolkit/components/social/test/browser/worker_relative.js @@ -10,6 +10,7 @@ onconnect = function(e) { } else { port.postMessage({topic: "done", result: "import worked but global is not available"}); } + return; } catch(e) { port.postMessage({topic: "done", result: "FAILED to importScripts, " + e.toString() }); return; From f085790e09f4aa566cbfaa24910e9857df04f1fe Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Wed, 17 Oct 2012 22:44:26 -0700 Subject: [PATCH 26/46] Bug 799644: Need to clear areas of rgba buffers we're about to repaint. r=mattwoodrow --- gfx/layers/ThebesLayerBuffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfx/layers/ThebesLayerBuffer.cpp b/gfx/layers/ThebesLayerBuffer.cpp index 21a9b0c4726..9e7df632343 100644 --- a/gfx/layers/ThebesLayerBuffer.cpp +++ b/gfx/layers/ThebesLayerBuffer.cpp @@ -312,7 +312,7 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType, // If we have no buffered data already, then destBuffer will be a fresh buffer // and we do not need to clear it below. - bool isClear = mBuffer == nullptr; + bool isClear = !HaveBuffer(); if (destBuffer) { if (HaveBuffer()) { From c4c2d5233d06bfabb6beb32de4dfa32b4bc73763 Mon Sep 17 00:00:00 2001 From: Brian Nicholson Date: Thu, 18 Oct 2012 00:01:01 -0700 Subject: [PATCH 27/46] Bug 718465 - Part 1: Only send SELECTED tab event if the tab has changed. r=mfinkle --- mobile/android/base/Tabs.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/android/base/Tabs.java b/mobile/android/base/Tabs.java index 53efdbdb8f5..a701b45f022 100644 --- a/mobile/android/base/Tabs.java +++ b/mobile/android/base/Tabs.java @@ -130,7 +130,7 @@ public class Tabs implements GeckoEventListener { final Tab tab = mTabs.get(id); // This avoids a NPE below, but callers need to be careful to // handle this case - if (tab == null) + if (tab == null || oldTab == tab) return null; mSelectedTab = tab; From ad37712739b68a83e76eaab4aa338c1cf5659953 Mon Sep 17 00:00:00 2001 From: Brian Nicholson Date: Thu, 18 Oct 2012 00:01:20 -0700 Subject: [PATCH 28/46] Bug 718465 - Part 2: Clear background color when selected tab changes. r=kats --- mobile/android/base/gfx/GeckoLayerClient.java | 6 +++++ mobile/android/base/gfx/LayerRenderer.java | 22 +++++++++++++++++-- mobile/android/base/gfx/LayerView.java | 7 +++--- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/mobile/android/base/gfx/GeckoLayerClient.java b/mobile/android/base/gfx/GeckoLayerClient.java index f834d573450..141b1795aa7 100644 --- a/mobile/android/base/gfx/GeckoLayerClient.java +++ b/mobile/android/base/gfx/GeckoLayerClient.java @@ -497,6 +497,12 @@ public class GeckoLayerClient // a full viewport update, which is fine because if browser.js has somehow moved to // be out of sync with this first-paint viewport, then we force them back in sync. abortPanZoomAnimation(); + + // Indicate that the document is about to be composited so the + // LayerView background can be removed. + if (mView.getPaintState() == LayerView.PAINT_START) { + mView.setPaintState(LayerView.PAINT_BEFORE_FIRST); + } } DisplayPortCalculator.resetPageState(); mDrawTimingQueue.reset(); diff --git a/mobile/android/base/gfx/LayerRenderer.java b/mobile/android/base/gfx/LayerRenderer.java index dfe5b1e50a3..139b0fb7ad8 100644 --- a/mobile/android/base/gfx/LayerRenderer.java +++ b/mobile/android/base/gfx/LayerRenderer.java @@ -6,6 +6,8 @@ package org.mozilla.gecko.gfx; import org.mozilla.gecko.GeckoAppShell; +import org.mozilla.gecko.Tab; +import org.mozilla.gecko.Tabs; import org.mozilla.gecko.gfx.Layer.RenderContext; import org.mozilla.gecko.mozglue.DirectBufferAllocator; @@ -32,7 +34,7 @@ import javax.microedition.khronos.egl.EGLConfig; /** * The layer renderer implements the rendering logic for a layer view. */ -public class LayerRenderer { +public class LayerRenderer implements Tabs.OnTabsChangedListener { private static final String LOGTAG = "GeckoLayerRenderer"; private static final String PROFTAG = "GeckoLayerRendererProf"; @@ -166,6 +168,8 @@ public class LayerRenderer { mCoordByteBuffer = DirectBufferAllocator.allocate(COORD_BUFFER_SIZE * 4); mCoordByteBuffer.order(ByteOrder.nativeOrder()); mCoordBuffer = mCoordByteBuffer.asFloatBuffer(); + + Tabs.registerOnTabsChangedListener(this); } @Override @@ -683,7 +687,9 @@ public class LayerRenderer { } } - // Remove white screen once we've painted + // Remove background color once we've painted. GeckoLayerClient is + // responsible for setting this flag before current document is + // composited. if (mView.getPaintState() == LayerView.PAINT_BEFORE_FIRST) { mView.post(new Runnable() { public void run() { @@ -694,4 +700,16 @@ public class LayerRenderer { } } } + + @Override + public void onTabChanged(final Tab tab, Tabs.TabEvents msg, Object data) { + // Sets the background of the newly selected tab. This background color + // gets cleared in endDrawing(). This function runs on the UI thread, + // but other code that touches the paint state is run on the compositor + // thread, so this may need to be changed if any problems appear. + if (msg == Tabs.TabEvents.SELECTED) { + mView.getChildAt(0).setBackgroundColor(tab.getCheckerboardColor()); + mView.setPaintState(LayerView.PAINT_START); + } + } } diff --git a/mobile/android/base/gfx/LayerView.java b/mobile/android/base/gfx/LayerView.java index ab3ab78c6f1..8c69c50f6c4 100644 --- a/mobile/android/base/gfx/LayerView.java +++ b/mobile/android/base/gfx/LayerView.java @@ -60,8 +60,9 @@ public class LayerView extends FrameLayout { private Listener mListener; /* Flags used to determine when to show the painted surface. */ - public static final int PAINT_BEFORE_FIRST = 0; - public static final int PAINT_AFTER_FIRST = 1; + public static final int PAINT_START = 0; + public static final int PAINT_BEFORE_FIRST = 1; + public static final int PAINT_AFTER_FIRST = 2; public boolean shouldUseTextureView() { // Disable TextureView support for now as it causes panning/zooming @@ -90,7 +91,7 @@ public class LayerView extends FrameLayout { super(context, attrs); mGLController = new GLController(this); - mPaintState = PAINT_BEFORE_FIRST; + mPaintState = PAINT_START; mCheckerboardColor = Color.WHITE; mCheckerboardShouldShowChecks = true; } From 13237d7b5c465b7d3290efaaf2421e7949bae411 Mon Sep 17 00:00:00 2001 From: Brian Nicholson Date: Thu, 18 Oct 2012 00:03:58 -0700 Subject: [PATCH 29/46] Bug 802881 - Use correct tab for getting background color. r=kats --- mobile/android/chrome/content/browser.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 5fa974560d5..04cdace9305 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -2800,12 +2800,9 @@ Tab.prototype = { // event fires; it's not clear that doing so is worth the effort. var backgroundColor = null; try { - let browser = BrowserApp.selectedBrowser; - if (browser) { - let { contentDocument, contentWindow } = browser; - let computedStyle = contentWindow.getComputedStyle(contentDocument.body); - backgroundColor = computedStyle.backgroundColor; - } + let { contentDocument, contentWindow } = this.browser; + let computedStyle = contentWindow.getComputedStyle(contentDocument.body); + backgroundColor = computedStyle.backgroundColor; } catch (e) { // Ignore. Catching and ignoring exceptions here ensures that Talos succeeds. } From c6451f58a11f2c23515ad76783d42eaee2b89c50 Mon Sep 17 00:00:00 2001 From: Nicholas Cameron Date: Thu, 18 Oct 2012 21:39:15 +1300 Subject: [PATCH 30/46] Back out changeset db4fd6efba17 for wrong bug number r=me --- gfx/layers/basic/BasicCanvasLayer.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/gfx/layers/basic/BasicCanvasLayer.cpp b/gfx/layers/basic/BasicCanvasLayer.cpp index d07e56807a0..d434d10f2b3 100644 --- a/gfx/layers/basic/BasicCanvasLayer.cpp +++ b/gfx/layers/basic/BasicCanvasLayer.cpp @@ -416,8 +416,6 @@ BasicShadowableCanvasLayer::Paint(gfxContext* aContext, Layer* aMaskLayer) if (handle) { mGLContext->MakeCurrent(); mGLContext->UpdateSharedHandle(flags, handle); - // call Painted() to reset our dirty 'bit' - Painted(); FireDidTransactionCallback(); BasicManager()->PaintedCanvas(BasicManager()->Hold(this), mNeedsYFlip, From ae19046b6a6f180b6146948b389770d9ad6fbf2c Mon Sep 17 00:00:00 2001 From: Nicholas Cameron Date: Thu, 18 Oct 2012 21:40:32 +1300 Subject: [PATCH 31/46] Bug 802518; add Painted() to BasicShadowableCanvasLayer::Paint; r=jgilbert DONTBUILD --- gfx/layers/basic/BasicCanvasLayer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gfx/layers/basic/BasicCanvasLayer.cpp b/gfx/layers/basic/BasicCanvasLayer.cpp index d434d10f2b3..d07e56807a0 100644 --- a/gfx/layers/basic/BasicCanvasLayer.cpp +++ b/gfx/layers/basic/BasicCanvasLayer.cpp @@ -416,6 +416,8 @@ BasicShadowableCanvasLayer::Paint(gfxContext* aContext, Layer* aMaskLayer) if (handle) { mGLContext->MakeCurrent(); mGLContext->UpdateSharedHandle(flags, handle); + // call Painted() to reset our dirty 'bit' + Painted(); FireDidTransactionCallback(); BasicManager()->PaintedCanvas(BasicManager()->Hold(this), mNeedsYFlip, From 1584d41fa2294b53b9419d6fed12251dbdf3153c Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Wed, 17 Oct 2012 17:51:57 +1300 Subject: [PATCH 32/46] Bug 801763. Don't try to update geometry for plugin widgets with no parent. r=mats --HG-- extra : rebase_source : d7d0f7c5536adc2cd0ad77c2b3169410f237d206 --- layout/generic/nsObjectFrame.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/layout/generic/nsObjectFrame.h b/layout/generic/nsObjectFrame.h index 4eb86922aa9..478ff54ec4d 100644 --- a/layout/generic/nsObjectFrame.h +++ b/layout/generic/nsObjectFrame.h @@ -120,6 +120,14 @@ public: void GetWidgetConfiguration(nsTArray* aConfigurations) { if (mWidget) { + if (!mWidget->GetParent()) { + // Plugin widgets should not be toplevel except when they're out of the + // document, in which case the plugin should not be registered for + // geometry updates and this should not be called. But apparently we + // have bugs where mWidget sometimes is toplevel here. Bail out. + NS_ERROR("Plugin widgets registered for geometry updates should not be toplevel"); + return; + } nsIWidget::Configuration* configuration = aConfigurations->AppendElement(); configuration->mChild = mWidget; configuration->mBounds = mNextConfigurationBounds; From ef3b486fb19ef5e70537da0a3c94c90a09f2cb08 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Wed, 17 Oct 2012 17:51:58 +1300 Subject: [PATCH 33/46] Bug 776505. Assert that nsDeviceContext is created on the main thread only. r=mats --HG-- extra : rebase_source : fcda449b3bf25c9827c2fa2f000c20460819ce53 --- gfx/src/nsDeviceContext.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/gfx/src/nsDeviceContext.cpp b/gfx/src/nsDeviceContext.cpp index 9c6846f1681..6660cb75e53 100644 --- a/gfx/src/nsDeviceContext.cpp +++ b/gfx/src/nsDeviceContext.cpp @@ -226,6 +226,7 @@ nsDeviceContext::nsDeviceContext() mPixelScale(1.0f), mPrintingScale(1.0f), mFontCache(nullptr) { + MOZ_ASSERT(NS_IsMainThread(), "nsDeviceContext created off main thread"); } // Note: we use a bare pointer for mFontCache so that nsFontCache From 7027f42f5da2494f18e169af307ee5a0d0c6367e Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 22 Jun 2012 17:06:49 +1200 Subject: [PATCH 34/46] Bug 703241. PresShell::DoScrollContentIntoView and PresShell::ScrollFrameRectIntoView should take transforms into account. r=matspal --HG-- extra : rebase_source : e1a16f9a19e78ea71044ee78af9fdbf00ec48c0b --- layout/base/nsPresShell.cpp | 24 +++++++++---- .../test_scroll_selection_into_view.html | 35 +++++++++++++++++++ layout/generic/nsIFrame.h | 6 +++- 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 79137790943..03709d015e0 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -2998,8 +2998,8 @@ AccumulateFrameBounds(nsIFrame* aContainerFrame, nsAutoLineIterator& aLines, int32_t& aCurLine) { - nsRect frameBounds = aFrame->GetRect() + - aFrame->GetParent()->GetOffsetTo(aContainerFrame); + nsIFrame* frame = aFrame; + nsRect frameBounds = nsRect(nsPoint(0, 0), aFrame->GetSize()); // If this is an inline frame and either the bounds height is 0 (quirks // layout model) or aUseWholeLineHeightForInlines is set, we need to @@ -3035,7 +3035,8 @@ AccumulateFrameBounds(nsIFrame* aContainerFrame, if (NS_SUCCEEDED(aLines->GetLine(index, &trash1, &trash2, lineBounds, &trash3))) { - lineBounds += f->GetOffsetTo(aContainerFrame); + frameBounds += frame->GetOffsetTo(f); + frame = f; if (lineBounds.y < frameBounds.y) { frameBounds.height = frameBounds.YMost() - lineBounds.y; frameBounds.y = lineBounds.y; @@ -3046,14 +3047,17 @@ AccumulateFrameBounds(nsIFrame* aContainerFrame, } } + nsRect transformedBounds = nsLayoutUtils::TransformFrameRectToAncestor(frame, + frameBounds, aContainerFrame); + if (aHaveRect) { // We can't use nsRect::UnionRect since it drops empty rects on // the floor, and we need to include them. (Thus we need // aHaveRect to know when to drop the initial value on the floor.) - aRect.UnionRectEdges(aRect, frameBounds); + aRect.UnionRectEdges(aRect, transformedBounds); } else { aHaveRect = true; - aRect = frameBounds; + aRect = transformedBounds; } } @@ -3354,8 +3358,14 @@ PresShell::ScrollFrameRectIntoView(nsIFrame* aFrame, break; } } - rect += container->GetPosition(); - nsIFrame* parent = container->GetParent(); + nsIFrame* parent; + if (container->IsTransformed()) { + container->GetTransformMatrix(nullptr, &parent); + rect = nsLayoutUtils::TransformFrameRectToAncestor(container, rect, parent); + } else { + rect += container->GetPosition(); + parent = container->GetParent(); + } if (!parent && !(aFlags & nsIPresShell::SCROLL_NO_PARENT_FRAMES)) { nsPoint extraOffset(0,0); parent = nsLayoutUtils::GetCrossDocParentFrame(container, &extraOffset); diff --git a/layout/base/tests/test_scroll_selection_into_view.html b/layout/base/tests/test_scroll_selection_into_view.html index 833b32ff16c..75ac009dd42 100644 --- a/layout/base/tests/test_scroll_selection_into_view.html +++ b/layout/base/tests/test_scroll_selection_into_view.html @@ -40,6 +40,29 @@
"> +
+
+ target +
+
+
+
+
+
+ target +
+
+
+
+
+
+
+ target +
+
+
+
+
 
+
+
+
diff --git a/parser/htmlparser/tests/reftest/reftest.list b/parser/htmlparser/tests/reftest/reftest.list
index cd378313cbf..d4015f890bd 100644
--- a/parser/htmlparser/tests/reftest/reftest.list
+++ b/parser/htmlparser/tests/reftest/reftest.list
@@ -5,6 +5,7 @@
 == bug582788-1.html bug582788-1-ref.html
 == bug582940-1.html bug582940-1-ref.html
 == bug592656-1.html bug592656-1-ref.html
+== bug599320-1.html bug599320-1-ref.html
 == bug608373-1.html bug608373-1-ref.html
 fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azureSkia) == view-source:bug482921-1.html bug482921-1-ref.html # bug 703201
 == view-source:bug482921-2.xhtml bug482921-2-ref.html

From ba0b96675c48c444ac75f088cd459ba7c5d0691d Mon Sep 17 00:00:00 2001
From: Chris Lord 
Date: Thu, 18 Oct 2012 12:53:33 +0100
Subject: [PATCH 40/46] Bug 802143 - Fix calculation of content bounds in
 ReusableTileStoreOGL. r=bgirard

FrameMetrics changed at some point so that the content rect and scroll offset
are stored pre-multiplied by the render resolution. The display-port calculation
in this function appears to have always been wrong(?)
---
 gfx/layers/opengl/ReusableTileStoreOGL.cpp | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/gfx/layers/opengl/ReusableTileStoreOGL.cpp b/gfx/layers/opengl/ReusableTileStoreOGL.cpp
index 4be94b40c74..8aaa4f80a65 100644
--- a/gfx/layers/opengl/ReusableTileStoreOGL.cpp
+++ b/gfx/layers/opengl/ReusableTileStoreOGL.cpp
@@ -218,15 +218,25 @@ ReusableTileStoreOGL::DrawTiles(TiledThebesLayerOGL* aLayer,
       if (parentMetrics.IsScrollable())
         scrollableLayer = parent;
       if (!parentMetrics.mDisplayPort.IsEmpty() && scrollableLayer) {
-          displayPort = parent->GetEffectiveTransform().
-            TransformBounds(gfxRect(
-              parentMetrics.mDisplayPort.x, parentMetrics.mDisplayPort.y,
-              parentMetrics.mDisplayPort.width, parentMetrics.mDisplayPort.height));
+          // Get the display-port bounds
+          displayPort = gfxRect(parentMetrics.mDisplayPort.x,
+                                parentMetrics.mDisplayPort.y,
+                                parentMetrics.mDisplayPort.width,
+                                parentMetrics.mDisplayPort.height);
+
+          // Check the scale transform applied to the root layer to determine
+          // the content resolution.
+          Layer* rootLayer = aLayer->Manager()->GetRoot();
+          const gfx3DMatrix& rootTransform = rootLayer->GetTransform();
+          float scaleX = rootTransform.GetXScale();
+          float scaleY = rootTransform.GetYScale();
+
+          // Get the content document bounds
           const FrameMetrics& metrics = scrollableLayer->GetFrameMetrics();
           const nsIntSize& contentSize = metrics.mContentRect.Size();
           gfx::Point scrollOffset =
-            gfx::Point(metrics.mScrollOffset.x * metrics.LayersPixelsPerCSSPixel().width,
-                       metrics.mScrollOffset.y * metrics.LayersPixelsPerCSSPixel().height);
+            gfx::Point((metrics.mScrollOffset.x * metrics.LayersPixelsPerCSSPixel().width) / scaleX,
+                       (metrics.mScrollOffset.y * metrics.LayersPixelsPerCSSPixel().height) / scaleY);
           const nsIntPoint& contentOrigin = metrics.mContentRect.TopLeft() -
             nsIntPoint(NS_lround(scrollOffset.x), NS_lround(scrollOffset.y));
           gfxRect contentRect = gfxRect(contentOrigin.x, contentOrigin.y,

From 8c3e7521f0bbf7974d60b9691ae6b1b3f5712a4c Mon Sep 17 00:00:00 2001
From: Gian-Carlo Pascutto 
Date: Thu, 18 Oct 2012 13:52:03 +0200
Subject: [PATCH 41/46] Bug 795281. r=bholley

---
 .../url-classifier/nsUrlClassifierProxies.cpp | 10 +++-
 .../url-classifier/nsUrlClassifierProxies.h   | 50 ++++++++++++-------
 2 files changed, 40 insertions(+), 20 deletions(-)

diff --git a/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp b/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp
index 30d5b3c92c7..69f5f8ef4f0 100644
--- a/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp
@@ -238,11 +238,17 @@ UrlClassifierUpdateObserverProxy::UpdateUrlRequestedRunnable::Run()
 NS_IMETHODIMP
 UrlClassifierUpdateObserverProxy::RekeyRequested()
 {
-  nsCOMPtr r =
-    NS_NewRunnableMethod(mTarget, &nsIUrlClassifierUpdateObserver::RekeyRequested);
+  nsCOMPtr r = new RekeyRequestedRunnable(mTarget);
   return NS_DispatchToMainThread(r);
 }
 
+NS_IMETHODIMP
+UrlClassifierUpdateObserverProxy::RekeyRequestedRunnable::Run()
+{
+  mTarget->RekeyRequested();
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 UrlClassifierUpdateObserverProxy::StreamFinished(nsresult aStatus,
                                                  uint32_t aDelay)
diff --git a/toolkit/components/url-classifier/nsUrlClassifierProxies.h b/toolkit/components/url-classifier/nsUrlClassifierProxies.h
index 9c7657d30ff..053f4eec782 100644
--- a/toolkit/components/url-classifier/nsUrlClassifierProxies.h
+++ b/toolkit/components/url-classifier/nsUrlClassifierProxies.h
@@ -7,6 +7,7 @@
 #define nsUrlClassifierProxies_h
 
 #include "nsIUrlClassifierDBService.h"
+#include "nsProxyRelease.h"
 #include "nsThreadUtils.h"
 #include "mozilla/Attributes.h"
 #include "nsIPrincipal.h"
@@ -162,7 +163,7 @@ class UrlClassifierLookupCallbackProxy MOZ_FINAL :
 {
 public:
   UrlClassifierLookupCallbackProxy(nsIUrlClassifierLookupCallback* aTarget)
-    : mTarget(aTarget)
+    : mTarget(new nsMainThreadPtrHolder(aTarget))
   { }
 
   NS_DECL_ISUPPORTS
@@ -171,7 +172,7 @@ public:
   class LookupCompleteRunnable : public nsRunnable
   {
   public:
-    LookupCompleteRunnable(nsIUrlClassifierLookupCallback* aTarget,
+    LookupCompleteRunnable(nsMainThreadPtrHolder* aTarget,
                            LookupResultArray *aResults)
       : mTarget(aTarget)
       , mResults(aResults)
@@ -180,19 +181,19 @@ public:
     NS_DECL_NSIRUNNABLE
 
   private:
-    nsCOMPtr mTarget;
+    nsMainThreadPtrHandle mTarget;
     LookupResultArray * mResults;
   };
 
 private:
-  nsCOMPtr mTarget;
+  nsMainThreadPtrHandle mTarget;
 };
 
 class UrlClassifierCallbackProxy MOZ_FINAL : public nsIUrlClassifierCallback
 {
 public:
   UrlClassifierCallbackProxy(nsIUrlClassifierCallback* aTarget)
-    : mTarget(aTarget)
+    : mTarget(new nsMainThreadPtrHolder(aTarget))
   { }
 
   NS_DECL_ISUPPORTS
@@ -201,7 +202,7 @@ public:
   class HandleEventRunnable : public nsRunnable
   {
   public:
-    HandleEventRunnable(nsIUrlClassifierCallback* aTarget,
+    HandleEventRunnable(nsMainThreadPtrHolder* aTarget,
                         const nsACString& aValue)
       : mTarget(aTarget)
       , mValue(aValue)
@@ -210,12 +211,12 @@ public:
     NS_DECL_NSIRUNNABLE
 
   private:
-    nsCOMPtr mTarget;
+    nsMainThreadPtrHandle mTarget;
     nsCString mValue;
   };
 
 private:
-  nsCOMPtr mTarget;
+  nsMainThreadPtrHandle mTarget;
 };
 
 class UrlClassifierUpdateObserverProxy MOZ_FINAL :
@@ -223,7 +224,7 @@ class UrlClassifierUpdateObserverProxy MOZ_FINAL :
 {
 public:
   UrlClassifierUpdateObserverProxy(nsIUrlClassifierUpdateObserver* aTarget)
-    : mTarget(aTarget)
+    : mTarget(new nsMainThreadPtrHolder(aTarget))
   { }
 
   NS_DECL_ISUPPORTS
@@ -232,7 +233,7 @@ public:
   class UpdateUrlRequestedRunnable : public nsRunnable
   {
   public:
-    UpdateUrlRequestedRunnable(nsIUrlClassifierUpdateObserver* aTarget,
+    UpdateUrlRequestedRunnable(nsMainThreadPtrHolder* aTarget,
                                const nsACString& aURL,
                                const nsACString& aTable,
                                const nsACString& aServerMAC)
@@ -245,14 +246,27 @@ public:
     NS_DECL_NSIRUNNABLE
 
   private:
-    nsCOMPtr mTarget;
+    nsMainThreadPtrHandle mTarget;
     nsCString mURL, mTable, mServerMAC;
   };
 
+  class RekeyRequestedRunnable : public nsRunnable
+  {
+  public:
+    RekeyRequestedRunnable(nsMainThreadPtrHolder* aTarget)
+      : mTarget(aTarget)
+    { }
+
+    NS_DECL_NSIRUNNABLE
+
+  private:
+    nsMainThreadPtrHandle mTarget;
+  };
+
   class StreamFinishedRunnable : public nsRunnable
   {
   public:
-    StreamFinishedRunnable(nsIUrlClassifierUpdateObserver* aTarget,
+    StreamFinishedRunnable(nsMainThreadPtrHolder* aTarget,
                            nsresult aStatus, uint32_t aDelay)
       : mTarget(aTarget)
       , mStatus(aStatus)
@@ -262,7 +276,7 @@ public:
     NS_DECL_NSIRUNNABLE
 
   private:
-    nsCOMPtr mTarget;
+    nsMainThreadPtrHandle mTarget;
     nsresult mStatus;
     uint32_t mDelay;
   };
@@ -270,7 +284,7 @@ public:
   class UpdateErrorRunnable : public nsRunnable
   {
   public:
-    UpdateErrorRunnable(nsIUrlClassifierUpdateObserver* aTarget,
+    UpdateErrorRunnable(nsMainThreadPtrHolder* aTarget,
                         nsresult aError)
       : mTarget(aTarget)
       , mError(aError)
@@ -279,14 +293,14 @@ public:
     NS_DECL_NSIRUNNABLE
 
   private:
-    nsCOMPtr mTarget;
+    nsMainThreadPtrHandle mTarget;
     nsresult mError;
   };
 
   class UpdateSuccessRunnable : public nsRunnable
   {
   public:
-    UpdateSuccessRunnable(nsIUrlClassifierUpdateObserver* aTarget,
+    UpdateSuccessRunnable(nsMainThreadPtrHolder* aTarget,
                           uint32_t aRequestedTimeout)
       : mTarget(aTarget)
       , mRequestedTimeout(aRequestedTimeout)
@@ -295,12 +309,12 @@ public:
     NS_DECL_NSIRUNNABLE
 
   private:
-    nsCOMPtr mTarget;
+    nsMainThreadPtrHandle mTarget;
     uint32_t mRequestedTimeout;
   };
 
 private:
-  nsCOMPtr mTarget;
+  nsMainThreadPtrHandle mTarget;
 };
 
 #endif // nsUrlClassifierProxies_h

From f417dde98c79cf696188586dbee3f0c32ca1be39 Mon Sep 17 00:00:00 2001
From: Chris Lord 
Date: Thu, 18 Oct 2012 12:59:17 +0100
Subject: [PATCH 42/46] Bug 802143 - Clarify coordinate spaces in
 ReusableTileStoreOGL::DrawTiles. r=bgirard

---
 gfx/layers/opengl/ReusableTileStoreOGL.cpp | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/gfx/layers/opengl/ReusableTileStoreOGL.cpp b/gfx/layers/opengl/ReusableTileStoreOGL.cpp
index 8aaa4f80a65..57bb0182c98 100644
--- a/gfx/layers/opengl/ReusableTileStoreOGL.cpp
+++ b/gfx/layers/opengl/ReusableTileStoreOGL.cpp
@@ -218,20 +218,20 @@ ReusableTileStoreOGL::DrawTiles(TiledThebesLayerOGL* aLayer,
       if (parentMetrics.IsScrollable())
         scrollableLayer = parent;
       if (!parentMetrics.mDisplayPort.IsEmpty() && scrollableLayer) {
-          // Get the display-port bounds
+          // Get the display-port bounds in screen-space.
           displayPort = gfxRect(parentMetrics.mDisplayPort.x,
                                 parentMetrics.mDisplayPort.y,
                                 parentMetrics.mDisplayPort.width,
                                 parentMetrics.mDisplayPort.height);
 
-          // Check the scale transform applied to the root layer to determine
+          // Calculate the scale transform applied to the root layer to determine
           // the content resolution.
           Layer* rootLayer = aLayer->Manager()->GetRoot();
           const gfx3DMatrix& rootTransform = rootLayer->GetTransform();
           float scaleX = rootTransform.GetXScale();
           float scaleY = rootTransform.GetYScale();
 
-          // Get the content document bounds
+          // Get the content document bounds, in screen-space.
           const FrameMetrics& metrics = scrollableLayer->GetFrameMetrics();
           const nsIntSize& contentSize = metrics.mContentRect.Size();
           gfx::Point scrollOffset =
@@ -269,6 +269,7 @@ ReusableTileStoreOGL::DrawTiles(TiledThebesLayerOGL* aLayer,
 
     // Subtract the display-port from the tile region.
     if (!displayPort.IsEmpty()) {
+      // Transform the display-port from screen space to layer space.
       gfxRect transformedRenderBounds = transform.Inverse().TransformBounds(displayPort);
       tileRegion.Sub(tileRegion, nsIntRect(transformedRenderBounds.x,
                                            transformedRenderBounds.y,
@@ -278,6 +279,7 @@ ReusableTileStoreOGL::DrawTiles(TiledThebesLayerOGL* aLayer,
 
     // Intersect the tile region with the content area.
     if (!contentBounds.IsEmpty()) {
+      // Transform the content bounds from screen space to layer space.
       gfxRect transformedRenderBounds = transform.Inverse().TransformBounds(contentBounds);
       tileRegion.And(tileRegion, nsIntRect(transformedRenderBounds.x,
                                            transformedRenderBounds.y,

From b3fe2c3786dc25dbaf07da5167d5ec15d152fd5f Mon Sep 17 00:00:00 2001
From: Graeme McCutcheon 
Date: Thu, 18 Oct 2012 12:23:30 +0100
Subject: [PATCH 43/46] Bug 802718 - Ensure internal widget state is restored
 after browser_minimize.js, to work around Unity bug on Ubuntu. r=gavin
 DONTBUILD

---
 browser/base/content/test/browser_minimize.js | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/browser/base/content/test/browser_minimize.js b/browser/base/content/test/browser_minimize.js
index 37e03b1f911..459f84b442b 100644
--- a/browser/base/content/test/browser_minimize.js
+++ b/browser/base/content/test/browser_minimize.js
@@ -20,6 +20,10 @@ function waitForInactive() {
 }
 
 function test() {
+    registerCleanupFunction(function() {
+      window.restore();
+    });
+
     waitForExplicitFinish();
     is(gBrowser.docShell.isActive, true, "Docshell should be active");
     window.minimize();

From bac58de07e26dec3505b4cee0adc4c41845dea9c Mon Sep 17 00:00:00 2001
From: Mike Hommey 
Date: Thu, 18 Oct 2012 14:44:12 +0200
Subject: [PATCH 44/46] Bug 794472 - Add quoting for some commands to make
 pymake happier. r=ted

---
 config/rules.mk         | 4 ++--
 configure.in            | 2 +-
 js/src/config/rules.mk  | 4 ++--
 toolkit/xre/Makefile.in | 2 +-
 4 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/config/rules.mk b/config/rules.mk
index 1f2e2f22456..1f0dc8018ab 100644
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -1116,8 +1116,8 @@ ifndef NO_SUBMAKEFILES_RULE
 ifdef SUBMAKEFILES
 # VPATH does not work on some machines in this case, so add $(srcdir)
 $(SUBMAKEFILES): % : $(srcdir)/%.in
-	$(PYTHON) $(DEPTH)$(addprefix /,$(subsrcdir))/config.status -n --file=$@
-	@$(TOUCH) $@
+	$(PYTHON) $(DEPTH)$(addprefix /,$(subsrcdir))/config.status -n --file="$@"
+	@$(TOUCH) "$@"
 endif
 endif
 
diff --git a/configure.in b/configure.in
index af17af1c4e4..a9fb5f16555 100644
--- a/configure.in
+++ b/configure.in
@@ -5844,7 +5844,7 @@ if test -n "$MOZ_ANGLE_RENDERER" -a -z "$CROSS_COMPILE"; then
   if test -n "`echo $MOZ_DIRECTX_SDK_REG_KEY | grep 'February 2010'`" ; then
     AC_MSG_ERROR([Found the February 2010 DirectX SDK. Need the June 2010 DirectX SDK, or newer.  Upgrade your SDK or reconfigure with --disable-webgl.])
   else
-    MOZ_DIRECTX_SDK_PATH=`reg query "$MOZ_DIRECTX_SDK_REG_KEY" //v InstallPath | grep REG_SZ | sed 's/.*\([[a-zA-Z]]\)\\:\\\\/\\1\\:\\\\/'`
+    MOZ_DIRECTX_SDK_PATH=`reg query "$MOZ_DIRECTX_SDK_REG_KEY" //v InstallPath | grep REG_SZ | sed 's/.*\([[a-zA-Z]]\)\\:\\\\/\\1\\:\\\\/' | sed 's,\\\\,/,g'`
   fi
 
   if test -n "$MOZ_DIRECTX_SDK_PATH" &&
diff --git a/js/src/config/rules.mk b/js/src/config/rules.mk
index 1f2e2f22456..1f0dc8018ab 100644
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -1116,8 +1116,8 @@ ifndef NO_SUBMAKEFILES_RULE
 ifdef SUBMAKEFILES
 # VPATH does not work on some machines in this case, so add $(srcdir)
 $(SUBMAKEFILES): % : $(srcdir)/%.in
-	$(PYTHON) $(DEPTH)$(addprefix /,$(subsrcdir))/config.status -n --file=$@
-	@$(TOUCH) $@
+	$(PYTHON) $(DEPTH)$(addprefix /,$(subsrcdir))/config.status -n --file="$@"
+	@$(TOUCH) "$@"
 endif
 endif
 
diff --git a/toolkit/xre/Makefile.in b/toolkit/xre/Makefile.in
index ca5c82a661f..18f6312de12 100644
--- a/toolkit/xre/Makefile.in
+++ b/toolkit/xre/Makefile.in
@@ -245,7 +245,7 @@ endif
 
 DEFINES += -DAPP_VERSION=$(MOZ_APP_VERSION)
 
-DEFINES += -DAPP_ID=$(MOZ_APP_ID)
+DEFINES += -DAPP_ID="$(MOZ_APP_ID)"
 
 $(srcdir)/nsAppRunner.cpp: $(DEPTH)/config/buildid $(milestone_txt)
 

From 3a3fbb075b80befe213bd524f56c6bb3b4cf963f Mon Sep 17 00:00:00 2001
From: Mike Hommey 
Date: Thu, 18 Oct 2012 14:46:33 +0200
Subject: [PATCH 45/46] Bug 794472 - Allow pymake to run more commands without
 sending them to a shell. r=ted

---
 build/pymake/pymake/data.py      |  20 +--
 build/pymake/pymake/functions.py |  28 +++-
 build/pymake/pymake/process.py   | 243 +++++++++++++++++++++++++------
 3 files changed, 226 insertions(+), 65 deletions(-)

diff --git a/build/pymake/pymake/data.py b/build/pymake/pymake/data.py
index 3ef8c18f0f4..720cb4ada03 100644
--- a/build/pymake/pymake/data.py
+++ b/build/pymake/pymake/data.py
@@ -1404,24 +1404,24 @@ class _NativeWrapper(_CommandWrapper):
                  pycommandpath, **kwargs):
         _CommandWrapper.__init__(self, cline, ignoreErrors, loc, context,
                                  **kwargs)
-        # get the module and method to call
-        parts, badchar = process.clinetoargv(cline, blacklist_gray=False)
-        if parts is None:
-            raise DataError("native command '%s': shell metacharacter '%s' in command line" % (cline, badchar), self.loc)
-        if len(parts) < 2:
-            raise DataError("native command '%s': no method name specified" % cline, self.loc)
         if pycommandpath:
             self.pycommandpath = re.split('[%s\s]+' % os.pathsep,
                                           pycommandpath)
         else:
             self.pycommandpath = None
-        self.module = parts[0]
-        self.method = parts[1]
-        self.cline_list = parts[2:]
 
     def __call__(self, cb):
+        # get the module and method to call
+        parts, badchar = process.clinetoargv(self.cline, self.kwargs['cwd'])
+        if parts is None:
+            raise DataError("native command '%s': shell metacharacter '%s' in command line" % (cline, badchar), self.loc)
+        if len(parts) < 2:
+            raise DataError("native command '%s': no method name specified" % cline, self.loc)
+        module = parts[0]
+        method = parts[1]
+        cline_list = parts[2:]
         self.usercb = cb
-        process.call_native(self.module, self.method, self.cline_list,
+        process.call_native(module, method, cline_list,
                             loc=self.loc, cb=self._cb, context=self.context,
                             pycommandpath=self.pycommandpath, **self.kwargs)
 
diff --git a/build/pymake/pymake/functions.py b/build/pymake/pymake/functions.py
index 3270a108617..85dbafb968f 100644
--- a/build/pymake/pymake/functions.py
+++ b/build/pymake/pymake/functions.py
@@ -3,7 +3,7 @@ Makefile functions.
 """
 
 import parser, util
-import subprocess, os, logging
+import subprocess, os, logging, sys
 from globrelative import glob
 from cStringIO import StringIO
 
@@ -766,16 +766,28 @@ class ShellFunction(Function):
     __slots__ = Function.__slots__
 
     def resolve(self, makefile, variables, fd, setting):
-        #TODO: call this once up-front somewhere and save the result?
-        shell, msys = util.checkmsyscompat()
+        from process import prepare_command
         cline = self._arguments[0].resolvestr(makefile, variables, setting)
+        executable, cline = prepare_command(cline, makefile.workdir, self.loc)
+
+        # subprocess.Popen doesn't use the PATH set in the env argument for
+        # finding the executable on some platforms (but strangely it does on
+        # others!), so set os.environ['PATH'] explicitly.
+        oldpath = os.environ['PATH']
+        if makefile.env is not None and 'PATH' in makefile.env:
+            os.environ['PATH'] = makefile.env['PATH']
+
+        log.debug("%s: running command '%s'" % (self.loc, ' '.join(cline)))
+        try:
+            p = subprocess.Popen(cline, executable=executable, env=makefile.env, shell=False,
+                                 stdout=subprocess.PIPE, cwd=makefile.workdir)
+        except OSError, e:
+            print >>sys.stderr, "Error executing command %s" % cline[0], e
+            return
+        finally:
+            os.environ['PATH'] = oldpath
 
-        log.debug("%s: running shell command '%s'" % (self.loc, cline))
-        cline = [shell, "-c", cline]
-        p = subprocess.Popen(cline, env=makefile.env, shell=False,
-                             stdout=subprocess.PIPE, cwd=makefile.workdir)
         stdout, stderr = p.communicate()
-
         stdout = stdout.replace('\r\n', '\n')
         if stdout.endswith('\n'):
             stdout = stdout[:-1]
diff --git a/build/pymake/pymake/process.py b/build/pymake/pymake/process.py
index 19a706d2f64..e7a831a18c6 100644
--- a/build/pymake/pymake/process.py
+++ b/build/pymake/pymake/process.py
@@ -15,83 +15,238 @@ if sys.platform=='win32':
 _log = logging.getLogger('pymake.process')
 
 _escapednewlines = re.compile(r'\\\n')
-# Characters that most likely indicate a shell script and that native commands
-# should reject
-_blacklist = re.compile(r'[$><;\[~`|&]' +
-    r'|\${|(?:^|\s){(?:$|\s)')  # Blacklist ${foo} and { commands }
-# Characters that probably indicate a shell script, but that native commands
-# shouldn't just reject
-_graylist = re.compile(r'[()]')
-# Characters that indicate we need to glob
-_needsglob = re.compile(r'[\*\?]')
 
-def clinetoargv(cline, blacklist_gray):
+def tokens2re(tokens):
+    # Create a pattern for non-escaped tokens, in the form:
+    #   (?pattern)
+    # which matches the pattern and captures it in a named match group.
+    # The group names and patterns come are given as a dict in the function
+    # argument.
+    nonescaped = r'(?%s)' % (name, value) for name, value in tokens.iteritems())
+    # The final pattern matches either the above pattern, or an escaped
+    # backslash, captured in the "escape" match group.
+    return re.compile('(?:%s|%s)' % (nonescaped, r'(?P\\\\)'))
+
+_unquoted_tokens = tokens2re({
+  'whitespace': r'[\t\r\n ]',
+  'quote': r'[\'"]',
+  'comment': '#',
+  'special': r'[<>&|`~(){}$;]',
+  'backslashed': r'\\[^\\]',
+  'glob': r'[\*\?]',
+})
+
+_doubly_quoted_tokens = tokens2re({
+  'quote': '"',
+  'backslashedquote': r'\\"',
+  'special': '\$',
+  'backslashed': r'\\[^\\"]',
+})
+
+class MetaCharacterException(Exception):
+    def __init__(self, char):
+        self.char = char
+
+class ClineSplitter(list):
+    """
+    Parses a given command line string and creates a list of command
+    and arguments, with wildcard expansion.
+    """
+    def __init__(self, cline, cwd):
+        self.cwd = cwd
+        self.arg = ''
+        self.cline = cline
+        self.glob = False
+        self._parse_unquoted()
+
+    def _push(self, str):
+        """
+        Push the given string as part of the current argument
+        """
+        self.arg += str
+
+    def _next(self):
+        """
+        Finalize current argument, effectively adding it to the list.
+        Perform globbing if needed.
+        """
+        if not self.arg:
+            return
+        if self.glob:
+            if os.path.isabs(self.arg):
+                path = self.arg
+            else:
+                path = os.path.join(self.cwd, self.arg)
+            globbed = glob.glob(path)
+            if not globbed:
+                # If globbing doesn't find anything, the literal string is
+                # used.
+                self.append(self.arg)
+            else:
+                self.extend(f[len(path)-len(self.arg):] for f in globbed)
+            self.glob = False
+        else:
+            self.append(self.arg)
+        self.arg = ''
+
+    def _parse_unquoted(self):
+        """
+        Parse command line remainder in the context of an unquoted string.
+        """
+        while self.cline:
+            # Find the next token
+            m = _unquoted_tokens.search(self.cline)
+            # If we find none, the remainder of the string can be pushed to
+            # the current argument and the argument finalized
+            if not m:
+                self._push(self.cline)
+                break
+            # The beginning of the string, up to the found token, is part of
+            # the current argument
+            self._push(self.cline[:m.start()])
+            self.cline = self.cline[m.end():]
+
+            match = dict([(name, value) for name, value in m.groupdict().items() if value])
+            if 'quote' in match:
+                # " or ' start a quoted string
+                if match['quote'] == '"':
+                    self._parse_doubly_quoted()
+                else:
+                    self._parse_quoted()
+            elif 'comment' in match:
+                # Comments are ignored. The current argument can be finalized,
+                # and parsing stopped.
+                break
+            elif 'special' in match:
+                # Unquoted, non-escaped special characters need to be sent to a
+                # shell.
+                raise MetaCharacterException, match['special']
+            elif 'whitespace' in match:
+                # Whitespaces terminate current argument.
+                self._next()
+            elif 'escape' in match:
+                # Escaped backslashes turn into a single backslash
+                self._push('\\')
+            elif 'backslashed' in match:
+                # Backslashed characters are unbackslashed
+                # e.g. echo \a -> a
+                self._push(match['backslashed'][1])
+            elif 'glob' in match:
+                # ? or * will need globbing
+                self.glob = True
+                self._push(m.group(0))
+            else:
+                raise Exception, "Shouldn't reach here"
+        self._next()
+
+    def _parse_quoted(self):
+        # Single quoted strings are preserved, except for the final quote
+        index = self.cline.find("'")
+        if index == -1:
+            raise Exception, 'Unterminated quoted string in command'
+        self._push(self.cline[:index])
+        self.cline = self.cline[index+1:]
+
+    def _parse_doubly_quoted(self):
+        if not self.cline:
+            raise Exception, 'Unterminated quoted string in command'
+        while self.cline:
+            m = _doubly_quoted_tokens.search(self.cline)
+            if not m:
+                raise Exception, 'Unterminated quoted string in command'
+            self._push(self.cline[:m.start()])
+            self.cline = self.cline[m.end():]
+            match = dict([(name, value) for name, value in m.groupdict().items() if value])
+            if 'quote' in match:
+                # a double quote ends the quoted string, so go back to
+                # unquoted parsing
+                return
+            elif 'special' in match:
+                # Unquoted, non-escaped special characters in a doubly quoted
+                # string still have a special meaning and need to be sent to a
+                # shell.
+                raise MetaCharacterException, match['special']
+            elif 'escape' in match:
+                # Escaped backslashes turn into a single backslash
+                self._push('\\')
+            elif 'backslashedquote' in match:
+                # Backslashed double quotes are un-backslashed
+                self._push('"')
+            elif 'backslashed' in match:
+                # Backslashed characters are kept backslashed
+                self._push(match['backslashed'])
+
+def clinetoargv(cline, cwd):
     """
     If this command line can safely skip the shell, return an argv array.
     @returns argv, badchar
     """
     str = _escapednewlines.sub('', cline)
-    m = _blacklist.search(str)
-    if m is not None:
-        return None, m.group(0)
-    if blacklist_gray:
-        m = _graylist.search(str)
-        if m is not None:
-            return None, m.group(0)
-
-    args = shlex.split(str, comments=True)
+    try:
+        args = ClineSplitter(str, cwd)
+    except MetaCharacterException, e:
+        return None, e.char
 
     if len(args) and args[0].find('=') != -1:
         return None, '='
 
     return args, None
 
-def doglobbing(args, cwd):
-    """
-    Perform any needed globbing on the argument list passed in
-    """
-    globbedargs = []
-    for arg in args:
-        if _needsglob.search(arg):
-            globbedargs.extend(glob.glob(os.path.join(cwd, arg)))
-        else:
-            globbedargs.append(arg)
-
-    return globbedargs
-
+# shellwords contains a set of shell builtin commands that need to be
+# executed within a shell. It also contains a set of commands that are known
+# to be giving problems when run directly instead of through the msys shell.
 shellwords = (':', '.', 'break', 'cd', 'continue', 'exec', 'exit', 'export',
               'getopts', 'hash', 'pwd', 'readonly', 'return', 'shift', 
               'test', 'times', 'trap', 'umask', 'unset', 'alias',
               'set', 'bind', 'builtin', 'caller', 'command', 'declare',
               'echo', 'enable', 'help', 'let', 'local', 'logout', 
               'printf', 'read', 'shopt', 'source', 'type', 'typeset',
-              'ulimit', 'unalias', 'set')
+              'ulimit', 'unalias', 'set', 'find')
+
+def prepare_command(cline, cwd, loc):
+    """
+    Returns a list of command and arguments for the given command line string.
+    If the command needs to be run through a shell for some reason, the
+    returned list contains the shell invocation.
+    """
 
-def call(cline, env, cwd, loc, cb, context, echo, justprint=False):
     #TODO: call this once up-front somewhere and save the result?
     shell, msys = util.checkmsyscompat()
 
     shellreason = None
+    executable = None
     if msys and cline.startswith('/'):
         shellreason = "command starts with /"
     else:
-        argv, badchar = clinetoargv(cline, blacklist_gray=True)
+        argv, badchar = clinetoargv(cline, cwd)
         if argv is None:
             shellreason = "command contains shell-special character '%s'" % (badchar,)
         elif len(argv) and argv[0] in shellwords:
             shellreason = "command starts with shell primitive '%s'" % (argv[0],)
-        else:
-            argv = doglobbing(argv, cwd)
+        elif argv and (os.sep in argv[0] or os.altsep and os.altsep in argv[0]):
+            executable = util.normaljoin(cwd, argv[0])
+            # Avoid "%1 is not a valid Win32 application" errors, assuming
+            # that if the executable path is to be resolved with PATH, it will
+            # be a Win32 executable.
+            if sys.platform == 'win32' and os.path.isfile(executable) and open(executable, 'rb').read(2) == "#!":
+                shellreason = "command executable starts with a hashbang"
 
     if shellreason is not None:
         _log.debug("%s: using shell: %s: '%s'", loc, shellreason, cline)
         if msys:
             if len(cline) > 3 and cline[1] == ':' and cline[2] == '/':
                 cline = '/' + cline[0] + cline[2:]
-        cline = [shell, "-c", cline]
-        context.call(cline, shell=False, env=env, cwd=cwd, cb=cb, echo=echo,
-                     justprint=justprint)
-        return
+        argv = [shell, "-c", cline]
+        executable = None
+
+    return executable, argv
+
+def call(cline, env, cwd, loc, cb, context, echo, justprint=False):
+    executable, argv = prepare_command(cline, cwd, loc)
 
     if not len(argv):
         cb(res=0)
@@ -106,17 +261,11 @@ def call(cline, env, cwd, loc, cb, context, echo, justprint=False):
         command.main(argv[2:], env, cwd, cb)
         return
 
-    if argv[0].find('/') != -1:
-        executable = util.normaljoin(cwd, argv[0])
-    else:
-        executable = None
-
     context.call(argv, executable=executable, shell=False, env=env, cwd=cwd, cb=cb,
                  echo=echo, justprint=justprint)
 
 def call_native(module, method, argv, env, cwd, loc, cb, context, echo, justprint=False,
                 pycommandpath=None):
-    argv = doglobbing(argv, cwd)
     context.call_native(module, method, argv, env=env, cwd=cwd, cb=cb,
                         echo=echo, justprint=justprint, pycommandpath=pycommandpath)
 

From d13ce06194110dfd1d05d3471f05a244dd924dea Mon Sep 17 00:00:00 2001
From: Mike Hommey 
Date: Thu, 18 Oct 2012 14:47:10 +0200
Subject: [PATCH 46/46] Bug 799441 - Build GIO module in libxul. r=ted

---
 configure.in                              |  6 ++++++
 extensions/gio/Makefile.in                | 14 +++-----------
 toolkit/library/Makefile.in               |  5 +++++
 toolkit/library/nsStaticXULComponents.cpp |  7 +++++++
 toolkit/toolkit-tiers.mk                  |  4 ++++
 5 files changed, 25 insertions(+), 11 deletions(-)

diff --git a/configure.in b/configure.in
index a9fb5f16555..37e6db8f6c9 100644
--- a/configure.in
+++ b/configure.in
@@ -6086,6 +6086,12 @@ if test -n "$LIBXUL_SDK_DIR" -a `echo "$MOZ_EXTENSIONS" | grep -c gio` -ne 0; th
     MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's|gio||'`
 fi
 
+if test `echo "$MOZ_EXTENSIONS" | grep -c gio` -ne 0; then
+    MOZ_GIO_COMPONENT=1
+    MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's|gio||'`
+fi
+AC_SUBST(MOZ_GIO_COMPONENT)
+
 if test -z "$MOZ_JSDEBUGGER" -a `echo "$MOZ_EXTENSIONS" | grep -c venkman` -ne 0; then
     AC_MSG_WARN([Cannot build venkman without JavaScript debug library. Removing venkman from MOZ_EXTENSIONS.])
     MOZ_EXTENSIONS=`echo $MOZ_EXTENSIONS | sed -e 's|venkman||'`
diff --git a/extensions/gio/Makefile.in b/extensions/gio/Makefile.in
index ccf2846c00c..79112a848eb 100644
--- a/extensions/gio/Makefile.in
+++ b/extensions/gio/Makefile.in
@@ -14,6 +14,9 @@ MODULE		= nkgio
 LIBRARY_NAME	= nkgio
 SHORT_LIBNAME	= nkgio
 IS_COMPONENT	= 1
+EXPORT_LIBRARY	= 1
+MODULE_NAME	= nsGIOModule
+LIBXUL_LIBRARY	= 1
 
 CPPSRCS		= \
 		nsGIOProtocolHandler.cpp \
@@ -21,15 +24,4 @@ CPPSRCS		= \
 
 LOCAL_INCLUDES	= $(MOZ_GIO_CFLAGS)
 
-EXTRA_DSO_LDOPTS = \
-		   $(XPCOM_GLUE_LDOPTS) \
-		   $(MOZ_COMPONENT_LIBS) \
-		   $(MOZ_GIO_LIBS) \
-		   $(NULL)
-
-# make sure this component is never statically linked into the main
-# application.  this is necessary since we don't want to force users
-# to install gio in order to use the rest of mozilla ;-)
-FORCE_SHARED_LIB= 1
-
 include $(topsrcdir)/config/rules.mk
diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in
index 7f9046ee746..6499758633a 100644
--- a/toolkit/library/Makefile.in
+++ b/toolkit/library/Makefile.in
@@ -333,6 +333,11 @@ COMPONENT_LIBS += gkdebug
 endif
 endif
 
+ifdef MOZ_GIO_COMPONENT
+DEFINES += -DMOZ_GIO_COMPONENT
+COMPONENT_LIBS += nkgio
+endif
+
 ifdef MOZ_APP_COMPONENT_LIBS
 COMPONENT_LIBS += $(MOZ_APP_COMPONENT_LIBS)
 endif
diff --git a/toolkit/library/nsStaticXULComponents.cpp b/toolkit/library/nsStaticXULComponents.cpp
index e1d90f2abf1..85b21a2875b 100644
--- a/toolkit/library/nsStaticXULComponents.cpp
+++ b/toolkit/library/nsStaticXULComponents.cpp
@@ -170,6 +170,12 @@
 #define PEERCONNECTION_MODULE
 #endif
 
+#if defined(MOZ_GIO_COMPONENT)
+#define GIO_MODULE MODULE(nsGIOModule)
+#else
+#define GIO_MODULE
+#endif
+
 #define XUL_MODULES                          \
     MODULE(nsUConvModule)                    \
     MODULE(nsI18nModule)                     \
@@ -228,6 +234,7 @@
     MODULE(jsinspector)                      \
     MODULE(jsdebugger)                       \
     PEERCONNECTION_MODULE                    \
+    GIO_MODULE                               \
     /* end of list */
 
 #define MODULE(_name) \
diff --git a/toolkit/toolkit-tiers.mk b/toolkit/toolkit-tiers.mk
index e87d7af81cc..4b16d2380c1 100644
--- a/toolkit/toolkit-tiers.mk
+++ b/toolkit/toolkit-tiers.mk
@@ -252,6 +252,10 @@ tier_platform_dirs += js/ductwork/debugger
 
 tier_platform_dirs += other-licenses/snappy
 
+ifdef MOZ_GIO_COMPONENT
+tier_platform_dirs += extensions/gio
+endif
+
 ifdef APP_LIBXUL_STATICDIRS
 # Applications can cheat and ask for code to be
 # built before libxul so libxul can be linked against it.