From cf618f7fe911a43565398aebaaa55c3f7bee8ee2 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Thu, 11 Jul 2013 16:58:57 +0200 Subject: [PATCH 01/58] Bug 886173 - Preserve playbackRate across pause/play. r=cpearce --- content/html/content/src/HTMLMediaElement.cpp | 2 - content/media/test/Makefile.in | 1 + content/media/test/manifest.js | 1 - content/media/test/test_playback_rate.html | 36 +-------- .../test/test_playback_rate_playpause.html | 73 +++++++++++++++++++ toolkit/content/widgets/videocontrols.xml | 1 + 6 files changed, 76 insertions(+), 38 deletions(-) create mode 100644 content/media/test/test_playback_rate_playpause.html diff --git a/content/html/content/src/HTMLMediaElement.cpp b/content/html/content/src/HTMLMediaElement.cpp index 86da5c2be9b..0349b708750 100644 --- a/content/html/content/src/HTMLMediaElement.cpp +++ b/content/html/content/src/HTMLMediaElement.cpp @@ -2097,8 +2097,6 @@ HTMLMediaElement::Play(ErrorResult& aRv) } } - SetPlaybackRate(mDefaultPlaybackRate); - mPaused = false; mAutoplaying = false; // We changed mPaused and mAutoplaying which can affect AddRemoveSelfReference diff --git a/content/media/test/Makefile.in b/content/media/test/Makefile.in index dd220bb8f85..e4c6ff73d5a 100644 --- a/content/media/test/Makefile.in +++ b/content/media/test/Makefile.in @@ -140,6 +140,7 @@ MOCHITEST_FILES = \ test_VideoPlaybackQuality.html \ test_VideoPlaybackQuality_disabled.html \ test_webvtt_disabled.html \ + test_playback_rate_playpause.html \ $(NULL) # Disabled on Windows for frequent intermittent failures diff --git a/content/media/test/manifest.js b/content/media/test/manifest.js index 8b143e5e40d..468d804beb4 100644 --- a/content/media/test/manifest.js +++ b/content/media/test/manifest.js @@ -38,7 +38,6 @@ var gProgressTests = [ // Used by test_played.html var gPlayedTests = [ { name:"big.wav", type:"audio/x-wav", duration:9.0 }, - { name:"sound.ogg", type:"audio/ogg", duration:4.0 }, { name:"seek.ogv", type:"video/ogg", duration:3.966 }, { name:"seek.webm", type:"video/webm", duration:3.966 }, { name:"gizmo.mp4", type:"video/mp4", duration:5.56 }, diff --git a/content/media/test/test_playback_rate.html b/content/media/test/test_playback_rate.html index e29455c4c1b..1adf8074f56 100644 --- a/content/media/test/test_playback_rate.html +++ b/content/media/test/test_playback_rate.html @@ -113,40 +113,7 @@ function onended(e) { ok(!t.muted, "The audio should be muted when playing at high speed, but should not appear as such."); is(t.currentTime, t.duration, "Current time should be equal to the duration (not change by playback rate)."); } - test_defaultPlaybackRate(e); -} - -function test_defaultPlaybackRate(e) { - var t = e.target; - t.currentTime = 0.0; - t.defaultPlaybackRate = SLOW_RATE; - t.addEventListener("timeupdate", ontimeupdate_defaultPlaybackRate); - t.startTimestamp = Date.now(); - t.play(); -} - -function ontimeupdate_defaultPlaybackRate(e) { - var t = e.target; - if (t.currentTime > t.duration / 10) { - t.oldCurrentTime = t.currentTime; - t.timestamp = Date.now(); - var delta = t.oldCurrentTime, - delta_wallclock = (t.timestamp - t.startTimestamp - t.bufferingTime) / 1000; - - t.bufferingTime = 0; - - is(t.playbackRate, SLOW_RATE, - "The playback rate shoud be "+SLOW_RATE+"." + t.token + '\n'); - is(t.defaultPlaybackRate, SLOW_RATE, - "The default playback rate shoud be "+SLOW_RATE+"." + t.token); - ok(delta_wallclock > delta , "We are effectively slowing down playback. (" + delta_wallclock + ", " + delta + ")"); - if (t.skippedFastPart) { - is(t.ratechangecount, 7, "We should have received 7 \"ratechange\" events."); - } else { - is(t.ratechangecount, 8, "We should have received 8 \"ratechange\" events."); - } - finish_test(t); - } + finish_test(t); } function onratechange(e) { @@ -207,7 +174,6 @@ function startTest(test, token) { element.playbackRate = VERY_SLOW_RATE; is(element.playbackRate, SLOW_RATE, "PlaybackRate should be clamped to " + SLOW_RATE + "."); element.play(); - is(element.playbackRate, 1.0, "playbackRate should be reset to 1.0 on play() call"); element.playbackRate = SLOW_RATE; }); } diff --git a/content/media/test/test_playback_rate_playpause.html b/content/media/test/test_playback_rate_playpause.html new file mode 100644 index 00000000000..b868a04b905 --- /dev/null +++ b/content/media/test/test_playback_rate_playpause.html @@ -0,0 +1,73 @@ + + + + Test that the playbackRate property is not reset when resuming the playback + + + + + +
+
+
+
+
+ + diff --git a/toolkit/content/widgets/videocontrols.xml b/toolkit/content/widgets/videocontrols.xml index 33f1b4ecea3..1e4a544f307 100644 --- a/toolkit/content/widgets/videocontrols.xml +++ b/toolkit/content/widgets/videocontrols.xml @@ -1004,6 +1004,7 @@ if (this.video.paused || this.video.ended) { this._triggeredByControls = true; this.hideClickToPlay(); + this.video.playbackRate = this.video.defaultPlaybackRate; this.video.play(); } else { this.video.pause(); From 24a1cea8b8e4b037b95321fa6234894ea6d0e3cb Mon Sep 17 00:00:00 2001 From: Shawn Huang Date: Fri, 19 Jul 2013 10:10:00 -0400 Subject: [PATCH 02/58] Bug 884239 - Remove the wrapper function of timer_create if ANDROID_VERSION is greater than JB MR1. r=mwu --- mozglue/build/BionicGlue.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mozglue/build/BionicGlue.cpp b/mozglue/build/BionicGlue.cpp index 46ca2c3d6b6..062faadf7c4 100644 --- a/mozglue/build/BionicGlue.cpp +++ b/mozglue/build/BionicGlue.cpp @@ -15,6 +15,7 @@ #define NS_EXPORT __attribute__ ((visibility("default"))) +#if ANDROID_VERSION < 17 || defined(MOZ_WIDGET_ANDROID) /* Android doesn't have pthread_atfork(), so we need to use our own. */ struct AtForkFuncs { void (*prepare)(void); @@ -59,11 +60,13 @@ private: }; static std::vector > atfork; +#endif #ifdef MOZ_WIDGET_GONK #include "cpuacct.h" #define WRAP(x) x +#if ANDROID_VERSION < 17 || defined(MOZ_WIDGET_ANDROID) extern "C" NS_EXPORT int timer_create(clockid_t, struct sigevent*, timer_t*) { @@ -71,12 +74,14 @@ timer_create(clockid_t, struct sigevent*, timer_t*) abort(); return -1; } +#endif #else #define cpuacct_add(x) #define WRAP(x) __wrap_##x #endif +#if ANDROID_VERSION < 17 || defined(MOZ_WIDGET_ANDROID) extern "C" NS_EXPORT int WRAP(pthread_atfork)(void (*prepare)(void), void (*parent)(void), void (*child)(void)) { @@ -117,6 +122,7 @@ WRAP(fork)(void) } return pid; } +#endif extern "C" NS_EXPORT int WRAP(raise)(int sig) From 57465b2e2b2a18ee89297c3eac35706a1d61ffd4 Mon Sep 17 00:00:00 2001 From: Ken Chang Date: Fri, 12 Jul 2013 13:01:37 +0800 Subject: [PATCH 03/58] Bug 886765 - Make sure that no other application will send traffic when we send/receive a MMS and data traffic is off. r=vicamo --- dom/system/gonk/NetworkManager.js | 73 ++++++++++++++++++++++--------- dom/system/gonk/net_worker.js | 14 ++++++ 2 files changed, 67 insertions(+), 20 deletions(-) diff --git a/dom/system/gonk/NetworkManager.js b/dom/system/gonk/NetworkManager.js index 98ff09a1b8f..eb0878a053a 100644 --- a/dom/system/gonk/NetworkManager.js +++ b/dom/system/gonk/NetworkManager.js @@ -235,6 +235,8 @@ NetworkManager.prototype = { network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_SUPL) { this.addHostRoute(network); } + // Add extra host route. For example, mms proxy or mmsc. + this.setExtraHostRoute(network); // Remove pre-created default route and let setAndConfigureActive() // to set default route only on preferred network this.removeDefaultRoute(network.name); @@ -256,9 +258,13 @@ NetworkManager.prototype = { network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_SUPL) { this.removeHostRoute(network); } + // Remove extra host route. For example, mms proxy or mmsc. + this.removeExtraHostRoute(network); // Remove routing table in /proc/net/route if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) { this.resetRoutingTable(network); + } else if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE) { + this.removeDefaultRoute(network.name); } // Abort ongoing captive portal detection on the wifi interface CaptivePortalDetectionHelper.notify(CaptivePortalDetectionHelper.EVENT_DISCONNECT, network); @@ -272,25 +278,13 @@ NetworkManager.prototype = { break; case TOPIC_INTERFACE_REGISTERED: let regNetwork = subject.QueryInterface(Ci.nsINetworkInterface); - if (regNetwork.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS) { - debug("Network '" + regNetwork.name + "' registered, adding mmsproxy and/or mmsc route"); - let mmsHosts = this.resolveHostname( - [ Services.prefs.getCharPref("ril.mms.mmsproxy"), - Services.prefs.getCharPref("ril.mms.mmsc") ] - ); - this.addHostRouteWithResolve(regNetwork, mmsHosts); - } + // Add extra host route. For example, mms proxy or mmsc. + this.setExtraHostRoute(regNetwork); break; case TOPIC_INTERFACE_UNREGISTERED: let unregNetwork = subject.QueryInterface(Ci.nsINetworkInterface); - if (unregNetwork.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS) { - debug("Network '" + unregNetwork.name + "' unregistered, removing mmsproxy and/or mmsc route"); - let mmsHosts = this.resolveHostname( - [ Services.prefs.getCharPref("ril.mms.mmsproxy"), - Services.prefs.getCharPref("ril.mms.mmsc") ] - ); - this.removeHostRouteWithResolve(unregNetwork, mmsHosts); - } + // Remove extra host route. For example, mms proxy or mmsc. + this.removeExtraHostRoute(unregNetwork); break; case TOPIC_MOZSETTINGS_CHANGED: let setting = JSON.parse(data); @@ -400,9 +394,7 @@ NetworkManager.prototype = { }, set preferredNetworkType(val) { if ([Ci.nsINetworkInterface.NETWORK_TYPE_WIFI, - Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE, - Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS, - Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_SUPL].indexOf(val) == -1) { + Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE].indexOf(val) == -1) { throw "Invalid network type"; } this._preferredNetworkType = val; @@ -415,6 +407,10 @@ NetworkManager.prototype = { _activeInfo: null, overrideActive: function overrideActive(network) { + if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS || + network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_SUPL) { + throw "Invalid network type"; + } this._overriddenActive = network; this.setAndConfigureActive(); }, @@ -463,6 +459,26 @@ NetworkManager.prototype = { } }, + setExtraHostRoute: function setExtraHostRoute(network) { + if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS) { + debug("Network '" + network.name + "' registered, adding mmsproxy and/or mmsc route"); + let mmsHosts = this.resolveHostname( + [Services.prefs.getCharPref("ril.mms.mmsproxy"), + Services.prefs.getCharPref("ril.mms.mmsc")]); + this.addHostRouteWithResolve(network, mmsHosts); + } + }, + + removeExtraHostRoute: function removeExtraHostRoute(network) { + if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS) { + debug("Network '" + network.name + "' unregistered, removing mmsproxy and/or mmsc route"); + let mmsHosts = this.resolveHostname( + [Services.prefs.getCharPref("ril.mms.mmsproxy"), + Services.prefs.getCharPref("ril.mms.mmsc")]); + this.removeHostRouteWithResolve(network, mmsHosts); + } + }, + /** * Determine the active interface and configure it. */ @@ -519,7 +535,13 @@ NetworkManager.prototype = { this.active.type != this.preferredNetworkType) { this.active = defaultDataNetwork; } - this.setDefaultRouteAndDNS(oldActive); + // Don't set default route on secondary APN + if (this.active.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS || + this.active.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_SUPL) { + this.setDNS(this.active); + } else { + this.setDefaultRouteAndDNS(oldActive); + } if (this.active != oldActive) { Services.obs.notifyObservers(this.active, TOPIC_ACTIVE_CHANGED, null); } @@ -540,6 +562,17 @@ NetworkManager.prototype = { this.worker.postMessage(options); }, + setDNS: function setDNS(networkInterface) { + debug("Going DNS to " + networkInterface.name); + let options = { + cmd: "setDNS", + ifname: networkInterface.name, + dns1_str: networkInterface.dns1, + dns2_str: networkInterface.dns2 + }; + this.worker.postMessage(options); + }, + setDefaultRouteAndDNS: function setDefaultRouteAndDNS(oldInterface) { debug("Going to change route and DNS to " + this.active.name); let options = { diff --git a/dom/system/gonk/net_worker.js b/dom/system/gonk/net_worker.js index f8f14c22c04..af783ae260d 100644 --- a/dom/system/gonk/net_worker.js +++ b/dom/system/gonk/net_worker.js @@ -197,6 +197,20 @@ self.onmessage = function onmessage(event) { } }; +/** +* Set DNS servers for given network interface. +*/ +function setDNS(options) { + let ifprops = getIFProperties(options.ifname); + let dns1_str = options.dns1_str || ifprops.dns1_str; + let dns2_str = options.dns2_str || ifprops.dns2_str; + libcutils.property_set("net.dns1", dns1_str); + libcutils.property_set("net.dns2", dns2_str); + // Bump the DNS change property. + let dnschange = libcutils.property_get("net.dnschange", "0"); + libcutils.property_set("net.dnschange", (parseInt(dnschange, 10) + 1).toString()); +} + /** * Set default route and DNS servers for given network interface. */ From 217467216d7004fb24e0e3f864565470883a9405 Mon Sep 17 00:00:00 2001 From: Changbin Park Date: Mon, 15 Jul 2013 09:53:41 +0900 Subject: [PATCH 04/58] Bug 889696 - Catch exception occuring while updating 3rd party apps on booting. r=fabrice --- dom/apps/src/Webapps.jsm | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dom/apps/src/Webapps.jsm b/dom/apps/src/Webapps.jsm index 3fe88337756..f186b121d2d 100644 --- a/dom/apps/src/Webapps.jsm +++ b/dom/apps/src/Webapps.jsm @@ -303,6 +303,9 @@ this.DOMApplicationRegistry = { baseDir = FileUtils.getDir("coreAppsDir", ["webapps", aId], false); if (!baseDir.exists()) { return; + } else if (!baseDir.directoryEntries.hasMoreElements()) { + debug("Error: Core app in " + baseDir.path + " is empty"); + return; } } catch(e) { // In ENG builds, we don't have apps in coreAppsDir. @@ -339,7 +342,11 @@ this.DOMApplicationRegistry = { filesToMove.forEach(function(aFile) { let file = baseDir.clone(); file.append(aFile); - file.copyTo(destDir, aFile); + try { + file.copyTo(destDir, aFile); + } catch(e) { + debug("Error: Failed to copy " + file.path + " to " + destDir.path); + } }); app.installState = "installed"; From 1e704c72256f313e8d4b0f2968d1857e4ddcbb63 Mon Sep 17 00:00:00 2001 From: Sankha Narayan Guria Date: Tue, 16 Jul 2013 20:43:25 +0530 Subject: [PATCH 05/58] Bug 858025 - Playback is maintained after seeking or pausing media; r=padenot --- toolkit/content/widgets/videocontrols.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/toolkit/content/widgets/videocontrols.xml b/toolkit/content/widgets/videocontrols.xml index 1e4a544f307..586076ad90c 100644 --- a/toolkit/content/widgets/videocontrols.xml +++ b/toolkit/content/widgets/videocontrols.xml @@ -173,9 +173,11 @@ this.isDragging = isDragging; if (isDragging) { this.wasPausedBeforeDrag = this.Utils.video.paused; + this.previousPlaybackRate = this.Utils.video.playbackRate; this.Utils.video.pause(); } else if (!this.wasPausedBeforeDrag) { // After the drag ends, resume playing. + this.Utils.video.playbackRate = this.previousPlaybackRate; this.Utils.video.play(); } } From 668a5b27fe2f2d05b889ad6fa457fa1f4d26f0f9 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Fri, 19 Jul 2013 08:06:02 -0600 Subject: [PATCH 06/58] Bug 875125 - Allow scripts to be parsed/emitted off the main thread, r=billm. --- js/src/builtin/Eval.cpp | 6 +- js/src/frontend/BytecodeCompiler.cpp | 56 ++++-- js/src/frontend/BytecodeCompiler.h | 12 +- js/src/frontend/BytecodeEmitter.cpp | 5 +- js/src/frontend/ParseMaps-inl.h | 9 +- js/src/frontend/Parser.cpp | 2 + js/src/gc/GCInternals.h | 2 + js/src/gc/Zone.cpp | 1 + js/src/gc/Zone.h | 8 +- js/src/ion/AsmJS.cpp | 10 +- js/src/ion/Ion.cpp | 4 +- js/src/jsapi.cpp | 63 ++++-- js/src/jsatom.cpp | 10 +- js/src/jscntxt.cpp | 7 +- js/src/jscntxt.h | 106 +++++----- js/src/jscntxtinlines.h | 114 +++++++++-- js/src/jscompartment.h | 6 +- js/src/jscompartmentinlines.h | 8 +- js/src/jsgc.cpp | 24 ++- js/src/jsobj.cpp | 5 +- js/src/jspubtd.h | 2 +- js/src/jsscript.cpp | 23 ++- js/src/jsscript.h | 6 +- js/src/jsworkers.cpp | 281 +++++++++++++++++++++++++-- js/src/jsworkers.h | 90 ++++++++- js/src/jswrapper.cpp | 2 +- js/src/shell/js.cpp | 53 +++++ js/src/vm/ArrayObject-inl.h | 8 +- js/src/vm/ArrayObject.h | 2 +- js/src/vm/Debugger.cpp | 8 +- js/src/vm/Runtime-inl.h | 12 ++ js/src/vm/Runtime.cpp | 4 + js/src/vm/Runtime.h | 78 +++++++- js/src/vm/String.cpp | 1 + 34 files changed, 844 insertions(+), 184 deletions(-) diff --git a/js/src/builtin/Eval.cpp b/js/src/builtin/Eval.cpp index 803b7417995..e20a93312e1 100644 --- a/js/src/builtin/Eval.cpp +++ b/js/src/builtin/Eval.cpp @@ -316,7 +316,8 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFrame .setNoScriptRval(false) .setPrincipals(principals) .setOriginPrincipals(originPrincipals); - JSScript *compiled = frontend::CompileScript(cx, scopeobj, callerScript, options, + JSScript *compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(), + scopeobj, callerScript, options, chars.get(), length, stableStr, staticLevel); if (!compiled) return false; @@ -380,7 +381,8 @@ js::DirectEvalFromIon(JSContext *cx, .setNoScriptRval(false) .setPrincipals(principals) .setOriginPrincipals(originPrincipals); - JSScript *compiled = frontend::CompileScript(cx, scopeobj, callerScript, options, + JSScript *compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(), + scopeobj, callerScript, options, chars.get(), length, stableStr, staticLevel); if (!compiled) return false; diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index d2fb320a57c..1b0855c0c8d 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -24,20 +24,21 @@ using namespace js::frontend; using mozilla::Maybe; static bool -CheckLength(JSContext *cx, size_t length) +CheckLength(ExclusiveContext *cx, size_t length) { // Note this limit is simply so we can store sourceStart and sourceEnd in // JSScript as 32-bits. It could be lifted fairly easily, since the compiler // is using size_t internally already. if (length > UINT32_MAX) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_SOURCE_TOO_LONG); + if (cx->isJSContext()) + JS_ReportErrorNumber(cx->asJSContext(), js_GetErrorMessage, NULL, JSMSG_SOURCE_TOO_LONG); return false; } return true; } static bool -SetSourceMap(JSContext *cx, TokenStream &tokenStream, ScriptSource *ss) +SetSourceMap(ExclusiveContext *cx, TokenStream &tokenStream, ScriptSource *ss) { if (tokenStream.hasSourceMap()) { if (!ss->setSourceMap(cx, tokenStream.releaseSourceMap())) @@ -74,13 +75,16 @@ CheckArgumentsWithinEval(JSContext *cx, Parser &parser, Handle } static bool -MaybeCheckEvalFreeVariables(JSContext *cx, HandleScript evalCaller, HandleObject scopeChain, +MaybeCheckEvalFreeVariables(ExclusiveContext *cxArg, HandleScript evalCaller, HandleObject scopeChain, Parser &parser, ParseContext &pc) { if (!evalCaller || !evalCaller->functionOrCallerFunction()) return true; + // Eval scripts are only compiled on the main thread. + JSContext *cx = cxArg->asJSContext(); + // Watch for uses of 'arguments' within the evaluated script, both as // free variables and as variables redeclared with 'var'. RootedFunction fun(cx, evalCaller->functionOrCallerFunction()); @@ -120,17 +124,18 @@ MaybeCheckEvalFreeVariables(JSContext *cx, HandleScript evalCaller, HandleObject } inline bool -CanLazilyParse(JSContext *cx, const CompileOptions &options) +CanLazilyParse(ExclusiveContext *cx, const CompileOptions &options) { return options.canLazilyParse && options.compileAndGo && options.sourcePolicy == CompileOptions::SAVE_SOURCE && - !cx->compartment()->debugMode(); + cx->isJSContext() && + !cx->asJSContext()->compartment()->debugMode(); } -inline void -MaybeCallSourceHandler(JSContext *cx, const CompileOptions &options, - const jschar *chars, size_t length) +void +frontend::MaybeCallSourceHandler(JSContext *cx, const CompileOptions &options, + const jschar *chars, size_t length) { JSSourceHandler listener = cx->runtime()->debugHooks.sourceHandler; void *listenerData = cx->runtime()->debugHooks.sourceHandlerData; @@ -143,7 +148,7 @@ MaybeCallSourceHandler(JSContext *cx, const CompileOptions &options, } JSScript * -frontend::CompileScript(JSContext *cx, HandleObject scopeChain, +frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject scopeChain, HandleScript evalCaller, const CompileOptions &options, const jschar *chars, size_t length, @@ -154,7 +159,8 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, RootedString source(cx, source_); SkipRoot skip(cx, &chars); - MaybeCallSourceHandler(cx, options, chars, length); + if (cx->isJSContext()) + MaybeCallSourceHandler(cx->asJSContext(), options, chars, length); /* * The scripted callerFrame can only be given for compile-and-go scripts @@ -176,11 +182,20 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, JS::RootedScriptSource sourceObject(cx, ScriptSourceObject::create(cx, ss)); if (!sourceObject) return NULL; - SourceCompressionToken mysct(cx); - SourceCompressionToken *sct = (extraSct) ? extraSct : &mysct; + + // Saving source is not yet supported when parsing off thread. + JS_ASSERT_IF(!cx->isJSContext(), !extraSct && options.sourcePolicy == CompileOptions::NO_SOURCE); + + SourceCompressionToken *sct = extraSct; + Maybe mysct; + if (cx->isJSContext() && !sct) { + mysct.construct(cx->asJSContext()); + sct = mysct.addr(); + } + switch (options.sourcePolicy) { case CompileOptions::SAVE_SOURCE: - if (!ss->setSourceCopy(cx, chars, length, false, sct)) + if (!ss->setSourceCopy(cx->asJSContext(), chars, length, false, sct)) return NULL; break; case CompileOptions::LAZY_SOURCE: @@ -194,14 +209,12 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, Maybe > syntaxParser; if (canLazilyParse) { - syntaxParser.construct(cx, &cx->tempLifoAlloc(), - options, chars, length, /* foldConstants = */ false, + syntaxParser.construct(cx, alloc, options, chars, length, /* foldConstants = */ false, (Parser *) NULL, (LazyScript *) NULL); } - Parser parser(cx, &cx->tempLifoAlloc(), - options, chars, length, /* foldConstants = */ true, + Parser parser(cx, alloc, options, chars, length, /* foldConstants = */ true, canLazilyParse ? &syntaxParser.ref() : NULL, NULL); parser.sct = sct; parser.ss = ss; @@ -327,7 +340,10 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, if (!FoldConstants(cx, &pn, &parser)) return NULL; - if (!NameFunctions(cx, pn)) + + // Inferring names for functions in compiled scripts is currently only + // supported while on the main thread. See bug 895395. + if (cx->isJSContext() && !NameFunctions(cx->asJSContext(), pn)) return NULL; if (!EmitTree(cx, &bce, pn)) @@ -354,7 +370,7 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, bce.tellDebuggerAboutCompiledScript(cx); - if (sct == &mysct && !sct->complete()) + if (sct && !extraSct && !sct->complete()) return NULL; return script; diff --git a/js/src/frontend/BytecodeCompiler.h b/js/src/frontend/BytecodeCompiler.h index 8f9f8d4a546..12721bcfec0 100644 --- a/js/src/frontend/BytecodeCompiler.h +++ b/js/src/frontend/BytecodeCompiler.h @@ -15,12 +15,14 @@ namespace js { class AutoNameVector; class LazyScript; +class LifoAlloc; struct SourceCompressionToken; namespace frontend { JSScript * -CompileScript(JSContext *cx, HandleObject scopeChain, HandleScript evalCaller, +CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, + HandleObject scopeChain, HandleScript evalCaller, const CompileOptions &options, const jschar *chars, size_t length, JSString *source_ = NULL, unsigned staticLevel = 0, SourceCompressionToken *extraSct = NULL); @@ -32,6 +34,14 @@ bool CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileOptions options, const AutoNameVector &formals, const jschar *chars, size_t length); +/* + * This should be called while still on the main thread if compilation will + * occur on a worker thread. + */ +void +MaybeCallSourceHandler(JSContext *cx, const CompileOptions &options, + const jschar *chars, size_t length); + /* * True if str consists of an IdentifierStart character, followed by one or * more IdentifierPart characters, i.e. it matches the IdentifierName production diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 5e91bcf186a..84287238ef2 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -4461,6 +4461,8 @@ EmitFor(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top static JS_NEVER_INLINE bool EmitFunc(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) { + cx->maybePause(); + FunctionBox *funbox = pn->pn_funbox; RootedFunction fun(cx, funbox->function()); JS_ASSERT_IF(fun->isInterpretedLazy(), fun->lazyScript()); @@ -4523,9 +4525,6 @@ EmitFunc(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) .setForEval(false) .setVersion(parent->getVersion()); - if (!cx->shouldBeJSContext()) - return false; - Rooted enclosingScope(cx, EnclosingStaticScope(bce)); Rooted sourceObject(cx, bce->script->sourceObject()); Rooted script(cx, JSScript::Create(cx, enclosingScope, false, options, diff --git a/js/src/frontend/ParseMaps-inl.h b/js/src/frontend/ParseMaps-inl.h index 883196dc844..a9172e425d0 100644 --- a/js/src/frontend/ParseMaps-inl.h +++ b/js/src/frontend/ParseMaps-inl.h @@ -20,6 +20,8 @@ AtomThingMapPtr::ensureMap(ExclusiveContext *cx) { if (map_) return true; + + AutoLockForExclusiveAccess lock(cx); map_ = cx->parseMapPool().acquire(); return !!map_; } @@ -30,6 +32,8 @@ AtomThingMapPtr::releaseMap(ExclusiveContext *cx) { if (!map_) return; + + AutoLockForExclusiveAccess lock(cx); cx->parseMapPool().release(map_); map_ = NULL; } @@ -38,6 +42,7 @@ template inline bool AtomDecls::init() { + AutoLockForExclusiveAccess lock(cx); map = cx->parseMapPool().acquire(); return map; } @@ -46,8 +51,10 @@ template inline AtomDecls::~AtomDecls() { - if (map) + if (map) { + AutoLockForExclusiveAccess lock(cx); cx->parseMapPool().release(map); + } } } /* namespace frontend */ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 1b2678954ac..6d46dd9cb67 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -2223,6 +2223,8 @@ Parser::functionArgsAndBodyGeneric(Node pn, HandleFunction fun, Fu // function without concern for conversion to strict mode, use of lazy // parsing and such. + context->maybePause(); + Node prelude = null(); bool hasRest; if (!functionArguments(kind, &prelude, pn, hasRest)) diff --git a/js/src/gc/GCInternals.h b/js/src/gc/GCInternals.h index a318017bc60..beb20074a9f 100644 --- a/js/src/gc/GCInternals.h +++ b/js/src/gc/GCInternals.h @@ -8,6 +8,7 @@ #define gc_GCInternals_h #include "jsapi.h" +#include "jsworkers.h" #include "vm/Runtime.h" @@ -50,6 +51,7 @@ class AutoTraceSession { void operator=(const AutoTraceSession&) MOZ_DELETE; js::HeapState prevState; + AutoPauseWorkersForGC pause; }; struct AutoPrepareForTracing diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index edf3ca1f8c0..448d205a74c 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -32,6 +32,7 @@ JS::Zone::Zone(JSRuntime *rt) gcTriggerBytes(0), gcHeapGrowthFactor(3.0), isSystem(false), + usedByExclusiveThread(false), scheduledForDestruction(false), maybeAlive(true), gcMallocBytes(0), diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index 12a96ec39ba..f054f9e8102 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -186,7 +186,10 @@ struct Zone : private JS::shadow::Zone, void scheduleGC() { JS_ASSERT(!rt->isHeapBusy()); - gcScheduled = true; + + /* Note: zones cannot be collected while in use by other threads. */ + if (!usedByExclusiveThread) + gcScheduled = true; } void unscheduleGC() { @@ -235,6 +238,9 @@ struct Zone : private JS::shadow::Zone, bool isSystem; + /* Whether this zone is being used by a thread with an ExclusiveContext. */ + bool usedByExclusiveThread; + /* * These flags help us to discover if a compartment that shouldn't be alive * manages to outlive a GC. diff --git a/js/src/ion/AsmJS.cpp b/js/src/ion/AsmJS.cpp index a4cb05c0e47..4f50c0666e1 100644 --- a/js/src/ion/AsmJS.cpp +++ b/js/src/ion/AsmJS.cpp @@ -4871,7 +4871,7 @@ CheckFunctionsSequential(ModuleCompiler &m) return true; } -#ifdef JS_PARALLEL_COMPILATION +#ifdef JS_WORKER_THREADS // State of compilation as tracked and updated by the main thread. struct ParallelGroupState { @@ -5063,7 +5063,7 @@ CheckFunctionsParallel(ModuleCompiler &m) } return true; } -#endif // JS_PARALLEL_COMPILATION +#endif // JS_WORKER_THREADS static bool CheckFuncPtrTable(ModuleCompiler &m, ParseNode *var) @@ -6311,7 +6311,7 @@ CheckModule(JSContext *cx, AsmJSParser &parser, ParseNode *stmtList, if (!CheckModuleGlobals(m)) return false; -#ifdef JS_PARALLEL_COMPILATION +#ifdef JS_WORKER_THREADS if (OffThreadCompilationEnabled(cx)) { if (!CheckFunctionsParallel(m)) return false; @@ -6369,9 +6369,9 @@ js::CompileAsmJS(JSContext *cx, AsmJSParser &parser, ParseNode *stmtList, bool * if (!EnsureAsmJSSignalHandlersInstalled(cx->runtime())) return Warn(cx, JSMSG_USE_ASM_TYPE_FAIL, "Platform missing signal handler support"); -# ifdef JS_PARALLEL_COMPILATION +# ifdef JS_WORKER_THREADS if (OffThreadCompilationEnabled(cx)) { - if (!EnsureParallelCompilationInitialized(cx->runtime())) + if (!EnsureWorkerThreadsInitialized(cx->runtime())) return Warn(cx, JSMSG_USE_ASM_TYPE_FAIL, "Failed compilation thread initialization"); } # endif diff --git a/js/src/ion/Ion.cpp b/js/src/ion/Ion.cpp index 0191efda32f..d93afcaba1e 100644 --- a/js/src/ion/Ion.cpp +++ b/js/src/ion/Ion.cpp @@ -193,7 +193,8 @@ IonRuntime::~IonRuntime() bool IonRuntime::initialize(JSContext *cx) { - AutoCompartment ac(cx, cx->runtime()->atomsCompartment); + AutoLockForExclusiveAccess lock(cx); + AutoCompartment ac(cx, cx->atomsCompartment()); IonContext ictx(cx, NULL); AutoFlushCache afc("IonRuntime::initialize"); @@ -277,6 +278,7 @@ IonRuntime::debugTrapHandler(JSContext *cx) if (!debugTrapHandler_) { // IonRuntime code stubs are shared across compartments and have to // be allocated in the atoms compartment. + AutoLockForExclusiveAccess lock(cx); AutoCompartment ac(cx, cx->runtime()->atomsCompartment); debugTrapHandler_ = generateDebugTrapHandler(cx); } diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 43e5063bd2c..9a73949baf9 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -686,6 +686,9 @@ PerThreadData::~PerThreadData() { if (dtoaState) js_DestroyDtoaState(dtoaState); + + if (isInList()) + removeFromThreadList(); } bool @@ -698,6 +701,22 @@ PerThreadData::init() return true; } +void +PerThreadData::addToThreadList() +{ + // PerThreadData which are created/destroyed off the main thread do not + // show up in the runtime's thread list. + runtime_->assertValidThread(); + runtime_->threadList.insertBack(this); +} + +void +PerThreadData::removeFromThreadList() +{ + runtime_->assertValidThread(); + removeFrom(runtime_->threadList); +} + JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads) : mainThread(this), interrupt(0), @@ -706,6 +725,10 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads) #ifdef DEBUG operationCallbackOwner(NULL), #endif + exclusiveAccessLock(NULL), + exclusiveAccessOwner(NULL), + mainThreadHasExclusiveAccess(false), + numExclusiveThreads(0), #endif atomsCompartment(NULL), systemZone(NULL), @@ -891,12 +914,17 @@ JSRuntime::init(uint32_t maxbytes) operationCallbackLock = PR_NewLock(); if (!operationCallbackLock) return false; + + exclusiveAccessLock = PR_NewLock(); + if (!exclusiveAccessLock) + return false; #endif if (!mainThread.init()) return false; js::TlsPerThreadData.set(&mainThread); + mainThread.addToThreadList(); if (!js_InitGC(this, maxbytes)) return false; @@ -957,19 +985,7 @@ JSRuntime::init(uint32_t maxbytes) JSRuntime::~JSRuntime() { -#ifdef JS_THREADSAFE - clearOwnerThread(); - - JS_ASSERT(!operationCallbackOwner); - if (operationCallbackLock) - PR_DestroyLock(operationCallbackLock); -#endif - - /* - * Even though all objects in the compartment are dead, we may have keep - * some filenames around because of gcKeepAtoms. - */ - FreeScriptData(this); + mainThread.removeFromThreadList(); #ifdef JS_THREADSAFE # ifdef JS_ION @@ -977,8 +993,24 @@ JSRuntime::~JSRuntime() js_delete(workerThreadState); # endif sourceCompressorThread.finish(); + + clearOwnerThread(); + + JS_ASSERT(!operationCallbackOwner); + if (operationCallbackLock) + PR_DestroyLock(operationCallbackLock); + + JS_ASSERT(!exclusiveAccessOwner); + if (exclusiveAccessLock) + PR_DestroyLock(exclusiveAccessLock); #endif + /* + * Even though all objects in the compartment are dead, we may have keep + * some filenames around because of gcKeepAtoms. + */ + FreeScriptData(this); + #ifdef DEBUG /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */ if (hasContexts()) { @@ -5204,7 +5236,7 @@ JS::Compile(JSContext *cx, HandleObject obj, CompileOptions options, JS_ASSERT_IF(options.principals, cx->compartment()->principals == options.principals); AutoLastFrameCheck lfc(cx); - return frontend::CompileScript(cx, obj, NullPtr(), options, chars, length); + return frontend::CompileScript(cx, &cx->tempLifoAlloc(), obj, NullPtr(), options, chars, length); } JSScript * @@ -5545,7 +5577,8 @@ JS::Evaluate(JSContext *cx, HandleObject obj, CompileOptions options, options.setCompileAndGo(true); options.setNoScriptRval(!rval); SourceCompressionToken sct(cx); - RootedScript script(cx, frontend::CompileScript(cx, obj, NullPtr(), options, + RootedScript script(cx, frontend::CompileScript(cx, &cx->tempLifoAlloc(), + obj, NullPtr(), options, chars, length, NULL, 0, &sct)); if (!script) return false; diff --git a/js/src/jsatom.cpp b/js/src/jsatom.cpp index 5a6d0ceff4f..1c0f5116d65 100644 --- a/js/src/jsatom.cpp +++ b/js/src/jsatom.cpp @@ -242,6 +242,8 @@ AtomizeAndTakeOwnership(ExclusiveContext *cx, jschar *tbchars, size_t length, In return s; } + AutoLockForExclusiveAccess lock(cx); + /* * If a GC occurs at js_NewStringCopy then |p| will still have the correct * hash, allowing us to avoid rehashing it. Even though the hash is @@ -258,7 +260,7 @@ AtomizeAndTakeOwnership(ExclusiveContext *cx, jschar *tbchars, size_t length, In return atom; } - AutoCompartment ac(cx, cx->asJSContext()->runtime()->atomsCompartment); + AutoCompartment ac(cx, cx->atomsCompartment()); JSFlatString *flat = js_NewString(cx, tbchars, length); if (!flat) { @@ -293,6 +295,8 @@ AtomizeAndCopyChars(ExclusiveContext *cx, const jschar *tbchars, size_t length, * GC will potentially free some table entries. */ + AutoLockForExclusiveAccess lock(cx); + AtomSet& atoms = cx->atoms(); AtomSet::AddPtr p = atoms.lookupForAdd(AtomHasher::Lookup(tbchars, length)); SkipRoot skipHash(cx, &p); /* Prevent the hash from being poisoned. */ @@ -302,7 +306,7 @@ AtomizeAndCopyChars(ExclusiveContext *cx, const jschar *tbchars, size_t length, return atom; } - AutoCompartment ac(cx, cx->asJSContext()->runtime()->atomsCompartment); + AutoCompartment ac(cx, cx->atomsCompartment()); JSFlatString *flat = js_NewStringCopyN(cx, tbchars, length); if (!flat) @@ -331,6 +335,8 @@ js::AtomizeString(ExclusiveContext *cx, JSString *str, if (ib != InternAtom || js::StaticStrings::isStatic(&atom)) return &atom; + AutoLockForExclusiveAccess lock(cx); + AtomSet::Ptr p = cx->atoms().lookup(AtomHasher::Lookup(&atom)); JS_ASSERT(p); /* Non-static atom must exist in atom state set. */ JS_ASSERT(p->asPtr() == &atom); diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 8514e1bf468..85d1fd3da1a 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -260,9 +260,10 @@ js::DestroyContext(JSContext *cx, DestroyContextMode mode) for (CompartmentsIter c(rt); !c.done(); c.next()) c->types.print(cx, false); - /* Off thread ion compilations depend on atoms still existing. */ + /* Off thread compilation and parsing depend on atoms still existing. */ for (CompartmentsIter c(rt); !c.done(); c.next()) CancelOffThreadIonCompile(c, NULL); + WaitForOffThreadParsingToFinish(rt); /* Unpin all common names before final GC. */ FinishCommonNames(rt); @@ -1034,7 +1035,8 @@ js_HandleExecutionInterrupt(JSContext *cx) js::ThreadSafeContext::ThreadSafeContext(JSRuntime *rt, PerThreadData *pt, ContextKind kind) : ContextFriendFields(rt), contextKind_(kind), - perThreadData(pt) + perThreadData(pt), + allocator_(NULL) { } bool @@ -1058,7 +1060,6 @@ JSContext::JSContext(JSRuntime *rt) reportGranularity(JS_DEFAULT_JITREPORT_GRANULARITY), resolvingList(NULL), generatingError(false), - enterCompartmentDepth_(0), savedFrameChains_(), defaultCompartmentObject_(NULL), cycleDetectorSet(MOZ_THIS_IN_INITIALIZER_LIST()), diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index d22d1a31218..9dce5c4c6cd 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -123,14 +123,15 @@ class DtoaCache; * may run in parallel with other threads operating on the same or other * compartments. * - * - ExclusiveContext is used by threads operating in one compartment, where - * other threads may operate in other compartments, but *not* the one which - * the ExclusiveContext is in. A thread with an ExclusiveContext may enter the - * atoms compartment and atomize strings, in which case a lock is used. + * - ExclusiveContext is used by threads operating in one compartment/zone, + * where other threads may operate in other compartments, but *not* the same + * compartment or zone which the ExclusiveContext is in. A thread with an + * ExclusiveContext may enter the atoms compartment and atomize strings, in + * which case a lock is used. * * - JSContext is used only by the runtime's main thread. The context may - * operate in any compartment which is not locked by an ExclusiveContext or - * ThreadSafeContext, and will only run in parallel with threads using such + * operate in any compartment or zone which is not used by an ExclusiveContext + * or ThreadSafeContext, and will only run in parallel with threads using such * contexts. * * An ExclusiveContext coerces to a ThreadSafeContext, and a JSContext coerces @@ -279,23 +280,65 @@ struct ThreadSafeContext : ContextFriendFields, } }; +struct WorkerThread; + class ExclusiveContext : public ThreadSafeContext { friend class gc::ArenaLists; friend class CompartmentChecker; - friend class AutoEnterAtomsCompartment; + friend class AutoCompartment; + friend class AutoLockForExclusiveAccess; friend struct StackBaseShape; friend void JSScript::initCompartmentAndPrincipals(ExclusiveContext *cx, const JS::CompileOptions &options); - inline void privateSetCompartment(JSCompartment *comp); + // The worker on which this context is running, if this is not a JSContext. + WorkerThread *workerThread; public: ExclusiveContext(JSRuntime *rt, PerThreadData *pt, ContextKind kind) - : ThreadSafeContext(rt, pt, kind) + : ThreadSafeContext(rt, pt, kind), + workerThread(NULL), + enterCompartmentDepth_(0) {} + /* + * "Entering" a compartment changes cx->compartment (which changes + * cx->global). Note that this does not push any StackFrame which means + * that it is possible for cx->fp()->compartment() != cx->compartment. + * This is not a problem since, in general, most places in the VM cannot + * know that they were called from script (e.g., they may have been called + * through the JSAPI via JS_CallFunction) and thus cannot expect fp. + * + * Compartments should be entered/left in a LIFO fasion. The depth of this + * enter/leave stack is maintained by enterCompartmentDepth_ and queried by + * hasEnteredCompartment. + * + * To enter a compartment, code should prefer using AutoCompartment over + * manually calling cx->enterCompartment/leaveCompartment. + */ + protected: + unsigned enterCompartmentDepth_; + inline void setCompartment(JSCompartment *comp); + public: + bool hasEnteredCompartment() const { + return enterCompartmentDepth_ > 0; + } +#ifdef DEBUG + unsigned getEnterCompartmentDepth() const { + return enterCompartmentDepth_; + } +#endif + + inline void enterCompartment(JSCompartment *c); + inline void leaveCompartment(JSCompartment *oldCompartment); + + void setWorkerThread(WorkerThread *workerThread); + + // If required, pause this thread until notified to continue by the main thread. + inline void maybePause() const; + inline bool typeInferenceEnabled() const; // Per compartment data that can be accessed freely from an ExclusiveContext. @@ -314,17 +357,22 @@ class ExclusiveContext : public ThreadSafeContext // Methods to access runtime wide data that must be protected by locks. frontend::ParseMapPool &parseMapPool() { - runtime_->assertValidThread(); + JS_ASSERT(runtime_->currentThreadHasExclusiveAccess()); return runtime_->parseMapPool; } AtomSet &atoms() { - runtime_->assertValidThread(); + JS_ASSERT(runtime_->currentThreadHasExclusiveAccess()); return runtime_->atoms; } + JSCompartment *atomsCompartment() { + JS_ASSERT(runtime_->currentThreadHasExclusiveAccess()); + return runtime_->atomsCompartment; + } + ScriptDataTable &scriptDataTable() { - runtime_->assertValidThread(); + JS_ASSERT(runtime_->currentThreadHasExclusiveAccess()); return runtime_->scriptDataTable; } }; @@ -353,6 +401,8 @@ struct JSContext : public js::ExclusiveContext, } js::PerThreadData &mainThread() const { return runtime()->mainThread; } + friend class js::ExclusiveContext; + private: /* Exception state -- the exception member is a GC root by definition. */ bool throwing; /* is there a pending exception? */ @@ -369,38 +419,6 @@ struct JSContext : public js::ExclusiveContext, /* True if generating an error, to prevent runaway recursion. */ bool generatingError; - inline void setCompartment(JSCompartment *comp); - - /* - * "Entering" a compartment changes cx->compartment (which changes - * cx->global). Note that this does not push any StackFrame which means - * that it is possible for cx->fp()->compartment() != cx->compartment. - * This is not a problem since, in general, most places in the VM cannot - * know that they were called from script (e.g., they may have been called - * through the JSAPI via JS_CallFunction) and thus cannot expect fp. - * - * Compartments should be entered/left in a LIFO fasion. The depth of this - * enter/leave stack is maintained by enterCompartmentDepth_ and queried by - * hasEnteredCompartment. - * - * To enter a compartment, code should prefer using AutoCompartment over - * manually calling cx->enterCompartment/leaveCompartment. - */ - private: - unsigned enterCompartmentDepth_; - public: - bool hasEnteredCompartment() const { - return enterCompartmentDepth_ > 0; - } -#ifdef DEBUG - unsigned getEnterCompartmentDepth() const { - return enterCompartmentDepth_; - } -#endif - - inline void enterCompartment(JSCompartment *c); - inline void leaveCompartment(JSCompartment *oldCompartment); - /* See JS_SaveFrameChain/JS_RestoreFrameChain. */ private: struct SavedFrameChain { diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h index 91ac5d0fb1a..a93ec9d4a4c 100644 --- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -13,6 +13,7 @@ #include "jsfriendapi.h" #include "jsgc.h" #include "jsiter.h" +#include "jsworkers.h" #include "builtin/Object.h" // For js::obj_construct #include "frontend/ParseMaps.h" @@ -375,6 +376,69 @@ ExclusiveContext::dtoaCache() return compartment_->dtoaCache; } +inline void +ExclusiveContext::maybePause() const +{ +#ifdef JS_WORKER_THREADS + if (workerThread && runtime_->workerThreadState->shouldPause) { + AutoLockWorkerThreadState lock(runtime_); + workerThread->pause(); + } +#endif +} + +class AutoLockForExclusiveAccess +{ +#ifdef JS_THREADSAFE + JSRuntime *runtime; + + void init(JSRuntime *rt) { + runtime = rt; + if (runtime->numExclusiveThreads) { + PR_Lock(runtime->exclusiveAccessLock); +#ifdef DEBUG + runtime->exclusiveAccessOwner = PR_GetCurrentThread(); +#endif + } else { + JS_ASSERT(!runtime->mainThreadHasExclusiveAccess); + runtime->mainThreadHasExclusiveAccess = true; + } + } + + public: + AutoLockForExclusiveAccess(ExclusiveContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + init(cx->runtime_); + } + AutoLockForExclusiveAccess(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + init(rt); + } + ~AutoLockForExclusiveAccess() { + if (runtime->numExclusiveThreads) { + JS_ASSERT(runtime->exclusiveAccessOwner == PR_GetCurrentThread()); +#ifdef DEBUG + runtime->exclusiveAccessOwner = NULL; +#endif + PR_Unlock(runtime->exclusiveAccessLock); + } else { + JS_ASSERT(runtime->mainThreadHasExclusiveAccess); + runtime->mainThreadHasExclusiveAccess = false; + } + } +#else // JS_THREADSAFE + public: + AutoLockForExclusiveAccess(ExclusiveContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + AutoLockForExclusiveAccess(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } +#endif // JS_THREADSAFE + + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + } /* namespace js */ inline js::LifoAlloc & @@ -411,55 +475,65 @@ JSContext::setDefaultCompartmentObjectIfUnset(JSObject *obj) } inline void -JSContext::enterCompartment(JSCompartment *c) +js::ExclusiveContext::enterCompartment(JSCompartment *c) { enterCompartmentDepth_++; c->enter(); setCompartment(c); - if (throwing) - wrapPendingException(); + + if (JSContext *cx = maybeJSContext()) { + if (cx->throwing) + cx->wrapPendingException(); + } } inline void -JSContext::leaveCompartment(JSCompartment *oldCompartment) +js::ExclusiveContext::leaveCompartment(JSCompartment *oldCompartment) { JS_ASSERT(hasEnteredCompartment()); enterCompartmentDepth_--; // Only call leave() after we've setCompartment()-ed away from the current // compartment. - JSCompartment *startingCompartment = compartment(); + JSCompartment *startingCompartment = compartment_; setCompartment(oldCompartment); startingCompartment->leave(); - if (throwing && oldCompartment) - wrapPendingException(); + if (JSContext *cx = maybeJSContext()) { + if (cx->throwing && oldCompartment) + cx->wrapPendingException(); + } } inline void -JSContext::setCompartment(JSCompartment *comp) +js::ExclusiveContext::setCompartment(JSCompartment *comp) { + // ExclusiveContexts can only be in the atoms zone or in exclusive zones. + JS_ASSERT_IF(!isJSContext() && comp != runtime_->atomsCompartment, + comp->zone()->usedByExclusiveThread); + + // Normal JSContexts cannot enter exclusive zones. + JS_ASSERT_IF(isJSContext() && comp, + !comp->zone()->usedByExclusiveThread); + + // Only one thread can be in the atoms compartment at a time. + JS_ASSERT_IF(comp == runtime_->atomsCompartment, + runtime_->currentThreadHasExclusiveAccess()); + + // Make sure that the atoms compartment has its own zone. + JS_ASSERT_IF(comp && comp != runtime_->atomsCompartment, + comp->zone() != runtime_->atomsCompartment->zone()); + // Both the current and the new compartment should be properly marked as // entered at this point. JS_ASSERT_IF(compartment_, compartment_->hasBeenEntered()); JS_ASSERT_IF(comp, comp->hasBeenEntered()); + compartment_ = comp; zone_ = comp ? comp->zone() : NULL; allocator_ = zone_ ? &zone_->allocator : NULL; } -inline void -js::ExclusiveContext::privateSetCompartment(JSCompartment *comp) -{ - if (isJSContext()) { - asJSContext()->setCompartment(comp); - } else { - compartment_ = comp; - if (zone_ != comp->zone()) - MOZ_CRASH(); - } -} - inline JSScript * JSContext::currentScript(jsbytecode **ppc, MaybeAllowCrossCompartment allowCrossCompartment) const diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 5680ef436e7..fcf7eda6f6b 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -456,15 +456,15 @@ class AssertCompartmentUnchanged class AutoCompartment { - JSContext * const cx_; + ExclusiveContext * const cx_; JSCompartment * const origin_; public: - inline AutoCompartment(JSContext *cx, JSObject *target); + inline AutoCompartment(ExclusiveContext *cx, JSObject *target); inline AutoCompartment(ExclusiveContext *cx, JSCompartment *target); inline ~AutoCompartment(); - JSContext *context() const { return cx_; } + ExclusiveContext *context() const { return cx_; } JSCompartment *origin() const { return origin_; } private: diff --git a/js/src/jscompartmentinlines.h b/js/src/jscompartmentinlines.h index e9526af44ea..b124e3a4a07 100644 --- a/js/src/jscompartmentinlines.h +++ b/js/src/jscompartmentinlines.h @@ -26,16 +26,16 @@ JSCompartment::maybeGlobal() const return global_; } -js::AutoCompartment::AutoCompartment(JSContext *cx, JSObject *target) +js::AutoCompartment::AutoCompartment(ExclusiveContext *cx, JSObject *target) : cx_(cx), - origin_(cx->compartment()) + origin_(cx->compartment_) { cx_->enterCompartment(target->compartment()); } js::AutoCompartment::AutoCompartment(ExclusiveContext *cx, JSCompartment *target) - : cx_(cx->asJSContext()), - origin_(cx_->compartment()) + : cx_(cx), + origin_(cx_->compartment_) { cx_->enterCompartment(target); } diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 72d19abb0df..0d3b8b8bc36 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -78,6 +78,7 @@ using mozilla::Swap; #include "jsobjinlines.h" #include "vm/String-inl.h" +#include "vm/Runtime-inl.h" #include "vm/Stack-inl.h" #ifdef XP_WIN @@ -2594,8 +2595,10 @@ PurgeRuntime(JSRuntime *rt) rt->sourceDataCache.purge(); rt->evalCache.clear(); - // FIXME bug 875125 this should check all instances of PerThreadData. - if (!rt->mainThread.activeCompilations) + bool activeCompilations = false; + for (ThreadDataIter iter(rt); !iter.done(); iter.next()) + activeCompilations |= iter->activeCompilations; + if (!activeCompilations) rt->parseMapPool.purgeAll(); } @@ -2768,8 +2771,11 @@ BeginMarkPhase(JSRuntime *rt) */ Zone *atomsZone = rt->atomsCompartment->zone(); - // FIXME bug 875125 this should check all instances of PerThreadData. - if (atomsZone->isGCScheduled() && rt->gcIsFull && !rt->mainThread.gcKeepAtoms) { + bool keepAtoms = false; + for (ThreadDataIter iter(rt); !iter.done(); iter.next()) + keepAtoms |= iter->gcKeepAtoms; + + if (atomsZone->isGCScheduled() && rt->gcIsFull && !keepAtoms) { JS_ASSERT(!atomsZone->isCollecting()); atomsZone->setGCState(Zone::Mark); } @@ -4012,7 +4018,8 @@ class AutoGCSession : AutoTraceSession { /* Start a new heap session. */ AutoTraceSession::AutoTraceSession(JSRuntime *rt, js::HeapState heapState) : runtime(rt), - prevState(rt->heapState) + prevState(rt->heapState), + pause(rt) { JS_ASSERT(!rt->noGCOrAllocationCheck); JS_ASSERT(!rt->isHeapBusy()); @@ -4343,8 +4350,11 @@ gc::IsIncrementalGCSafe(JSRuntime *rt) { JS_ASSERT(!rt->mainThread.suppressGC); - // FIXME bug 875125 this should check all instances of PerThreadData. - if (rt->mainThread.gcKeepAtoms) + bool keepAtoms = false; + for (ThreadDataIter iter(rt); !iter.done(); iter.next()) + keepAtoms |= iter->gcKeepAtoms; + + if (keepAtoms) return IncrementalSafety::Unsafe("gcKeepAtoms set"); if (!rt->gcIncrementalEnabled) diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 0e422306399..070c39fa9ec 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -3465,13 +3465,10 @@ CallAddPropertyHookDense(ExclusiveContext *cx, Class *clasp, HandleObject obj, u { /* Inline addProperty for array objects. */ if (obj->is()) { - if (!cx->shouldBeJSContext()) - return false; - Rooted arr(cx, &obj->as()); uint32_t length = arr->length(); if (index >= length) - ArrayObject::setLength(cx->asJSContext(), arr, index + 1); + ArrayObject::setLength(cx, arr, index + 1); return true; } diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index c894d4a2bb5..03f44ac301e 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -305,7 +305,7 @@ struct ContextFriendFields explicit ContextFriendFields(JSRuntime *rt) : runtime_(rt), compartment_(NULL), zone_(NULL), autoGCRooters(NULL) { -#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING) +#ifdef JSGC_TRACK_EXACT_ROOTS mozilla::PodArrayZero(thingGCRooters); #endif #if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE) diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 74e8a1e6871..17284f3a94b 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -39,6 +39,7 @@ #include "jsscriptinlines.h" #include "vm/ScopeObject-inl.h" +#include "vm/Runtime-inl.h" #include "vm/Stack-inl.h" using namespace js; @@ -945,7 +946,7 @@ Class ScriptSourceObject::class_ = { }; ScriptSourceObject * -ScriptSourceObject::create(JSContext *cx, ScriptSource *source) +ScriptSourceObject::create(ExclusiveContext *cx, ScriptSource *source) { RootedObject object(cx, NewObjectWithGivenProto(cx, &class_, NULL, cx->global())); if (!object) @@ -1456,7 +1457,7 @@ ScriptSource::performXDR(XDRState *xdr) } bool -ScriptSource::setFilename(JSContext *cx, const char *filename) +ScriptSource::setFilename(ExclusiveContext *cx, const char *filename) { JS_ASSERT(!filename_); size_t len = strlen(filename) + 1; @@ -1470,12 +1471,14 @@ ScriptSource::setFilename(JSContext *cx, const char *filename) } bool -ScriptSource::setSourceMap(JSContext *cx, jschar *sourceMapURL) +ScriptSource::setSourceMap(ExclusiveContext *cx, jschar *sourceMapURL) { JS_ASSERT(sourceMapURL); if (hasSourceMap()) { - if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, js_GetErrorMessage, NULL, - JSMSG_ALREADY_HAS_SOURCEMAP, filename_)) { + if (cx->isJSContext() && + !JS_ReportErrorFlagsAndNumber(cx->asJSContext(), JSREPORT_WARNING, js_GetErrorMessage, + NULL, JSMSG_ALREADY_HAS_SOURCEMAP, filename_)) + { js_free(sourceMapURL); return false; } @@ -1520,6 +1523,8 @@ js::SaveSharedScriptData(ExclusiveContext *cx, Handle script, Shared ASSERT(script != NULL); ASSERT(ssd != NULL); + AutoLockForExclusiveAccess lock(cx); + ScriptBytecodeHasher::Lookup l(ssd); ScriptDataTable::AddPtr p = cx->scriptDataTable().lookupForAdd(l); @@ -1558,12 +1563,16 @@ js::SweepScriptData(JSRuntime *rt) { JS_ASSERT(rt->gcIsFull); ScriptDataTable &table = rt->scriptDataTable; + + bool keepAtoms = false; + for (ThreadDataIter iter(rt); !iter.done(); iter.next()) + keepAtoms |= iter->gcKeepAtoms; + for (ScriptDataTable::Enum e(table); !e.empty(); e.popFront()) { SharedScriptData *entry = e.front(); if (entry->marked) { entry->marked = false; - } else if (!rt->mainThread.gcKeepAtoms) { - // FIXME bug 875125 this should check all instances of PerThreadData. + } else if (!keepAtoms) { js_free(entry); e.removeFront(); } diff --git a/js/src/jsscript.h b/js/src/jsscript.h index ca7adab5a65..827926bb2dd 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -348,13 +348,13 @@ class ScriptSource template bool performXDR(XDRState *xdr); - bool setFilename(JSContext *cx, const char *filename); + bool setFilename(ExclusiveContext *cx, const char *filename); const char *filename() const { return filename_; } // Source maps - bool setSourceMap(JSContext *cx, jschar *sourceMapURL); + bool setSourceMap(ExclusiveContext *cx, jschar *sourceMapURL); const jschar *sourceMap(); bool hasSourceMap() const { return sourceMap_ != NULL; } @@ -388,7 +388,7 @@ class ScriptSourceObject : public JSObject static Class class_; static void finalize(FreeOp *fop, JSObject *obj); - static ScriptSourceObject *create(JSContext *cx, ScriptSource *source); + static ScriptSourceObject *create(ExclusiveContext *cx, ScriptSource *source); ScriptSource *source() { return static_cast(getReservedSlot(SOURCE_SLOT).toPrivate()); diff --git a/js/src/jsworkers.cpp b/js/src/jsworkers.cpp index c1df8c7d23d..5135ef880ab 100644 --- a/js/src/jsworkers.cpp +++ b/js/src/jsworkers.cpp @@ -10,20 +10,27 @@ #include "prmjtime.h" -#ifdef JS_PARALLEL_COMPILATION +#include "frontend/BytecodeCompiler.h" + +#ifdef JS_WORKER_THREADS # include "ion/AsmJS.h" # include "ion/IonBuilder.h" # include "ion/ExecutionModeInlines.h" #endif +#include "jscntxtinlines.h" +#include "jscompartmentinlines.h" + +#include "vm/ObjectImpl-inl.h" + using namespace js; using mozilla::DebugOnly; -#ifdef JS_PARALLEL_COMPILATION +#ifdef JS_WORKER_THREADS bool -js::EnsureParallelCompilationInitialized(JSRuntime *rt) +js::EnsureWorkerThreadsInitialized(JSRuntime *rt) { if (rt->workerThreadState) return true; @@ -69,7 +76,7 @@ bool js::StartOffThreadIonCompile(JSContext *cx, ion::IonBuilder *builder) { JSRuntime *rt = cx->runtime(); - if (!EnsureParallelCompilationInitialized(rt)) + if (!EnsureWorkerThreadsInitialized(rt)) return false; WorkerThreadState &state = *cx->runtime()->workerThreadState; @@ -155,6 +162,124 @@ js::CancelOffThreadIonCompile(JSCompartment *compartment, JSScript *script) } } +static JSClass workerGlobalClass = { + "internal-worker-global", JSCLASS_GLOBAL_FLAGS, + JS_PropertyStub, JS_DeletePropertyStub, + JS_PropertyStub, JS_StrictPropertyStub, + JS_EnumerateStub, JS_ResolveStub, + JS_ConvertStub, NULL +}; + +ParseTask::ParseTask(JSRuntime *rt, ExclusiveContext *cx, const CompileOptions &options, + const jschar *chars, size_t length) + : runtime(rt), cx(cx), options(options), chars(chars), length(length), + alloc(JSRuntime::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), script(NULL) +{ + if (options.principals) + JS_HoldPrincipals(options.principals); + if (options.originPrincipals) + JS_HoldPrincipals(options.originPrincipals); +} + +ParseTask::~ParseTask() +{ + if (options.principals) + JS_DropPrincipals(runtime, options.principals); + if (options.originPrincipals) + JS_DropPrincipals(runtime, options.originPrincipals); + + // ParseTask takes over ownership of its input exclusive context. + js_delete(cx); +} + +bool +js::StartOffThreadParseScript(JSContext *cx, const CompileOptions &options, + const jschar *chars, size_t length) +{ + frontend::MaybeCallSourceHandler(cx, options, chars, length); + + JSRuntime *rt = cx->runtime(); + if (!EnsureWorkerThreadsInitialized(rt)) + return false; + + JS::CompartmentOptions compartmentOptions(cx->compartment()->options()); + compartmentOptions.setZone(JS::FreshZone); + + JSObject *global = JS_NewGlobalObject(cx, &workerGlobalClass, NULL, compartmentOptions); + if (!global) + return false; + + // For now, type inference is always disabled in exclusive zones. + // This restriction would be fairly easy to lift. + global->zone()->types.inferenceEnabled = false; + + // Initialize all classes needed for parsing while we are still on the main + // thread. + { + AutoCompartment ac(cx, global); + + RootedObject obj(cx); + if (!js_GetClassObject(cx, global, JSProto_Function, &obj) || + !js_GetClassObject(cx, global, JSProto_Array, &obj) || + !js_GetClassObject(cx, global, JSProto_RegExp, &obj)) + { + return false; + } + } + + global->zone()->usedByExclusiveThread = true; + + ScopedJSDeletePtr workercx( + cx->new_(cx->runtime(), (PerThreadData *) NULL, + ThreadSafeContext::Context_Exclusive)); + if (!workercx) + return false; + + workercx->enterCompartment(global->compartment()); + + ScopedJSDeletePtr task( + cx->new_(cx->runtime(), workercx.get(), options, chars, length)); + if (!task) + return false; + + workercx.forget(); + + WorkerThreadState &state = *cx->runtime()->workerThreadState; + JS_ASSERT(state.numThreads); + + AutoLockWorkerThreadState lock(rt); + + if (!state.parseWorklist.append(task.get())) + return false; + + task.forget(); + + state.notify(WorkerThreadState::WORKER); + return true; +} + +void +js::WaitForOffThreadParsingToFinish(JSRuntime *rt) +{ + if (!rt->workerThreadState) + return; + + WorkerThreadState &state = *rt->workerThreadState; + + AutoLockWorkerThreadState lock(rt); + + while (true) { + if (state.parseWorklist.empty()) { + bool parseInProgress = false; + for (size_t i = 0; i < state.numThreads; i++) + parseInProgress |= !!state.threads[i].parseTask; + if (!parseInProgress) + break; + } + state.wait(WorkerThreadState::MAIN); + } +} + bool WorkerThreadState::init(JSRuntime *rt) { @@ -197,6 +322,8 @@ WorkerThreadState::init(JSRuntime *rt) numThreads = 0; return false; } + helper.threadData.construct(rt); + helper.threadData.ref().addToThreadList(); } resetAsmJSFailureState(); @@ -324,6 +451,7 @@ WorkerThread::destroy() } PR_JoinThread(thread); + threadData.ref().removeFromThreadList(); } /* static */ @@ -339,7 +467,7 @@ WorkerThread::handleAsmJSWorkload(WorkerThreadState &state) { JS_ASSERT(state.isLocked()); JS_ASSERT(state.canStartAsmJSCompile()); - JS_ASSERT(!ionBuilder && !asmData); + JS_ASSERT(idle()); asmData = state.asmJSWorklist.popCopy(); bool success = false; @@ -385,7 +513,7 @@ WorkerThread::handleIonWorkload(WorkerThreadState &state) { JS_ASSERT(state.isLocked()); JS_ASSERT(state.canStartIonCompile()); - JS_ASSERT(!ionBuilder && !asmData); + JS_ASSERT(idle()); ionBuilder = state.ionWorklist.popCopy(); @@ -410,24 +538,58 @@ WorkerThread::handleIonWorkload(WorkerThreadState &state) runtime->triggerOperationCallback(); } +void +ExclusiveContext::setWorkerThread(WorkerThread *workerThread) +{ + this->workerThread = workerThread; + this->perThreadData = workerThread->threadData.addr(); +} + +void +WorkerThread::handleParseWorkload(WorkerThreadState &state) +{ + JS_ASSERT(state.isLocked()); + JS_ASSERT(!state.parseWorklist.empty()); + JS_ASSERT(idle()); + + parseTask = state.parseWorklist.popCopy(); + parseTask->cx->setWorkerThread(this); + + { + AutoUnlockWorkerThreadState unlock(runtime); + parseTask->script = frontend::CompileScript(parseTask->cx, &parseTask->alloc, + NullPtr(), NullPtr(), + parseTask->options, + parseTask->chars, parseTask->length); + } + + state.parseFinishedList.append(parseTask); + parseTask = NULL; + + // Notify the main thread in case it is waiting for the parse/emit to finish. + state.notify(WorkerThreadState::MAIN); +} + void WorkerThread::threadLoop() { WorkerThreadState &state = *runtime->workerThreadState; - state.lock(); + AutoLockWorkerThreadState lock(runtime); - threadData.construct(runtime); js::TlsPerThreadData.set(threadData.addr()); while (true) { JS_ASSERT(!ionBuilder && !asmData); - // Block until an Ion or AsmJS task is available. - while (!state.canStartIonCompile() && !state.canStartAsmJSCompile()) { - if (terminate) { - state.unlock(); + // Block until a task is available. + while (!state.canStartIonCompile() && + !state.canStartAsmJSCompile() && + state.parseWorklist.empty()) + { + if (state.shouldPause) + pause(); + if (terminate) return; - } state.wait(WorkerThreadState::WORKER); } @@ -436,10 +598,78 @@ WorkerThread::threadLoop() handleAsmJSWorkload(state); else if (state.canStartIonCompile()) handleIonWorkload(state); + else if (!state.parseWorklist.empty()) + handleParseWorkload(state); } } -#else /* JS_PARALLEL_COMPILATION */ +AutoPauseWorkersForGC::AutoPauseWorkersForGC(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) + : runtime(rt), needsUnpause(false) +{ + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + + if (!runtime->workerThreadState) + return; + + runtime->assertValidThread(); + + WorkerThreadState &state = *runtime->workerThreadState; + if (!state.numThreads) + return; + + AutoLockWorkerThreadState lock(runtime); + + // Tolerate reentrant use of AutoPauseWorkersForGC. + if (state.shouldPause) { + JS_ASSERT(state.numPaused == state.numThreads); + return; + } + + needsUnpause = true; + + state.shouldPause = 1; + + while (state.numPaused != state.numThreads) { + state.notifyAll(WorkerThreadState::WORKER); + state.wait(WorkerThreadState::MAIN); + } +} + +AutoPauseWorkersForGC::~AutoPauseWorkersForGC() +{ + if (!needsUnpause) + return; + + WorkerThreadState &state = *runtime->workerThreadState; + AutoLockWorkerThreadState lock(runtime); + + state.shouldPause = 0; + + // Notify all workers, to ensure that each wakes up. + state.notifyAll(WorkerThreadState::WORKER); +} + +void +WorkerThread::pause() +{ + WorkerThreadState &state = *runtime->workerThreadState; + JS_ASSERT(state.isLocked()); + JS_ASSERT(state.shouldPause); + + JS_ASSERT(state.numPaused < state.numThreads); + state.numPaused++; + + // Don't bother to notify the main thread until all workers have paused. + if (state.numPaused == state.numThreads) + state.notify(WorkerThreadState::MAIN); + + while (state.shouldPause) + state.wait(WorkerThreadState::WORKER); + + state.numPaused--; +} + +#else /* JS_WORKER_THREADS */ bool js::StartOffThreadAsmJSCompile(JSContext *cx, AsmJSParallelTask *asmData) @@ -458,4 +688,25 @@ js::CancelOffThreadIonCompile(JSCompartment *compartment, JSScript *script) { } -#endif /* JS_PARALLEL_COMPILATION */ +bool +js::StartOffThreadParseScript(JSContext *cx, const CompileOptions &options, + const jschar *chars, size_t length) +{ + MOZ_ASSUME_UNREACHABLE("Off thread compilation not available in non-THREADSAFE builds"); +} + +void +js::WaitForOffThreadParsingToFinish(JSRuntime *rt) +{ +} + +AutoPauseWorkersForGC::AutoPauseWorkersForGC(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) +{ + MOZ_GUARD_OBJECT_NOTIFIER_INIT; +} + +AutoPauseWorkersForGC::~AutoPauseWorkersForGC() +{ +} + +#endif /* JS_WORKER_THREADS */ diff --git a/js/src/jsworkers.h b/js/src/jsworkers.h index 383f04d7426..3efc0f932e5 100644 --- a/js/src/jsworkers.h +++ b/js/src/jsworkers.h @@ -30,10 +30,11 @@ namespace ion { } #if defined(JS_THREADSAFE) && defined(JS_ION) -# define JS_PARALLEL_COMPILATION +# define JS_WORKER_THREADS struct WorkerThread; struct AsmJSParallelTask; +struct ParseTask; /* Per-runtime state for off thread work items. */ class WorkerThreadState @@ -43,23 +44,35 @@ class WorkerThreadState WorkerThread *threads; size_t numThreads; + /* + * Whether all worker threads thread should pause their activity. This acts + * like the runtime's interrupt field and may be read without locking. + */ + volatile size_t shouldPause; + + /* After shouldPause is set, the number of threads which are paused. */ + uint32_t numPaused; + enum CondVar { MAIN, WORKER }; /* Shared worklist for Ion worker threads. */ - js::Vector ionWorklist; + Vector ionWorklist; /* Worklist for AsmJS worker threads. */ - js::Vector asmJSWorklist; + Vector asmJSWorklist; /* * Finished list for AsmJS worker threads. * Simultaneous AsmJS compilations all service the same AsmJS module. * The main thread must pick up finished optimizations and perform codegen. */ - js::Vector asmJSFinishedList; + Vector asmJSFinishedList; + + /* Shared worklist for parsing/emitting scripts on worker threads. */ + Vector parseWorklist, parseFinishedList; WorkerThreadState() { mozilla::PodZero(this); } ~WorkerThreadState(); @@ -152,10 +165,19 @@ struct WorkerThread /* Any AsmJS data currently being optimized by Ion on this thread. */ AsmJSParallelTask *asmData; + /* Any source being parsed/emitted on this thread */ + ParseTask *parseTask; + + bool idle() const { + return !ionBuilder && !asmData && !parseTask; + } + + void pause(); void destroy(); void handleAsmJSWorkload(WorkerThreadState &state); void handleIonWorkload(WorkerThreadState &state); + void handleParseWorkload(WorkerThreadState &state); static void ThreadMain(void *arg); void threadLoop(); @@ -166,7 +188,7 @@ struct WorkerThread inline bool OffThreadCompilationEnabled(JSContext *cx) { -#ifdef JS_PARALLEL_COMPILATION +#ifdef JS_WORKER_THREADSj return ion::js_IonOptions.parallelCompilation && cx->runtime()->useHelperThreads() && cx->runtime()->helperThreadCount() != 0; @@ -179,7 +201,7 @@ OffThreadCompilationEnabled(JSContext *cx) /* Initialize worker threads unless already initialized. */ bool -EnsureParallelCompilationInitialized(JSRuntime *rt); +EnsureWorkerThreadsInitialized(JSRuntime *rt); /* Perform MIR optimization and LIR generation on a single function. */ bool @@ -199,6 +221,18 @@ StartOffThreadIonCompile(JSContext *cx, ion::IonBuilder *builder); void CancelOffThreadIonCompile(JSCompartment *compartment, JSScript *script); +/* + * Start a parse/emit cycle for a stream of source. The characters must stay + * alive until the compilation finishes. + */ +bool +StartOffThreadParseScript(JSContext *cx, const CompileOptions &options, + const jschar *chars, size_t length); + +/* Block until in progress and pending off thread parse jobs have finished. */ +void +WaitForOffThreadParsingToFinish(JSRuntime *rt); + class AutoLockWorkerThreadState { JSRuntime *rt; @@ -211,7 +245,7 @@ class AutoLockWorkerThreadState : rt(rt) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; -#ifdef JS_PARALLEL_COMPILATION +#ifdef JS_WORKER_THREADS JS_ASSERT(rt->workerThreadState); rt->workerThreadState->lock(); #else @@ -221,7 +255,7 @@ class AutoLockWorkerThreadState ~AutoLockWorkerThreadState() { -#ifdef JS_PARALLEL_COMPILATION +#ifdef JS_WORKER_THREADS rt->workerThreadState->unlock(); #endif } @@ -239,7 +273,7 @@ class AutoUnlockWorkerThreadState : rt(rt) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; -#ifdef JS_PARALLEL_COMPILATION +#ifdef JS_WORKER_THREADS JS_ASSERT(rt->workerThreadState); rt->workerThreadState->unlock(); #else @@ -249,12 +283,48 @@ class AutoUnlockWorkerThreadState ~AutoUnlockWorkerThreadState() { -#ifdef JS_PARALLEL_COMPILATION +#ifdef JS_WORKER_THREADS rt->workerThreadState->lock(); #endif } }; +/* Pause any threads that are running jobs off thread during GC activity. */ +class AutoPauseWorkersForGC +{ + JSRuntime *runtime; + bool needsUnpause; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + + public: + AutoPauseWorkersForGC(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM); + ~AutoPauseWorkersForGC(); +}; + +/* Wait for any in progress off thread parses to halt. */ +void +PauseOffThreadParsing(); + +/* Resume any paused off thread parses. */ +void +ResumeOffThreadParsing(); + +struct ParseTask +{ + JSRuntime *runtime; + ExclusiveContext *cx; + CompileOptions options; + const jschar *chars; + size_t length; + LifoAlloc alloc; + + JSScript *script; + + ParseTask(JSRuntime *rt, ExclusiveContext *cx, const CompileOptions &options, + const jschar *chars, size_t length); + ~ParseTask(); +}; + } /* namespace js */ #endif /* jsworkers_h */ diff --git a/js/src/jswrapper.cpp b/js/src/jswrapper.cpp index a7ace525c13..4e770c36332 100644 --- a/js/src/jswrapper.cpp +++ b/js/src/jswrapper.cpp @@ -136,7 +136,7 @@ js::TransparentObjectWrapper(JSContext *cx, HandleObject existing, HandleObject ErrorCopier::~ErrorCopier() { - JSContext *cx = ac.ref().context(); + JSContext *cx = ac.ref().context()->asJSContext(); if (ac.ref().origin() != cx->compartment() && cx->isExceptionPending()) { RootedValue exc(cx, cx->getPendingException()); if (exc.isObject() && exc.toObject().is() && diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index f37994dd195..a7e329747a9 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -3229,6 +3229,53 @@ SyntaxParse(JSContext *cx, unsigned argc, jsval *vp) return true; } +#ifdef JS_THREADSAFE + +static JSBool +OffThreadCompileScript(JSContext *cx, unsigned argc, jsval *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + if (args.length() < 1) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, + "offThreadCompileScript", "0", "s"); + return false; + } + if (!args[0].isString()) { + const char *typeName = JS_GetTypeName(cx, JS_TypeOfValue(cx, args[0])); + JS_ReportError(cx, "expected string to parse, got %s", typeName); + return false; + } + + JSString *scriptContents = args[0].toString(); + CompileOptions options(cx); + options.setFileAndLine("", 1) + .setCompileAndGo(true) + .setSourcePolicy(CompileOptions::NO_SOURCE); + + const jschar *chars = JS_GetStringCharsZ(cx, scriptContents); + if (!chars) + return false; + size_t length = JS_GetStringLength(scriptContents); + + // Prevent the string contents from ever being GC'ed. This will leak memory + // but since the compiled script is never consumed there isn't much choice. + JSString **permanentRoot = cx->new_(); + if (!permanentRoot) + return false; + *permanentRoot = scriptContents; + if (!JS_AddStringRoot(cx, permanentRoot)) + return false; + + if (!StartOffThreadParseScript(cx, options, chars, length)) + return false; + + args.rval().setUndefined(); + return true; +} + +#endif // JS_THREADSAFE + struct FreeOnReturn { JSContext *cx; @@ -3798,6 +3845,12 @@ static const JSFunctionSpecWithHelp shell_functions[] = { "syntaxParse(code)", " Check the syntax of a string, returning success value"), +#ifdef JS_THREADSAFE + JS_FN_HELP("offThreadCompileScript", OffThreadCompileScript, 1, 0, +"offThreadCompileScript(code)", +" Trigger an off thread parse/emit for the input string"), +#endif + JS_FN_HELP("timeout", Timeout, 1, 0, "timeout([seconds], [func])", " Get/Set the limit in seconds for the execution time for the current context.\n" diff --git a/js/src/vm/ArrayObject-inl.h b/js/src/vm/ArrayObject-inl.h index f91cbe220f2..3a051e2bfea 100644 --- a/js/src/vm/ArrayObject-inl.h +++ b/js/src/vm/ArrayObject-inl.h @@ -15,15 +15,15 @@ namespace js { /* static */ inline void -ArrayObject::setLength(JSContext *cx, Handle arr, uint32_t length) +ArrayObject::setLength(ExclusiveContext *cx, Handle arr, uint32_t length) { JS_ASSERT(arr->lengthIsWritable()); if (length > INT32_MAX) { /* Track objects with overflowing lengths in type information. */ - js::types::MarkTypeObjectFlags(cx, arr, js::types::OBJECT_FLAG_LENGTH_OVERFLOW); - jsid lengthId = js::NameToId(cx->names().length); - js::types::AddTypePropertyId(cx, arr, lengthId, js::types::Type::DoubleType()); + types::MarkTypeObjectFlags(cx, arr, types::OBJECT_FLAG_LENGTH_OVERFLOW); + jsid lengthId = NameToId(cx->names().length); + types::AddTypePropertyId(cx, arr, lengthId, types::Type::DoubleType()); } arr->getElementsHeader()->length = length; diff --git a/js/src/vm/ArrayObject.h b/js/src/vm/ArrayObject.h index c401bf76890..629c6b60edc 100644 --- a/js/src/vm/ArrayObject.h +++ b/js/src/vm/ArrayObject.h @@ -24,7 +24,7 @@ class ArrayObject : public JSObject return getElementsHeader()->length; } - static inline void setLength(JSContext *cx, Handle arr, uint32_t length); + static inline void setLength(ExclusiveContext *cx, Handle arr, uint32_t length); // Variant of setLength for use on arrays where the length cannot overflow int32_t. void setLengthInt32(uint32_t length) { diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 7d2e7722632..68f29f46b79 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -750,7 +750,7 @@ JSTrapStatus Debugger::handleUncaughtExceptionHelper(Maybe &ac, MutableHandleValue *vp, bool callHook) { - JSContext *cx = ac.ref().context(); + JSContext *cx = ac.ref().context()->asJSContext(); if (cx->isExceptionPending()) { if (callHook && uncaughtExceptionHook) { Value fval = ObjectValue(*uncaughtExceptionHook); @@ -849,7 +849,7 @@ bool Debugger::receiveCompletionValue(Maybe &ac, bool ok, Value val, MutableHandleValue vp) { - JSContext *cx = ac.ref().context(); + JSContext *cx = ac.ref().context()->asJSContext(); JSTrapStatus status; RootedValue value(cx); @@ -875,7 +875,7 @@ Debugger::parseResumptionValue(Maybe &ac, bool ok, const Value } /* Check that rv is {return: val} or {throw: val}. */ - JSContext *cx = ac.ref().context(); + JSContext *cx = ac.ref().context()->asJSContext(); Rooted obj(cx); RootedShape shape(cx); RootedId returnId(cx, NameToId(cx->names().return_)); @@ -4126,7 +4126,7 @@ js::EvaluateInEnv(JSContext *cx, Handle env, HandleValue thisv, AbstractFr .setFileAndLine(filename, lineno) .setCanLazilyParse(false); RootedScript callerScript(cx, frame ? frame.script() : NULL); - RootedScript script(cx, frontend::CompileScript(cx, env, callerScript, + RootedScript script(cx, frontend::CompileScript(cx, &cx->tempLifoAlloc(), env, callerScript, options, chars.get(), length, /* source = */ NULL, /* staticLevel = */ frame ? 1 : 0)); diff --git a/js/src/vm/Runtime-inl.h b/js/src/vm/Runtime-inl.h index c11d21ea646..44dfec94d54 100644 --- a/js/src/vm/Runtime-inl.h +++ b/js/src/vm/Runtime-inl.h @@ -13,6 +13,7 @@ #include "jsfriendapi.h" #include "jsgc.h" #include "jsiter.h" +#include "jsworkers.h" #include "builtin/Object.h" // For js::obj_construct #include "frontend/ParseMaps.h" @@ -76,6 +77,17 @@ NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entry_, js::gc::Initi return NULL; } +inline +ThreadDataIter::ThreadDataIter(JSRuntime *rt) +{ +#ifdef JS_WORKER_THREADS + // Only allow iteration over a runtime's threads when those threads are + // paused, to avoid racing when reading data from the PerThreadData. + JS_ASSERT_IF(rt->workerThreadState, rt->workerThreadState->shouldPause); +#endif + iter = rt->threadList.getFirst(); +} + } /* namespace js */ #endif /* vm_Runtime_inl_h */ diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index fba2644746e..fd1d28476b3 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -21,6 +21,7 @@ #include "js/MemoryMetrics.h" #include "yarr/BumpPointerAllocator.h" +#include "jscntxtinlines.h" #include "jsgcinlines.h" using namespace js; @@ -46,6 +47,9 @@ NewObjectCache::clearNurseryObjects(JSRuntime *rt) void JSRuntime::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes *rtSizes) { + // Several tables in the runtime enumerated below can be used off thread. + AutoLockForExclusiveAccess lock(this); + rtSizes->object = mallocSizeOf(this); rtSizes->atomsTable = atoms.sizeOfExcludingThis(mallocSizeOf); diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 8a83f267949..653d16a375a 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -447,7 +447,8 @@ namespace js { * JSRuntime as the field |mainThread|. During Parallel JS sections, * however, there will be one instance per worker thread. */ -class PerThreadData : public js::PerThreadDataFriendFields +class PerThreadData : public PerThreadDataFriendFields, + public mozilla::LinkedListElement { /* * Backpointer to the full shared JSRuntime* with which this @@ -556,6 +557,8 @@ class PerThreadData : public js::PerThreadDataFriendFields ~PerThreadData(); bool init(); + void addToThreadList(); + void removeFromThreadList(); bool associatedWith(const JSRuntime *rt) { return runtime_ == rt; } }; @@ -640,6 +643,8 @@ class MarkingValidator; typedef Vector ZoneVector; +class AutoLockForExclusiveAccess; + } // namespace js struct JSRuntime : public JS::shadow::Runtime, @@ -655,7 +660,13 @@ struct JSRuntime : public JS::shadow::Runtime, * sizeof(js::shadow::Runtime). See * PerThreadDataFriendFields::getMainThread. */ - js::PerThreadData mainThread; + js::PerThreadData mainThread; + + /* + * List of per-thread data in the runtime, including mainThread. Currently + * this does not include instances of PerThreadData created for PJS. + */ + mozilla::LinkedList threadList; /* * If non-zero, we were been asked to call the operation callback as soon @@ -712,6 +723,37 @@ struct JSRuntime : public JS::shadow::Runtime, #endif } +#ifdef JS_THREADSAFE + private: + /* + * Lock taken when using per-runtime or per-zone data that could otherwise + * be accessed simultaneously by both the main thread and another thread + * with an ExclusiveContext. + * + * Locking this only occurs if there is actually a thread other than the + * main thread with an ExclusiveContext which could access such data. + */ + PRLock *exclusiveAccessLock; + mozilla::DebugOnly exclusiveAccessOwner; + mozilla::DebugOnly mainThreadHasExclusiveAccess; + + /* Number of non-main threads with an ExclusiveContext. */ + size_t numExclusiveThreads; + + friend class js::AutoLockForExclusiveAccess; + + public: +#endif // JS_THREADSAFE + + bool currentThreadHasExclusiveAccess() { +#if defined(JS_THREADSAFE) && defined(DEBUG) + return (!numExclusiveThreads && mainThreadHasExclusiveAccess) || + exclusiveAccessOwner == PR_GetCurrentThread(); +#else + return true; +#endif + } + /* Default compartment. */ JSCompartment *atomsCompartment; @@ -1714,6 +1756,38 @@ class RuntimeAllocPolicy void reportAllocOverflow() const {} }; +/* + * Enumerate all the per thread data in a runtime. + */ +class ThreadDataIter { + PerThreadData *iter; + +public: + explicit inline ThreadDataIter(JSRuntime *rt); + + bool done() const { + return !iter; + } + + void next() { + JS_ASSERT(!done()); + iter = iter->getNext(); + } + + PerThreadData *get() const { + JS_ASSERT(!done()); + return iter; + } + + operator PerThreadData *() const { + return get(); + } + + PerThreadData *operator ->() const { + return get(); + } +}; + } /* namespace js */ #ifdef _MSC_VER diff --git a/js/src/vm/String.cpp b/js/src/vm/String.cpp index 2cc1c198605..56c3191a858 100644 --- a/js/src/vm/String.cpp +++ b/js/src/vm/String.cpp @@ -660,6 +660,7 @@ const StaticStrings::SmallChar StaticStrings::toSmallChar[] = { R7(0) }; bool StaticStrings::init(JSContext *cx) { + AutoLockForExclusiveAccess lock(cx); AutoCompartment ac(cx, cx->runtime()->atomsCompartment); for (uint32_t i = 0; i < UNIT_STATIC_LIMIT; i++) { From ccc625409714b03d0284063faae3dd9f231d809e Mon Sep 17 00:00:00 2001 From: Mina Almasry Date: Fri, 19 Jul 2013 10:32:51 -0400 Subject: [PATCH 07/58] Bug 291082 - preventDefault now blocks keyboard navigation in select-one drop-down lists. r=mounir, r=Neil This patch makes select drop-down lists respect preventDefault keypress event, and so the select list doesn't process them anymore. --- layout/forms/nsListControlFrame.cpp | 44 ++++--- layout/forms/test/Makefile.in | 1 + .../test/test_select_prevent_default.html | 107 ++++++++++++++++++ 3 files changed, 135 insertions(+), 17 deletions(-) create mode 100644 layout/forms/test/test_select_prevent_default.html diff --git a/layout/forms/nsListControlFrame.cpp b/layout/forms/nsListControlFrame.cpp index 9d0187dd263..0b18f78f6e3 100644 --- a/layout/forms/nsListControlFrame.cpp +++ b/layout/forms/nsListControlFrame.cpp @@ -142,14 +142,14 @@ nsListControlFrame::DestroyFrom(nsIFrame* aDestructRoot) mEventListener->SetFrame(nullptr); - mContent->RemoveEventListener(NS_LITERAL_STRING("keypress"), mEventListener, - false); - mContent->RemoveEventListener(NS_LITERAL_STRING("mousedown"), mEventListener, - false); - mContent->RemoveEventListener(NS_LITERAL_STRING("mouseup"), mEventListener, - false); - mContent->RemoveEventListener(NS_LITERAL_STRING("mousemove"), mEventListener, - false); + mContent->RemoveSystemEventListener(NS_LITERAL_STRING("keypress"), + mEventListener, false); + mContent->RemoveSystemEventListener(NS_LITERAL_STRING("mousedown"), + mEventListener, false); + mContent->RemoveSystemEventListener(NS_LITERAL_STRING("mouseup"), + mEventListener, false); + mContent->RemoveSystemEventListener(NS_LITERAL_STRING("mousemove"), + mEventListener, false); nsFormControlFrame::RegUnRegAccessKey(static_cast(this), false); nsHTMLScrollFrame::DestroyFrom(aDestructRoot); @@ -996,14 +996,14 @@ nsListControlFrame::Init(nsIContent* aContent, // we need to hook up our listeners before the editor is initialized mEventListener = new nsListEventListener(this); - mContent->AddEventListener(NS_LITERAL_STRING("keypress"), mEventListener, - false, false); - mContent->AddEventListener(NS_LITERAL_STRING("mousedown"), mEventListener, - false, false); - mContent->AddEventListener(NS_LITERAL_STRING("mouseup"), mEventListener, - false, false); - mContent->AddEventListener(NS_LITERAL_STRING("mousemove"), mEventListener, - false, false); + mContent->AddSystemEventListener(NS_LITERAL_STRING("keypress"), + mEventListener, false, false); + mContent->AddSystemEventListener(NS_LITERAL_STRING("mousedown"), + mEventListener, false, false); + mContent->AddSystemEventListener(NS_LITERAL_STRING("mouseup"), + mEventListener, false, false); + mContent->AddSystemEventListener(NS_LITERAL_STRING("mousemove"), + mEventListener, false, false); mStartSelectionIndex = kNothingSelected; mEndSelectionIndex = kNothingSelected; @@ -2374,7 +2374,17 @@ nsListControlFrame::KeyPress(nsIDOMEvent* aKeyEvent) default: { // Select option with this as the first character // XXX Not I18N compliant - + + // We skip processing all key events in the keys that are not in the + // cases above, if they have been prevented. The keys listed in the cases + // above are required to navigate inside the list. These keys are also + // not prevented in most UAs, so this is also a compatibility issue. + bool defaultPrevented; + aKeyEvent->GetDefaultPrevented(&defaultPrevented); + if (defaultPrevented) { + return NS_OK; + } + if (isControl && charcode != ' ') { return NS_OK; } diff --git a/layout/forms/test/Makefile.in b/layout/forms/test/Makefile.in index c7c91b119f7..ec0111d3783 100644 --- a/layout/forms/test/Makefile.in +++ b/layout/forms/test/Makefile.in @@ -45,6 +45,7 @@ MOCHITEST_FILES = test_bug231389.html \ test_bug704049.html \ test_bug869314.html \ test_listcontrol_search.html \ + test_select_prevent_default.html \ $(NULL) MOCHITEST_CHROME_FILES = \ diff --git a/layout/forms/test/test_select_prevent_default.html b/layout/forms/test/test_select_prevent_default.html new file mode 100644 index 00000000000..df1cd6abc1f --- /dev/null +++ b/layout/forms/test/test_select_prevent_default.html @@ -0,0 +1,107 @@ + + + + + +Test for Bug 291082 + + + + + + +Mozilla Bug 291082 +
+
    +
  • + + select onkeydown="event.preventDefault();" +
  • +
  • + + select onkeypress="event.preventDefault();" +
  • +
  • + + li onkeydown="event.preventDefault();" +
  • +
  • + + li onkeypress="event.preventDefault();" +
  • +
  • + + select.addEventListener("keydown", function(event) { event.preventDefault(); }); +
  • +
  • + + select.addEventListener("keypress", function(event) { event.preventDefault(); }); +
  • +
+
+
+
+ + From a0acaa5dce47af7e18cbacf143eb3988a299a7b7 Mon Sep 17 00:00:00 2001 From: Sankha Narayan Guria Date: Fri, 19 Jul 2013 08:19:44 +0530 Subject: [PATCH 08/58] Bug 866847 - Implement map#forEach and Set#forEach. r=evilpie --- js/src/Makefile.in | 2 + js/src/builtin/Map.js | 36 ++++++++++++ js/src/builtin/MapObject.cpp | 2 + js/src/builtin/Set.js | 36 ++++++++++++ js/src/builtin/Utilities.js | 7 ++- .../jit-test/tests/collections/Map-forEach.js | 58 +++++++++++++++++++ .../jit-test/tests/collections/Set-forEach.js | 57 ++++++++++++++++++ 7 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 js/src/builtin/Map.js create mode 100644 js/src/builtin/Set.js create mode 100644 js/src/jit-test/tests/collections/Map-forEach.js create mode 100644 js/src/jit-test/tests/collections/Set-forEach.js diff --git a/js/src/Makefile.in b/js/src/Makefile.in index 7fafa7451be..e0a96e4afd5 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -642,6 +642,8 @@ selfhosting_srcs := \ $(srcdir)/builtin/Number.js \ $(srcdir)/builtin/ParallelArray.js \ $(srcdir)/builtin/String.js \ + $(srcdir)/builtin/Set.js \ + $(srcdir)/builtin/Map.js \ $(NULL) selfhosted_out_h_deps := \ diff --git a/js/src/builtin/Map.js b/js/src/builtin/Map.js new file mode 100644 index 00000000000..dfa86d4e806 --- /dev/null +++ b/js/src/builtin/Map.js @@ -0,0 +1,36 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* ES6 20121122 draft 15.14.4.4. */ + +function MapForEach(callbackfn, thisArg = undefined) { + /* Step 1-2. */ + var M = this; + if (!IsObject(M)) + ThrowError(JSMSG_BAD_TYPE, typeof M); + + /* Step 3-4. */ + try { + std_Map_has.call(M); + } catch (e) { + ThrowError(JSMSG_BAD_TYPE, typeof M); + } + + /* Step 5. */ + if (!IsCallable(callbackfn)) + ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); + + /* Step 6-8. */ + var entries = std_Map_iterator.call(M); + while (true) { + try { + var entry = std_Map_iterator_next.call(entries); + } catch (err) { + if (err instanceof StopIteration) + break; + throw err; + } + callFunction(callbackfn, thisArg, entry[1], entry[0], M); + } +} diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index 7a6e0ab0f99..0a92c999cdf 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -1036,6 +1036,7 @@ const JSFunctionSpec MapObject::methods[] = { JS_FN("keys", keys, 0, 0), JS_FN("values", values, 0, 0), JS_FN("clear", clear, 0, 0), + {"forEach", {NULL, NULL}, 2, 0, "MapForEach"}, JS_FS_END }; @@ -1592,6 +1593,7 @@ const JSFunctionSpec SetObject::methods[] = { JS_FN("delete", delete_, 1, 0), JS_FN("entries", entries, 0, 0), JS_FN("clear", clear, 0, 0), + {"forEach", {NULL, NULL}, 2, 0, "SetForEach"}, JS_FS_END }; diff --git a/js/src/builtin/Set.js b/js/src/builtin/Set.js new file mode 100644 index 00000000000..a99d35d1436 --- /dev/null +++ b/js/src/builtin/Set.js @@ -0,0 +1,36 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* ES6 20121122 draft 15.16.4.6. */ + +function SetForEach(callbackfn, thisArg = undefined) { + /* Step 1-2. */ + var S = this; + if (!IsObject(S)) + ThrowError(JSMSG_BAD_TYPE, typeof S); + + /* Step 3-4. */ + try { + std_Set_has.call(S); + } catch (e) { + ThrowError(JSMSG_BAD_TYPE, typeof S); + } + + /* Step 5-6. */ + if (!IsCallable(callbackfn)) + ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); + + /* Step 7-8. */ + var values = std_Set_iterator.call(S); + while (true) { + try { + var entry = std_Set_iterator_next.call(values); + } catch (err) { + if (err instanceof StopIteration) + break; + throw err; + } + callFunction(callbackfn, thisArg, entry, entry, S); + } +} diff --git a/js/src/builtin/Utilities.js b/js/src/builtin/Utilities.js index 8792f496a37..724e100658e 100644 --- a/js/src/builtin/Utilities.js +++ b/js/src/builtin/Utilities.js @@ -73,7 +73,12 @@ var std_String_toUpperCase = String.prototype.toUpperCase; var std_WeakMap_get = WeakMap.prototype.get; var std_WeakMap_has = WeakMap.prototype.has; var std_WeakMap_set = WeakMap.prototype.set; - +var std_Map_has = Map.prototype.has; +var std_Set_has = Set.prototype.has; +var std_Map_iterator = Map().iterator; +var std_Set_iterator = Set().iterator; +var std_Map_iterator_next = Object.getPrototypeOf(Map().iterator()).next; +var std_Set_iterator_next = Object.getPrototypeOf(Set().iterator()).next; /********** List specification type **********/ diff --git a/js/src/jit-test/tests/collections/Map-forEach.js b/js/src/jit-test/tests/collections/Map-forEach.js new file mode 100644 index 00000000000..6d51dcd9a42 --- /dev/null +++ b/js/src/jit-test/tests/collections/Map-forEach.js @@ -0,0 +1,58 @@ +/* test Map.prototype.forEach */ + +load(libdir + 'asserts.js'); + +// testing success conditions of Map.prototype.forEach + +var testMap = new Map(); + +function callback(value, key, map) { + testMap.set(key, value); + assertEq(map.has(key), true); + assertEq(map.get(key), value); +} + +var initialMap = new Map([['a', 1], ['b', 2.3], [false, undefined]]); +initialMap.forEach(callback); + +// test that both the Maps are equal and are in same order +var iterator = initialMap.iterator(); +var count = 0; +for (var [k, v] of testMap) { + assertEq(initialMap.has(k), true); + assertEq(initialMap.get(k), testMap.get(k)); + assertEq(iterator.next()[1], testMap.get(k)); + count++; +} + +//check both the Maps we have are equal in size +assertEq(initialMap.size, testMap.size); +assertEq(initialMap.size, count); + +var x = { abc: 'test'}; +function callback2(value, key, map) { + assertEq(x, this); +} +initialMap = new Map([['a', 1]]); +initialMap.forEach(callback2, x); + +// testing failure conditions of Map.prototype.forEach + +var s = new Set([1, 2, 3]); +assertThrowsInstanceOf(function() { + Map.prototype.forEach.call(s, callback); +}, TypeError, "Map.prototype.forEach should raise TypeError if not used on a Map"); + +var fn = 2; +assertThrowsInstanceOf(function() { + initialMap.forEach(fn); +}, TypeError, "Map.prototype.forEach should raise TypeError if callback is not a function"); + +// testing that Map#forEach uses internal next() function and does not stop when +// StopIteration exception is thrown + +var m = new Map([["one", 1]]); +Object.getPrototypeOf(m.iterator()).next = function () { throw "FAIL"; }; +assertThrowsInstanceOf(function () { + m.forEach(function () { throw StopIteration; }); +}, StopIteration, "Map.prototype.forEach should use intrinsic next method."); diff --git a/js/src/jit-test/tests/collections/Set-forEach.js b/js/src/jit-test/tests/collections/Set-forEach.js new file mode 100644 index 00000000000..fa7b85f3326 --- /dev/null +++ b/js/src/jit-test/tests/collections/Set-forEach.js @@ -0,0 +1,57 @@ +/* test Set.prototype.forEach */ + +load(libdir + 'asserts.js'); + +// testing success conditions of Set.prototype.forEach + +var testSet = new Set(); + +function callback(value, key, set) { + assertEq(value, key); + testSet.add(value); + assertEq(set.has(key), true); +} + +var initialSet = new Set(['a', 1, undefined]); +initialSet.forEach(callback); + +// test that both the Sets are equal and are in same order +var iterator = initialSet.iterator(); +var count = 0; +for (var v of testSet) { + assertEq(initialSet.has(v), true); + assertEq(iterator.next(), v); + count++; +} + +//check both the Sets we have are equal in size +assertEq(initialSet.size, testSet.size); +assertEq(initialSet.size, count); + +var x = { abc: 'test'}; +function callback2(value, key, set) { + assertEq(x, this); +} +initialSet = new Set(['a']); +initialSet.forEach(callback2, x); + +// testing failure conditions of Set.prototype.forEach + +var m = new Map([['a', 1], ['b', 2.3], ['c', undefined]]); +assertThrowsInstanceOf(function() { + Set.prototype.forEach.call(m, callback); +}, TypeError, "Set.prototype.forEach should raise TypeError if not a used on a Set"); + +var fn = 2; +assertThrowsInstanceOf(function() { + initialSet.forEach(fn); +}, TypeError, "Set.prototype.forEach should raise TypeError if callback is not a function"); + +// testing that Set#forEach uses internal next() function and does not stop when +// StopIteration exception is thrown + +var s = new Set(["one", 1]); +Object.getPrototypeOf(s.iterator()).next = function () { throw "FAIL"; }; +assertThrowsInstanceOf(function () { + s.forEach(function () { throw StopIteration; }); +}, StopIteration, "Set.prototype.forEach should use intrinsic next method."); From 1ac69282f5354ae7b8dcfcf9ad32c0195fba7ad7 Mon Sep 17 00:00:00 2001 From: Bear Travis Date: Thu, 18 Jul 2013 14:21:47 -0700 Subject: [PATCH 09/58] Bug 893298 - Correctly calculate button and button child's desired height to vertically center the child. r=bz --- layout/forms/nsHTMLButtonControlFrame.cpp | 29 ++++++----------- layout/reftests/forms/button/reftest.list | 1 + .../forms/button/vertical-centering-ref.html | 25 +++++++++++++++ .../forms/button/vertical-centering.html | 32 +++++++++++++++++++ 4 files changed, 68 insertions(+), 19 deletions(-) create mode 100644 layout/reftests/forms/button/vertical-centering-ref.html create mode 100644 layout/reftests/forms/button/vertical-centering.html diff --git a/layout/forms/nsHTMLButtonControlFrame.cpp b/layout/forms/nsHTMLButtonControlFrame.cpp index 16213ea512c..faffe093cf5 100644 --- a/layout/forms/nsHTMLButtonControlFrame.cpp +++ b/layout/forms/nsHTMLButtonControlFrame.cpp @@ -266,38 +266,28 @@ nsHTMLButtonControlFrame::ReflowButtonContents(nsPresContext* aPresContext, xoffset, aFocusPadding.top + aReflowState.mComputedBorderPadding.top, 0, aStatus); - - // calculate the min internal height so the contents gets centered correctly. - // XXXbz this assumes border-box sizing. - nscoord minInternalHeight = aReflowState.mComputedMinHeight - - aReflowState.mComputedBorderPadding.TopBottom(); - minInternalHeight = std::max(minInternalHeight, 0); // Compute our desired height before vertically centering our children + nscoord actualDesiredHeight = 0; if (aReflowState.ComputedHeight() != NS_INTRINSICSIZE) { - aDesiredSize.height = aReflowState.ComputedHeight(); + actualDesiredHeight = aReflowState.ComputedHeight(); } else { - aDesiredSize.height += aFocusPadding.TopBottom(); + actualDesiredHeight = aDesiredSize.height + aFocusPadding.TopBottom(); // Make sure we obey min/max-height in the case when we're doing intrinsic // sizing (we get it for free when we have a non-intrinsic // aReflowState.ComputedHeight()). Note that we do this before adjusting // for borderpadding, since mComputedMaxHeight and mComputedMinHeight are // content heights. - aDesiredSize.height = NS_CSS_MINMAX(aDesiredSize.height, + actualDesiredHeight = NS_CSS_MINMAX(actualDesiredHeight, aReflowState.mComputedMinHeight, aReflowState.mComputedMaxHeight); } - // center child vertically - nscoord yoff = 0; - if (aReflowState.ComputedHeight() != NS_INTRINSICSIZE) { - yoff = (aReflowState.ComputedHeight() - aDesiredSize.height)/2; - if (yoff < 0) { - yoff = 0; - } - } else if (aDesiredSize.height < minInternalHeight) { - yoff = (minInternalHeight - aDesiredSize.height) / 2; + // center child vertically in the content area + nscoord yoff = (actualDesiredHeight - aFocusPadding.TopBottom() - aDesiredSize.height) / 2; + if (yoff < 0) { + yoff = 0; } // Place the child @@ -309,8 +299,9 @@ nsHTMLButtonControlFrame::ReflowButtonContents(nsPresContext* aPresContext, aDesiredSize.ascent = aFirstKid->GetBaseline(); // Adjust the baseline by our offset (since we moved the child's - // baseline by that much). + // baseline by that much), and set our actual desired height. aDesiredSize.ascent += yoff; + aDesiredSize.height = actualDesiredHeight; } nsresult nsHTMLButtonControlFrame::SetFormProperty(nsIAtom* aName, const nsAString& aValue) diff --git a/layout/reftests/forms/button/reftest.list b/layout/reftests/forms/button/reftest.list index 8b0c1e30ea1..eeb0b16a7b8 100644 --- a/layout/reftests/forms/button/reftest.list +++ b/layout/reftests/forms/button/reftest.list @@ -2,3 +2,4 @@ asserts(2) == first-letter-1.html first-letter-1-ref.html asserts(1) != first-letter-1.html first-letter-1-noref.html == max-height.html max-height-ref.html == min-height.html min-height-ref.html +== vertical-centering.html vertical-centering-ref.html diff --git a/layout/reftests/forms/button/vertical-centering-ref.html b/layout/reftests/forms/button/vertical-centering-ref.html new file mode 100644 index 00000000000..5e7a34cc1a3 --- /dev/null +++ b/layout/reftests/forms/button/vertical-centering-ref.html @@ -0,0 +1,25 @@ + + + + + + +
button
+
button
+ + diff --git a/layout/reftests/forms/button/vertical-centering.html b/layout/reftests/forms/button/vertical-centering.html new file mode 100644 index 00000000000..a096ca0b19b --- /dev/null +++ b/layout/reftests/forms/button/vertical-centering.html @@ -0,0 +1,32 @@ + + + + + + + +
button
+ + From eea48dff05ac1c5d09ca99b1467eef231a1aa3f0 Mon Sep 17 00:00:00 2001 From: Mina Almasry Date: Fri, 19 Jul 2013 10:32:52 -0400 Subject: [PATCH 10/58] Bug 895076 - domUtils.getCSSValuesForProperty now returns non keyword values. r=bz This patch makes getCSSValuesForProperty return some none keyword values: auto, normal, none, all, calc, -moz-calc, -moz-element, -moz-element-rect, rgb, hsl, -moz-rgba, -moz-hsla, rgba, hsla, cubic-bezer, and steps. --- layout/inspector/src/inDOMUtils.cpp | 76 +++++++++++++++++++--- layout/inspector/tests/test_bug877690.html | 28 ++++++-- 2 files changed, 90 insertions(+), 14 deletions(-) diff --git a/layout/inspector/src/inDOMUtils.cpp b/layout/inspector/src/inDOMUtils.cpp index 19410f217fc..6990e7a1a25 100644 --- a/layout/inspector/src/inDOMUtils.cpp +++ b/layout/inspector/src/inDOMUtils.cpp @@ -419,6 +419,16 @@ inDOMUtils::GetCSSPropertyNames(uint32_t aFlags, uint32_t* aCount, return NS_OK; } +static void InsertNoDuplicates(nsTArray& aArray, + const nsAString& aString) +{ + size_t i = aArray.IndexOfFirstElementGt(aString); + if (i > 0 && aArray[i-1].Equals(aString)) { + return; + } + aArray.InsertElementAt(i, aString); +} + static void GetKeywordsForProperty(const nsCSSProperty aProperty, nsTArray& aArray) { @@ -431,8 +441,8 @@ static void GetKeywordsForProperty(const nsCSSProperty aProperty, size_t i = 0; while (nsCSSKeyword(keywordTable[i]) != eCSSKeyword_UNKNOWN) { nsCSSKeyword word = nsCSSKeyword(keywordTable[i]); - CopyASCIItoUTF16(nsCSSKeywords::GetStringValue(word), - *aArray.AppendElement()); + InsertNoDuplicates(aArray, + NS_ConvertASCIItoUTF16(nsCSSKeywords::GetStringValue(word))); // Increment counter by 2, because in this table every second // element is a nsCSSKeyword. i += 2; @@ -440,11 +450,10 @@ static void GetKeywordsForProperty(const nsCSSProperty aProperty, } } -static void GetColorsForProperty(const nsCSSProperty propertyID, +static void GetColorsForProperty(const uint32_t aParserVariant, nsTArray& aArray) { - uint32_t propertyParserVariant = nsCSSProps::ParserVariant(propertyID); - if (propertyParserVariant & VARIANT_COLOR) { + if (aParserVariant & VARIANT_COLOR) { size_t size; const char * const *allColorNames = NS_AllColorNames(&size); for (size_t i = 0; i < size; i++) { @@ -454,6 +463,45 @@ static void GetColorsForProperty(const nsCSSProperty propertyID, return; } +static void GetOtherValuesForProperty(const uint32_t aParserVariant, + nsTArray& aArray) +{ + if (aParserVariant & VARIANT_AUTO) { + InsertNoDuplicates(aArray, NS_LITERAL_STRING("auto")); + } + if (aParserVariant & VARIANT_NORMAL) { + InsertNoDuplicates(aArray, NS_LITERAL_STRING("normal")); + } + if(aParserVariant & VARIANT_ALL) { + InsertNoDuplicates(aArray, NS_LITERAL_STRING("all")); + } + if (aParserVariant & VARIANT_NONE) { + InsertNoDuplicates(aArray, NS_LITERAL_STRING("none")); + } + if (aParserVariant & VARIANT_ELEMENT) { + InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-element")); + } + if (aParserVariant & VARIANT_IMAGE_RECT) { + InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-image-rect")); + } + if (aParserVariant & VARIANT_COLOR) { + InsertNoDuplicates(aArray, NS_LITERAL_STRING("rgb")); + InsertNoDuplicates(aArray, NS_LITERAL_STRING("hsl")); + InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-rgba")); + InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-hsla")); + InsertNoDuplicates(aArray, NS_LITERAL_STRING("rgba")); + InsertNoDuplicates(aArray, NS_LITERAL_STRING("hsla")); + } + if (aParserVariant & VARIANT_TIMING_FUNCTION) { + InsertNoDuplicates(aArray, NS_LITERAL_STRING("cubic-bezier")); + InsertNoDuplicates(aArray, NS_LITERAL_STRING("steps")); + } + if (aParserVariant & VARIANT_CALC) { + InsertNoDuplicates(aArray, NS_LITERAL_STRING("calc")); + InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-calc")); + } +} + NS_IMETHODIMP inDOMUtils::GetCSSValuesForProperty(const nsAString& aProperty, uint32_t* aLength, @@ -466,20 +514,28 @@ inDOMUtils::GetCSSValuesForProperty(const nsAString& aProperty, } nsTArray array; - // All CSS properties take initial and inherit. - array.AppendElement(NS_LITERAL_STRING("-moz-initial")); - array.AppendElement(NS_LITERAL_STRING("inherit")); + // We start collecting the values, BUT colors need to go in first, because array + // needs to stay sorted, and the colors are sorted, so we just append them. if (!nsCSSProps::IsShorthand(propertyID)) { // Property is longhand. + uint32_t propertyParserVariant = nsCSSProps::ParserVariant(propertyID); + // Get colors first. + GetColorsForProperty(propertyParserVariant, array); GetKeywordsForProperty(propertyID, array); - GetColorsForProperty(propertyID, array); + GetOtherValuesForProperty(propertyParserVariant, array); } else { // Property is shorthand. CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subproperty, propertyID) { + uint32_t propertyParserVariant = nsCSSProps::ParserVariant(*subproperty); + // Get colors first. + GetColorsForProperty(propertyParserVariant, array); GetKeywordsForProperty(*subproperty, array); - GetColorsForProperty(*subproperty, array); + GetOtherValuesForProperty(propertyParserVariant, array); } } + // All CSS properties take initial and inherit. + InsertNoDuplicates(array, NS_LITERAL_STRING("-moz-initial")); + InsertNoDuplicates(array, NS_LITERAL_STRING("inherit")); *aLength = array.Length(); PRUnichar** ret = diff --git a/layout/inspector/tests/test_bug877690.html b/layout/inspector/tests/test_bug877690.html index 6dc3f4b6ba9..1be4b1a4e22 100644 --- a/layout/inspector/tests/test_bug877690.html +++ b/layout/inspector/tests/test_bug877690.html @@ -63,7 +63,7 @@ function do_test() { "purple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "slategrey", "snow", "springgreen", "steelblue", "tan", "teal", "thistle", "tomato", "transparent", "turquoise", "violet", "wheat", - "white", "whitesmoke", "yellow", "yellowgreen" ]; + "white", "whitesmoke", "yellow", "yellowgreen", "rgb", "hsl", "-moz-rgba", "-moz-hsla", "rgba", "hsla" ]; ok(testValues(values, expected), "property color's values."); // test a shorthand property @@ -91,7 +91,7 @@ function do_test() { "violet", "wheat", "white", "whitesmoke", "yellow", "yellowgreen", "no-repeat", "repeat", "repeat-x", "repeat-y", "fixed", "scroll", "center", "top", "bottom", "left", "right", "border-box", "padding-box", "content-box", "border-box", "padding-box", "content-box", "contain", - "cover" ]; + "cover", "rgb", "hsl", "-moz-rgba", "-moz-hsla", "rgba", "hsla", "none", "-moz-element", "-moz-image-rect" ]; ok(testValues(values, expected), "Shorthand property values."); // test keywords only @@ -118,13 +118,13 @@ function do_test() { "purple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "slategrey", "snow", "springgreen", "steelblue", "tan", "teal", "thistle", "tomato", "transparent", "turquoise", "violet", "wheat", "white", "whitesmoke", - "yellow", "yellowgreen" ]; + "yellow", "yellowgreen", "calc", "-moz-calc", "rgb", "hsl", "-moz-rgba", "-moz-hsla", "rgba", "hsla" ]; ok(testValues(values, expected), "property border-top's values."); // tests no keywords or colors var prop = "padding-bottom"; var values = utils.getCSSValuesForProperty(prop); - var expected = [ "-moz-initial", "inherit" ]; + var expected = [ "-moz-initial", "inherit", "calc", "-moz-calc" ]; ok(testValues(values, expected), "property padding-bottom's values."); // test proprety @@ -143,6 +143,26 @@ function do_test() { var expected = [ "-moz-initial", "inherit", "none", "left", "right" ]; ok(testValues(values, expected), "proprety float values"); + // Test property with "auto" + var prop = "margin"; + var values = utils.getCSSValuesForProperty(prop); + var expected = [ "-moz-calc", "-moz-initial", "auto", "calc", "inherit", "logical", "physical" ]; + ok(testValues(values, expected), "property margin's values."); + + // Test property with "normal" + var prop = "font-style"; + var values = utils.getCSSValuesForProperty(prop); + var expected = [ "-moz-initial", "inherit", "italic", "normal", "oblique" ]; + ok(testValues(values, expected), "property font-style's values."); + + // Test property with "cubic-bezier" and "step". + var prop = "-moz-transition"; + var values = utils.getCSSValuesForProperty(prop); + var expected = [ "-moz-initial", "all", "cubic-bezier", "ease", "ease-in", "ease-in-out", + "ease-out", "inherit", "linear", "none", "step-end", "step-start", + "steps" ]; + ok(testValues(values, expected), "property -moz-transition's values."); + // test invalid property var prop = "invalidProperty"; try { From fc122275c01a2cafad86af131eacea2e98fbf73e Mon Sep 17 00:00:00 2001 From: David Rajchenbach-Teller Date: Fri, 19 Jul 2013 10:32:52 -0400 Subject: [PATCH 11/58] Bug 867143 - Cache Session Restore state aggressively. r=ttaubert --- .../content/content-sessionStore.js | 20 +- .../sessionstore/src/SessionStore.jsm | 451 ++++++++++++------ 2 files changed, 321 insertions(+), 150 deletions(-) diff --git a/browser/components/sessionstore/content/content-sessionStore.js b/browser/components/sessionstore/content/content-sessionStore.js index bdf0fef0c14..43bf6ff6da1 100644 --- a/browser/components/sessionstore/content/content-sessionStore.js +++ b/browser/components/sessionstore/content/content-sessionStore.js @@ -13,7 +13,7 @@ function debug(msg) { let EventListener = { DOM_EVENTS: [ - "pageshow", "change", "input" + "pageshow", "change", "input", "MozStorageChanged" ], init: function () { @@ -30,6 +30,24 @@ let EventListener = { case "change": sendAsyncMessage("SessionStore:input"); break; + case "MozStorageChanged": + { + let isSessionStorage = true; + // We are only interested in sessionStorage events + try { + if (event.storageArea != content.sessionStorage) { + isSessionStorage = false; + } + } catch (ex) { + // This page does not even have sessionStorage + // (this is typically the case of about: pages) + isSessionStorage = false; + } + if (isSessionStorage) { + sendAsyncMessage("SessionStore:MozStorageChanged"); + } + break; + } default: debug("received unknown event '" + event.type + "'"); break; diff --git a/browser/components/sessionstore/src/SessionStore.jsm b/browser/components/sessionstore/src/SessionStore.jsm index dca404711e0..443b3513fb2 100644 --- a/browser/components/sessionstore/src/SessionStore.jsm +++ b/browser/components/sessionstore/src/SessionStore.jsm @@ -58,7 +58,11 @@ const MESSAGES = [ // The content script has received a pageshow event. This happens when a // page is loaded from bfcache without any network activity, i.e. when // clicking the back or forward button. - "SessionStore:pageshow" + "SessionStore:pageshow", + + // The content script has received a MozStorageChanged event dealing + // with a change in the contents of the sessionStorage. + "SessionStore:MozStorageChanged" ]; // These are tab events that we listen to. @@ -120,9 +124,16 @@ XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter", "@mozilla.org/xre/app-info;1", "nsICrashReporter"); #endif +/** + * |true| if we are in debug mode, |false| otherwise. + * Debug mode is controlled by preference browser.sessionstore.debug + */ +let gDebuggingEnabled = false; function debug(aMsg) { - aMsg = ("SessionStore: " + aMsg).replace(/\S{80}/g, "$&\n"); - Services.console.logStringMessage(aMsg); + if (gDebuggingEnabled) { + aMsg = ("SessionStore: " + aMsg).replace(/\S{80}/g, "$&\n"); + Services.console.logStringMessage(aMsg); + } } this.SessionStore = { @@ -537,9 +548,13 @@ let SessionStoreInternal = { }, _initPrefs : function() { - XPCOMUtils.defineLazyGetter(this, "_prefBranch", function () { - return Services.prefs.getBranch("browser."); - }); + this._prefBranch = Services.prefs.getBranch("browser."); + + gDebuggingEnabled = this._prefBranch.getBoolPref("sessionstore.debug"); + + Services.prefs.addObserver("browser.sessionstore.debug", () => { + gDebuggingEnabled = this._prefBranch.getBoolPref("sessionstore.debug"); + }, false); // minimal interval between two save operations (in milliseconds) XPCOMUtils.defineLazyGetter(this, "_interval", function () { @@ -621,37 +636,43 @@ let SessionStoreInternal = { if (this._disabledForMultiProcess) return; - switch (aTopic) { - case "domwindowopened": // catch new windows - this.onOpen(aSubject); - break; - case "domwindowclosed": // catch closed windows - this.onClose(aSubject); - break; - case "quit-application-requested": - this.onQuitApplicationRequested(); - break; - case "quit-application-granted": - this.onQuitApplicationGranted(); - break; - case "browser-lastwindow-close-granted": - this.onLastWindowCloseGranted(); - break; - case "quit-application": - this.onQuitApplication(aData); - break; - case "browser:purge-session-history": // catch sanitization - this.onPurgeSessionHistory(); - break; - case "browser:purge-domain-data": - this.onPurgeDomainData(aData); - break; - case "nsPref:changed": // catch pref changes - this.onPrefChange(aData); - break; - case "timer-callback": // timer call back for delayed saving - this.onTimerCallback(); - break; + try { + switch (aTopic) { + case "domwindowopened": // catch new windows + this.onOpen(aSubject); + break; + case "domwindowclosed": // catch closed windows + this.onClose(aSubject); + break; + case "quit-application-requested": + this.onQuitApplicationRequested(); + break; + case "quit-application-granted": + this.onQuitApplicationGranted(); + break; + case "browser-lastwindow-close-granted": + this.onLastWindowCloseGranted(); + break; + case "quit-application": + this.onQuitApplication(aData); + break; + case "browser:purge-session-history": // catch sanitization + this.onPurgeSessionHistory(); + break; + case "browser:purge-domain-data": + this.onPurgeDomainData(aData); + break; + case "nsPref:changed": // catch pref changes + this.onPrefChange(aData); + break; + case "timer-callback": // timer call back for delayed saving + this.onTimerCallback(); + break; + } + } catch (ex) { + debug("Uncaught error during observe"); + debug(ex); + debug(ex.stack); } }, @@ -670,6 +691,10 @@ let SessionStoreInternal = { case "SessionStore:input": this.onTabInput(win, browser); break; + case "SessionStore:MozStorageChanged": + TabStateCache.delete(browser); + this.saveStateDelayed(win); + break; default: debug("received unknown message '" + aMessage.name + "'"); break; @@ -1091,6 +1116,7 @@ let SessionStoreInternal = { let openWindows = {}; this._forEachBrowserWindow(function(aWindow) { Array.forEach(aWindow.gBrowser.tabs, function(aTab) { + TabStateCache.delete(aTab); delete aTab.linkedBrowser.__SS_data; delete aTab.linkedBrowser.__SS_tabStillLoading; delete aTab.linkedBrowser.__SS_formDataSaved; @@ -1314,9 +1340,8 @@ let SessionStoreInternal = { return; } - // make sure that the tab related data is up-to-date - var tabState = this._collectTabData(aTab); - this._updateTextAndScrollDataForTab(aWindow, aTab.linkedBrowser, tabState); + // Get the latest data for this tab (generally, from the cache) + let tabState = this._collectTabData(aTab); // store closed-tab data for undo if (this._shouldSaveTabState(tabState)) { @@ -1337,7 +1362,8 @@ let SessionStoreInternal = { }, /** - * When a tab loads, save state. + * When a tab loads, invalidate its cached state, trigger async save. + * * @param aWindow * Window reference * @param aBrowser @@ -1353,6 +1379,8 @@ let SessionStoreInternal = { return; } + TabStateCache.delete(aBrowser); + delete aBrowser.__SS_data; delete aBrowser.__SS_tabStillLoading; delete aBrowser.__SS_formDataSaved; @@ -1373,6 +1401,8 @@ let SessionStoreInternal = { // deleting __SS_formDataSaved will cause us to recollect form data delete aBrowser.__SS_formDataSaved; + TabStateCache.delete(aBrowser); + this.saveStateDelayed(aWindow, 3000); }, @@ -1496,20 +1526,41 @@ let SessionStoreInternal = { if (!aTab.ownerDocument || !aTab.ownerDocument.defaultView.__SSi) throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); - var tabState = this._collectTabData(aTab); - - var window = aTab.ownerDocument.defaultView; - this._updateTextAndScrollDataForTab(window, aTab.linkedBrowser, tabState); + let tabState = this._collectTabData(aTab); return this._toJSONString(tabState); }, setTabState: function ssi_setTabState(aTab, aState) { - var tabState = JSON.parse(aState); - if (!tabState.entries || !aTab.ownerDocument || !aTab.ownerDocument.defaultView.__SSi) + // Remove the tab state from the cache. + // Note that we cannot simply replace the contents of the cache + // as |aState| can be an incomplete state that will be completed + // by |restoreHistoryPrecursor|. + let tabState = JSON.parse(aState); + if (!tabState) { + debug("Empty state argument"); throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + } + if (typeof tabState != "object") { + debug("State argument does not represent an object"); + throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + } + if (!("entries" in tabState)) { + debug("State argument must contain field 'entries'"); + throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + } + if (!aTab.ownerDocument) { + debug("Tab argument must have an owner document"); + throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + } - var window = aTab.ownerDocument.defaultView; + let window = aTab.ownerDocument.defaultView; + if (!("__SSi" in window)) { + debug("Default view of ownerDocument must have a unique identifier"); + throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + } + + TabStateCache.delete(aTab); this._setWindowStateBusy(window); this.restoreHistoryPrecursor(window, [aTab], [tabState], 0, 0, 0); }, @@ -1519,9 +1570,9 @@ let SessionStoreInternal = { !aWindow.getBrowser) throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); - var tabState = this._collectTabData(aTab, true); - var sourceWindow = aTab.ownerDocument.defaultView; - this._updateTextAndScrollDataForTab(sourceWindow, aTab.linkedBrowser, tabState, true); + // Duplicate the tab state + let tabState = this._cloneFullTabData(aTab); + tabState.index += aDelta; tabState.index = Math.max(1, Math.min(tabState.index, tabState.entries.length)); tabState.pinned = false; @@ -1691,6 +1742,7 @@ let SessionStoreInternal = { if (aWindow.__SSi && this._windows[aWindow.__SSi].extData && this._windows[aWindow.__SSi].extData[aKey]) delete this._windows[aWindow.__SSi].extData[aKey]; + this.saveStateDelayed(aWindow); }, getTabValue: function ssi_getTabValue(aTab, aKey) { @@ -1706,6 +1758,7 @@ let SessionStoreInternal = { }, setTabValue: function ssi_setTabValue(aTab, aKey, aStringValue) { + TabStateCache.delete(aTab); // If the tab hasn't been restored, then set the data there, otherwise we // could lose newly added data. let saveTo; @@ -1724,6 +1777,7 @@ let SessionStoreInternal = { }, deleteTabValue: function ssi_deleteTabValue(aTab, aKey) { + TabStateCache.delete(aTab); // We want to make sure that if data is accessed early, we attempt to delete // that data from __SS_data as well. Otherwise we'll throw in cases where // data can be set or read. @@ -1737,6 +1791,7 @@ let SessionStoreInternal = { if (deleteFrom && deleteFrom[aKey]) delete deleteFrom[aKey]; + this.saveStateDelayed(aTab.ownerDocument.defaultView); }, persistTabAttribute: function ssi_persistTabAttribute(aName) { @@ -1914,32 +1969,51 @@ let SessionStoreInternal = { /* ........ Saving Functionality .............. */ /** - * Store all session data for a window - * @param aWindow - * Window reference + * Collect data related to a single tab + * + * @param aTab + * tabbrowser tab + * + * @returns {TabData} An object with the data for this tab. If the + * tab has not been invalidated since the last call to + * _collectTabData(aTab), the same object is returned. */ - _saveWindowHistory: function ssi_saveWindowHistory(aWindow) { - var tabbrowser = aWindow.gBrowser; - var tabs = tabbrowser.tabs; - var tabsData = this._windows[aWindow.__SSi].tabs = []; + _collectTabData: function ssi_collectTabData(aTab) { + if (!aTab) { + throw new TypeError("Expecting a tab"); + } + let tabData; + if ((tabData = TabStateCache.get(aTab))) { + return tabData; + } + tabData = new TabData(this._collectBaseTabData(aTab)); + TabStateCache.set(aTab, tabData); - for (var i = 0; i < tabs.length; i++) - tabsData.push(this._collectTabData(tabs[i])); - - this._windows[aWindow.__SSi].selected = tabbrowser.mTabBox.selectedIndex + 1; + this._updateTextAndScrollDataForTab(aTab, tabData); + return tabData; }, /** - * Collect data related to a single tab + * Collect data related to a single tab, including private data. + * Use with caution. + * * @param aTab * tabbrowser tab - * @param aFullData - * always return privacy sensitive data (use with care) - * @returns object + * + * @returns {object} An object with the data for this tab. This object + * is recomputed at every call. */ - _collectTabData: function ssi_collectTabData(aTab, aFullData) { - var tabData = { entries: [], lastAccessed: aTab.lastAccessed }; - var browser = aTab.linkedBrowser; + _cloneFullTabData: function ssi_cloneFullTabData(aTab) { + let options = { includePrivateData: true }; + let tabData = this._collectBaseTabData(aTab, options); + this._updateTextAndScrollDataForTab(aTab, tabData, options); + return tabData; + }, + + _collectBaseTabData: function ssi_collectBaseTabData(aTab, aOptions = null) { + let includePrivateData = aOptions && aOptions.includePrivateData; + let tabData = {entries: [], lastAccessed: aTab.lastAccessed }; + let browser = aTab.linkedBrowser; if (!browser || !browser.currentURI) // can happen when calling this function right after .addTab() @@ -1974,7 +2048,7 @@ let SessionStoreInternal = { if (history && browser.__SS_data && browser.__SS_data.entries[history.index] && browser.__SS_data.entries[history.index].url == browser.currentURI.spec && - history.index < this._sessionhistory_max_entries - 1 && !aFullData) { + history.index < this._sessionhistory_max_entries - 1 && !includePrivateData) { tabData = browser.__SS_data; tabData.index = history.index + 1; } @@ -1983,7 +2057,7 @@ let SessionStoreInternal = { try { for (var j = 0; j < history.count; j++) { let entry = this._serializeHistoryEntry(history.getEntryAtIndex(j, false), - aFullData, aTab.pinned, browser.__SS_hostSchemeData); + includePrivateData, aTab.pinned, browser.__SS_hostSchemeData); tabData.entries.push(entry); } // If we make it through the for loop, then we're ok and we should clear @@ -2009,7 +2083,7 @@ let SessionStoreInternal = { tabData.index = history.index + 1; // make sure not to cache privacy sensitive data which shouldn't get out - if (!aFullData) + if (!includePrivateData) browser.__SS_data = tabData; } else if (browser.currentURI.spec != "about:blank" || @@ -2058,7 +2132,7 @@ let SessionStoreInternal = { delete tabData.extData; if (history && browser.docShell instanceof Ci.nsIDocShell) { - let storageData = SessionStorage.serialize(browser.docShell, aFullData) + let storageData = SessionStorage.serialize(browser.docShell, includePrivateData) if (Object.keys(storageData).length) tabData.storage = storageData; } @@ -2071,7 +2145,7 @@ let SessionStoreInternal = { * Used for data storage * @param aEntry * nsISHEntry instance - * @param aFullData + * @param aIncludePrivateData * always return privacy sensitive data (use with care) * @param aIsPinned * the tab is pinned and should be treated differently for privacy @@ -2080,7 +2154,7 @@ let SessionStoreInternal = { * @returns object */ _serializeHistoryEntry: - function ssi_serializeHistoryEntry(aEntry, aFullData, aIsPinned, aHostSchemeData) { + function ssi_serializeHistoryEntry(aEntry, aIncludePrivateData, aIsPinned, aHostSchemeData) { var entry = { url: aEntry.URI.spec }; try { @@ -2131,7 +2205,7 @@ let SessionStoreInternal = { try { var prefPostdata = this._prefBranch.getIntPref("sessionstore.postdata"); - if (aEntry.postData && (aFullData || prefPostdata && + if (aEntry.postData && (aIncludePrivateData || prefPostdata && this.checkPrivacyLevel(aEntry.URI.schemeIs("https"), aIsPinned))) { aEntry.postData.QueryInterface(Ci.nsISeekableStream). seek(Ci.nsISeekableStream.NS_SEEK_SET, 0); @@ -2140,7 +2214,7 @@ let SessionStoreInternal = { stream.setInputStream(aEntry.postData); var postBytes = stream.readByteArray(stream.available()); var postdata = String.fromCharCode.apply(null, postBytes); - if (aFullData || prefPostdata == -1 || + if (aIncludePrivateData || prefPostdata == -1 || postdata.replace(/^(Content-.*\r\n)+(\r\n)*/, "").length <= prefPostdata) { // We can stop doing base64 encoding once our serialization into JSON @@ -2201,7 +2275,7 @@ let SessionStoreInternal = { break; } - children.push(this._serializeHistoryEntry(child, aFullData, + children.push(this._serializeHistoryEntry(child, aIncludePrivateData, aIsPinned, aHostSchemeData)); } } @@ -2214,37 +2288,25 @@ let SessionStoreInternal = { }, /** - * go through all tabs and store the current scroll positions + * Go through all frames and store the current scroll positions * and innerHTML content of WYSIWYG editors - * @param aWindow - * Window reference - */ - _updateTextAndScrollData: function ssi_updateTextAndScrollData(aWindow) { - var browsers = aWindow.gBrowser.browsers; - this._windows[aWindow.__SSi].tabs.forEach(function (tabData, i) { - try { - this._updateTextAndScrollDataForTab(aWindow, browsers[i], tabData); - } - catch (ex) { debug(ex); } // get as much data as possible, ignore failures (might succeed the next time) - }, this); - }, - - /** - * go through all frames and store the current scroll positions - * and innerHTML content of WYSIWYG editors - * @param aWindow - * Window reference - * @param aBrowser - * single browser reference + * + * @param aTab + * tabbrowser tab * @param aTabData * tabData object to add the information to - * @param aFullData - * always return privacy sensitive data (use with care) + * @param options + * An optional object that may contain the following field: + * - includePrivateData: always return privacy sensitive data + * (use with care) */ _updateTextAndScrollDataForTab: - function ssi_updateTextAndScrollDataForTab(aWindow, aBrowser, aTabData, aFullData) { + function ssi_updateTextAndScrollDataForTab(aTab, aTabData, aOptions = null) { + let includePrivateData = aOptions && aOptions.includePrivateData; + let window = aTab.ownerDocument.defaultView; + let browser = aTab.linkedBrowser; // we shouldn't update data for incompletely initialized tabs - if (aBrowser.__SS_data && aBrowser.__SS_tabStillLoading) + if (browser.__SS_data && browser.__SS_tabStillLoading) return; var tabIndex = (aTabData.index || aTabData.entries.length) - 1; @@ -2252,22 +2314,22 @@ let SessionStoreInternal = { if (!aTabData.entries[tabIndex]) return; - let selectedPageStyle = aBrowser.markupDocumentViewer.authorStyleDisabled ? "_nostyle" : - this._getSelectedPageStyle(aBrowser.contentWindow); + let selectedPageStyle = browser.markupDocumentViewer.authorStyleDisabled ? "_nostyle" : + this._getSelectedPageStyle(browser.contentWindow); if (selectedPageStyle) aTabData.pageStyle = selectedPageStyle; else if (aTabData.pageStyle) delete aTabData.pageStyle; - this._updateTextAndScrollDataForFrame(aWindow, aBrowser.contentWindow, + this._updateTextAndScrollDataForFrame(window, browser.contentWindow, aTabData.entries[tabIndex], - !aBrowser.__SS_formDataSaved, aFullData, + !browser.__SS_formDataSaved, includePrivateData, !!aTabData.pinned); - aBrowser.__SS_formDataSaved = true; - if (aBrowser.currentURI.spec == "about:config") + browser.__SS_formDataSaved = true; + if (browser.currentURI.spec == "about:config") aTabData.entries[tabIndex].formdata = { id: { - "textbox": aBrowser.contentDocument.getElementById("textbox").value + "textbox": browser.contentDocument.getElementById("textbox").value }, xpath: {} }; @@ -2284,26 +2346,26 @@ let SessionStoreInternal = { * part of a tabData object to add the information to * @param aUpdateFormData * update all form data for this tab - * @param aFullData + * @param aIncludePrivateData * always return privacy sensitive data (use with care) * @param aIsPinned * the tab is pinned and should be treated differently for privacy */ _updateTextAndScrollDataForFrame: function ssi_updateTextAndScrollDataForFrame(aWindow, aContent, aData, - aUpdateFormData, aFullData, aIsPinned) { + aUpdateFormData, aIncludePrivateData, aIsPinned) { for (var i = 0; i < aContent.frames.length; i++) { if (aData.children && aData.children[i]) this._updateTextAndScrollDataForFrame(aWindow, aContent.frames[i], aData.children[i], aUpdateFormData, - aFullData, aIsPinned); + aIncludePrivateData, aIsPinned); } var isHTTPS = this._getURIFromString((aContent.parent || aContent). document.location.href).schemeIs("https"); let topURL = aContent.top.document.location.href; let isAboutSR = topURL == "about:sessionrestore" || topURL == "about:welcomeback"; - if (aFullData || this.checkPrivacyLevel(isHTTPS, aIsPinned) || isAboutSR) { - if (aFullData || aUpdateFormData) { + if (aIncludePrivateData || this.checkPrivacyLevel(isHTTPS, aIsPinned) || isAboutSR) { + if (aIncludePrivateData || aUpdateFormData) { let formData = DocumentUtils.getFormData(aContent.document); // We want to avoid saving data for about:sessionrestore as a string. @@ -2426,28 +2488,6 @@ let SessionStoreInternal = { } }, - /** - * store all hosts for a URL - * @param aWindow - * Window reference - */ - _updateCookieHosts: function ssi_updateCookieHosts(aWindow) { - var hosts = this._internalWindows[aWindow.__SSi].hosts = {}; - - // Since _updateCookiesHosts is only ever called for open windows during a - // session, we can call into _extractHostsForCookiesFromHostScheme directly - // using data that is attached to each browser. - for (let i = 0; i < aWindow.gBrowser.tabs.length; i++) { - let tab = aWindow.gBrowser.tabs[i]; - let hostSchemeData = tab.linkedBrowser.__SS_hostSchemeData || []; - for (let j = 0; j < hostSchemeData.length; j++) { - this._extractHostsForCookiesFromHostScheme(hostSchemeData[j].host, - hostSchemeData[j].scheme, - hosts, true, tab.pinned); - } - } - }, - /** * Serialize cookie data * @param aWindows @@ -2685,10 +2725,29 @@ let SessionStoreInternal = { if (!this._isWindowLoaded(aWindow)) return; + let tabbrowser = aWindow.gBrowser; + let tabs = tabbrowser.tabs; + let winData = this._windows[aWindow.__SSi]; + let tabsData = winData.tabs = []; + let hosts = this._internalWindows[aWindow.__SSi].hosts = {}; + // update the internal state data for this window - this._saveWindowHistory(aWindow); - this._updateTextAndScrollData(aWindow); - this._updateCookieHosts(aWindow); + for (let tab of tabs) { + tabsData.push(this._collectTabData(tab)); + + // Since we are only ever called for open + // windows during a session, we can call into + // _extractHostsForCookiesFromHostScheme directly using data + // that is attached to each browser. + let hostSchemeData = tab.linkedBrowser.__SS_hostSchemeData || []; + for (let j = 0; j < hostSchemeData.length; j++) { + this._extractHostsForCookiesFromHostScheme(hostSchemeData[j].host, + hostSchemeData[j].scheme, + hosts, true, tab.pinned); + } + } + winData.selected = tabbrowser.mTabBox.selectedIndex + 1; + this._updateWindowFeatures(aWindow); // Make sure we keep __SS_lastSessionWindowID around for cases like entering @@ -2987,6 +3046,7 @@ let SessionStoreInternal = { restoreHistoryPrecursor: function ssi_restoreHistoryPrecursor(aWindow, aTabs, aTabData, aSelectTab, aIx, aCount, aRestoreImmediately = false) { + var tabbrowser = aWindow.gBrowser; // make sure that all browsers and their histories are available @@ -3002,7 +3062,7 @@ let SessionStoreInternal = { var restoreHistoryFunc = function(self) { self.restoreHistoryPrecursor(aWindow, aTabs, aTabData, aSelectTab, aIx, aCount + 1, aRestoreImmediately); - } + }; aWindow.setTimeout(restoreHistoryFunc, 100, this); return; } @@ -3138,7 +3198,6 @@ let SessionStoreInternal = { var tab = aTabs.shift(); var tabData = aTabData.shift(); - var browser = aWindow.gBrowser.getBrowserForTab(tab); var history = browser.webNavigation.sessionHistory; @@ -3703,7 +3762,7 @@ let SessionStoreInternal = { * @param aDelay * Milliseconds to delay */ - saveStateDelayed: function ssi_saveStateDelayed(aWindow, aDelay) { + saveStateDelayed: function ssi_saveStateDelayed(aWindow = null, aDelay = 2000) { if (aWindow) { this._dirtyWindows[aWindow.__SSi] = true; } @@ -3713,7 +3772,7 @@ let SessionStoreInternal = { var minimalDelay = this._lastSaveTime + this._interval - Date.now(); // if we have to wait, set a timer, otherwise saveState directly - aDelay = Math.max(minimalDelay, aDelay || 2000); + aDelay = Math.max(minimalDelay, aDelay); if (aDelay > 0) { this._saveTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); this._saveTimer.init(this, aDelay, Ci.nsITimer.TYPE_ONE_SHOT); @@ -3985,6 +4044,7 @@ let SessionStoreInternal = { if (tab.linkedBrowser == aBrowser) return tab; } + return undefined; }, /** @@ -4807,11 +4867,25 @@ SessionStoreSHistoryListener.prototype = { Ci.nsISupportsWeakReference ]), browser: null, - OnHistoryNewEntry: function(aNewURI) { }, - OnHistoryGoBack: function(aBackURI) { return true; }, - OnHistoryGoForward: function(aForwardURI) { return true; }, - OnHistoryGotoIndex: function(aIndex, aGotoURI) { return true; }, - OnHistoryPurge: function(aNumEntries) { return true; }, +// The following events (with the exception of OnHistoryPurge) +// accompany either a "load" or a "pageshow" which will in turn cause +// invalidations. + OnHistoryNewEntry: function(aNewURI) { + + }, + OnHistoryGoBack: function(aBackURI) { + return true; + }, + OnHistoryGoForward: function(aForwardURI) { + return true; + }, + OnHistoryGotoIndex: function(aIndex, aGotoURI) { + return true; + }, + OnHistoryPurge: function(aNumEntries) { + TabStateCache.delete(this.tab); + return true; + }, OnHistoryReload: function(aReloadURI, aReloadFlags) { // On reload, we want to make sure that session history loads the right // URI. In order to do that, we will juet call restoreTab. That will remove @@ -4834,4 +4908,83 @@ String.prototype.hasRootDomain = function hasRootDomain(aDomain) { let prevChar = this[index - 1]; return (index == (this.length - aDomain.length)) && (prevChar == "." || prevChar == "/"); +}; + +function TabData(obj = null) { + if (obj) { + if (obj instanceof TabData) { + // FIXME: Can we get rid of this? + return obj; + } + for (let [key, value] in Iterator(obj)) { + this[key] = value; + } + } + return this; } + +/** + * A cache for tabs data. + * + * This cache implements a weak map from tabs (as XUL elements) + * to tab data (as instances of TabData). + * + * Note that we should never cache private data, as: + * - that data is used very seldom by SessionStore; + * - caching private data in addition to public data is memory consuming. + */ +let TabStateCache = { + _data: new WeakMap(), + + /** + * Add or replace an entry in the cache. + * + * @param {XULElement} aTab The key, which may be either a tab + * or the corresponding browser. The binding will disappear + * if the tab/browser is destroyed. + * @param {TabData} aValue The data associated to |aTab|. + */ + set: function(aTab, aValue) { + let key = this._normalizeToBrowser(aTab); + if (!(aValue instanceof TabData)) { + throw new TypeError("Attempting to cache a non TabData"); + } + this._data.set(key, aValue); + }, + + /** + * Return the tab data associated with a tab. + * + * @param {XULElement} aKey The tab or the associated browser. + * + * @return {TabData|undefined} The data if available, |undefined| + * otherwise. + */ + get: function(aKey) { + let key = this._normalizeToBrowser(aKey); + return this._data.get(key); + }, + + /** + * Delete the tab data associated with a tab. + * + * @param {XULElement} aKey The tab or the associated browser. + * + * Noop of there is no tab data associated with the tab. + */ + delete: function(aKey) { + let key = this._normalizeToBrowser(aKey); + this._data.delete(key); + }, + + _normalizeToBrowser: function(aKey) { + let nodeName = aKey.localName; + if (nodeName == "tab") { + return aKey.linkedBrowser; + } + if (nodeName == "browser") { + return aKey; + } + throw new TypeError("Key is neither a tab nor a browser: " + nodeName); + } +}; From c6c561735c1aa389e8611d466516e91417fb799f Mon Sep 17 00:00:00 2001 From: David Rajchenbach-Teller Date: Fri, 19 Jul 2013 10:32:52 -0400 Subject: [PATCH 12/58] Bug 867143 - sessionStorage/localStorage tests. r=ttaubert --- .../components/sessionstore/test/Makefile.in | 1 + .../test/browser_sessionStorage.js | 89 +++++++++++++++++++ browser/components/sessionstore/test/head.js | 75 +++++++++++++--- 3 files changed, 151 insertions(+), 14 deletions(-) create mode 100644 browser/components/sessionstore/test/browser_sessionStorage.js diff --git a/browser/components/sessionstore/test/Makefile.in b/browser/components/sessionstore/test/Makefile.in index 371c778ede0..1b744b26b7b 100644 --- a/browser/components/sessionstore/test/Makefile.in +++ b/browser/components/sessionstore/test/Makefile.in @@ -27,6 +27,7 @@ MOCHITEST_BROWSER_FILES = \ browser_input.js \ browser_input_sample.html \ browser_pageshow.js \ + browser_sessionStorage.js \ browser_upgrade_backup.js \ browser_windowRestore_perwindowpb.js \ browser_248970_b_perwindowpb.js \ diff --git a/browser/components/sessionstore/test/browser_sessionStorage.js b/browser/components/sessionstore/test/browser_sessionStorage.js new file mode 100644 index 00000000000..0436d1ea172 --- /dev/null +++ b/browser/components/sessionstore/test/browser_sessionStorage.js @@ -0,0 +1,89 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +let Scope = {}; +Cu.import("resource://gre/modules/Task.jsm", Scope); +Cu.import("resource://gre/modules/Promise.jsm", Scope); +let {Task, Promise} = Scope; + +function promiseBrowserLoaded(aBrowser) { + let deferred = Promise.defer(); + whenBrowserLoaded(aBrowser, () => deferred.resolve()); + return deferred.promise; +} + +function forceWriteState() { + let deferred = Promise.defer(); + const PREF = "browser.sessionstore.interval"; + const TOPIC = "sessionstore-state-write"; + + Services.obs.addObserver(function observe() { + Services.obs.removeObserver(observe, TOPIC); + Services.prefs.clearUserPref(PREF); + deferred.resolve(); + }, TOPIC, false); + + Services.prefs.setIntPref(PREF, 0); + return deferred.promise; +} + +function waitForStorageChange(aTab) { + let deferred = Promise.defer(); + waitForContentMessage(aTab.linkedBrowser, + "sessionstore:MozStorageChanged", + 200, + ((x) => deferred.resolve(x))); + return deferred.promise; +} + +function test() { + + waitForExplicitFinish(); + + let tab; + Task.spawn(function() { + try { + tab = gBrowser.addTab("http://example.com"); + // about:home supports sessionStorage and localStorage + + let win = tab.linkedBrowser.contentWindow; + + // Flush loading and next save, call getBrowserState() + // a few times to ensure that everything is cached. + yield promiseBrowserLoaded(tab.linkedBrowser); + yield forceWriteState(); + info("Calling getBrowserState() to populate cache"); + ss.getBrowserState(); + + info("Change sessionStorage, ensure that state is saved"); + win.sessionStorage["SESSION_STORAGE_KEY"] = "SESSION_STORAGE_VALUE"; + yield waitForStorageChange(tab); + yield forceWriteState(); + + let state = ss.getBrowserState(); + ok(state.indexOf("SESSION_STORAGE_KEY") != -1, "Key appears in state"); + ok(state.indexOf("SESSION_STORAGE_VALUE") != -1, "Value appears in state"); + + + info("Change localStorage, ensure that state is not saved"); + win.localStorage["LOCAL_STORAGE_KEY"] = "LOCAL_STORAGE_VALUE"; + yield waitForStorageChange(tab); + yield forceWriteState(); + + state = ss.getBrowserState(); + ok(state.indexOf("LOCAL_STORAGE_KEY") == -1, "Key does not appear in state"); + ok(state.indexOf("LOCAL_STORAGE_VALUE") == -1, "Value does not appear in state"); + } catch (ex) { + ok(false, ex); + info(ex.stack); + } finally { + // clean up + if (tab) { + gBrowser.removeTab(tab); + } + + executeSoon(finish); + } + }); +} diff --git a/browser/components/sessionstore/test/head.js b/browser/components/sessionstore/test/head.js index ac2849b581b..36de8e159be 100644 --- a/browser/components/sessionstore/test/head.js +++ b/browser/components/sessionstore/test/head.js @@ -156,31 +156,28 @@ function waitForTabState(aTab, aState, aCallback) { ss.setTabState(aTab, JSON.stringify(aState)); } -// waitForSaveState waits for a state write but not necessarily for the state to -// turn dirty. -function waitForSaveState(aSaveStateCallback) { +/** + * Wait for a content -> chrome message. + */ +function waitForContentMessage(aBrowser, aTopic, aTimeout, aCallback) { + let mm = aBrowser.messageManager; let observing = false; - let topic = "sessionstore-state-write"; - - let sessionSaveTimeout = 1000 + - Services.prefs.getIntPref("browser.sessionstore.interval"); - function removeObserver() { if (!observing) return; - Services.obs.removeObserver(observer, topic); + mm.removeMessageListener(aTopic, observer); observing = false; } let timeout = setTimeout(function () { removeObserver(); - aSaveStateCallback(); - }, sessionSaveTimeout); + aCallback(false); + }, aTimeout); function observer(aSubject, aTopic, aData) { removeObserver(); timeout = clearTimeout(timeout); - executeSoon(aSaveStateCallback); + executeSoon(() => aCallback(true)); } registerCleanupFunction(function() { @@ -191,8 +188,58 @@ function waitForSaveState(aSaveStateCallback) { }); observing = true; - Services.obs.addObserver(observer, topic, false); -}; + mm.addMessageListener(aTopic, observer); +} + +function waitForTopic(aTopic, aTimeout, aCallback) { + let observing = false; + function removeObserver() { + if (!observing) + return; + Services.obs.removeObserver(observer, aTopic); + observing = false; + } + + let timeout = setTimeout(function () { + removeObserver(); + aCallback(false); + }, aTimeout); + + function observer(aSubject, aTopic, aData) { + removeObserver(); + timeout = clearTimeout(timeout); + executeSoon(() => aCallback(true)); + } + + registerCleanupFunction(function() { + removeObserver(); + if (timeout) { + clearTimeout(timeout); + } + }); + + observing = true; + Services.obs.addObserver(observer, aTopic, false); +} + +/** + * Wait until session restore has finished collecting its data and is + * getting ready to write that data ("sessionstore-state-write"). + * + * This function is meant to be called immediately after the code + * that will trigger the saving. + * + * Note that this does not wait for the disk write to be complete. + * + * @param {function} aCallback If sessionstore-state-write is sent + * within buffering interval + 100 ms, the callback is passed |true|, + * otherwise, it is passed |false|. + */ +function waitForSaveState(aCallback) { + let timeout = 100 + + Services.prefs.getIntPref("browser.sessionstore.interval"); + return waitForTopic("sessionstore-state-write", timeout, aCallback); +} function whenBrowserLoaded(aBrowser, aCallback = next) { aBrowser.addEventListener("load", function onLoad() { From 8388fc5f158297210d77d43fc555e04b8cb53d56 Mon Sep 17 00:00:00 2001 From: "Adam Dane [:hobophobe]" Date: Thu, 18 Jul 2013 15:00:46 -0500 Subject: [PATCH 13/58] Bug 894381 - FindBar buttons should be enabled when moving tab between windows. r=dao --- browser/base/content/tabbrowser.xml | 3 ++- browser/base/content/test/browser_bug537013.js | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index 0ee38ed6efa..8778967e4ce 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -2098,8 +2098,9 @@ if (otherFindBar && otherFindBar.findMode == otherFindBar.FIND_NORMAL) { let ourFindBar = this.getFindBar(aOurTab); - ourFindBar.hidden = otherFindBar.hidden; ourFindBar._findField.value = otherFindBar._findField.value; + if (!otherFindBar.hidden) + ourFindBar.onFindCommand(); } // Finish tearing down the tab that's going away. diff --git a/browser/base/content/test/browser_bug537013.js b/browser/base/content/test/browser_bug537013.js index 2a54dfc9640..78cc5ec5a4e 100644 --- a/browser/base/content/test/browser_bug537013.js +++ b/browser/base/content/test/browser_bug537013.js @@ -98,6 +98,8 @@ function checkNewWindow() { ok(!newWindow.gFindBar.hidden, "New window shows find bar!"); is(newWindow.gFindBar._findField.value, texts[1], "New window find bar has correct find value!"); + ok(!newWindow.gFindBar.getElement("find-next").disabled, + "New window findbar has enabled buttons!"); newWindow.close(); finish(); } From 59bd9d964959fccce21762981d76dab690fa8d8f Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 19 Jul 2013 16:40:56 +0200 Subject: [PATCH 14/58] Bug 882543 - Retain storage for media streams accross iterations instead of reallocating. r=jlebar,roc --- content/media/MediaStreamGraph.cpp | 12 ++++++------ content/media/MediaStreamGraphImpl.h | 5 +++++ xpcom/glue/nsTArray.h | 14 ++++++++++++++ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/content/media/MediaStreamGraph.cpp b/content/media/MediaStreamGraph.cpp index 369d423cf19..f3facb4c428 100644 --- a/content/media/MediaStreamGraph.cpp +++ b/content/media/MediaStreamGraph.cpp @@ -489,10 +489,10 @@ MediaStreamGraphImpl::UpdateStreamOrderForStream(nsTArray* aStack, void MediaStreamGraphImpl::UpdateStreamOrder() { - nsTArray > oldStreams; - oldStreams.SwapElements(mStreams); - for (uint32_t i = 0; i < oldStreams.Length(); ++i) { - MediaStream* stream = oldStreams[i]; + mOldStreams.SwapElements(mStreams); + mStreams.ClearAndRetainStorage(); + for (uint32_t i = 0; i < mOldStreams.Length(); ++i) { + MediaStream* stream = mOldStreams[i]; stream->mHasBeenOrdered = false; stream->mIsConsumed = false; stream->mIsOnOrderingStack = false; @@ -504,8 +504,8 @@ MediaStreamGraphImpl::UpdateStreamOrder() } nsAutoTArray stack; - for (uint32_t i = 0; i < oldStreams.Length(); ++i) { - nsRefPtr& s = oldStreams[i]; + for (uint32_t i = 0; i < mOldStreams.Length(); ++i) { + nsRefPtr& s = mOldStreams[i]; if (!s->mAudioOutputs.IsEmpty() || !s->mVideoOutputs.IsEmpty()) { MarkConsumed(s); } diff --git a/content/media/MediaStreamGraphImpl.h b/content/media/MediaStreamGraphImpl.h index 628c1f5525a..4a1f4c8ed47 100644 --- a/content/media/MediaStreamGraphImpl.h +++ b/content/media/MediaStreamGraphImpl.h @@ -370,6 +370,11 @@ public: // is not running and this state can be used from the main thread. nsTArray > mStreams; + /** + * mOldStreams is used as temporary storage for streams when computing the + * order in which we compute them. + */ + nsTArray > mOldStreams; /** * The current graph time for the current iteration of the RunThread control * loop. diff --git a/xpcom/glue/nsTArray.h b/xpcom/glue/nsTArray.h index 06a6ae64f3a..3a386477005 100644 --- a/xpcom/glue/nsTArray.h +++ b/xpcom/glue/nsTArray.h @@ -1042,6 +1042,20 @@ public: // // Mutation methods // + // This method call the destructor on each element of the array, empties it, + // but does not shrink the array's capacity. + // + // Make sure to call Compact() if needed to avoid keeping a huge array + // around. + void ClearAndRetainStorage() { + if (base_type::mHdr == EmptyHdr()) { + return; + } + + DestructRange(0, Length()); + base_type::mHdr->mLength = 0; + } + // This method replaces a range of elements in this array. // @param start The starting index of the elements to replace. From 8b65e8ec62d1fe7b0e0b89a59049b34421e86350 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 19 Jul 2013 16:40:57 +0200 Subject: [PATCH 15/58] Bug 882543 - Actually run offline MSG offline. r=roc --- content/media/MediaStreamGraph.cpp | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/content/media/MediaStreamGraph.cpp b/content/media/MediaStreamGraph.cpp index f3facb4c428..a750f714b86 100644 --- a/content/media/MediaStreamGraph.cpp +++ b/content/media/MediaStreamGraph.cpp @@ -313,20 +313,30 @@ MediaStreamGraphImpl::GetAudioPosition(MediaStream* aStream) void MediaStreamGraphImpl::UpdateCurrentTime() { - GraphTime prevCurrentTime = mCurrentTime; - TimeStamp now = TimeStamp::Now(); - GraphTime nextCurrentTime = - SecondsToMediaTime((now - mCurrentTimeStamp).ToSeconds()) + mCurrentTime; + GraphTime prevCurrentTime, nextCurrentTime; + if (mRealtime) { + TimeStamp now = TimeStamp::Now(); + prevCurrentTime = mCurrentTime; + nextCurrentTime = + SecondsToMediaTime((now - mCurrentTimeStamp).ToSeconds()) + mCurrentTime; + + mCurrentTimeStamp = now; + LOG(PR_LOG_DEBUG+1, ("Updating current time to %f (real %f, mStateComputedTime %f)", + MediaTimeToSeconds(nextCurrentTime), + (now - mInitialTimeStamp).ToSeconds(), + MediaTimeToSeconds(mStateComputedTime))); + } else { + prevCurrentTime = mCurrentTime; + nextCurrentTime = mCurrentTime + MEDIA_GRAPH_TARGET_PERIOD_MS; + LOG(PR_LOG_DEBUG+1, ("Updating offline current time to %f (mStateComputedTime %f)", + MediaTimeToSeconds(nextCurrentTime), + MediaTimeToSeconds(mStateComputedTime))); + } + if (mStateComputedTime < nextCurrentTime) { LOG(PR_LOG_WARNING, ("Media graph global underrun detected")); nextCurrentTime = mStateComputedTime; } - mCurrentTimeStamp = now; - - LOG(PR_LOG_DEBUG+1, ("Updating current time to %f (real %f, mStateComputedTime %f)", - MediaTimeToSeconds(nextCurrentTime), - (now - mInitialTimeStamp).ToSeconds(), - MediaTimeToSeconds(mStateComputedTime))); if (prevCurrentTime >= nextCurrentTime) { NS_ASSERTION(prevCurrentTime == nextCurrentTime, "Time can't go backwards!"); From a9cb9340ab343f419cbba03c64d53163d82769cd Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 19 Jul 2013 16:40:57 +0200 Subject: [PATCH 16/58] Bug 882543 - Don't spam the main thread when rendering an offline graph. r=ehsan,roc --- content/media/MediaStreamGraph.cpp | 53 +++++++++++++++++++--------- content/media/MediaStreamGraphImpl.h | 10 ++++++ 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/content/media/MediaStreamGraph.cpp b/content/media/MediaStreamGraph.cpp index a750f714b86..eed493eedc1 100644 --- a/content/media/MediaStreamGraph.cpp +++ b/content/media/MediaStreamGraph.cpp @@ -898,28 +898,47 @@ MediaStreamGraphImpl::PlayVideo(MediaStream* aStream) } } +bool +MediaStreamGraphImpl::ShouldUpdateMainThread() +{ + if (mRealtime) { + return true; + } + + TimeStamp now = TimeStamp::Now(); + if ((now - mLastMainThreadUpdate).ToMilliseconds() > MEDIA_GRAPH_TARGET_PERIOD_MS) { + mLastMainThreadUpdate = now; + return true; + } + return false; +} + void MediaStreamGraphImpl::PrepareUpdatesToMainThreadState(bool aFinalUpdate) { mMonitor.AssertCurrentThreadOwns(); - mStreamUpdates.SetCapacity(mStreamUpdates.Length() + mStreams.Length()); - for (uint32_t i = 0; i < mStreams.Length(); ++i) { - MediaStream* stream = mStreams[i]; - if (!stream->MainThreadNeedsUpdates()) { - continue; + // We don't want to update the main thread about timing update when we are not + // running in realtime. + if (ShouldUpdateMainThread()) { + mStreamUpdates.SetCapacity(mStreamUpdates.Length() + mStreams.Length()); + for (uint32_t i = 0; i < mStreams.Length(); ++i) { + MediaStream* stream = mStreams[i]; + if (!stream->MainThreadNeedsUpdates()) { + continue; + } + StreamUpdate* update = mStreamUpdates.AppendElement(); + update->mGraphUpdateIndex = stream->mGraphUpdateIndices.GetAt(mCurrentTime); + update->mStream = stream; + update->mNextMainThreadCurrentTime = + GraphTimeToStreamTime(stream, mCurrentTime); + update->mNextMainThreadFinished = + stream->mFinished && + StreamTimeToGraphTime(stream, stream->GetBufferEnd()) <= mCurrentTime; + } + if (!mPendingUpdateRunnables.IsEmpty()) { + mUpdateRunnables.MoveElementsFrom(mPendingUpdateRunnables); } - StreamUpdate* update = mStreamUpdates.AppendElement(); - update->mGraphUpdateIndex = stream->mGraphUpdateIndices.GetAt(mCurrentTime); - update->mStream = stream; - update->mNextMainThreadCurrentTime = - GraphTimeToStreamTime(stream, mCurrentTime); - update->mNextMainThreadFinished = - stream->mFinished && - StreamTimeToGraphTime(stream, stream->GetBufferEnd()) <= mCurrentTime; - } - if (!mPendingUpdateRunnables.IsEmpty()) { - mUpdateRunnables.MoveElementsFrom(mPendingUpdateRunnables); } // Don't send the message to the main thread if it's not going to have @@ -2178,7 +2197,7 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(bool aRealtime) } #endif - mCurrentTimeStamp = mInitialTimeStamp = TimeStamp::Now(); + mCurrentTimeStamp = mInitialTimeStamp = mLastMainThreadUpdate = TimeStamp::Now(); } NS_IMPL_ISUPPORTS1(MediaStreamGraphShutdownObserver, nsIObserver) diff --git a/content/media/MediaStreamGraphImpl.h b/content/media/MediaStreamGraphImpl.h index 4a1f4c8ed47..dcc9ba719aa 100644 --- a/content/media/MediaStreamGraphImpl.h +++ b/content/media/MediaStreamGraphImpl.h @@ -190,6 +190,12 @@ public: * mMonitor must be held. */ void PrepareUpdatesToMainThreadState(bool aFinalUpdate); + /** + * If we are rendering in non-realtime mode, we don't want to send messages to + * the main thread at each iteration for performance reasons. We instead + * notify the main thread at the same rate + */ + bool ShouldUpdateMainThread(); // The following methods are the various stages of RunThread processing. /** * Compute a new current time for the graph and advance all on-graph-thread @@ -394,6 +400,10 @@ public: * The real timestamp of the latest run of UpdateCurrentTime. */ TimeStamp mCurrentTimeStamp; + /** + * Date of the last time we updated the main thread with the graph state. + */ + TimeStamp mLastMainThreadUpdate; /** * Which update batch we are currently processing. */ From 20dac73d80d179ce0f7488549e1c77999bee92f8 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 19 Jul 2013 16:40:57 +0200 Subject: [PATCH 17/58] Bug 882543 - Register the MSG thread for in the profiler. r=benwa --- content/media/MediaStreamGraph.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/content/media/MediaStreamGraph.cpp b/content/media/MediaStreamGraph.cpp index eed493eedc1..994c245e35b 100644 --- a/content/media/MediaStreamGraph.cpp +++ b/content/media/MediaStreamGraph.cpp @@ -23,6 +23,7 @@ #include "AudioNodeStream.h" #include #include "DOMMediaStream.h" +#include "GeckoProfiler.h" using namespace mozilla::layers; using namespace mozilla::dom; @@ -1201,6 +1202,7 @@ MediaStreamGraphImpl::RunThread() if (!mRealtime) { mNonRealtimeIsRunning = false; } + profiler_unregister_thread(); } void @@ -1246,6 +1248,23 @@ MediaStreamGraphImpl::ForceShutDown() namespace { +class MediaStreamGraphInitThreadRunnable : public nsRunnable { +public: + explicit MediaStreamGraphInitThreadRunnable(MediaStreamGraphImpl* aGraph) + : mGraph(aGraph) + { + } + NS_IMETHOD Run() + { + char aLocal; + profiler_register_thread("MediaStreamGraph", &aLocal); + mGraph->RunThread(); + return NS_OK; + } +private: + MediaStreamGraphImpl* mGraph; +}; + class MediaStreamGraphThreadRunnable : public nsRunnable { public: explicit MediaStreamGraphThreadRunnable(MediaStreamGraphImpl* aGraph) @@ -1385,7 +1404,7 @@ MediaStreamGraphImpl::RunInStableState() // Start the thread now. We couldn't start it earlier because // the graph might exit immediately on finding it has no streams. The // first message for a new graph must create a stream. - nsCOMPtr event = new MediaStreamGraphThreadRunnable(this); + nsCOMPtr event = new MediaStreamGraphInitThreadRunnable(this); NS_NewNamedThread("MediaStreamGrph", getter_AddRefs(mThread), event); } From ccf69241ce67f8ce1215619ee68f0456d17747ad Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 19 Jul 2013 16:40:58 +0200 Subject: [PATCH 18/58] Bug 882543 - Use a linked list for ordering stream instead of an array. r=ehsan --- content/media/MediaStreamGraph.cpp | 19 ++++++++++--------- content/media/MediaStreamGraph.h | 3 ++- content/media/MediaStreamGraphImpl.h | 5 ++++- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/content/media/MediaStreamGraph.cpp b/content/media/MediaStreamGraph.cpp index 994c245e35b..d323f5758cb 100644 --- a/content/media/MediaStreamGraph.cpp +++ b/content/media/MediaStreamGraph.cpp @@ -4,6 +4,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "MediaStreamGraphImpl.h" +#include "mozilla/LinkedList.h" #include "AudioSegment.h" #include "VideoSegment.h" @@ -465,22 +466,22 @@ MediaStreamGraphImpl::MarkConsumed(MediaStream* aStream) } void -MediaStreamGraphImpl::UpdateStreamOrderForStream(nsTArray* aStack, +MediaStreamGraphImpl::UpdateStreamOrderForStream(mozilla::LinkedList* aStack, already_AddRefed aStream) { nsRefPtr stream = aStream; NS_ASSERTION(!stream->mHasBeenOrdered, "stream should not have already been ordered"); if (stream->mIsOnOrderingStack) { - for (int32_t i = aStack->Length() - 1; ; --i) { - aStack->ElementAt(i)->AsProcessedStream()->mInCycle = true; - if (aStack->ElementAt(i) == stream) - break; - } + MediaStream* iter = aStack->getLast(); + do { + iter->AsProcessedStream()->mInCycle = true; + iter = iter->getPrevious(); + } while (iter != stream); return; } ProcessedMediaStream* ps = stream->AsProcessedStream(); if (ps) { - aStack->AppendElement(stream); + aStack->insertBack(stream); stream->mIsOnOrderingStack = true; for (uint32_t i = 0; i < ps->mInputs.Length(); ++i) { MediaStream* source = ps->mInputs[i]->mSource; @@ -489,7 +490,7 @@ MediaStreamGraphImpl::UpdateStreamOrderForStream(nsTArray* aStack, UpdateStreamOrderForStream(aStack, s.forget()); } } - aStack->RemoveElementAt(aStack->Length() - 1); + aStack->popLast(); stream->mIsOnOrderingStack = false; } @@ -514,7 +515,7 @@ MediaStreamGraphImpl::UpdateStreamOrder() } } - nsAutoTArray stack; + mozilla::LinkedList stack; for (uint32_t i = 0; i < mOldStreams.Length(); ++i) { nsRefPtr& s = mOldStreams[i]; if (!s->mAudioOutputs.IsEmpty() || !s->mVideoOutputs.IsEmpty()) { diff --git a/content/media/MediaStreamGraph.h b/content/media/MediaStreamGraph.h index 9cf5df5459b..2465e673780 100644 --- a/content/media/MediaStreamGraph.h +++ b/content/media/MediaStreamGraph.h @@ -7,6 +7,7 @@ #define MOZILLA_MEDIASTREAMGRAPH_H_ #include "mozilla/Mutex.h" +#include "mozilla/LinkedList.h" #include "AudioStream.h" #include "nsTArray.h" #include "nsIRunnable.h" @@ -257,7 +258,7 @@ struct AudioChunk; * for those objects in arbitrary order and the MediaStreamGraph has to be able * to handle this. */ -class MediaStream { +class MediaStream : public mozilla::LinkedListElement { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaStream) diff --git a/content/media/MediaStreamGraphImpl.h b/content/media/MediaStreamGraphImpl.h index dcc9ba719aa..695fb5f1239 100644 --- a/content/media/MediaStreamGraphImpl.h +++ b/content/media/MediaStreamGraphImpl.h @@ -15,6 +15,9 @@ namespace mozilla { +template +class LinkedList; + #ifdef PR_LOGGING extern PRLogModuleInfo* gMediaStreamGraphLog; #define LOG(type, msg) PR_LOG(gMediaStreamGraphLog, type, msg) @@ -221,7 +224,7 @@ public: * If aStream hasn't already been ordered, push it onto aStack and order * its children. */ - void UpdateStreamOrderForStream(nsTArray* aStack, + void UpdateStreamOrderForStream(mozilla::LinkedList* aStack, already_AddRefed aStream); /** * Mark aStream and all its inputs (recursively) as consumed. From c63953ed615c5729b3e4cac452987ae71ea73a9e Mon Sep 17 00:00:00 2001 From: Simon Montagu Date: Fri, 19 Jul 2013 17:44:46 +0300 Subject: [PATCH 19/58] Move the caret invalidation from CharacterDataChanged to CharacterDataWillChange so that the text doesn't change under the caret before invalidation. Bug 887631, r=ehsan --- layout/base/nsPresShell.cpp | 23 ++++++++++++++++++----- layout/base/nsPresShell.h | 1 + 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 312dd4bfade..6ad0c590fff 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -3917,15 +3917,13 @@ PresShell::FlushPendingNotifications(mozilla::ChangesToFlush aFlush) } void -PresShell::CharacterDataChanged(nsIDocument *aDocument, - nsIContent* aContent, - CharacterDataChangeInfo* aInfo) +PresShell::CharacterDataWillChange(nsIDocument *aDocument, + nsIContent* aContent, + CharacterDataChangeInfo* aInfo) { NS_PRECONDITION(!mIsDocumentGone, "Unexpected CharacterDataChanged"); NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument"); - nsAutoCauseReflowNotifier crNotifier(this); - if (mCaret) { // Invalidate the caret's current location before we call into the frame // constructor. It is important to do this now, and not wait until the @@ -3933,8 +3931,23 @@ PresShell::CharacterDataChanged(nsIDocument *aDocument, // text frame the caret is in to forget what part of the content they // refer to, making it hard for them to return the correct continuation // frame to the caret. + // + // It's also important to do this before the content actually changes, since + // in bidi text the caret needs to look at the content to determine its + // position and shape. mCaret->InvalidateOutsideCaret(); } +} + +void +PresShell::CharacterDataChanged(nsIDocument *aDocument, + nsIContent* aContent, + CharacterDataChangeInfo* aInfo) +{ + NS_PRECONDITION(!mIsDocumentGone, "Unexpected CharacterDataChanged"); + NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument"); + + nsAutoCauseReflowNotifier crNotifier(this); // Call this here so it only happens for real content mutations and // not cases when the frame constructor calls its own methods to force diff --git a/layout/base/nsPresShell.h b/layout/base/nsPresShell.h index 4dbb48be7ed..bae0a07295a 100644 --- a/layout/base/nsPresShell.h +++ b/layout/base/nsPresShell.h @@ -251,6 +251,7 @@ public: NS_DECL_NSIDOCUMENTOBSERVER_STYLERULEREMOVED // nsIMutationObserver + NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATAWILLCHANGE NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED From 324fb85dbe3683efff96cc51b64911ff8c71042c Mon Sep 17 00:00:00 2001 From: Douglas Crosher Date: Fri, 19 Jul 2013 20:42:38 +1000 Subject: [PATCH 20/58] Bug 895830 - OdinMonkey: fix compilation of the perf spewer support. r=luke --- js/src/ion/AsmJS.cpp | 8 ++++---- js/src/ion/AsmJSLink.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/js/src/ion/AsmJS.cpp b/js/src/ion/AsmJS.cpp index 4f50c0666e1..c944a5b6614 100644 --- a/js/src/ion/AsmJS.cpp +++ b/js/src/ion/AsmJS.cpp @@ -1452,14 +1452,14 @@ class MOZ_STACK_CLASS ModuleCompiler #ifdef JS_ION_PERF bool trackPerfProfiledFunction(const Func &func, unsigned endCodeOffset) { unsigned lineno = 0U, columnIndex = 0U; - tokenStream_.srcCoords.lineNumAndColumnIndex(func.srcOffset(), &lineno, &columnIndex); + parser().tokenStream.srcCoords.lineNumAndColumnIndex(func.srcOffset(), &lineno, &columnIndex); - unsigned startCodeOffset = func.codeLabel()->offset(); + unsigned startCodeOffset = func.code()->offset(); return module_->trackPerfProfiledFunction(func.name(), startCodeOffset, endCodeOffset, lineno, columnIndex); } bool trackPerfProfiledBlocks(AsmJSPerfSpewer &perfSpewer, const Func &func, unsigned endCodeOffset) { - unsigned startCodeOffset = func.codeLabel()->offset(); + unsigned startCodeOffset = func.code()->offset(); perfSpewer.noteBlocksOffsets(masm_); return module_->trackPerfProfiledBlocks(func.name(), startCodeOffset, endCodeOffset, perfSpewer.basicBlocks()); } @@ -4788,7 +4788,7 @@ GenerateCode(ModuleCompiler &m, ModuleCompiler::Func &func, MIRGenerator &mir, L #ifdef JS_ION_PERF if (PerfBlockEnabled()) { - if (!m.trackPerfProfiledBlocks(mirGen.perfSpewer(), func, m.masm().size())) + if (!m.trackPerfProfiledBlocks(mir.perfSpewer(), func, m.masm().size())) return false; } else if (PerfFuncEnabled()) { if (!m.trackPerfProfiledFunction(func, m.masm().size())) diff --git a/js/src/ion/AsmJSLink.cpp b/js/src/ion/AsmJSLink.cpp index f5ee7174c72..8393f472ec6 100644 --- a/js/src/ion/AsmJSLink.cpp +++ b/js/src/ion/AsmJSLink.cpp @@ -492,7 +492,7 @@ SendFunctionsToPerf(JSContext *cx, AsmJSModule &module) unsigned long base = (unsigned long) module.functionCode(); const AsmJSModule::PostLinkFailureInfo &info = module.postLinkFailureInfo(); - const char *filename = const_cast(info.scriptSource_->filename()); + const char *filename = const_cast(info.scriptSource->filename()); for (unsigned i = 0; i < module.numPerfFunctions(); i++) { const AsmJSModule::ProfiledFunction &func = module.perfProfiledFunction(i); @@ -527,7 +527,7 @@ SendBlocksToPerf(JSContext *cx, AsmJSModule &module) unsigned long funcBaseAddress = (unsigned long) module.functionCode(); const AsmJSModule::PostLinkFailureInfo &info = module.postLinkFailureInfo(); - const char *filename = const_cast(info.scriptSource_->filename()); + const char *filename = const_cast(info.scriptSource->filename()); for (unsigned i = 0; i < module.numPerfBlocksFunctions(); i++) { const AsmJSModule::ProfiledBlocksFunction &func = module.perfProfiledBlocksFunction(i); From 83c09139220c6f301078c3a8d5dbd1ca4176e951 Mon Sep 17 00:00:00 2001 From: Gervase Markham Date: Fri, 19 Jul 2013 16:08:33 +0100 Subject: [PATCH 21/58] Bug 715549 - remove last vestiges of tri-licence. DONTBUILD. --- build/macosx/universal/unify | 2 +- build/package/mac_osx/pkg-dmg | 2 +- build/pgo/js-input/string-base64.html | 40 ++--------------- .../css/nsIDOMCSSFontFeatureValuesRule.idl | 38 ++-------------- gfx/thebes/gfxSVGGlyphs.cpp | 38 ++-------------- gfx/thebes/gfxSVGGlyphs.h | 38 ++-------------- image/public/imgIOnloadBlocker.idl | 38 ++-------------- intl/locales/af/hyphenation/LICENSE | 39 ++-------------- intl/locales/bg/hyphenation/LICENSE | 39 ++-------------- intl/locales/ca/hyphenation/LICENSE | 39 ++-------------- intl/locales/cy/hyphenation/LICENSE | 39 ++-------------- intl/locales/da/hyphenation/LICENSE | 39 ++-------------- intl/locales/de-1901/hyphenation/LICENSE | 39 ++-------------- intl/locales/de-1996/hyphenation/LICENSE | 38 ++-------------- intl/locales/de-CH/hyphenation/LICENSE | 39 ++-------------- intl/locales/eo/hyphenation/LICENSE | 39 ++-------------- intl/locales/es/hyphenation/LICENSE | 39 ++-------------- intl/locales/et/hyphenation/LICENSE | 39 ++-------------- intl/locales/gl/hyphenation/LICENSE | 39 ++-------------- intl/locales/hr/hyphenation/LICENSE | 39 ++-------------- intl/locales/hsb/hyphenation/LICENSE | 39 ++-------------- intl/locales/hu/hyphenation/LICENSE | 39 ++-------------- intl/locales/ia/hyphenation/LICENSE | 39 ++-------------- intl/locales/is/hyphenation/LICENSE | 44 ++----------------- intl/locales/it/hyphenation/LICENSE | 39 ++-------------- intl/locales/kmr/hyphenation/LICENSE | 39 ++-------------- intl/locales/la/hyphenation/LICENSE | 38 ++-------------- intl/locales/lt/hyphenation/LICENSE | 38 ++-------------- intl/locales/mn/hyphenation/LICENSE | 39 ++-------------- intl/locales/nl/hyphenation/LICENSE | 39 ++-------------- intl/locales/pt/hyphenation/LICENSE | 38 ++-------------- intl/locales/ru/hyphenation/LICENSE | 38 ++-------------- intl/locales/sh/hyphenation/LICENSE | 39 ++-------------- intl/locales/sl/hyphenation/LICENSE | 39 ++-------------- intl/locales/sv/hyphenation/LICENSE | 39 ++-------------- intl/locales/tr/hyphenation/LICENSE | 38 ++-------------- intl/locales/uk/hyphenation/LICENSE | 39 ++-------------- js/xpconnect/tests/unit/test_tearoffs.js | 38 ++-------------- media/mtransport/third_party/Makefile.in | 39 ++-------------- media/webrtc/webrtc-config.mk | 38 ++-------------- testing/mozbase/mozlog/setup.py | 6 +-- widget/nsIWidgetListener.h | 37 ++-------------- 42 files changed, 122 insertions(+), 1401 deletions(-) diff --git a/build/macosx/universal/unify b/build/macosx/universal/unify index 81f27021850..82b24560f41 100755 --- a/build/macosx/universal/unify +++ b/build/macosx/universal/unify @@ -139,7 +139,7 @@ recommended. =head1 LICENSE -MPL 1.1/GPL 2.0/LGPL 2.1. Your choice +MPL 2. =head1 AUTHOR diff --git a/build/package/mac_osx/pkg-dmg b/build/package/mac_osx/pkg-dmg index 9e8728a1af6..d3b27da7dcd 100755 --- a/build/package/mac_osx/pkg-dmg +++ b/build/package/mac_osx/pkg-dmg @@ -225,7 +225,7 @@ later are recommended. =head1 LICENSE -MPL 1.1/GPL 2.0/LGPL 2.1. Your choice. +MPL 2. =head1 AUTHOR diff --git a/build/pgo/js-input/string-base64.html b/build/pgo/js-input/string-base64.html index a09439b533c..53280ef2bb5 100644 --- a/build/pgo/js-input/string-base64.html +++ b/build/pgo/js-input/string-base64.html @@ -38,43 +38,9 @@ var _sunSpiderStartDate = new Date(); -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla XML-RPC Client component. - * - * The Initial Developer of the Original Code is - * Digital Creations 2, Inc. - * Portions created by the Initial Developer are Copyright (C) 2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Martijn Pieters (original author) - * Samuel Sieb - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // From: http://lxr.mozilla.org/mozilla/source/extensions/xml-rpc/src/nsXmlRpcClient.js#956 diff --git a/dom/interfaces/css/nsIDOMCSSFontFeatureValuesRule.idl b/dom/interfaces/css/nsIDOMCSSFontFeatureValuesRule.idl index 1347d5a1c38..2575d0c42ee 100644 --- a/dom/interfaces/css/nsIDOMCSSFontFeatureValuesRule.idl +++ b/dom/interfaces/css/nsIDOMCSSFontFeatureValuesRule.idl @@ -1,39 +1,7 @@ /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2004 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * John Daggett (original author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsIDOMCSSRule.idl" diff --git a/gfx/thebes/gfxSVGGlyphs.cpp b/gfx/thebes/gfxSVGGlyphs.cpp index d7e0f2f5c2b..ed9533354c4 100644 --- a/gfx/thebes/gfxSVGGlyphs.cpp +++ b/gfx/thebes/gfxSVGGlyphs.cpp @@ -1,38 +1,6 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla Foundation code. - * - * The Initial Developer of the Original Code is the Mozilla Foundation - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Edwin Flores - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "gfxSVGGlyphs.h" diff --git a/gfx/thebes/gfxSVGGlyphs.h b/gfx/thebes/gfxSVGGlyphs.h index 6255dcc4104..9c5d3ce32a7 100644 --- a/gfx/thebes/gfxSVGGlyphs.h +++ b/gfx/thebes/gfxSVGGlyphs.h @@ -1,38 +1,6 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla Foundation code. - * - * The Initial Developer of the Original Code is the Mozilla Foundation - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Edwin Flores - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef GFX_SVG_GLYPHS_WRAPPER_H #define GFX_SVG_GLYPHS_WRAPPER_H diff --git a/image/public/imgIOnloadBlocker.idl b/image/public/imgIOnloadBlocker.idl index f2c31bcaffb..c4075330d02 100644 --- a/image/public/imgIOnloadBlocker.idl +++ b/image/public/imgIOnloadBlocker.idl @@ -1,40 +1,8 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2012 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Kyle Huey (original author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsISupports.idl" diff --git a/intl/locales/af/hyphenation/LICENSE b/intl/locales/af/hyphenation/LICENSE index 7e897854e5d..aac400af207 100644 --- a/intl/locales/af/hyphenation/LICENSE +++ b/intl/locales/af/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_af.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/bg/hyphenation/LICENSE b/intl/locales/bg/hyphenation/LICENSE index ca46143cd32..113086aed5a 100644 --- a/intl/locales/bg/hyphenation/LICENSE +++ b/intl/locales/bg/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_bg.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/ca/hyphenation/LICENSE b/intl/locales/ca/hyphenation/LICENSE index cdd04333a8e..569aab43b4b 100644 --- a/intl/locales/ca/hyphenation/LICENSE +++ b/intl/locales/ca/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_ca.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/cy/hyphenation/LICENSE b/intl/locales/cy/hyphenation/LICENSE index 2a863b99d8c..d2842acba41 100644 --- a/intl/locales/cy/hyphenation/LICENSE +++ b/intl/locales/cy/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_cy.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/da/hyphenation/LICENSE b/intl/locales/da/hyphenation/LICENSE index 98c926d25a5..d7b4fc53e4d 100644 --- a/intl/locales/da/hyphenation/LICENSE +++ b/intl/locales/da/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_da.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/de-1901/hyphenation/LICENSE b/intl/locales/de-1901/hyphenation/LICENSE index 0a06cc5ac24..7b75870fe02 100644 --- a/intl/locales/de-1901/hyphenation/LICENSE +++ b/intl/locales/de-1901/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_de-1901.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/de-1996/hyphenation/LICENSE b/intl/locales/de-1996/hyphenation/LICENSE index 98f2b3f03b4..aa406926c66 100644 --- a/intl/locales/de-1996/hyphenation/LICENSE +++ b/intl/locales/de-1996/hyphenation/LICENSE @@ -3,42 +3,10 @@ License information for hyph_de-1996.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/de-CH/hyphenation/LICENSE b/intl/locales/de-CH/hyphenation/LICENSE index 6d7e281358a..3ce9d0ea6a6 100644 --- a/intl/locales/de-CH/hyphenation/LICENSE +++ b/intl/locales/de-CH/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_de-CH.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/eo/hyphenation/LICENSE b/intl/locales/eo/hyphenation/LICENSE index 59f90c3d982..1e4e83cb7c1 100644 --- a/intl/locales/eo/hyphenation/LICENSE +++ b/intl/locales/eo/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_eo.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/es/hyphenation/LICENSE b/intl/locales/es/hyphenation/LICENSE index efabf2c7484..2db4d80c495 100644 --- a/intl/locales/es/hyphenation/LICENSE +++ b/intl/locales/es/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_es.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/et/hyphenation/LICENSE b/intl/locales/et/hyphenation/LICENSE index 8caca7e57e4..626f47c5e6a 100644 --- a/intl/locales/et/hyphenation/LICENSE +++ b/intl/locales/et/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_et.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/gl/hyphenation/LICENSE b/intl/locales/gl/hyphenation/LICENSE index 2a5ccfcd5cb..6cd3b01121e 100644 --- a/intl/locales/gl/hyphenation/LICENSE +++ b/intl/locales/gl/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_gl.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/hr/hyphenation/LICENSE b/intl/locales/hr/hyphenation/LICENSE index fb6c7317360..208eebe20e3 100644 --- a/intl/locales/hr/hyphenation/LICENSE +++ b/intl/locales/hr/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_hr.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/hsb/hyphenation/LICENSE b/intl/locales/hsb/hyphenation/LICENSE index c3294dd4350..f72fd2464c4 100644 --- a/intl/locales/hsb/hyphenation/LICENSE +++ b/intl/locales/hsb/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_hsb.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/hu/hyphenation/LICENSE b/intl/locales/hu/hyphenation/LICENSE index 02a55abb3f2..10df00eedcc 100644 --- a/intl/locales/hu/hyphenation/LICENSE +++ b/intl/locales/hu/hyphenation/LICENSE @@ -5,40 +5,7 @@ by processing the TeX hyphenation patterns with substrings.pl. % Huhyphn - hungarian hyphenation patterns v20110815 % -% ***** BEGIN LICENSE BLOCK ***** -% Version: MPL 1.1/GPL 2.0/LGPL 2.1 -% -% The contents of this file are subject to the Mozilla Public License Version -% 1.1 (the "License"); you may not use this file except in compliance with -% the License. You may obtain a copy of the License at -% http://www.mozilla.org/MPL/ -% -% Software distributed under the License is distributed on an "AS IS" basis, -% WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -% for the specific language governing rights and limitations under the -% License. -% -% The Original Code is the Huhyphn - hungarian hyphenation patterns. -% -% The Initial Developer of the Original Code is -% Bence Nagy. -% Portions created by the Initial Developer are Copyright (C) 2003 -% the Initial Developer. All Rights Reserved. -% -% Contributor(s): -% Bence Nagy -% -% Alternatively, the contents of this file may be used under the terms of -% either the GNU General Public License Version 2 or later (the "GPL"), or -% the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -% in which case the provisions of the GPL or the LGPL are applicable instead -% of those above. If you wish to allow use of your version of this file only -% under the terms of either the GPL or the LGPL, and not to allow others to -% use your version of this file under the terms of the MPL, indicate your -% decision by deleting the provisions above and replace them with the notice -% and other provisions required by the GPL or the LGPL. If you do not delete -% the provisions above, a recipient may use your version of this file under -% the terms of any one of the MPL, the GPL or the LGPL. -% -% ***** END LICENSE BLOCK ***** +% This Source Code Form is subject to the terms of the Mozilla Public +% License, v. 2.0. If a copy of the MPL was not distributed with this +% file, You can obtain one at http://mozilla.org/MPL/2.0/. % diff --git a/intl/locales/ia/hyphenation/LICENSE b/intl/locales/ia/hyphenation/LICENSE index 0bd5aa6d1a4..0d31e126e2a 100644 --- a/intl/locales/ia/hyphenation/LICENSE +++ b/intl/locales/ia/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_ia.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/is/hyphenation/LICENSE b/intl/locales/is/hyphenation/LICENSE index dfe16bf30ed..8c9026179c0 100644 --- a/intl/locales/is/hyphenation/LICENSE +++ b/intl/locales/is/hyphenation/LICENSE @@ -3,48 +3,10 @@ License information for hyph_is.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** - -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -At the time this file was first modified, a complete, unmodified copy of -the LPPL Work was available from: -http://tug.org/svn/texhyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns/?pathrev=580 +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/it/hyphenation/LICENSE b/intl/locales/it/hyphenation/LICENSE index f2bc28ba1c0..234f5d54296 100644 --- a/intl/locales/it/hyphenation/LICENSE +++ b/intl/locales/it/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_it.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/kmr/hyphenation/LICENSE b/intl/locales/kmr/hyphenation/LICENSE index 3c21ec49b5b..4a92360d015 100644 --- a/intl/locales/kmr/hyphenation/LICENSE +++ b/intl/locales/kmr/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_kmr.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/la/hyphenation/LICENSE b/intl/locales/la/hyphenation/LICENSE index fb081cfa329..363799e68a4 100644 --- a/intl/locales/la/hyphenation/LICENSE +++ b/intl/locales/la/hyphenation/LICENSE @@ -3,42 +3,10 @@ License information for hyph_la.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/lt/hyphenation/LICENSE b/intl/locales/lt/hyphenation/LICENSE index 6a057cd1456..5e8900622d5 100644 --- a/intl/locales/lt/hyphenation/LICENSE +++ b/intl/locales/lt/hyphenation/LICENSE @@ -3,42 +3,10 @@ License information for hyph_lt.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/mn/hyphenation/LICENSE b/intl/locales/mn/hyphenation/LICENSE index b1c0d882c84..9d493451405 100644 --- a/intl/locales/mn/hyphenation/LICENSE +++ b/intl/locales/mn/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_mn.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/nl/hyphenation/LICENSE b/intl/locales/nl/hyphenation/LICENSE index b5cec3d6ec7..e83289fd0ab 100644 --- a/intl/locales/nl/hyphenation/LICENSE +++ b/intl/locales/nl/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_nl.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/pt/hyphenation/LICENSE b/intl/locales/pt/hyphenation/LICENSE index 0c3234da6de..61938eddbd7 100644 --- a/intl/locales/pt/hyphenation/LICENSE +++ b/intl/locales/pt/hyphenation/LICENSE @@ -3,42 +3,10 @@ License information for hyph_pt.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/ru/hyphenation/LICENSE b/intl/locales/ru/hyphenation/LICENSE index f251d05a7c8..0e4d895bb85 100644 --- a/intl/locales/ru/hyphenation/LICENSE +++ b/intl/locales/ru/hyphenation/LICENSE @@ -3,42 +3,10 @@ License information for hyph_ru.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/sh/hyphenation/LICENSE b/intl/locales/sh/hyphenation/LICENSE index 8c4a213a1f7..ea67a9c2ac2 100644 --- a/intl/locales/sh/hyphenation/LICENSE +++ b/intl/locales/sh/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_sh.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/sl/hyphenation/LICENSE b/intl/locales/sl/hyphenation/LICENSE index cbdb40bdee7..d6e6ab0d741 100644 --- a/intl/locales/sl/hyphenation/LICENSE +++ b/intl/locales/sl/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_sl.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/sv/hyphenation/LICENSE b/intl/locales/sv/hyphenation/LICENSE index ca8f6822ae0..13c99c67261 100644 --- a/intl/locales/sv/hyphenation/LICENSE +++ b/intl/locales/sv/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_sv.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/tr/hyphenation/LICENSE b/intl/locales/tr/hyphenation/LICENSE index 38d8810aad0..44d9b96b12a 100644 --- a/intl/locales/tr/hyphenation/LICENSE +++ b/intl/locales/tr/hyphenation/LICENSE @@ -3,42 +3,10 @@ License information for hyph_tr.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/intl/locales/uk/hyphenation/LICENSE b/intl/locales/uk/hyphenation/LICENSE index ec20eccca62..bfdb034dff6 100644 --- a/intl/locales/uk/hyphenation/LICENSE +++ b/intl/locales/uk/hyphenation/LICENSE @@ -3,42 +3,9 @@ License information for hyph_uk.dic: This file is based on the TeX hyphenation patterns distributed under the LaTeX Project Public License (LPPL) as part of the hyph-utf8 package. -***** BEGIN LICENSE BLOCK ***** -Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -The contents of this file are subject to the Mozilla Public License Version -1.1 (the "License"); you may not use this file except in compliance with -the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -for the specific language governing rights and limitations under the -License. - -The Original Code is Mozilla hyphenation service. - -The Initial Developer of the Original Code is -Mozilla Foundation. -Portions created by the Initial Developer are Copyright (C) 2011 -the Initial Developer. All Rights Reserved. - -Contributor(s): - Jonathan Kew - -Alternatively, the contents of this file may be used under the terms of -either the GNU General Public License Version 2 or later (the "GPL"), or -the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -in which case the provisions of the GPL or the LGPL are applicable instead -of those above. If you wish to allow use of your version of this file only -under the terms of either the GPL or the LGPL, and not to allow others to -use your version of this file under the terms of the MPL, indicate your -decision by deleting the provisions above and replace them with the notice -and other provisions required by the GPL or the LGPL. If you do not delete -the provisions above, a recipient may use your version of this file under -the terms of any one of the MPL, the GPL or the LGPL. - -***** END LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/js/xpconnect/tests/unit/test_tearoffs.js b/js/xpconnect/tests/unit/test_tearoffs.js index 6dc6a07212e..02f0a632933 100644 --- a/js/xpconnect/tests/unit/test_tearoffs.js +++ b/js/xpconnect/tests/unit/test_tearoffs.js @@ -1,38 +1,6 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is XPConnect Test Code. - * - * The Initial Developer of the Original Code is The Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Bobby Holley - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ const Cc = Components.classes; const Ci = Components.interfaces; diff --git a/media/mtransport/third_party/Makefile.in b/media/mtransport/third_party/Makefile.in index b877809b811..478f151e04e 100644 --- a/media/mtransport/third_party/Makefile.in +++ b/media/mtransport/third_party/Makefile.in @@ -1,39 +1,6 @@ -# ***** BEGIN LICENSE BLOCK ***** -# Version: MPL 1.1/GPL 2.0/LGPL 2.1 -# -# The contents of this file are subject to the Mozilla Public License Version -# 1.1 (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# http://www.mozilla.org/MPL/ -# -# Software distributed under the License is distributed on an "AS IS" basis, -# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -# for the specific language governing rights and limitations under the -# License. -# -# The Original Code is Mozilla code. -# -# The Initial Developer of the Original Code is the Mozilla Foundation. -# Portions created by the Initial Developer are Copyright (C) 2010 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Chris Pearce -# Eric Rescorla -# -# Alternatively, the contents of this file may be used under the terms of -# either the GNU General Public License Version 2 or later (the "GPL"), or -# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -# in which case the provisions of the GPL or the LGPL are applicable instead -# of those above. If you wish to allow use of your version of this file only -# under the terms of either the GPL or the LGPL, and not to allow others to -# use your version of this file under the terms of the MPL, indicate your -# decision by deleting the provisions above and replace them with the notice -# and other provisions required by the GPL or the LGPL. If you do not delete -# the provisions above, a recipient may use your version of this file under -# the terms of any one of the MPL, the GPL or the LGPL. -# -# ***** END LICENSE BLOCK ***** +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. DEPTH = @DEPTH@ diff --git a/media/webrtc/webrtc-config.mk b/media/webrtc/webrtc-config.mk index 64a487ff99f..80390a10e22 100644 --- a/media/webrtc/webrtc-config.mk +++ b/media/webrtc/webrtc-config.mk @@ -1,38 +1,6 @@ -# ***** BEGIN LICENSE BLOCK ***** -# Version: MPL 1.1/GPL 2.0/LGPL 2.1 -# -# The contents of this file are subject to the Mozilla Public License Version -# 1.1 (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# http://www.mozilla.org/MPL/ -# -# Software distributed under the License is distributed on an "AS IS" basis, -# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -# for the specific language governing rights and limitations under the -# License. -# -# The Original Code is the Mozilla platform. -# -# The Initial Developer of the Original Code is -# the Mozilla Foundation . -# Portions created by the Initial Developer are Copyright (C) 2009 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# -# Alternatively, the contents of this file may be used under the terms of -# either the GNU General Public License Version 2 or later (the "GPL"), or -# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -# in which case the provisions of the GPL or the LGPL are applicable instead -# of those above. If you wish to allow use of your version of this file only -# under the terms of either the GPL or the LGPL, and not to allow others to -# use your version of this file under the terms of the MPL, indicate your -# decision by deleting the provisions above and replace them with the notice -# and other provisions required by the GPL or the LGPL. If you do not delete -# the provisions above, a recipient may use your version of this file under -# the terms of any one of the MPL, the GPL or the LGPL. -# -# ***** END LICENSE BLOCK ***** +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. ifndef INCLUDED_CONFIG_MK $(error Must include config.mk before this file.) diff --git a/testing/mozbase/mozlog/setup.py b/testing/mozbase/mozlog/setup.py index a0c027a03a0..f88f51cc621 100644 --- a/testing/mozbase/mozlog/setup.py +++ b/testing/mozbase/mozlog/setup.py @@ -24,15 +24,15 @@ setup(name=PACKAGE_NAME, author='Mozilla Automation and Testing Team', author_email='tools@lists.mozilla.org', url='https://wiki.mozilla.org/Auto-tools/Projects/MozBase', - license='MPL 1.1/GPL 2.0/LGPL 2.1', + license='MPL 2', packages=['mozlog'], zip_safe=False, platforms =['Any'], classifiers=['Development Status :: 4 - Beta', 'Environment :: Console', 'Intended Audience :: Developers', - 'License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1)', - 'Operating System :: OS Independent', + 'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)', + ' Operating System :: OS Independent', 'Topic :: Software Development :: Libraries :: Python Modules', ] ) diff --git a/widget/nsIWidgetListener.h b/widget/nsIWidgetListener.h index d3d16653608..3c99b43b58c 100644 --- a/widget/nsIWidgetListener.h +++ b/widget/nsIWidgetListener.h @@ -1,37 +1,6 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozila.org code. - * - * The Initial Developer of the Original Code is Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef nsIWidgetListener_h__ #define nsIWidgetListener_h__ From 5c25e99c40a4cffe00b148cc30ab07fe89bb70c3 Mon Sep 17 00:00:00 2001 From: Alexander Surkov Date: Fri, 19 Jul 2013 11:20:51 -0400 Subject: [PATCH 22/58] Bug 888247 - ARIA columnheader/rowheader shouldn't be selectable by default, r=tbsaunde --- accessible/src/base/ARIAMap.cpp | 4 +- accessible/src/base/ARIAStateMap.cpp | 10 +++++ accessible/src/base/ARIAStateMap.h | 1 + accessible/src/generic/ARIAGridAccessible.cpp | 4 +- accessible/tests/mochitest/table.js | 13 +++++-- .../mochitest/table/test_sels_ariagrid.html | 38 +++++++++++++++++-- 6 files changed, 58 insertions(+), 12 deletions(-) diff --git a/accessible/src/base/ARIAMap.cpp b/accessible/src/base/ARIAMap.cpp index af64f4a90e4..e8899b18492 100644 --- a/accessible/src/base/ARIAMap.cpp +++ b/accessible/src/base/ARIAMap.cpp @@ -112,7 +112,7 @@ static nsRoleMapEntry sWAIRoleMaps[] = eNoLiveAttr, eTableCell, kNoReqStates, - eARIASelectable, + eARIASelectableIfDefined, eARIAReadonlyOrEditableIfDefined }, { // combobox @@ -463,7 +463,7 @@ static nsRoleMapEntry sWAIRoleMaps[] = eNoLiveAttr, eTableCell, kNoReqStates, - eARIASelectable, + eARIASelectableIfDefined, eARIAReadonlyOrEditableIfDefined }, { // scrollbar diff --git a/accessible/src/base/ARIAStateMap.cpp b/accessible/src/base/ARIAStateMap.cpp index 6452ef971dd..61bd35dae34 100644 --- a/accessible/src/base/ARIAStateMap.cpp +++ b/accessible/src/base/ARIAStateMap.cpp @@ -300,6 +300,16 @@ aria::MapToState(EStateRule aRule, dom::Element* aElement, uint64_t* aState) return true; } + case eARIASelectableIfDefined: + { + static const TokenTypeData data( + nsGkAtoms::aria_selected, eBoolType, + states::SELECTABLE, states::SELECTED); + + MapTokenType(aElement, aState, data); + return true; + } + case eReadonlyUntilEditable: { if (!(*aState & states::EDITABLE)) diff --git a/accessible/src/base/ARIAStateMap.h b/accessible/src/base/ARIAStateMap.h index afb4401851c..65195979267 100644 --- a/accessible/src/base/ARIAStateMap.h +++ b/accessible/src/base/ARIAStateMap.h @@ -42,6 +42,7 @@ enum EStateRule eARIAReadonlyOrEditableIfDefined, eARIARequired, eARIASelectable, + eARIASelectableIfDefined, eReadonlyUntilEditable, eIndeterminateIfNoValue }; diff --git a/accessible/src/generic/ARIAGridAccessible.cpp b/accessible/src/generic/ARIAGridAccessible.cpp index ae69a1ac593..5250fa3d294 100644 --- a/accessible/src/generic/ARIAGridAccessible.cpp +++ b/accessible/src/generic/ARIAGridAccessible.cpp @@ -465,8 +465,8 @@ ARIAGridAccessible::SetARIASelected(Accessible* aAccessible, rv = content->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected, NS_LITERAL_STRING("true"), aNotify); else - rv = content->UnsetAttr(kNameSpaceID_None, - nsGkAtoms::aria_selected, aNotify); + rv = content->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected, + NS_LITERAL_STRING("false"), aNotify); NS_ENSURE_SUCCESS(rv, rv); diff --git a/accessible/tests/mochitest/table.js b/accessible/tests/mochitest/table.js index 46a2c4700d1..5bd37bd12ee 100644 --- a/accessible/tests/mochitest/table.js +++ b/accessible/tests/mochitest/table.js @@ -361,7 +361,8 @@ function testTableSelection(aIdentifier, aCellsArray, aMsg) for (var colIdx = 0; colIdx < colsCount; colIdx++) { var isColSelected = true; for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) { - if (aCellsArray[rowIdx][colIdx] == false) { + if (aCellsArray[rowIdx][colIdx] == false || + aCellsArray[rowIdx][colIdx] == undefined) { isColSelected = false; break; } @@ -401,7 +402,8 @@ function testTableSelection(aIdentifier, aCellsArray, aMsg) for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) { var isRowSelected = true; for (var colIdx = 0; colIdx < colsCount; colIdx++) { - if (aCellsArray[rowIdx][colIdx] == false) { + if (aCellsArray[rowIdx][colIdx] == false || + aCellsArray[rowIdx][colIdx] == undefined) { isRowSelected = false; break; } @@ -442,7 +444,8 @@ function testTableSelection(aIdentifier, aCellsArray, aMsg) if (aCellsArray[rowIdx][colIdx] & kSpanned) continue; - is(acc.isCellSelected(rowIdx, colIdx), aCellsArray[rowIdx][colIdx], + var isSelected = aCellsArray[rowIdx][colIdx] == true; + is(acc.isCellSelected(rowIdx, colIdx), isSelected, msg + "Wrong selection state of cell at " + rowIdx + " row and " + colIdx + " column for " + prettyName(aIdentifier)); @@ -496,7 +499,9 @@ function testTableSelection(aIdentifier, aCellsArray, aMsg) var cell = acc.getCellAt(rowIdx, colIdx); var isSel = aCellsArray[rowIdx][colIdx]; - if (isSel) + if (isSel == undefined) + testStates(cell, 0, 0, STATE_SELECTABLE | STATE_SELECTED); + else if (isSel == true) testStates(cell, STATE_SELECTED); else testStates(cell, STATE_SELECTABLE, 0, STATE_SELECTED); diff --git a/accessible/tests/mochitest/table/test_sels_ariagrid.html b/accessible/tests/mochitest/table/test_sels_ariagrid.html index 26eaea060c6..e8b08247101 100644 --- a/accessible/tests/mochitest/table/test_sels_ariagrid.html +++ b/accessible/tests/mochitest/table/test_sels_ariagrid.html @@ -54,6 +54,21 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=410052 testUnselectTableColumn("grid2", 0, cellsArray); testUnselectTableRow("grid2", 0, cellsArray); + ////////////////////////////////////////////////////////////////////////// + // ARIA grid (column and row headers) + + cellsArray = + [ + [ undefined, true, false], + [ undefined, true, false] + ]; + + testTableSelection("grid3", cellsArray); + testSelectTableColumn("grid3", 0, cellsArray); + testSelectTableRow("grid3", 0, cellsArray); + testUnselectTableColumn("grid3", 0, cellsArray); + testUnselectTableRow("grid3", 0, cellsArray); + SimpleTest.finish(); } @@ -65,10 +80,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=410052 Mozilla Bug 410052 + href="https://bugzilla.mozilla.org/show_bug.cgi?id=410052">Bug 410052 Mozilla Bug 513848 + href="https://bugzilla.mozilla.org/show_bug.cgi?id=513848">Bug 513848 + Bug 888247

@@ -112,8 +130,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=410052
- - + +
header1header2header1header2
@@ -127,5 +145,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=410052 +
+
+
col header1
+
col header2
+
col header3
+
+
+
row header1
+
row header2
+
row header3
+
+
From 6cb879edfa89682f9ed5b8ff3164df59314eba27 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 19 Jul 2013 11:22:40 -0400 Subject: [PATCH 23/58] Bug 894931. Add reftest. r=dbaron --- layout/reftests/bugs/894931-1-ref.html | 8 ++++++++ layout/reftests/bugs/894931-1.html | 15 +++++++++++++++ layout/reftests/bugs/reftest.list | 1 + 3 files changed, 24 insertions(+) create mode 100644 layout/reftests/bugs/894931-1-ref.html create mode 100644 layout/reftests/bugs/894931-1.html diff --git a/layout/reftests/bugs/894931-1-ref.html b/layout/reftests/bugs/894931-1-ref.html new file mode 100644 index 00000000000..bed8ffb61f9 --- /dev/null +++ b/layout/reftests/bugs/894931-1-ref.html @@ -0,0 +1,8 @@ + + + +
+
+
+ + diff --git a/layout/reftests/bugs/894931-1.html b/layout/reftests/bugs/894931-1.html new file mode 100644 index 00000000000..2ff2ebc90fb --- /dev/null +++ b/layout/reftests/bugs/894931-1.html @@ -0,0 +1,15 @@ + + + +
+
+
+ + + diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 7791fd7683f..3945b9790a5 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1770,3 +1770,4 @@ random-if(Android&&AndroidVersion>=15) == 875060-1.html 875060-1-ref.html #Bug 8 == 883987-1e.html 883987-1-ref.html == 883987-1f.html 883987-1-ref.html == 890495-1.html 890495-1-ref.html +== 894931-1.html 894931-1-ref.html From a9720868ea4eff1da04d904a298293df18bc8b48 Mon Sep 17 00:00:00 2001 From: Benjamin Smedberg Date: Fri, 19 Jul 2013 10:02:47 -0400 Subject: [PATCH 24/58] Bug 889480 - When NP_Initialize fails, we should not try to call NP_Shutdown later, r=gfritzsche --HG-- extra : rebase_source : d6749449a9ef910b65336ce69aa0ad558711f6e7 --- dom/plugins/ipc/PluginModuleParent.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index 075679cb7a2..91548a8ddc1 100755 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -1192,9 +1192,11 @@ PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs uint32_t flags = 0; if (!CallNP_Initialize(flags, error)) { + mShutdown = true; return NS_ERROR_FAILURE; } else if (*error != NPERR_NO_ERROR) { + mShutdown = true; return NS_OK; } @@ -1220,8 +1222,14 @@ PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error) flags |= kAllowAsyncDrawing; #endif - if (!CallNP_Initialize(flags, error)) + if (!CallNP_Initialize(flags, error)) { + mShutdown = true; return NS_ERROR_FAILURE; + } + if (*error != NPERR_NO_ERROR) { + mShutdown = true; + return NS_OK; + } #if defined XP_WIN // Send the info needed to join the chrome process's audio session to the From 67d9f93f7423a0f99d6a37fc0806655f52b8d8ab Mon Sep 17 00:00:00 2001 From: Benjamin Smedberg Date: Fri, 19 Jul 2013 10:02:47 -0400 Subject: [PATCH 25/58] Bug 888908 - When the location bar is missing, don't auto-popup the plugin notification (ever). It will still pop up when clicking the in-page UI. And Australis will make this code moot anyway, r=jaws --HG-- extra : rebase_source : 71a035bf35cd8bb7910d54c34df073c3daf654e7 --- browser/base/content/browser-plugins.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/browser/base/content/browser-plugins.js b/browser/base/content/browser-plugins.js index 44933eca9f5..056d67900a2 100644 --- a/browser/base/content/browser-plugins.js +++ b/browser/base/content/browser-plugins.js @@ -766,8 +766,7 @@ var gPluginHandler = { fallbackType == plugin.PLUGIN_BLOCKLISTED; }); let dismissed = notification ? notification.dismissed : true; - // Always show the doorhanger if the anchor is not available. - if (!isElementVisible(gURLBar) || aPrimaryPlugin) + if (aPrimaryPlugin) dismissed = false; let primaryPluginPermission = null; From dd57b47a65113bb0be2ec208f7a32fb376ca8b8e Mon Sep 17 00:00:00 2001 From: Benjamin Smedberg Date: Fri, 19 Jul 2013 10:02:48 -0400 Subject: [PATCH 26/58] Bug 889788 - Plugin doorhanger breaks when plugins are dynamically removed from a page. This implements the short-term solution of hiding the plugin doorhanger when no more plugins are on the page (the better long-term solution will keep showing the UI and track all the plugins a page ever uses). This also implements a short-term solution when a user enables a plugin. Also bug 887088 - Short-term UI solution: when a user loads multiple tabs from a site and enables a plugin on one of them, the plugins are not enabled on other tabs but the "continue allowing" button does nothing. This patch makes the "Continue Allowing" button enable existing plugins of that type. r=jaws r=jschoenick --HG-- extra : rebase_source : a60ae3259579ea63d51921dc3c70836da2d7ab3a --- browser/base/content/browser-plugins.js | 45 ++++++++++++--------- browser/base/content/browser.js | 1 + browser/base/content/urlbarBindings.xml | 29 +++++++++---- content/base/src/nsObjectLoadingContent.cpp | 28 +++++++++---- 4 files changed, 68 insertions(+), 35 deletions(-) diff --git a/browser/base/content/browser-plugins.js b/browser/base/content/browser-plugins.js index 056d67900a2..6d30118dfd6 100644 --- a/browser/base/content/browser-plugins.js +++ b/browser/base/content/browser-plugins.js @@ -217,14 +217,21 @@ var gPluginHandler = { }, handleEvent : function(event) { - let plugin = event.target; - let doc = plugin.ownerDocument; - - // We're expecting the target to be a plugin. - if (!(plugin instanceof Ci.nsIObjectLoadingContent)) - return; + let plugin; + let doc; let eventType = event.type; + if (eventType === "PluginRemoved") { + doc = event.target; + } + else { + plugin = event.target; + doc = plugin.ownerDocument; + + if (!(plugin instanceof Ci.nsIObjectLoadingContent)) + return; + } + if (eventType == "PluginBindingAttached") { // The plugin binding fires this event when it is created. // As an untrusted event, ensure that this object actually has a binding @@ -304,12 +311,13 @@ var gPluginHandler = { break; case "PluginInstantiated": + case "PluginRemoved": this._showClickToPlayNotification(browser); break; } // Hide the in-content UI if it's too big. The crashed plugin handler already did this. - if (eventType != "PluginCrashed") { + if (eventType != "PluginCrashed" && eventType != "PluginRemoved") { let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox"); if (overlay != null && this.isTooSmall(plugin, overlay)) overlay.style.visibility = "hidden"; @@ -686,18 +694,12 @@ var gPluginHandler = { switch (aNewState) { case "allownow": - if (aPluginInfo.fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE) { - return; - } permission = Ci.nsIPermissionManager.ALLOW_ACTION; expireType = Ci.nsIPermissionManager.EXPIRE_SESSION; expireTime = Date.now() + Services.prefs.getIntPref(this.PREF_SESSION_PERSIST_MINUTES) * 60 * 1000; break; case "allowalways": - if (aPluginInfo.fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE) { - return; - } permission = Ci.nsIPermissionManager.ALLOW_ACTION; expireType = Ci.nsIPermissionManager.EXPIRE_TIME; expireTime = Date.now() + @@ -705,25 +707,28 @@ var gPluginHandler = { break; case "block": - if (aPluginInfo.fallbackType != Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE) { - return; - } permission = Ci.nsIPermissionManager.PROMPT_ACTION; expireType = Ci.nsIPermissionManager.EXPIRE_NEVER; expireTime = 0; break; + // In case a plugin has already been allowed in another tab, the "continue allowing" button + // shouldn't change any permissions but should run the plugin-enablement code below. + case "continue": + break; default: Cu.reportError(Error("Unexpected plugin state: " + aNewState)); return; } let browser = aNotification.browser; - Services.perms.add(browser.currentURI, aPluginInfo.permissionString, - permission, expireType, expireTime); + if (aNewState != "continue") { + Services.perms.add(browser.currentURI, aPluginInfo.permissionString, + permission, expireType, expireTime); - if (aNewState == "block") { - return; + if (aNewState == "block") { + return; + } } // Manually activate the plugins that would have been automatically diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index d68fc1c8c6b..1b2c280ea15 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -755,6 +755,7 @@ var gBrowserInit = { gBrowser.addEventListener("PluginCrashed", gPluginHandler, true); gBrowser.addEventListener("PluginOutdated", gPluginHandler, true); gBrowser.addEventListener("PluginInstantiated", gPluginHandler, true); + gBrowser.addEventListener("PluginRemoved", gPluginHandler, true); gBrowser.addEventListener("NewPluginInstalled", gPluginHandler.newPluginInstalled, true); diff --git a/browser/base/content/urlbarBindings.xml b/browser/base/content/urlbarBindings.xml index 060a9aaabd2..8414b3ac0db 100644 --- a/browser/base/content/urlbarBindings.xml +++ b/browser/base/content/urlbarBindings.xml @@ -1574,12 +1574,19 @@ this.appendChild(item); this._items.push(item); } - if (this.notification.options.centerActions.length == 1) { - this._setState(this._states.SINGLE); - } else if (this.notification.options.primaryPlugin) { - this._setState(this._states.MULTI_COLLAPSED); - } else { - this._setState(this._states.MULTI_EXPANDED); + switch (this.notification.options.centerActions.length) { + case 0: + PopupNotifications._dismiss(); + break; + case 1: + this._setState(this._states.SINGLE); + break; + default: + if (this.notification.options.primaryPlugin) { + this._setState(this._states.MULTI_COLLAPSED); + } else { + this._setState(this._states.MULTI_EXPANDED); + } } ]]> @@ -1645,7 +1652,7 @@ button2 = { label: "pluginContinue.label", accesskey: "pluginContinue.accesskey", - action: "_cancel", + action: "_singleContinue", default: true }; switch (action.blocklistState) { @@ -1819,6 +1826,14 @@ this._cancel(); ]]> + + + GetCurrentDoc()) + , mEvent(aEvent) + { + } + + nsSimplePluginEvent(nsIDocument* aTarget, const nsAString& aEvent) + : mTarget(aTarget) + , mDocument(aTarget) + , mEvent(aEvent) + { + } ~nsSimplePluginEvent() {} NS_IMETHOD Run(); private: - nsCOMPtr mContent; + nsCOMPtr mTarget; + nsCOMPtr mDocument; nsString mEvent; }; NS_IMETHODIMP nsSimplePluginEvent::Run() { - LOG(("OBJLC [%p]: nsSimplePluginEvent firing event \"%s\"", mContent.get(), + LOG(("OBJLC [%p]: nsSimplePluginEvent firing event \"%s\"", mTarget.get(), mEvent.get())); - nsContentUtils::DispatchTrustedEvent(mContent->GetDocument(), mContent, + nsContentUtils::DispatchTrustedEvent(mDocument, mTarget, mEvent, true, true); return NS_OK; } @@ -674,7 +684,9 @@ nsObjectLoadingContent::UnbindFromTree(bool aDeep, bool aNullParent) /// would keep the docshell around, but trash the frameloader UnloadObject(); } - + nsCOMPtr ev = new nsSimplePluginEvent(thisContent->GetCurrentDoc(), + NS_LITERAL_STRING("PluginRemoved")); + NS_DispatchToCurrentThread(ev); } nsObjectLoadingContent::nsObjectLoadingContent() From 27f7f9641784e8eaf873b62958817be1fb7d97d2 Mon Sep 17 00:00:00 2001 From: Benjamin Smedberg Date: Fri, 19 Jul 2013 10:02:48 -0400 Subject: [PATCH 27/58] Bug 888292 - De-emphasize the plugin icon in the address bar when it doesn't need to catch the user's attention. With this change, the only time the icon will be "alert blue" is when a plugin is click-to-activate and it's too small to show the overlay inline in the page. Icons provided by shorlander. ui-review=lco r=jaws --HG-- extra : rebase_source : 29f8c8ad4fd0234f1d2bf14451416ac7f744c6fb --- browser/base/content/browser-plugins.js | 38 ++++++++---- browser/base/content/browser.xul | 1 + browser/themes/linux/browser.css | 26 ++++++++- browser/themes/linux/jar.mn | 3 + browser/themes/osx/browser.css | 54 +++++++++++++++++- browser/themes/osx/jar.mn | 6 ++ .../plugins/notification-pluginAlert.png | Bin 0 -> 648 bytes .../plugins/notification-pluginAlert@2x.png | Bin 0 -> 1189 bytes .../plugins/notification-pluginBlocked.png | Bin 0 -> 968 bytes .../plugins/notification-pluginBlocked@2x.png | Bin 0 -> 2067 bytes .../plugins/notification-pluginNormal.png | Bin 0 -> 340 bytes .../plugins/notification-pluginNormal@2x.png | Bin 0 -> 469 bytes browser/themes/windows/browser.css | 26 ++++++++- browser/themes/windows/jar.mn | 6 ++ .../mozapps/plugins/content/pluginProblem.xml | 6 +- toolkit/themes/linux/mozapps/jar.mn | 2 - .../mozapps/plugins/pluginBlocked-16.png | Bin 830 -> 0 bytes toolkit/themes/osx/mozapps/jar.mn | 2 - .../osx/mozapps/plugins/pluginBlocked-16.png | Bin 823 -> 0 bytes toolkit/themes/windows/mozapps/jar.mn | 4 -- .../mozapps/plugins/pluginBlocked-16-aero.png | Bin 638 -> 0 bytes .../mozapps/plugins/pluginBlocked-16.png | Bin 699 -> 0 bytes 22 files changed, 147 insertions(+), 27 deletions(-) create mode 100644 browser/themes/shared/plugins/notification-pluginAlert.png create mode 100644 browser/themes/shared/plugins/notification-pluginAlert@2x.png create mode 100644 browser/themes/shared/plugins/notification-pluginBlocked.png create mode 100644 browser/themes/shared/plugins/notification-pluginBlocked@2x.png create mode 100644 browser/themes/shared/plugins/notification-pluginNormal.png create mode 100644 browser/themes/shared/plugins/notification-pluginNormal@2x.png delete mode 100644 toolkit/themes/linux/mozapps/plugins/pluginBlocked-16.png delete mode 100644 toolkit/themes/osx/mozapps/plugins/pluginBlocked-16.png delete mode 100644 toolkit/themes/windows/mozapps/plugins/pluginBlocked-16-aero.png delete mode 100644 toolkit/themes/windows/mozapps/plugins/pluginBlocked-16.png diff --git a/browser/base/content/browser-plugins.js b/browser/base/content/browser-plugins.js index 6d30118dfd6..35254d4f0aa 100644 --- a/browser/base/content/browser-plugins.js +++ b/browser/base/content/browser-plugins.js @@ -250,6 +250,7 @@ var gPluginHandler = { } } + let shouldShowNotification = false; let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document); switch (eventType) { @@ -275,7 +276,7 @@ var gPluginHandler = { case "PluginBlocklisted": case "PluginOutdated": - this._showClickToPlayNotification(browser); + shouldShowNotification = true; break; case "PluginVulnerableUpdatable": @@ -297,7 +298,7 @@ var gPluginHandler = { let vulnerabilityText = doc.getAnonymousElementByAttribute(plugin, "anonid", "vulnerabilityStatus"); vulnerabilityText.textContent = vulnerabilityString; } - this._showClickToPlayNotification(browser); + shouldShowNotification = true; break; case "PluginPlayPreview": @@ -307,12 +308,12 @@ var gPluginHandler = { case "PluginDisabled": let manageLink = doc.getAnonymousElementByAttribute(plugin, "class", "managePluginsLink"); this.addLinkClickCallback(manageLink, "managePlugins"); - this._showClickToPlayNotification(browser); + shouldShowNotification = true; break; case "PluginInstantiated": case "PluginRemoved": - this._showClickToPlayNotification(browser); + shouldShowNotification = true; break; } @@ -322,6 +323,12 @@ var gPluginHandler = { if (overlay != null && this.isTooSmall(plugin, overlay)) overlay.style.visibility = "hidden"; } + + // Only show the notification after we've done the isTooSmall check, so + // that the notification can decide whether to show the "alert" icon + if (shouldShowNotification) { + this._showClickToPlayNotification(browser); + } }, isKnownPlugin: function PH_isKnownPlugin(objLoadingContent) { @@ -754,6 +761,7 @@ var gPluginHandler = { let notification = PopupNotifications.getNotification("click-to-play-plugins", aBrowser); let contentWindow = aBrowser.contentWindow; + let contentDoc = aBrowser.contentDocument; let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindowUtils); let plugins = cwu.plugins; @@ -764,12 +772,23 @@ var gPluginHandler = { return; } - let haveVulnerablePlugin = plugins.some(function(plugin) { + let icon = 'plugins-notification-icon'; + for (let plugin of plugins) { let fallbackType = plugin.pluginFallbackType; - return fallbackType == plugin.PLUGIN_VULNERABLE_UPDATABLE || - fallbackType == plugin.PLUGIN_VULNERABLE_NO_UPDATE || - fallbackType == plugin.PLUGIN_BLOCKLISTED; - }); + if (fallbackType == plugin.PLUGIN_VULNERABLE_UPDATABLE || + fallbackType == plugin.PLUGIN_VULNERABLE_NO_UPDATE || + fallbackType == plugin.PLUGIN_BLOCKLISTED) { + icon = 'blocked-plugins-notification-icon'; + break; + } + if (fallbackType == plugin.PLUGIN_CLICK_TO_PLAY) { + let overlay = contentDoc.getAnonymousElementByAttribute(plugin, "class", "mainBox"); + if (!overlay || overlay.style.visibility == 'hidden') { + icon = 'alert-plugins-notification-icon'; + } + } + } + let dismissed = notification ? notification.dismissed : true; if (aPrimaryPlugin) dismissed = false; @@ -784,7 +803,6 @@ var gPluginHandler = { eventCallback: this._clickToPlayNotificationEventCallback, primaryPlugin: primaryPluginPermission }; - let icon = haveVulnerablePlugin ? "blocked-plugins-notification-icon" : "plugins-notification-icon"; PopupNotifications.show(aBrowser, "click-to-play-plugins", "", icon, null, null, options); diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul index f1c20424915..8aab2b82aa6 100644 --- a/browser/base/content/browser.xul +++ b/browser/base/content/browser.xul @@ -505,6 +505,7 @@ + diff --git a/browser/themes/linux/browser.css b/browser/themes/linux/browser.css index 67bee159ef5..50710e34239 100644 --- a/browser/themes/linux/browser.css +++ b/browser/themes/linux/browser.css @@ -1285,11 +1285,33 @@ toolbar[iconsize="small"] #webrtc-status-button { } #plugins-notification-icon { - list-style-image: url(chrome://mozapps/skin/plugins/pluginGeneric-16.png); + list-style-image: url(chrome://browser/skin/notification-pluginNormal.png); +} + +#alert-plugins-notification-icon { + list-style-image: url(chrome://browser/skin/notification-pluginAlert.png); } #blocked-plugins-notification-icon { - list-style-image: url(chrome://mozapps/skin/plugins/notifyPluginBlocked.png); + list-style-image: url(chrome://browser/skin/notification-pluginBlocked.png); +} + +#plugins-notification-icon, +#alert-plugins-notification-icon, +#blocked-plugins-notification-icon { + -moz-image-region: rect(0, 16px, 16px, 0); +} + +#plugins-notification-icon:hover, +#alert-plugins-notification-icon:hover, +#blocked-plugins-notification-icon:hover { + -moz-image-region: rect(0, 32px, 16px, 16px); +} + +#plugins-notification-icon:active, +#alert-plugins-notification-icon:active, +#blocked-plugins-notification-icon:active { + -moz-image-region: rect(0, 48px, 16px, 32px); } #plugin-install-notification-icon { diff --git a/browser/themes/linux/jar.mn b/browser/themes/linux/jar.mn index 203aba1a8ab..8145b2ed9e6 100644 --- a/browser/themes/linux/jar.mn +++ b/browser/themes/linux/jar.mn @@ -235,3 +235,6 @@ browser.jar: #endif skin/classic/browser/webapps-16.png skin/classic/browser/webapps-64.png + skin/classic/browser/notification-pluginNormal.png (../shared/plugins/notification-pluginNormal.png) + skin/classic/browser/notification-pluginAlert.png (../shared/plugins/notification-pluginAlert.png) + skin/classic/browser/notification-pluginBlocked.png (../shared/plugins/notification-pluginBlocked.png) diff --git a/browser/themes/osx/browser.css b/browser/themes/osx/browser.css index d26c9f8595a..291ae478e88 100644 --- a/browser/themes/osx/browser.css +++ b/browser/themes/osx/browser.css @@ -3144,16 +3144,64 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { } #plugins-notification-icon { - list-style-image: url(chrome://mozapps/skin/plugins/pluginGeneric-16.png); + list-style-image: url(chrome://browser/skin/notification-pluginNormal.png); +} + +#alert-plugins-notification-icon { + list-style-image: url(chrome://browser/skin/notification-pluginAlert.png); } #blocked-plugins-notification-icon { - list-style-image: url(chrome://mozapps/skin/plugins/notifyPluginBlocked.png); + list-style-image: url(chrome://browser/skin/notification-pluginBlocked.png); +} + +#plugins-notification-icon, +#alert-plugins-notification-icon, +#blocked-plugins-notification-icon { + -moz-image-region: rect(0, 16px, 16px, 0); +} + +#plugins-notification-icon:hover, +#alert-plugins-notification-icon:hover, +#blocked-plugins-notification-icon:hover { + -moz-image-region: rect(0, 32px, 16px, 16px); +} + +#plugins-notification-icon:active, +#alert-plugins-notification-icon:active, +#blocked-plugins-notification-icon:active { + -moz-image-region: rect(0, 48px, 16px, 32px); } @media (min-resolution: 2dppx) { + #plugins-notification-icon { + list-style-image: url(chrome://browser/skin/notification-pluginNormal@2x.png); + } + + #alert-plugins-notification-icon { + list-style-image: url(chrome://browser/skin/notification-pluginAlert@2x.png); + } + #blocked-plugins-notification-icon { - list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked.png); + list-style-image: url(chrome://browser/skin/notification-pluginBlocked@2x.png); + } + + #plugins-notification-icon, + #alert-plugins-notification-icon, + #blocked-plugins-notification-icon { + -moz-image-region: rect(0, 32px, 32px, 0); + } + + #plugins-notification-icon:hover, + #alert-plugins-notification-icon:hover, + #blocked-plugins-notification-icon:hover { + -moz-image-region: rect(0, 64px, 32px, 32px); + } + + #plugins-notification-icon:active, + #alert-plugins-notification-icon:active, + #blocked-plugins-notification-icon:active { + -moz-image-region: rect(0, 96px, 32px, 64px); } } diff --git a/browser/themes/osx/jar.mn b/browser/themes/osx/jar.mn index 0c59df83198..3702c4d629c 100644 --- a/browser/themes/osx/jar.mn +++ b/browser/themes/osx/jar.mn @@ -331,6 +331,12 @@ browser.jar: skin/classic/browser/webapps-16.png skin/classic/browser/webapps-16@2x.png skin/classic/browser/webapps-64.png + skin/classic/browser/notification-pluginNormal.png (../shared/plugins/notification-pluginNormal.png) + skin/classic/browser/notification-pluginAlert.png (../shared/plugins/notification-pluginAlert.png) + skin/classic/browser/notification-pluginBlocked.png (../shared/plugins/notification-pluginBlocked.png) + skin/classic/browser/notification-pluginNormal@2x.png (../shared/plugins/notification-pluginNormal@2x.png) + skin/classic/browser/notification-pluginAlert@2x.png (../shared/plugins/notification-pluginAlert@2x.png) + skin/classic/browser/notification-pluginBlocked@2x.png (../shared/plugins/notification-pluginBlocked@2x.png) % override chrome://browser/skin/keyhole-circle.png chrome://browser/skin/lion/keyhole-circle.png os=Darwin osversion>=10.7 % override chrome://browser/skin/Toolbar.png chrome://browser/skin/lion/Toolbar.png os=Darwin osversion>=10.7 diff --git a/browser/themes/shared/plugins/notification-pluginAlert.png b/browser/themes/shared/plugins/notification-pluginAlert.png new file mode 100644 index 0000000000000000000000000000000000000000..7492fdd8670488b9b510d913424dcc46f5e1ab57 GIT binary patch literal 648 zcmV;30(bq1P)u2ZAW(aaL;CA-H8 z?M6CpOarJt8^CzLh4J8xbr(MMpmRq{gL8cS&F13)%_8T%H-Ot6t6fb zv}^R)kw)A-4(ZK6`W~)Gk5MMym4>uuZlnC4FK*1o#jWpB3@L8TNpUq#zDUf=wb^XN zuXI<3a3Ez_!IXu1(2g*$L(`dEwz{&*s0Zbc9~k^#1qa`w9<-yo>j9Cr5fdDQfvBeQ z@gf+I-*$Nt9CUX*AnL#S0}OP5ZpFcUk1Q}C-#_pc9CY`81Ck5iKm*22Fd#p0?lm~j zfY$5Zz<>(uP5%S~^0&lZfddWjUCDz171%Rc00Z({`d)&8ZNR_`IM9IM1u!7L_4EsH zpaGtK+y zp%SE0F?p&~o)J_$1AXEf;01{{kPxj@MM0`)q)1h45}M%HdppD2`h2=O zpJQ8Ub}hWp=A8BY?>Dn^GrM;Q!jB9$-F7}|9)I=*ytL5#>snMcP7Hcq4xdU-r0Xdf zE4?TEwP^pzow!z)pHtB_P0s(7U)M=5_)+boE$ChDsu(-1wuaWaj4%WLYk=MkA$>al zx){PR#Y2Al;0O8kMdpAQv8e9(6eG93YMb4S7&^M8KsoCOU`Rk$7HE(HU!~BuaQJha zRQL<(rt;zCAG65Rk{x7C`UJd}33`l^uQyrRY zu}Qaw2zLu@_IY02=q|x2r6F0z+1FWT+J+i`Zru#NPE7~a)b)N02HRlYH^NR9|0E{DP7Pycp88E*N3mujmSMKv_@m=7H67>6(i_95BdY`ny zK1k=>M3f&9XE`jti>;B(j6MIg4{?6cbI~2-I%w39V$e1lJv$sgwB2%xQjv<;SoU3y z)IM88Z4@Hq_lB6v)|FLYL_kFo{J%*ZWIAOOOwlo9x*2@C(cZVQ#z9N?QRafwae1LpjdR$DGd#@KN|6e5~;ei~sac zlHs1rUb|YM>W%wyZqFS@=iQRKB5}v&^Ya6W|0MqFBMJA>&RsYgWdOm}?P#zU0e|dc z@0$XiT%@hBbfQdv9LsMV$KKtLWrn^U=5R@qAo@l9b z31UkSvIPi0bv6R|UkZS~321s_f`J1-f%v6GnEdA6#LL>i8IbboWB@N=31S;O0JPcx zpwMeT8h8=*y$I^1%K(1{G)}ee4AAvm&oEr? z0n5O50pNfcz=59wIB*7Vv=k+PfjMLa%J>0G5W9_u{}M#ShA4X(%%S-lf?s4n*PuR* zto_6X*+lx4g#ENM)E%-qj+wmhho~m_R>#NM7(f26t-S&m@kbe;;V=H;!S@E-KO2?b zmEk)}@@nL}LVjJ03;(y|!>9Ql)`RfPH&31#fBaKnI==g_h#CyvF}!ZXtXy9eeq|Sg z4TkXz-2q&3u<7%v@GHBZX@=a?%EUDXX$ASN{U^Wx-G8v2FsI_100000NkvXXu0mjf Db0|vx literal 0 HcmV?d00001 diff --git a/browser/themes/shared/plugins/notification-pluginBlocked.png b/browser/themes/shared/plugins/notification-pluginBlocked.png new file mode 100644 index 0000000000000000000000000000000000000000..e2e9489004eb7cd0661d6ebf8d3a7be4869fddca GIT binary patch literal 968 zcmV;(12_DMP)d_#%mJIr=;mM<*>H>6j?C~P30x3`C>MI=1vmT=PvV8)f{>sWCL$N0 zF)^S*!~{c@@TP%5c~NpF#XD?EL=t?j-(=OkypALMbQc)`UdIr+Zy`JFax ze*}Q=QDl)%$fw;RB>MawG0&|JkS-89T1jrSg^-Ta;O^QNapo0rS$~R049_=f$h{w_ z1$IW@ZD~Vt%?py5-!uJvOUV7cj?niip?4+Wt7Rma`8-*`KNP<}%aIC#eaO@G1lFJ8 z5kBaV{*9#s`;dt?&CKi3l@^lz-o*s_kcVnD^WPqKxm@A%`i(bUaz-{aIPSL9&iIyQ zC;nEQZf>0G2YFBSe+e&lZuQhVN&h*q_4UrR zbt~rjL7w*I<4c6Ay~LZ_FCLObpnM)4;h|WQ(uw3 zEO4h|A(X*)!YE9PW42hZVNE4^-Euc}gwXVG%0Buv&?;MWjA$;at6xJ#q-eh~ySV*NI(iD$B=|5-IbIo#QVv1?Ie?)KZTCZ5S!3;ej0 zVAI>xfY=xNk%?Ypcot24MGx@j3WCkOa3eAYKZSR-kKtJ~^%d>&KdsGyjz&a3-;dPg zK89z})K_$Y(6Pmo`=N?Z4t~eJ>*V;lP!4`)uD_>>a-UQZ%E9kQU#=2*+bajX5kBue q`4_ckLT{44Rnaq{{f`&X|KeZ!dReTe@;)B`00002*B!Z|Cu@r{GOIa7!&ebQ&zqp*)`Z5^Y8}37(A|H6F82-m{G5T;C9P5(NoytHOU4A@1 zS^ldj%(j<~weCKKrXMhzxu2mSosNGM!+~WCdzLVeMwcItPj&#=hZZr+)<~}5+PV5< z`RA81%+^S*5%c5m$@2erC&O%w`^lr{BpEd?|3`2nQ4ic?(9q9sTKu96f7&y3ASKw!8q&{jb5-YeUFC8Nt`v z9ofgn%+{H4HN=1E%U=W|`it(y*r9zuAOM6ya%jx+x4)vlWCdocCpI9kDG!D`QH1bE zA5aeEheL8`EPVX$2s~AS+3Jb;jdaCgMAHKc;W)6DA}E9YRvCQES+fsKS&J}RJ>3M@ za&Lo*p7km4o^C)m7%+wROk>1jR8wrgjErf~@T3)7?8?%fY+zX?cVgr2TKZJ_lks4ZR{FVsT z9fVO$G5-^~Pf#)V&g;?T#w>%hBpKDzO+ZKXEs)W(sTe`;I6@OXOK=bOs_Kdj7=JVa zGHyQq7{Wd;!jlu$AP@Jd>WcXq-7v{$e1w*)@o@xwK1*;9_p0jZCg5wjW0f)d)+-2( zkHrP|s_Kdj;CHMt{O|2Wm?kqGxK~wI%s)bRurh3~?V@Im#Rd1O>gp!oY$l!ICERRp zMPSq&rK|E$sI+`6R?EFAt=NDYKUoPG!Hee*_KZgHys#N6Egy^3a<57&=GU%dkl}7? zfq%purQz{XsI+`6R?EFAt!@HTHx2$F7pAUXi!$3yMy!^5RXVW&!$r#=BRD*Sko$TR zm2R3?E%&N)V*dNf8Dw}}PE1@Ij-t{{6RYK3l}wl)W|DQRJy1>MjIR)Q0m0|cj*H&8RParc09RD>k5?KFgPJxtuNosa}AVGfR+%dsTJC{MYGOfsFTx*23M> zjgh_{OK=bOs_N<{;5e;IDtcbthMTrdOK^`-O|bzzbY4*5{_`I&)!StW?lGz<=D*6H z*(x|wy$$Z}PD^l)QBB!Ui1 z(2d58mS#AQ)kgMxT9^j2b;JgA&;*;oM$c}py!0D*j@Q9=t_9xKW_YyP$Ua+1I?UD) z^Q-S*FvAG*8xuVJgN!_e7QIKMoNt|PUPeQ)Hhf!R9Z1Z3CJtRxcI*GdwJn7`w8 zhD0JhkV&I2R@pzKfkaTZl=TT;Y)U(y!t7tuJ0lTXNYUq4FJ|`b^sS9Vu=B2&`QJVi x=g(!0zgqX7LiW|Z|LgquZGM~I=C}XS_HQy{wkLG#8hZc$002ovPDHLkV1lI|6Y~H7 literal 0 HcmV?d00001 diff --git a/browser/themes/shared/plugins/notification-pluginNormal.png b/browser/themes/shared/plugins/notification-pluginNormal.png new file mode 100644 index 0000000000000000000000000000000000000000..979e92b7f51d98aebc1ce4b6255954e6ee8a12dd GIT binary patch literal 340 zcmV-a0jvIrP)!{g1%Z; zM<2o2S8!6_$>(r!Oq;xts|oinPThZS(+f}Px?Z18J=nqRC-n%@G)3{d1E+bq zEDM}~-;8gb&hw1=3+xGaE3}5*+Fmo4KA*i00RIvyzz;-k{jXx0000t^y1IGDue2QPDpC00000 LNkvXXu0mjf<5tiP literal 0 HcmV?d00001 diff --git a/browser/themes/windows/browser.css b/browser/themes/windows/browser.css index f73c23b65bd..85c488853eb 100644 --- a/browser/themes/windows/browser.css +++ b/browser/themes/windows/browser.css @@ -2537,11 +2537,33 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] { } #plugins-notification-icon { - list-style-image: url(chrome://mozapps/skin/plugins/pluginGeneric-16.png); + list-style-image: url(chrome://browser/skin/notification-pluginNormal.png); +} + +#alert-plugins-notification-icon { + list-style-image: url(chrome://browser/skin/notification-pluginAlert.png); } #blocked-plugins-notification-icon { - list-style-image: url(chrome://mozapps/skin/plugins/notifyPluginBlocked.png); + list-style-image: url(chrome://browser/skin/notification-pluginBlocked.png); +} + +#plugins-notification-icon, +#alert-plugins-notification-icon, +#blocked-plugins-notification-icon { + -moz-image-region: rect(0, 16px, 16px, 0); +} + +#plugins-notification-icon:hover, +#alert-plugins-notification-icon:hover, +#blocked-plugins-notification-icon:hover { + -moz-image-region: rect(0, 32px, 16px, 16px); +} + +#plugins-notification-icon:active, +#alert-plugins-notification-icon:active, +#blocked-plugins-notification-icon:active { + -moz-image-region: rect(0, 48px, 16px, 32px); } #plugin-install-notification-icon { diff --git a/browser/themes/windows/jar.mn b/browser/themes/windows/jar.mn index d9368bef2b2..c0a8c75b67a 100644 --- a/browser/themes/windows/jar.mn +++ b/browser/themes/windows/jar.mn @@ -72,6 +72,9 @@ browser.jar: skin/classic/browser/urlbar-history-dropmarker.png skin/classic/browser/webapps-16.png skin/classic/browser/webapps-64.png + skin/classic/browser/notification-pluginNormal.png (../shared/plugins/notification-pluginNormal.png) + skin/classic/browser/notification-pluginAlert.png (../shared/plugins/notification-pluginAlert.png) + skin/classic/browser/notification-pluginBlocked.png (../shared/plugins/notification-pluginBlocked.png) skin/classic/browser/webRTC-shareDevice-16.png skin/classic/browser/webRTC-shareDevice-64.png skin/classic/browser/webRTC-sharingDevice-16.png @@ -326,6 +329,9 @@ browser.jar: skin/classic/aero/browser/urlbar-history-dropmarker.png skin/classic/aero/browser/webapps-16.png skin/classic/aero/browser/webapps-64.png + skin/classic/aero/browser/notification-pluginNormal.png (../shared/plugins/notification-pluginNormal.png) + skin/classic/aero/browser/notification-pluginAlert.png (../shared/plugins/notification-pluginAlert.png) + skin/classic/aero/browser/notification-pluginBlocked.png (../shared/plugins/notification-pluginBlocked.png) skin/classic/aero/browser/webRTC-shareDevice-16.png skin/classic/aero/browser/webRTC-shareDevice-64.png skin/classic/aero/browser/webRTC-sharingDevice-16.png diff --git a/toolkit/mozapps/plugins/content/pluginProblem.xml b/toolkit/mozapps/plugins/content/pluginProblem.xml index 8eada662db2..5c26d2accb7 100644 --- a/toolkit/mozapps/plugins/content/pluginProblem.xml +++ b/toolkit/mozapps/plugins/content/pluginProblem.xml @@ -74,8 +74,10 @@ - // Notify browser-plugins.js that we were attached - this.dispatchEvent(new CustomEvent("PluginBindingAttached")); + // Notify browser-plugins.js that we were attached, on a delay because + // this binding doesn't complete layout until the constructor + // completes. + setTimeout(() => { this.dispatchEvent(new CustomEvent("PluginBindingAttached")) }, 0); diff --git a/toolkit/themes/linux/mozapps/jar.mn b/toolkit/themes/linux/mozapps/jar.mn index 9c49a177611..63545741e5f 100644 --- a/toolkit/themes/linux/mozapps/jar.mn +++ b/toolkit/themes/linux/mozapps/jar.mn @@ -29,10 +29,8 @@ toolkit.jar: + skin/classic/mozapps/passwordmgr/key.png (passwordmgr/key-16.png) + skin/classic/mozapps/passwordmgr/key-16.png (passwordmgr/key-16.png) + skin/classic/mozapps/passwordmgr/key-64.png (passwordmgr/key-64.png) -+ skin/classic/mozapps/plugins/notifyPluginBlocked.png (plugins/pluginBlocked-16.png) + skin/classic/mozapps/plugins/notifyPluginCrashed.png (plugins/pluginGeneric-16.png) + skin/classic/mozapps/plugins/notifyPluginGeneric.png (plugins/pluginGeneric-16.png) -+ skin/classic/mozapps/plugins/notifyPluginOutdated.png (plugins/pluginBlocked-16.png) + skin/classic/mozapps/plugins/pluginGeneric.png (plugins/pluginGeneric.png) + skin/classic/mozapps/plugins/pluginDisabled.png (plugins/pluginDisabled.png) + skin/classic/mozapps/plugins/pluginBlocked.png (plugins/pluginBlocked.png) diff --git a/toolkit/themes/linux/mozapps/plugins/pluginBlocked-16.png b/toolkit/themes/linux/mozapps/plugins/pluginBlocked-16.png deleted file mode 100644 index d4dd69dd3d2e6e2a68e1e0bfa43db30883279c26..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 830 zcmV-E1Ht@>P)N0$gZ>c!000+sMObt} zb#!QNasW(WaBm<(VQgV-VQyq{Woh4$8Y%z)02p*dSad^jWnpw_Z*Cw|X>DZyGB7YW zEio}IFf_X303`qb0#ivuK~y-6jgUV`lyMlxKhN`fU+)e?l2q=lKekjNOWp0J& zZF-uvxjEWrXQ`~Lkm~EBY}N_jg@DB|Un><3R#&M!e@?i(%#Io9IOf~I!C(FMj~|=> z_Nm1S0rh>N_I6%8d`L2i2zPhUOa}G5BYS|bE+|D2)ga)~$OwhCH7cbNtzBJo4h`XD zv-F=n&AUgB_+Bj1dhQ(At}d#D0_D1(41~+egpVK73TR6U?f37K=E-jH79BiDR`+$hlo+`&CCK_-(iQZmXCniwmQ0GAP_Xhibs3OiGKx$xsPuVR0 zrX!bYz~bCtfjU=fL=M6Az9CTky+H)%AA-u_BALz2LwtDe9-<1)p{m674FJSB)b~;6 zC{IpO&E@`rtGOKI$;sLVzF!m7f1q)^^En9GGJ}I)1|o#h(^R{=(R7-4Ym4aBD-!+v zjZ;44^Z2R(fEUBn2lMl{B9Zjb#~+Sowi(6oH2^WQ|K*O%PvBGzI*9?o(*OVf07*qo IM6N<$f?yGC`~Uy| diff --git a/toolkit/themes/osx/mozapps/jar.mn b/toolkit/themes/osx/mozapps/jar.mn index 65aaded8914..94eacef83b8 100644 --- a/toolkit/themes/osx/mozapps/jar.mn +++ b/toolkit/themes/osx/mozapps/jar.mn @@ -63,10 +63,8 @@ toolkit.jar: skin/classic/mozapps/plugins/contentPluginMissing.png (plugins/contentPluginMissing.png) skin/classic/mozapps/plugins/contentPluginClickToPlay.png (plugins/contentPluginClickToPlay.png) skin/classic/mozapps/plugins/contentPluginClickToPlayPlain.png (plugins/contentPluginClickToPlayPlain.png) - skin/classic/mozapps/plugins/notifyPluginBlocked.png (plugins/pluginBlocked-16.png) skin/classic/mozapps/plugins/notifyPluginCrashed.png (plugins/notifyPluginGeneric.png) skin/classic/mozapps/plugins/notifyPluginGeneric.png (plugins/notifyPluginGeneric.png) - skin/classic/mozapps/plugins/notifyPluginOutdated.png (plugins/notifyPluginGeneric.png) skin/classic/mozapps/plugins/pluginProblem.css (plugins/pluginProblem.css) skin/classic/mozapps/plugins/pluginGeneric.png (plugins/pluginGeneric.png) skin/classic/mozapps/plugins/pluginDisabled.png (plugins/pluginDisabled.png) diff --git a/toolkit/themes/osx/mozapps/plugins/pluginBlocked-16.png b/toolkit/themes/osx/mozapps/plugins/pluginBlocked-16.png deleted file mode 100644 index 1700ed11f285d6bcdd4d18997438624d25ba3718..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 823 zcmV-71IYY|P)G%#S{`rVPa}aXUwK< zZMxsj@3-@g1%-Ik2j_c#p7%NLbIyAXr)e7g=i@Hf*A@N#PnG$6A6p1!bEs-?@HS25 z3kS<%MQ(NVA(u#8RaKSC%d&oZYO3$tW-lF7cf&-Y9(ijpQt;9ah?V|e%lL260C ztAPR6U5_VTO@s=bM?8_hk6;iPhXW}Ju{xPVZ+|~@=`_?r0fNbd^=#HV6bJ;E0>gc` zduMBY9#L7wPa-&VIy{)3hPt~8C7%b^+KR}+0=D<}aX`3*&fW8R7l`X*3Tz+U?sQdc zEo34J1X>jZdZV$Fpd!s#7)DV9PkWl#j4Kuk44DjE%gYX?K%bYSh|%F_v$VIPa&HeN z0%JQnh!W|TZmgrQ?u?9}ZfFR~*KOq9zr(4bL|6`)167oythucXMyC^SyRknv2YpQq zZd$D{+3m2lw4i=+5**zuH#9&Y2j`;5gsBzuQ__mECLA3h;`8BTWd-)GE~Mgdd?OWR zy2I4dgWSdjq7xH1TUvrdd5N8!tuZchAS<$**0NbNQKnDV*HMhcz*FoTJsDw84F)7; zXHnDJ3qxZgBtd|vs%ge8DTo$}o3T&`GRL8Hd>q!!PRK+CIgu#`dJ3<3W(KygG5qrT zA*(75L~)aGc~*@fO-tTTRRbT1T(dMa8B~&32!~5m=4ft)#9n}E;*gx227~!8g7Esu z@$nmiGhDfxEo2QI!1D-r?BTdUL%BrV-Q6f29+qnOyCf|>Po-XNi6VP}I9cvbNwZMQ zWQ}CkZ*kn{Tb>UGbUN*GM~AlPa)k#>rcs8K&zQ@c3(dq-o5<{B^-py=uhHegbS(CP z)+b~vafQE|io2vk_2sat%X`_fT*@r|>HpsX3;=y}Lr6=eHM0N!002ovPDHLkV1kiH Bb{zl! diff --git a/toolkit/themes/windows/mozapps/jar.mn b/toolkit/themes/windows/mozapps/jar.mn index 9a67eaf0ff7..54e4ca45b52 100644 --- a/toolkit/themes/windows/mozapps/jar.mn +++ b/toolkit/themes/windows/mozapps/jar.mn @@ -67,10 +67,8 @@ toolkit.jar: skin/classic/mozapps/plugins/contentPluginMissing.png (plugins/contentPluginMissing.png) skin/classic/mozapps/plugins/contentPluginClickToPlay.png (plugins/contentPluginClickToPlay.png) skin/classic/mozapps/plugins/contentPluginClickToPlayPlain.png (plugins/contentPluginClickToPlayPlain.png) - skin/classic/mozapps/plugins/notifyPluginBlocked.png (plugins/pluginBlocked-16.png) skin/classic/mozapps/plugins/notifyPluginCrashed.png (plugins/pluginGeneric-16.png) skin/classic/mozapps/plugins/notifyPluginGeneric.png (plugins/pluginGeneric-16.png) - skin/classic/mozapps/plugins/notifyPluginOutdated.png (plugins/pluginBlocked-16.png) skin/classic/mozapps/plugins/pluginProblem.css (plugins/pluginProblem.css) skin/classic/mozapps/plugins/pluginGeneric.png (plugins/pluginGeneric.png) skin/classic/mozapps/plugins/pluginDisabled.png (plugins/pluginDisabled.png) @@ -150,10 +148,8 @@ toolkit.jar: skin/classic/aero/mozapps/plugins/contentPluginMissing.png (plugins/contentPluginMissing.png) skin/classic/aero/mozapps/plugins/contentPluginClickToPlay.png (plugins/contentPluginClickToPlay.png) skin/classic/aero/mozapps/plugins/contentPluginClickToPlayPlain.png (plugins/contentPluginClickToPlayPlain.png) - skin/classic/aero/mozapps/plugins/notifyPluginBlocked.png (plugins/pluginBlocked-16-aero.png) skin/classic/aero/mozapps/plugins/notifyPluginCrashed.png (plugins/pluginGeneric-16-aero.png) skin/classic/aero/mozapps/plugins/notifyPluginGeneric.png (plugins/pluginGeneric-16-aero.png) - skin/classic/aero/mozapps/plugins/notifyPluginOutdated.png (plugins/pluginBlocked-16-aero.png) skin/classic/aero/mozapps/plugins/pluginProblem.css (plugins/pluginProblem.css) skin/classic/aero/mozapps/plugins/pluginGeneric.png (plugins/pluginGeneric-aero.png) skin/classic/aero/mozapps/plugins/pluginDisabled.png (plugins/pluginDisabled-aero.png) diff --git a/toolkit/themes/windows/mozapps/plugins/pluginBlocked-16-aero.png b/toolkit/themes/windows/mozapps/plugins/pluginBlocked-16-aero.png deleted file mode 100644 index 4a66446e6256df3d7a836c2633a824ec0f8253b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 638 zcmV-^0)hRBP)O z(MXImLco$mCG-afT?qLTZt7#NOIO_%gjUp@;6Awa2M8`x5lXe%iW>SLB%!&l={e)Q zx3`tjMGwrKbI+XbJKvm{5mHM0j|nE|pPwgz_e)E!{dW7Mk>M54m`$t4( z(tJsnL;;0$26v+hH&pHE!NG3?*L!;iA_7)MKs_O#T85jF`=MR0I%ans!`LsfLqK(s|mp_NFj zqPffc`@U!HG!=31<-Yrp_wRY$=lf20o`?T2gy(^GKIxyTO#aQs z)?3;O!3?;;N_Bb^mU%;OyeTQ0(y+gNM(Xe}Kk@tX8UkOuR5lTbPUb4tX1Re9bdxu1 z9Cfu;DLFI(&$bX1JK(vlA4}{%1Q3v_48U{jsEEZ+l6y8Bflb8YMf?3czPx;fcxE$< z)g}_f0Y9cKyoH+Shrap=JwwAt3=ZdlIw=&RCtZx>3vdbP!^$!=(l)xK;4l8oK8|sY zluQ-7MD!U*QZBY`eCvBn(Jh2t|R?+lQ@F6%5wuIQU`#h09lfWD3EJiLAc|z7Z;$YnsTN zpFsA)L>S6nyabC-Utg`jrjya!Uzg8kaCCRMEX5K&eL;=-#!h2yXBuf*mc$$qM ze|9`9RwRJ~R1-2-q@xC(xzUDgm>r>XAJwFSb_bD*4IY>FWv&StP*`@&HeAbQh0%O? zA0tb8m-6+Qo3MC9!f}YV>_43b4(&|e(KR1=>FzC Date: Fri, 19 Jul 2013 12:00:29 -0400 Subject: [PATCH 28/58] Backed out changesets 24c800ff4936 and 5e4e054f3c00 (bug 867143) for mochitest orange. --- .../content/content-sessionStore.js | 20 +- .../sessionstore/src/SessionStore.jsm | 451 ++++++------------ .../components/sessionstore/test/Makefile.in | 1 - .../test/browser_sessionStorage.js | 89 ---- browser/components/sessionstore/test/head.js | 115 ++--- 5 files changed, 184 insertions(+), 492 deletions(-) delete mode 100644 browser/components/sessionstore/test/browser_sessionStorage.js diff --git a/browser/components/sessionstore/content/content-sessionStore.js b/browser/components/sessionstore/content/content-sessionStore.js index 43bf6ff6da1..bdf0fef0c14 100644 --- a/browser/components/sessionstore/content/content-sessionStore.js +++ b/browser/components/sessionstore/content/content-sessionStore.js @@ -13,7 +13,7 @@ function debug(msg) { let EventListener = { DOM_EVENTS: [ - "pageshow", "change", "input", "MozStorageChanged" + "pageshow", "change", "input" ], init: function () { @@ -30,24 +30,6 @@ let EventListener = { case "change": sendAsyncMessage("SessionStore:input"); break; - case "MozStorageChanged": - { - let isSessionStorage = true; - // We are only interested in sessionStorage events - try { - if (event.storageArea != content.sessionStorage) { - isSessionStorage = false; - } - } catch (ex) { - // This page does not even have sessionStorage - // (this is typically the case of about: pages) - isSessionStorage = false; - } - if (isSessionStorage) { - sendAsyncMessage("SessionStore:MozStorageChanged"); - } - break; - } default: debug("received unknown event '" + event.type + "'"); break; diff --git a/browser/components/sessionstore/src/SessionStore.jsm b/browser/components/sessionstore/src/SessionStore.jsm index 443b3513fb2..dca404711e0 100644 --- a/browser/components/sessionstore/src/SessionStore.jsm +++ b/browser/components/sessionstore/src/SessionStore.jsm @@ -58,11 +58,7 @@ const MESSAGES = [ // The content script has received a pageshow event. This happens when a // page is loaded from bfcache without any network activity, i.e. when // clicking the back or forward button. - "SessionStore:pageshow", - - // The content script has received a MozStorageChanged event dealing - // with a change in the contents of the sessionStorage. - "SessionStore:MozStorageChanged" + "SessionStore:pageshow" ]; // These are tab events that we listen to. @@ -124,16 +120,9 @@ XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter", "@mozilla.org/xre/app-info;1", "nsICrashReporter"); #endif -/** - * |true| if we are in debug mode, |false| otherwise. - * Debug mode is controlled by preference browser.sessionstore.debug - */ -let gDebuggingEnabled = false; function debug(aMsg) { - if (gDebuggingEnabled) { - aMsg = ("SessionStore: " + aMsg).replace(/\S{80}/g, "$&\n"); - Services.console.logStringMessage(aMsg); - } + aMsg = ("SessionStore: " + aMsg).replace(/\S{80}/g, "$&\n"); + Services.console.logStringMessage(aMsg); } this.SessionStore = { @@ -548,13 +537,9 @@ let SessionStoreInternal = { }, _initPrefs : function() { - this._prefBranch = Services.prefs.getBranch("browser."); - - gDebuggingEnabled = this._prefBranch.getBoolPref("sessionstore.debug"); - - Services.prefs.addObserver("browser.sessionstore.debug", () => { - gDebuggingEnabled = this._prefBranch.getBoolPref("sessionstore.debug"); - }, false); + XPCOMUtils.defineLazyGetter(this, "_prefBranch", function () { + return Services.prefs.getBranch("browser."); + }); // minimal interval between two save operations (in milliseconds) XPCOMUtils.defineLazyGetter(this, "_interval", function () { @@ -636,43 +621,37 @@ let SessionStoreInternal = { if (this._disabledForMultiProcess) return; - try { - switch (aTopic) { - case "domwindowopened": // catch new windows - this.onOpen(aSubject); - break; - case "domwindowclosed": // catch closed windows - this.onClose(aSubject); - break; - case "quit-application-requested": - this.onQuitApplicationRequested(); - break; - case "quit-application-granted": - this.onQuitApplicationGranted(); - break; - case "browser-lastwindow-close-granted": - this.onLastWindowCloseGranted(); - break; - case "quit-application": - this.onQuitApplication(aData); - break; - case "browser:purge-session-history": // catch sanitization - this.onPurgeSessionHistory(); - break; - case "browser:purge-domain-data": - this.onPurgeDomainData(aData); - break; - case "nsPref:changed": // catch pref changes - this.onPrefChange(aData); - break; - case "timer-callback": // timer call back for delayed saving - this.onTimerCallback(); - break; - } - } catch (ex) { - debug("Uncaught error during observe"); - debug(ex); - debug(ex.stack); + switch (aTopic) { + case "domwindowopened": // catch new windows + this.onOpen(aSubject); + break; + case "domwindowclosed": // catch closed windows + this.onClose(aSubject); + break; + case "quit-application-requested": + this.onQuitApplicationRequested(); + break; + case "quit-application-granted": + this.onQuitApplicationGranted(); + break; + case "browser-lastwindow-close-granted": + this.onLastWindowCloseGranted(); + break; + case "quit-application": + this.onQuitApplication(aData); + break; + case "browser:purge-session-history": // catch sanitization + this.onPurgeSessionHistory(); + break; + case "browser:purge-domain-data": + this.onPurgeDomainData(aData); + break; + case "nsPref:changed": // catch pref changes + this.onPrefChange(aData); + break; + case "timer-callback": // timer call back for delayed saving + this.onTimerCallback(); + break; } }, @@ -691,10 +670,6 @@ let SessionStoreInternal = { case "SessionStore:input": this.onTabInput(win, browser); break; - case "SessionStore:MozStorageChanged": - TabStateCache.delete(browser); - this.saveStateDelayed(win); - break; default: debug("received unknown message '" + aMessage.name + "'"); break; @@ -1116,7 +1091,6 @@ let SessionStoreInternal = { let openWindows = {}; this._forEachBrowserWindow(function(aWindow) { Array.forEach(aWindow.gBrowser.tabs, function(aTab) { - TabStateCache.delete(aTab); delete aTab.linkedBrowser.__SS_data; delete aTab.linkedBrowser.__SS_tabStillLoading; delete aTab.linkedBrowser.__SS_formDataSaved; @@ -1340,8 +1314,9 @@ let SessionStoreInternal = { return; } - // Get the latest data for this tab (generally, from the cache) - let tabState = this._collectTabData(aTab); + // make sure that the tab related data is up-to-date + var tabState = this._collectTabData(aTab); + this._updateTextAndScrollDataForTab(aWindow, aTab.linkedBrowser, tabState); // store closed-tab data for undo if (this._shouldSaveTabState(tabState)) { @@ -1362,8 +1337,7 @@ let SessionStoreInternal = { }, /** - * When a tab loads, invalidate its cached state, trigger async save. - * + * When a tab loads, save state. * @param aWindow * Window reference * @param aBrowser @@ -1379,8 +1353,6 @@ let SessionStoreInternal = { return; } - TabStateCache.delete(aBrowser); - delete aBrowser.__SS_data; delete aBrowser.__SS_tabStillLoading; delete aBrowser.__SS_formDataSaved; @@ -1401,8 +1373,6 @@ let SessionStoreInternal = { // deleting __SS_formDataSaved will cause us to recollect form data delete aBrowser.__SS_formDataSaved; - TabStateCache.delete(aBrowser); - this.saveStateDelayed(aWindow, 3000); }, @@ -1526,41 +1496,20 @@ let SessionStoreInternal = { if (!aTab.ownerDocument || !aTab.ownerDocument.defaultView.__SSi) throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); - let tabState = this._collectTabData(aTab); + var tabState = this._collectTabData(aTab); + + var window = aTab.ownerDocument.defaultView; + this._updateTextAndScrollDataForTab(window, aTab.linkedBrowser, tabState); return this._toJSONString(tabState); }, setTabState: function ssi_setTabState(aTab, aState) { - // Remove the tab state from the cache. - // Note that we cannot simply replace the contents of the cache - // as |aState| can be an incomplete state that will be completed - // by |restoreHistoryPrecursor|. - let tabState = JSON.parse(aState); - if (!tabState) { - debug("Empty state argument"); + var tabState = JSON.parse(aState); + if (!tabState.entries || !aTab.ownerDocument || !aTab.ownerDocument.defaultView.__SSi) throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); - } - if (typeof tabState != "object") { - debug("State argument does not represent an object"); - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); - } - if (!("entries" in tabState)) { - debug("State argument must contain field 'entries'"); - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); - } - if (!aTab.ownerDocument) { - debug("Tab argument must have an owner document"); - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); - } - let window = aTab.ownerDocument.defaultView; - if (!("__SSi" in window)) { - debug("Default view of ownerDocument must have a unique identifier"); - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); - } - - TabStateCache.delete(aTab); + var window = aTab.ownerDocument.defaultView; this._setWindowStateBusy(window); this.restoreHistoryPrecursor(window, [aTab], [tabState], 0, 0, 0); }, @@ -1570,9 +1519,9 @@ let SessionStoreInternal = { !aWindow.getBrowser) throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); - // Duplicate the tab state - let tabState = this._cloneFullTabData(aTab); - + var tabState = this._collectTabData(aTab, true); + var sourceWindow = aTab.ownerDocument.defaultView; + this._updateTextAndScrollDataForTab(sourceWindow, aTab.linkedBrowser, tabState, true); tabState.index += aDelta; tabState.index = Math.max(1, Math.min(tabState.index, tabState.entries.length)); tabState.pinned = false; @@ -1742,7 +1691,6 @@ let SessionStoreInternal = { if (aWindow.__SSi && this._windows[aWindow.__SSi].extData && this._windows[aWindow.__SSi].extData[aKey]) delete this._windows[aWindow.__SSi].extData[aKey]; - this.saveStateDelayed(aWindow); }, getTabValue: function ssi_getTabValue(aTab, aKey) { @@ -1758,7 +1706,6 @@ let SessionStoreInternal = { }, setTabValue: function ssi_setTabValue(aTab, aKey, aStringValue) { - TabStateCache.delete(aTab); // If the tab hasn't been restored, then set the data there, otherwise we // could lose newly added data. let saveTo; @@ -1777,7 +1724,6 @@ let SessionStoreInternal = { }, deleteTabValue: function ssi_deleteTabValue(aTab, aKey) { - TabStateCache.delete(aTab); // We want to make sure that if data is accessed early, we attempt to delete // that data from __SS_data as well. Otherwise we'll throw in cases where // data can be set or read. @@ -1791,7 +1737,6 @@ let SessionStoreInternal = { if (deleteFrom && deleteFrom[aKey]) delete deleteFrom[aKey]; - this.saveStateDelayed(aTab.ownerDocument.defaultView); }, persistTabAttribute: function ssi_persistTabAttribute(aName) { @@ -1969,51 +1914,32 @@ let SessionStoreInternal = { /* ........ Saving Functionality .............. */ /** - * Collect data related to a single tab - * - * @param aTab - * tabbrowser tab - * - * @returns {TabData} An object with the data for this tab. If the - * tab has not been invalidated since the last call to - * _collectTabData(aTab), the same object is returned. + * Store all session data for a window + * @param aWindow + * Window reference */ - _collectTabData: function ssi_collectTabData(aTab) { - if (!aTab) { - throw new TypeError("Expecting a tab"); - } - let tabData; - if ((tabData = TabStateCache.get(aTab))) { - return tabData; - } - tabData = new TabData(this._collectBaseTabData(aTab)); - TabStateCache.set(aTab, tabData); + _saveWindowHistory: function ssi_saveWindowHistory(aWindow) { + var tabbrowser = aWindow.gBrowser; + var tabs = tabbrowser.tabs; + var tabsData = this._windows[aWindow.__SSi].tabs = []; - this._updateTextAndScrollDataForTab(aTab, tabData); - return tabData; + for (var i = 0; i < tabs.length; i++) + tabsData.push(this._collectTabData(tabs[i])); + + this._windows[aWindow.__SSi].selected = tabbrowser.mTabBox.selectedIndex + 1; }, /** - * Collect data related to a single tab, including private data. - * Use with caution. - * + * Collect data related to a single tab * @param aTab * tabbrowser tab - * - * @returns {object} An object with the data for this tab. This object - * is recomputed at every call. + * @param aFullData + * always return privacy sensitive data (use with care) + * @returns object */ - _cloneFullTabData: function ssi_cloneFullTabData(aTab) { - let options = { includePrivateData: true }; - let tabData = this._collectBaseTabData(aTab, options); - this._updateTextAndScrollDataForTab(aTab, tabData, options); - return tabData; - }, - - _collectBaseTabData: function ssi_collectBaseTabData(aTab, aOptions = null) { - let includePrivateData = aOptions && aOptions.includePrivateData; - let tabData = {entries: [], lastAccessed: aTab.lastAccessed }; - let browser = aTab.linkedBrowser; + _collectTabData: function ssi_collectTabData(aTab, aFullData) { + var tabData = { entries: [], lastAccessed: aTab.lastAccessed }; + var browser = aTab.linkedBrowser; if (!browser || !browser.currentURI) // can happen when calling this function right after .addTab() @@ -2048,7 +1974,7 @@ let SessionStoreInternal = { if (history && browser.__SS_data && browser.__SS_data.entries[history.index] && browser.__SS_data.entries[history.index].url == browser.currentURI.spec && - history.index < this._sessionhistory_max_entries - 1 && !includePrivateData) { + history.index < this._sessionhistory_max_entries - 1 && !aFullData) { tabData = browser.__SS_data; tabData.index = history.index + 1; } @@ -2057,7 +1983,7 @@ let SessionStoreInternal = { try { for (var j = 0; j < history.count; j++) { let entry = this._serializeHistoryEntry(history.getEntryAtIndex(j, false), - includePrivateData, aTab.pinned, browser.__SS_hostSchemeData); + aFullData, aTab.pinned, browser.__SS_hostSchemeData); tabData.entries.push(entry); } // If we make it through the for loop, then we're ok and we should clear @@ -2083,7 +2009,7 @@ let SessionStoreInternal = { tabData.index = history.index + 1; // make sure not to cache privacy sensitive data which shouldn't get out - if (!includePrivateData) + if (!aFullData) browser.__SS_data = tabData; } else if (browser.currentURI.spec != "about:blank" || @@ -2132,7 +2058,7 @@ let SessionStoreInternal = { delete tabData.extData; if (history && browser.docShell instanceof Ci.nsIDocShell) { - let storageData = SessionStorage.serialize(browser.docShell, includePrivateData) + let storageData = SessionStorage.serialize(browser.docShell, aFullData) if (Object.keys(storageData).length) tabData.storage = storageData; } @@ -2145,7 +2071,7 @@ let SessionStoreInternal = { * Used for data storage * @param aEntry * nsISHEntry instance - * @param aIncludePrivateData + * @param aFullData * always return privacy sensitive data (use with care) * @param aIsPinned * the tab is pinned and should be treated differently for privacy @@ -2154,7 +2080,7 @@ let SessionStoreInternal = { * @returns object */ _serializeHistoryEntry: - function ssi_serializeHistoryEntry(aEntry, aIncludePrivateData, aIsPinned, aHostSchemeData) { + function ssi_serializeHistoryEntry(aEntry, aFullData, aIsPinned, aHostSchemeData) { var entry = { url: aEntry.URI.spec }; try { @@ -2205,7 +2131,7 @@ let SessionStoreInternal = { try { var prefPostdata = this._prefBranch.getIntPref("sessionstore.postdata"); - if (aEntry.postData && (aIncludePrivateData || prefPostdata && + if (aEntry.postData && (aFullData || prefPostdata && this.checkPrivacyLevel(aEntry.URI.schemeIs("https"), aIsPinned))) { aEntry.postData.QueryInterface(Ci.nsISeekableStream). seek(Ci.nsISeekableStream.NS_SEEK_SET, 0); @@ -2214,7 +2140,7 @@ let SessionStoreInternal = { stream.setInputStream(aEntry.postData); var postBytes = stream.readByteArray(stream.available()); var postdata = String.fromCharCode.apply(null, postBytes); - if (aIncludePrivateData || prefPostdata == -1 || + if (aFullData || prefPostdata == -1 || postdata.replace(/^(Content-.*\r\n)+(\r\n)*/, "").length <= prefPostdata) { // We can stop doing base64 encoding once our serialization into JSON @@ -2275,7 +2201,7 @@ let SessionStoreInternal = { break; } - children.push(this._serializeHistoryEntry(child, aIncludePrivateData, + children.push(this._serializeHistoryEntry(child, aFullData, aIsPinned, aHostSchemeData)); } } @@ -2288,25 +2214,37 @@ let SessionStoreInternal = { }, /** - * Go through all frames and store the current scroll positions + * go through all tabs and store the current scroll positions * and innerHTML content of WYSIWYG editors - * - * @param aTab - * tabbrowser tab + * @param aWindow + * Window reference + */ + _updateTextAndScrollData: function ssi_updateTextAndScrollData(aWindow) { + var browsers = aWindow.gBrowser.browsers; + this._windows[aWindow.__SSi].tabs.forEach(function (tabData, i) { + try { + this._updateTextAndScrollDataForTab(aWindow, browsers[i], tabData); + } + catch (ex) { debug(ex); } // get as much data as possible, ignore failures (might succeed the next time) + }, this); + }, + + /** + * go through all frames and store the current scroll positions + * and innerHTML content of WYSIWYG editors + * @param aWindow + * Window reference + * @param aBrowser + * single browser reference * @param aTabData * tabData object to add the information to - * @param options - * An optional object that may contain the following field: - * - includePrivateData: always return privacy sensitive data - * (use with care) + * @param aFullData + * always return privacy sensitive data (use with care) */ _updateTextAndScrollDataForTab: - function ssi_updateTextAndScrollDataForTab(aTab, aTabData, aOptions = null) { - let includePrivateData = aOptions && aOptions.includePrivateData; - let window = aTab.ownerDocument.defaultView; - let browser = aTab.linkedBrowser; + function ssi_updateTextAndScrollDataForTab(aWindow, aBrowser, aTabData, aFullData) { // we shouldn't update data for incompletely initialized tabs - if (browser.__SS_data && browser.__SS_tabStillLoading) + if (aBrowser.__SS_data && aBrowser.__SS_tabStillLoading) return; var tabIndex = (aTabData.index || aTabData.entries.length) - 1; @@ -2314,22 +2252,22 @@ let SessionStoreInternal = { if (!aTabData.entries[tabIndex]) return; - let selectedPageStyle = browser.markupDocumentViewer.authorStyleDisabled ? "_nostyle" : - this._getSelectedPageStyle(browser.contentWindow); + let selectedPageStyle = aBrowser.markupDocumentViewer.authorStyleDisabled ? "_nostyle" : + this._getSelectedPageStyle(aBrowser.contentWindow); if (selectedPageStyle) aTabData.pageStyle = selectedPageStyle; else if (aTabData.pageStyle) delete aTabData.pageStyle; - this._updateTextAndScrollDataForFrame(window, browser.contentWindow, + this._updateTextAndScrollDataForFrame(aWindow, aBrowser.contentWindow, aTabData.entries[tabIndex], - !browser.__SS_formDataSaved, includePrivateData, + !aBrowser.__SS_formDataSaved, aFullData, !!aTabData.pinned); - browser.__SS_formDataSaved = true; - if (browser.currentURI.spec == "about:config") + aBrowser.__SS_formDataSaved = true; + if (aBrowser.currentURI.spec == "about:config") aTabData.entries[tabIndex].formdata = { id: { - "textbox": browser.contentDocument.getElementById("textbox").value + "textbox": aBrowser.contentDocument.getElementById("textbox").value }, xpath: {} }; @@ -2346,26 +2284,26 @@ let SessionStoreInternal = { * part of a tabData object to add the information to * @param aUpdateFormData * update all form data for this tab - * @param aIncludePrivateData + * @param aFullData * always return privacy sensitive data (use with care) * @param aIsPinned * the tab is pinned and should be treated differently for privacy */ _updateTextAndScrollDataForFrame: function ssi_updateTextAndScrollDataForFrame(aWindow, aContent, aData, - aUpdateFormData, aIncludePrivateData, aIsPinned) { + aUpdateFormData, aFullData, aIsPinned) { for (var i = 0; i < aContent.frames.length; i++) { if (aData.children && aData.children[i]) this._updateTextAndScrollDataForFrame(aWindow, aContent.frames[i], aData.children[i], aUpdateFormData, - aIncludePrivateData, aIsPinned); + aFullData, aIsPinned); } var isHTTPS = this._getURIFromString((aContent.parent || aContent). document.location.href).schemeIs("https"); let topURL = aContent.top.document.location.href; let isAboutSR = topURL == "about:sessionrestore" || topURL == "about:welcomeback"; - if (aIncludePrivateData || this.checkPrivacyLevel(isHTTPS, aIsPinned) || isAboutSR) { - if (aIncludePrivateData || aUpdateFormData) { + if (aFullData || this.checkPrivacyLevel(isHTTPS, aIsPinned) || isAboutSR) { + if (aFullData || aUpdateFormData) { let formData = DocumentUtils.getFormData(aContent.document); // We want to avoid saving data for about:sessionrestore as a string. @@ -2488,6 +2426,28 @@ let SessionStoreInternal = { } }, + /** + * store all hosts for a URL + * @param aWindow + * Window reference + */ + _updateCookieHosts: function ssi_updateCookieHosts(aWindow) { + var hosts = this._internalWindows[aWindow.__SSi].hosts = {}; + + // Since _updateCookiesHosts is only ever called for open windows during a + // session, we can call into _extractHostsForCookiesFromHostScheme directly + // using data that is attached to each browser. + for (let i = 0; i < aWindow.gBrowser.tabs.length; i++) { + let tab = aWindow.gBrowser.tabs[i]; + let hostSchemeData = tab.linkedBrowser.__SS_hostSchemeData || []; + for (let j = 0; j < hostSchemeData.length; j++) { + this._extractHostsForCookiesFromHostScheme(hostSchemeData[j].host, + hostSchemeData[j].scheme, + hosts, true, tab.pinned); + } + } + }, + /** * Serialize cookie data * @param aWindows @@ -2725,29 +2685,10 @@ let SessionStoreInternal = { if (!this._isWindowLoaded(aWindow)) return; - let tabbrowser = aWindow.gBrowser; - let tabs = tabbrowser.tabs; - let winData = this._windows[aWindow.__SSi]; - let tabsData = winData.tabs = []; - let hosts = this._internalWindows[aWindow.__SSi].hosts = {}; - // update the internal state data for this window - for (let tab of tabs) { - tabsData.push(this._collectTabData(tab)); - - // Since we are only ever called for open - // windows during a session, we can call into - // _extractHostsForCookiesFromHostScheme directly using data - // that is attached to each browser. - let hostSchemeData = tab.linkedBrowser.__SS_hostSchemeData || []; - for (let j = 0; j < hostSchemeData.length; j++) { - this._extractHostsForCookiesFromHostScheme(hostSchemeData[j].host, - hostSchemeData[j].scheme, - hosts, true, tab.pinned); - } - } - winData.selected = tabbrowser.mTabBox.selectedIndex + 1; - + this._saveWindowHistory(aWindow); + this._updateTextAndScrollData(aWindow); + this._updateCookieHosts(aWindow); this._updateWindowFeatures(aWindow); // Make sure we keep __SS_lastSessionWindowID around for cases like entering @@ -3046,7 +2987,6 @@ let SessionStoreInternal = { restoreHistoryPrecursor: function ssi_restoreHistoryPrecursor(aWindow, aTabs, aTabData, aSelectTab, aIx, aCount, aRestoreImmediately = false) { - var tabbrowser = aWindow.gBrowser; // make sure that all browsers and their histories are available @@ -3062,7 +3002,7 @@ let SessionStoreInternal = { var restoreHistoryFunc = function(self) { self.restoreHistoryPrecursor(aWindow, aTabs, aTabData, aSelectTab, aIx, aCount + 1, aRestoreImmediately); - }; + } aWindow.setTimeout(restoreHistoryFunc, 100, this); return; } @@ -3198,6 +3138,7 @@ let SessionStoreInternal = { var tab = aTabs.shift(); var tabData = aTabData.shift(); + var browser = aWindow.gBrowser.getBrowserForTab(tab); var history = browser.webNavigation.sessionHistory; @@ -3762,7 +3703,7 @@ let SessionStoreInternal = { * @param aDelay * Milliseconds to delay */ - saveStateDelayed: function ssi_saveStateDelayed(aWindow = null, aDelay = 2000) { + saveStateDelayed: function ssi_saveStateDelayed(aWindow, aDelay) { if (aWindow) { this._dirtyWindows[aWindow.__SSi] = true; } @@ -3772,7 +3713,7 @@ let SessionStoreInternal = { var minimalDelay = this._lastSaveTime + this._interval - Date.now(); // if we have to wait, set a timer, otherwise saveState directly - aDelay = Math.max(minimalDelay, aDelay); + aDelay = Math.max(minimalDelay, aDelay || 2000); if (aDelay > 0) { this._saveTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); this._saveTimer.init(this, aDelay, Ci.nsITimer.TYPE_ONE_SHOT); @@ -4044,7 +3985,6 @@ let SessionStoreInternal = { if (tab.linkedBrowser == aBrowser) return tab; } - return undefined; }, /** @@ -4867,25 +4807,11 @@ SessionStoreSHistoryListener.prototype = { Ci.nsISupportsWeakReference ]), browser: null, -// The following events (with the exception of OnHistoryPurge) -// accompany either a "load" or a "pageshow" which will in turn cause -// invalidations. - OnHistoryNewEntry: function(aNewURI) { - - }, - OnHistoryGoBack: function(aBackURI) { - return true; - }, - OnHistoryGoForward: function(aForwardURI) { - return true; - }, - OnHistoryGotoIndex: function(aIndex, aGotoURI) { - return true; - }, - OnHistoryPurge: function(aNumEntries) { - TabStateCache.delete(this.tab); - return true; - }, + OnHistoryNewEntry: function(aNewURI) { }, + OnHistoryGoBack: function(aBackURI) { return true; }, + OnHistoryGoForward: function(aForwardURI) { return true; }, + OnHistoryGotoIndex: function(aIndex, aGotoURI) { return true; }, + OnHistoryPurge: function(aNumEntries) { return true; }, OnHistoryReload: function(aReloadURI, aReloadFlags) { // On reload, we want to make sure that session history loads the right // URI. In order to do that, we will juet call restoreTab. That will remove @@ -4908,83 +4834,4 @@ String.prototype.hasRootDomain = function hasRootDomain(aDomain) { let prevChar = this[index - 1]; return (index == (this.length - aDomain.length)) && (prevChar == "." || prevChar == "/"); -}; - -function TabData(obj = null) { - if (obj) { - if (obj instanceof TabData) { - // FIXME: Can we get rid of this? - return obj; - } - for (let [key, value] in Iterator(obj)) { - this[key] = value; - } - } - return this; } - -/** - * A cache for tabs data. - * - * This cache implements a weak map from tabs (as XUL elements) - * to tab data (as instances of TabData). - * - * Note that we should never cache private data, as: - * - that data is used very seldom by SessionStore; - * - caching private data in addition to public data is memory consuming. - */ -let TabStateCache = { - _data: new WeakMap(), - - /** - * Add or replace an entry in the cache. - * - * @param {XULElement} aTab The key, which may be either a tab - * or the corresponding browser. The binding will disappear - * if the tab/browser is destroyed. - * @param {TabData} aValue The data associated to |aTab|. - */ - set: function(aTab, aValue) { - let key = this._normalizeToBrowser(aTab); - if (!(aValue instanceof TabData)) { - throw new TypeError("Attempting to cache a non TabData"); - } - this._data.set(key, aValue); - }, - - /** - * Return the tab data associated with a tab. - * - * @param {XULElement} aKey The tab or the associated browser. - * - * @return {TabData|undefined} The data if available, |undefined| - * otherwise. - */ - get: function(aKey) { - let key = this._normalizeToBrowser(aKey); - return this._data.get(key); - }, - - /** - * Delete the tab data associated with a tab. - * - * @param {XULElement} aKey The tab or the associated browser. - * - * Noop of there is no tab data associated with the tab. - */ - delete: function(aKey) { - let key = this._normalizeToBrowser(aKey); - this._data.delete(key); - }, - - _normalizeToBrowser: function(aKey) { - let nodeName = aKey.localName; - if (nodeName == "tab") { - return aKey.linkedBrowser; - } - if (nodeName == "browser") { - return aKey; - } - throw new TypeError("Key is neither a tab nor a browser: " + nodeName); - } -}; diff --git a/browser/components/sessionstore/test/Makefile.in b/browser/components/sessionstore/test/Makefile.in index 1b744b26b7b..371c778ede0 100644 --- a/browser/components/sessionstore/test/Makefile.in +++ b/browser/components/sessionstore/test/Makefile.in @@ -27,7 +27,6 @@ MOCHITEST_BROWSER_FILES = \ browser_input.js \ browser_input_sample.html \ browser_pageshow.js \ - browser_sessionStorage.js \ browser_upgrade_backup.js \ browser_windowRestore_perwindowpb.js \ browser_248970_b_perwindowpb.js \ diff --git a/browser/components/sessionstore/test/browser_sessionStorage.js b/browser/components/sessionstore/test/browser_sessionStorage.js deleted file mode 100644 index 0436d1ea172..00000000000 --- a/browser/components/sessionstore/test/browser_sessionStorage.js +++ /dev/null @@ -1,89 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -let Scope = {}; -Cu.import("resource://gre/modules/Task.jsm", Scope); -Cu.import("resource://gre/modules/Promise.jsm", Scope); -let {Task, Promise} = Scope; - -function promiseBrowserLoaded(aBrowser) { - let deferred = Promise.defer(); - whenBrowserLoaded(aBrowser, () => deferred.resolve()); - return deferred.promise; -} - -function forceWriteState() { - let deferred = Promise.defer(); - const PREF = "browser.sessionstore.interval"; - const TOPIC = "sessionstore-state-write"; - - Services.obs.addObserver(function observe() { - Services.obs.removeObserver(observe, TOPIC); - Services.prefs.clearUserPref(PREF); - deferred.resolve(); - }, TOPIC, false); - - Services.prefs.setIntPref(PREF, 0); - return deferred.promise; -} - -function waitForStorageChange(aTab) { - let deferred = Promise.defer(); - waitForContentMessage(aTab.linkedBrowser, - "sessionstore:MozStorageChanged", - 200, - ((x) => deferred.resolve(x))); - return deferred.promise; -} - -function test() { - - waitForExplicitFinish(); - - let tab; - Task.spawn(function() { - try { - tab = gBrowser.addTab("http://example.com"); - // about:home supports sessionStorage and localStorage - - let win = tab.linkedBrowser.contentWindow; - - // Flush loading and next save, call getBrowserState() - // a few times to ensure that everything is cached. - yield promiseBrowserLoaded(tab.linkedBrowser); - yield forceWriteState(); - info("Calling getBrowserState() to populate cache"); - ss.getBrowserState(); - - info("Change sessionStorage, ensure that state is saved"); - win.sessionStorage["SESSION_STORAGE_KEY"] = "SESSION_STORAGE_VALUE"; - yield waitForStorageChange(tab); - yield forceWriteState(); - - let state = ss.getBrowserState(); - ok(state.indexOf("SESSION_STORAGE_KEY") != -1, "Key appears in state"); - ok(state.indexOf("SESSION_STORAGE_VALUE") != -1, "Value appears in state"); - - - info("Change localStorage, ensure that state is not saved"); - win.localStorage["LOCAL_STORAGE_KEY"] = "LOCAL_STORAGE_VALUE"; - yield waitForStorageChange(tab); - yield forceWriteState(); - - state = ss.getBrowserState(); - ok(state.indexOf("LOCAL_STORAGE_KEY") == -1, "Key does not appear in state"); - ok(state.indexOf("LOCAL_STORAGE_VALUE") == -1, "Value does not appear in state"); - } catch (ex) { - ok(false, ex); - info(ex.stack); - } finally { - // clean up - if (tab) { - gBrowser.removeTab(tab); - } - - executeSoon(finish); - } - }); -} diff --git a/browser/components/sessionstore/test/head.js b/browser/components/sessionstore/test/head.js index 36de8e159be..ac2849b581b 100644 --- a/browser/components/sessionstore/test/head.js +++ b/browser/components/sessionstore/test/head.js @@ -156,90 +156,43 @@ function waitForTabState(aTab, aState, aCallback) { ss.setTabState(aTab, JSON.stringify(aState)); } -/** - * Wait for a content -> chrome message. - */ -function waitForContentMessage(aBrowser, aTopic, aTimeout, aCallback) { - let mm = aBrowser.messageManager; +// waitForSaveState waits for a state write but not necessarily for the state to +// turn dirty. +function waitForSaveState(aSaveStateCallback) { let observing = false; - function removeObserver() { - if (!observing) - return; - mm.removeMessageListener(aTopic, observer); - observing = false; - } + let topic = "sessionstore-state-write"; - let timeout = setTimeout(function () { - removeObserver(); - aCallback(false); - }, aTimeout); - - function observer(aSubject, aTopic, aData) { - removeObserver(); - timeout = clearTimeout(timeout); - executeSoon(() => aCallback(true)); - } - - registerCleanupFunction(function() { - removeObserver(); - if (timeout) { - clearTimeout(timeout); - } - }); - - observing = true; - mm.addMessageListener(aTopic, observer); -} - -function waitForTopic(aTopic, aTimeout, aCallback) { - let observing = false; - function removeObserver() { - if (!observing) - return; - Services.obs.removeObserver(observer, aTopic); - observing = false; - } - - let timeout = setTimeout(function () { - removeObserver(); - aCallback(false); - }, aTimeout); - - function observer(aSubject, aTopic, aData) { - removeObserver(); - timeout = clearTimeout(timeout); - executeSoon(() => aCallback(true)); - } - - registerCleanupFunction(function() { - removeObserver(); - if (timeout) { - clearTimeout(timeout); - } - }); - - observing = true; - Services.obs.addObserver(observer, aTopic, false); -} - -/** - * Wait until session restore has finished collecting its data and is - * getting ready to write that data ("sessionstore-state-write"). - * - * This function is meant to be called immediately after the code - * that will trigger the saving. - * - * Note that this does not wait for the disk write to be complete. - * - * @param {function} aCallback If sessionstore-state-write is sent - * within buffering interval + 100 ms, the callback is passed |true|, - * otherwise, it is passed |false|. - */ -function waitForSaveState(aCallback) { - let timeout = 100 + + let sessionSaveTimeout = 1000 + Services.prefs.getIntPref("browser.sessionstore.interval"); - return waitForTopic("sessionstore-state-write", timeout, aCallback); -} + + function removeObserver() { + if (!observing) + return; + Services.obs.removeObserver(observer, topic); + observing = false; + } + + let timeout = setTimeout(function () { + removeObserver(); + aSaveStateCallback(); + }, sessionSaveTimeout); + + function observer(aSubject, aTopic, aData) { + removeObserver(); + timeout = clearTimeout(timeout); + executeSoon(aSaveStateCallback); + } + + registerCleanupFunction(function() { + removeObserver(); + if (timeout) { + clearTimeout(timeout); + } + }); + + observing = true; + Services.obs.addObserver(observer, topic, false); +}; function whenBrowserLoaded(aBrowser, aCallback = next) { aBrowser.addEventListener("load", function onLoad() { From e759c0e570e750d1f494bc27442ae3e1c54b1998 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Fri, 19 Jul 2013 12:00:48 -0400 Subject: [PATCH 29/58] Backed out 5 changesets (bug 882543) for crashtest orange on a CLOSED TREE. Backed out changeset b36516aab389 (bug 882543) Backed out changeset 07550003a24a (bug 882543) Backed out changeset f4045c40afb4 (bug 882543) Backed out changeset 1b87e0bd2858 (bug 882543) Backed out changeset 8d76a3440800 (bug 882543) --- content/media/MediaStreamGraph.cpp | 135 +++++++++------------------ content/media/MediaStreamGraph.h | 3 +- content/media/MediaStreamGraphImpl.h | 20 +--- xpcom/glue/nsTArray.h | 14 --- 4 files changed, 45 insertions(+), 127 deletions(-) diff --git a/content/media/MediaStreamGraph.cpp b/content/media/MediaStreamGraph.cpp index d323f5758cb..369d423cf19 100644 --- a/content/media/MediaStreamGraph.cpp +++ b/content/media/MediaStreamGraph.cpp @@ -4,7 +4,6 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "MediaStreamGraphImpl.h" -#include "mozilla/LinkedList.h" #include "AudioSegment.h" #include "VideoSegment.h" @@ -24,7 +23,6 @@ #include "AudioNodeStream.h" #include #include "DOMMediaStream.h" -#include "GeckoProfiler.h" using namespace mozilla::layers; using namespace mozilla::dom; @@ -315,30 +313,20 @@ MediaStreamGraphImpl::GetAudioPosition(MediaStream* aStream) void MediaStreamGraphImpl::UpdateCurrentTime() { - GraphTime prevCurrentTime, nextCurrentTime; - if (mRealtime) { - TimeStamp now = TimeStamp::Now(); - prevCurrentTime = mCurrentTime; - nextCurrentTime = - SecondsToMediaTime((now - mCurrentTimeStamp).ToSeconds()) + mCurrentTime; - - mCurrentTimeStamp = now; - LOG(PR_LOG_DEBUG+1, ("Updating current time to %f (real %f, mStateComputedTime %f)", - MediaTimeToSeconds(nextCurrentTime), - (now - mInitialTimeStamp).ToSeconds(), - MediaTimeToSeconds(mStateComputedTime))); - } else { - prevCurrentTime = mCurrentTime; - nextCurrentTime = mCurrentTime + MEDIA_GRAPH_TARGET_PERIOD_MS; - LOG(PR_LOG_DEBUG+1, ("Updating offline current time to %f (mStateComputedTime %f)", - MediaTimeToSeconds(nextCurrentTime), - MediaTimeToSeconds(mStateComputedTime))); - } - + GraphTime prevCurrentTime = mCurrentTime; + TimeStamp now = TimeStamp::Now(); + GraphTime nextCurrentTime = + SecondsToMediaTime((now - mCurrentTimeStamp).ToSeconds()) + mCurrentTime; if (mStateComputedTime < nextCurrentTime) { LOG(PR_LOG_WARNING, ("Media graph global underrun detected")); nextCurrentTime = mStateComputedTime; } + mCurrentTimeStamp = now; + + LOG(PR_LOG_DEBUG+1, ("Updating current time to %f (real %f, mStateComputedTime %f)", + MediaTimeToSeconds(nextCurrentTime), + (now - mInitialTimeStamp).ToSeconds(), + MediaTimeToSeconds(mStateComputedTime))); if (prevCurrentTime >= nextCurrentTime) { NS_ASSERTION(prevCurrentTime == nextCurrentTime, "Time can't go backwards!"); @@ -466,22 +454,22 @@ MediaStreamGraphImpl::MarkConsumed(MediaStream* aStream) } void -MediaStreamGraphImpl::UpdateStreamOrderForStream(mozilla::LinkedList* aStack, +MediaStreamGraphImpl::UpdateStreamOrderForStream(nsTArray* aStack, already_AddRefed aStream) { nsRefPtr stream = aStream; NS_ASSERTION(!stream->mHasBeenOrdered, "stream should not have already been ordered"); if (stream->mIsOnOrderingStack) { - MediaStream* iter = aStack->getLast(); - do { - iter->AsProcessedStream()->mInCycle = true; - iter = iter->getPrevious(); - } while (iter != stream); + for (int32_t i = aStack->Length() - 1; ; --i) { + aStack->ElementAt(i)->AsProcessedStream()->mInCycle = true; + if (aStack->ElementAt(i) == stream) + break; + } return; } ProcessedMediaStream* ps = stream->AsProcessedStream(); if (ps) { - aStack->insertBack(stream); + aStack->AppendElement(stream); stream->mIsOnOrderingStack = true; for (uint32_t i = 0; i < ps->mInputs.Length(); ++i) { MediaStream* source = ps->mInputs[i]->mSource; @@ -490,7 +478,7 @@ MediaStreamGraphImpl::UpdateStreamOrderForStream(mozilla::LinkedListpopLast(); + aStack->RemoveElementAt(aStack->Length() - 1); stream->mIsOnOrderingStack = false; } @@ -501,10 +489,10 @@ MediaStreamGraphImpl::UpdateStreamOrderForStream(mozilla::LinkedList > oldStreams; + oldStreams.SwapElements(mStreams); + for (uint32_t i = 0; i < oldStreams.Length(); ++i) { + MediaStream* stream = oldStreams[i]; stream->mHasBeenOrdered = false; stream->mIsConsumed = false; stream->mIsOnOrderingStack = false; @@ -515,9 +503,9 @@ MediaStreamGraphImpl::UpdateStreamOrder() } } - mozilla::LinkedList stack; - for (uint32_t i = 0; i < mOldStreams.Length(); ++i) { - nsRefPtr& s = mOldStreams[i]; + nsAutoTArray stack; + for (uint32_t i = 0; i < oldStreams.Length(); ++i) { + nsRefPtr& s = oldStreams[i]; if (!s->mAudioOutputs.IsEmpty() || !s->mVideoOutputs.IsEmpty()) { MarkConsumed(s); } @@ -900,47 +888,28 @@ MediaStreamGraphImpl::PlayVideo(MediaStream* aStream) } } -bool -MediaStreamGraphImpl::ShouldUpdateMainThread() -{ - if (mRealtime) { - return true; - } - - TimeStamp now = TimeStamp::Now(); - if ((now - mLastMainThreadUpdate).ToMilliseconds() > MEDIA_GRAPH_TARGET_PERIOD_MS) { - mLastMainThreadUpdate = now; - return true; - } - return false; -} - void MediaStreamGraphImpl::PrepareUpdatesToMainThreadState(bool aFinalUpdate) { mMonitor.AssertCurrentThreadOwns(); - // We don't want to update the main thread about timing update when we are not - // running in realtime. - if (ShouldUpdateMainThread()) { - mStreamUpdates.SetCapacity(mStreamUpdates.Length() + mStreams.Length()); - for (uint32_t i = 0; i < mStreams.Length(); ++i) { - MediaStream* stream = mStreams[i]; - if (!stream->MainThreadNeedsUpdates()) { - continue; - } - StreamUpdate* update = mStreamUpdates.AppendElement(); - update->mGraphUpdateIndex = stream->mGraphUpdateIndices.GetAt(mCurrentTime); - update->mStream = stream; - update->mNextMainThreadCurrentTime = - GraphTimeToStreamTime(stream, mCurrentTime); - update->mNextMainThreadFinished = - stream->mFinished && - StreamTimeToGraphTime(stream, stream->GetBufferEnd()) <= mCurrentTime; - } - if (!mPendingUpdateRunnables.IsEmpty()) { - mUpdateRunnables.MoveElementsFrom(mPendingUpdateRunnables); + mStreamUpdates.SetCapacity(mStreamUpdates.Length() + mStreams.Length()); + for (uint32_t i = 0; i < mStreams.Length(); ++i) { + MediaStream* stream = mStreams[i]; + if (!stream->MainThreadNeedsUpdates()) { + continue; } + StreamUpdate* update = mStreamUpdates.AppendElement(); + update->mGraphUpdateIndex = stream->mGraphUpdateIndices.GetAt(mCurrentTime); + update->mStream = stream; + update->mNextMainThreadCurrentTime = + GraphTimeToStreamTime(stream, mCurrentTime); + update->mNextMainThreadFinished = + stream->mFinished && + StreamTimeToGraphTime(stream, stream->GetBufferEnd()) <= mCurrentTime; + } + if (!mPendingUpdateRunnables.IsEmpty()) { + mUpdateRunnables.MoveElementsFrom(mPendingUpdateRunnables); } // Don't send the message to the main thread if it's not going to have @@ -1203,7 +1172,6 @@ MediaStreamGraphImpl::RunThread() if (!mRealtime) { mNonRealtimeIsRunning = false; } - profiler_unregister_thread(); } void @@ -1249,23 +1217,6 @@ MediaStreamGraphImpl::ForceShutDown() namespace { -class MediaStreamGraphInitThreadRunnable : public nsRunnable { -public: - explicit MediaStreamGraphInitThreadRunnable(MediaStreamGraphImpl* aGraph) - : mGraph(aGraph) - { - } - NS_IMETHOD Run() - { - char aLocal; - profiler_register_thread("MediaStreamGraph", &aLocal); - mGraph->RunThread(); - return NS_OK; - } -private: - MediaStreamGraphImpl* mGraph; -}; - class MediaStreamGraphThreadRunnable : public nsRunnable { public: explicit MediaStreamGraphThreadRunnable(MediaStreamGraphImpl* aGraph) @@ -1405,7 +1356,7 @@ MediaStreamGraphImpl::RunInStableState() // Start the thread now. We couldn't start it earlier because // the graph might exit immediately on finding it has no streams. The // first message for a new graph must create a stream. - nsCOMPtr event = new MediaStreamGraphInitThreadRunnable(this); + nsCOMPtr event = new MediaStreamGraphThreadRunnable(this); NS_NewNamedThread("MediaStreamGrph", getter_AddRefs(mThread), event); } @@ -2217,7 +2168,7 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(bool aRealtime) } #endif - mCurrentTimeStamp = mInitialTimeStamp = mLastMainThreadUpdate = TimeStamp::Now(); + mCurrentTimeStamp = mInitialTimeStamp = TimeStamp::Now(); } NS_IMPL_ISUPPORTS1(MediaStreamGraphShutdownObserver, nsIObserver) diff --git a/content/media/MediaStreamGraph.h b/content/media/MediaStreamGraph.h index 2465e673780..9cf5df5459b 100644 --- a/content/media/MediaStreamGraph.h +++ b/content/media/MediaStreamGraph.h @@ -7,7 +7,6 @@ #define MOZILLA_MEDIASTREAMGRAPH_H_ #include "mozilla/Mutex.h" -#include "mozilla/LinkedList.h" #include "AudioStream.h" #include "nsTArray.h" #include "nsIRunnable.h" @@ -258,7 +257,7 @@ struct AudioChunk; * for those objects in arbitrary order and the MediaStreamGraph has to be able * to handle this. */ -class MediaStream : public mozilla::LinkedListElement { +class MediaStream { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaStream) diff --git a/content/media/MediaStreamGraphImpl.h b/content/media/MediaStreamGraphImpl.h index 695fb5f1239..628c1f5525a 100644 --- a/content/media/MediaStreamGraphImpl.h +++ b/content/media/MediaStreamGraphImpl.h @@ -15,9 +15,6 @@ namespace mozilla { -template -class LinkedList; - #ifdef PR_LOGGING extern PRLogModuleInfo* gMediaStreamGraphLog; #define LOG(type, msg) PR_LOG(gMediaStreamGraphLog, type, msg) @@ -193,12 +190,6 @@ public: * mMonitor must be held. */ void PrepareUpdatesToMainThreadState(bool aFinalUpdate); - /** - * If we are rendering in non-realtime mode, we don't want to send messages to - * the main thread at each iteration for performance reasons. We instead - * notify the main thread at the same rate - */ - bool ShouldUpdateMainThread(); // The following methods are the various stages of RunThread processing. /** * Compute a new current time for the graph and advance all on-graph-thread @@ -224,7 +215,7 @@ public: * If aStream hasn't already been ordered, push it onto aStack and order * its children. */ - void UpdateStreamOrderForStream(mozilla::LinkedList* aStack, + void UpdateStreamOrderForStream(nsTArray* aStack, already_AddRefed aStream); /** * Mark aStream and all its inputs (recursively) as consumed. @@ -379,11 +370,6 @@ public: // is not running and this state can be used from the main thread. nsTArray > mStreams; - /** - * mOldStreams is used as temporary storage for streams when computing the - * order in which we compute them. - */ - nsTArray > mOldStreams; /** * The current graph time for the current iteration of the RunThread control * loop. @@ -403,10 +389,6 @@ public: * The real timestamp of the latest run of UpdateCurrentTime. */ TimeStamp mCurrentTimeStamp; - /** - * Date of the last time we updated the main thread with the graph state. - */ - TimeStamp mLastMainThreadUpdate; /** * Which update batch we are currently processing. */ diff --git a/xpcom/glue/nsTArray.h b/xpcom/glue/nsTArray.h index 3a386477005..06a6ae64f3a 100644 --- a/xpcom/glue/nsTArray.h +++ b/xpcom/glue/nsTArray.h @@ -1042,20 +1042,6 @@ public: // // Mutation methods // - // This method call the destructor on each element of the array, empties it, - // but does not shrink the array's capacity. - // - // Make sure to call Compact() if needed to avoid keeping a huge array - // around. - void ClearAndRetainStorage() { - if (base_type::mHdr == EmptyHdr()) { - return; - } - - DestructRange(0, Length()); - base_type::mHdr->mLength = 0; - } - // This method replaces a range of elements in this array. // @param start The starting index of the elements to replace. From 404372d3dd8f48c2386edc545f412a27d53b26b6 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 17 Jul 2013 09:58:00 +0200 Subject: [PATCH 30/58] Bug 894854: env var disabling censoring of self-hosted script frames (r=till) It is only aenabled for debug builds. The env var is: MOZ_SHOW_ALL_JS_FRAMES --- js/src/vm/Stack.cpp | 8 ++++++++ js/src/vm/Stack.h | 13 +++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 7633ad47796..4a36d503441 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -1220,6 +1220,14 @@ ScriptFrameIter::frameSlotValue(size_t index) const # pragma optimize("", on) #endif +#ifdef DEBUG +/* static */ +bool NonBuiltinScriptFrameIter::includeSelfhostedFrames() { + static char* env = getenv("MOZ_SHOW_ALL_JS_FRAMES"); + return (bool)env; +} +#endif + /*****************************************************************************/ JSObject * diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 20a62ed7e57..0d30d0f02f0 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -1540,9 +1540,18 @@ class ScriptFrameIter /* A filtering of the ScriptFrameIter to only stop at non-self-hosted scripts. */ class NonBuiltinScriptFrameIter : public ScriptFrameIter { +#ifdef DEBUG + static bool includeSelfhostedFrames(); +#else + static bool includeSelfhostedFrames() { + return false; + } +#endif + void settle() { - while (!done() && script()->selfHosted) - ScriptFrameIter::operator++(); + if (!includeSelfhostedFrames()) + while (!done() && script()->selfHosted) + ScriptFrameIter::operator++(); } public: From 0f2fac7086b7a985bd1bcd74786389e6efc6000a Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Thu, 18 Jul 2013 15:10:23 -0700 Subject: [PATCH 31/58] Bug 895647 - new GC type: js::LazyScript, r=terrence DONTBUILD --HG-- extra : rebase_source : 78d019afe1f46c056c561c2faf4dac351ffb4454 --- js/src/devtools/rootAnalysis/computeGCTypes.js | 1 + 1 file changed, 1 insertion(+) diff --git a/js/src/devtools/rootAnalysis/computeGCTypes.js b/js/src/devtools/rootAnalysis/computeGCTypes.js index 8918d5f9f51..799d837e6d3 100644 --- a/js/src/devtools/rootAnalysis/computeGCTypes.js +++ b/js/src/devtools/rootAnalysis/computeGCTypes.js @@ -94,6 +94,7 @@ addGCType('JSString'); addGCType('js::Shape'); addGCType('js::BaseShape'); addGCType('JSScript'); +addGCType('js::LazyScript'); addGCType('js::ion::IonCode'); addGCPointer('JS::Value'); addGCPointer('jsid'); From abb6379863489eb434b81a16e8d322e86df2635b Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Thu, 18 Jul 2013 15:12:46 -0700 Subject: [PATCH 32/58] Bug 895654 - Remove references to Unrooted from the static exact rooting analysis; r=bhackett,sfink,terrence DONTBUILD --HG-- extra : rebase_source : 32046960a39679cf82916dc7d35ea3374de700f8 --- js/src/devtools/rootAnalysis/annotations.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/js/src/devtools/rootAnalysis/annotations.js b/js/src/devtools/rootAnalysis/annotations.js index b00d13c7bd3..548dd644546 100644 --- a/js/src/devtools/rootAnalysis/annotations.js +++ b/js/src/devtools/rootAnalysis/annotations.js @@ -94,10 +94,6 @@ function ignoreEdgeUse(edge, variable) var name = callee.Variable.Name[0]; if (/~Anchor/.test(name)) return true; - if (/::Unrooted\(\)/.test(name)) - return true; - if (/::~Unrooted\(\)/.test(name)) - return true; if (/~DebugOnly/.test(name)) return true; } From b4d9092033c20e7f4ca44d9cdfe23b12e26b7666 Mon Sep 17 00:00:00 2001 From: Wes Johnston Date: Thu, 18 Jul 2013 16:35:34 -0700 Subject: [PATCH 33/58] Bug 885783 - Attach webrtc to a foreground notification. r=bnicholson --- mobile/android/base/GeckoAppShell.java | 9 +- mobile/android/base/NotificationClient.java | 24 ++++- mobile/android/base/NotificationHandler.java | 100 ++++++++++++++----- mobile/android/base/NotificationHelper.java | 6 +- mobile/android/base/NotificationService.java | 28 ++++-- 5 files changed, 118 insertions(+), 49 deletions(-) diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index 80b4f81382d..1c83ac3b0cf 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -1256,13 +1256,6 @@ public class GeckoAppShell public static void showAlertNotification(String aImageUrl, String aAlertTitle, String aAlertText, String aAlertCookie, String aAlertName) { - Log.d(LOGTAG, "GeckoAppShell.showAlertNotification\n" + - "- image = '" + aImageUrl + "'\n" + - "- title = '" + aAlertTitle + "'\n" + - "- text = '" + aAlertText +"'\n" + - "- cookie = '" + aAlertCookie +"'\n" + - "- name = '" + aAlertName + "'"); - // The intent to launch when the user clicks the expanded notification String app = getContext().getClass().getName(); Intent notificationIntent = new Intent(GeckoApp.ACTION_ALERT_CALLBACK); @@ -1316,7 +1309,7 @@ public class GeckoAppShell if (GeckoApp.ACTION_ALERT_CALLBACK.equals(aAction)) { callObserver(aAlertName, "alertclickcallback", aAlertCookie); - if (sNotificationClient.isProgressStyle(notificationID)) { + if (sNotificationClient.isOngoing(notificationID)) { // When clicked, keep the notification if it displays progress return; } diff --git a/mobile/android/base/NotificationClient.java b/mobile/android/base/NotificationClient.java index 95b1145964a..6855944a6ff 100644 --- a/mobile/android/base/NotificationClient.java +++ b/mobile/android/base/NotificationClient.java @@ -5,6 +5,7 @@ package org.mozilla.gecko; +import android.app.Notification; import android.app.PendingIntent; import android.text.TextUtils; import android.util.Log; @@ -88,6 +89,25 @@ public abstract class NotificationClient { } } + /** + * Adds a notification. + * + * @see NotificationHandler#add(int, Notification) + */ + public synchronized void add(final int notificationID, final Notification notification) { + mTaskQueue.add(new Runnable() { + @Override + public void run() { + mHandler.add(notificationID, notification); + } + }); + notify(); + + if (!mReady) { + bind(); + } + } + /** * Updates a notification. * @@ -141,9 +161,9 @@ public abstract class NotificationClient { * * @see NotificationHandler#isProgressStyle(int) */ - public boolean isProgressStyle(int notificationID) { + public boolean isOngoing(int notificationID) { final NotificationHandler handler = mHandler; - return handler != null && handler.isProgressStyle(notificationID); + return handler != null && handler.isOngoing(notificationID); } protected void bind() { diff --git a/mobile/android/base/NotificationHandler.java b/mobile/android/base/NotificationHandler.java index 97ff324214b..5ce7842a46e 100644 --- a/mobile/android/base/NotificationHandler.java +++ b/mobile/android/base/NotificationHandler.java @@ -7,16 +7,20 @@ package org.mozilla.gecko; import org.mozilla.gecko.gfx.BitmapUtils; +import android.app.Notification; +import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.net.Uri; +import android.util.Log; import java.util.concurrent.ConcurrentHashMap; public class NotificationHandler { - private final ConcurrentHashMap - mAlertNotifications = new ConcurrentHashMap(); + private final ConcurrentHashMap + mNotifications = new ConcurrentHashMap(); private final Context mContext; + private final NotificationManager mNotificationManager; /** * Notification associated with this service's foreground state. @@ -28,10 +32,11 @@ public class NotificationHandler { * associated with an active progress notification if and only if at least * one download is in progress. */ - private AlertNotification mForegroundNotification; + private Notification mForegroundNotification; public NotificationHandler(Context context) { mContext = context; + mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); } /** @@ -56,8 +61,23 @@ public class NotificationHandler { notification.setLatestEventInfo(mContext, aAlertTitle, aAlertText, contentIntent); - notification.show(); - mAlertNotifications.put(notification.getId(), notification); + mNotificationManager.notify(notificationID, notification); + mNotifications.put(notificationID, notification); + } + + /** + * Adds a notification. + * + * @param id the unique ID of the notification + * @param aNotification the Notification to add + */ + public void add(int id, Notification notification) { + mNotificationManager.notify(id, notification); + mNotifications.put(id, notification); + + if (mForegroundNotification == null && isOngoing(notification)) { + setForegroundNotification(id, notification); + } } /** @@ -69,15 +89,18 @@ public class NotificationHandler { * @param aAlertText text of the notification */ public void update(int notificationID, long aProgress, long aProgressMax, String aAlertText) { - final AlertNotification notification = mAlertNotifications.get(notificationID); + final Notification notification = mNotifications.get(notificationID); if (notification == null) { return; } - notification.updateProgress(aAlertText, aProgress, aProgressMax); + if (notification instanceof AlertNotification) { + AlertNotification alert = (AlertNotification)notification; + alert.updateProgress(aAlertText, aProgress, aProgressMax); + } - if (mForegroundNotification == null && notification.isProgressStyle()) { - setForegroundNotification(notification); + if (mForegroundNotification == null && isOngoing(notification)) { + setForegroundNotification(notificationID, notification); } // Hide the notification at 100% @@ -92,11 +115,11 @@ public class NotificationHandler { * @param notificationID ID of existing notification */ public void remove(int notificationID) { - final AlertNotification notification = mAlertNotifications.remove(notificationID); + final Notification notification = mNotifications.remove(notificationID); if (notification != null) { - updateForegroundNotification(notification); - notification.cancel(); + updateForegroundNotification(notificationID, notification); } + mNotificationManager.cancel(notificationID); } /** @@ -108,38 +131,65 @@ public class NotificationHandler { * @return whether all notifications have been removed */ public boolean isDone() { - return mAlertNotifications.isEmpty(); + return mNotifications.isEmpty(); } /** - * Determines whether a notification is showing progress. + * Determines whether a notification should hold a foreground service to keep Gecko alive * - * @param notificationID the notification to check - * @return whether the notification is progress style + * @param notificationID the id of the notification to check + * @return whether the notification is ongoing */ - public boolean isProgressStyle(int notificationID) { - final AlertNotification notification = mAlertNotifications.get(notificationID); - return notification != null && notification.isProgressStyle(); + public boolean isOngoing(int notificationID) { + final Notification notification = mNotifications.get(notificationID); + return isOngoing(notification); } - protected void setForegroundNotification(AlertNotification notification) { + /** + * Determines whether a notification should hold a foreground service to keep Gecko alive + * + * @param notification the notification to check + * @return whether the notification is ongoing + */ + public boolean isOngoing(Notification notification) { + if (notification != null && (isProgressStyle(notification) || ((notification.flags & Notification.FLAG_ONGOING_EVENT) > 0))) { + return true; + } + return false; + } + + /** + * Helper method to determines whether a notification is an AlertNotification that is showing progress + * This method will be deprecated when AlertNotifications are removed (bug 893289). + * + * @param notification the notification to check + * @return whether the notification is an AlertNotification showing progress. + */ + private boolean isProgressStyle(Notification notification) { + if (notification != null && notification instanceof AlertNotification) { + return ((AlertNotification)notification).isProgressStyle(); + } + return false; + } + + protected void setForegroundNotification(int id, Notification notification) { mForegroundNotification = notification; } - private void updateForegroundNotification(AlertNotification oldNotification) { + private void updateForegroundNotification(int id, Notification oldNotification) { if (mForegroundNotification == oldNotification) { // If we're removing the notification associated with the // foreground, we need to pick another active notification to act // as the foreground notification. - AlertNotification foregroundNotification = null; - for (final AlertNotification notification : mAlertNotifications.values()) { - if (notification.isProgressStyle()) { + Notification foregroundNotification = null; + for (final Notification notification : mNotifications.values()) { + if (isOngoing(notification)) { foregroundNotification = notification; break; } } - setForegroundNotification(foregroundNotification); + setForegroundNotification(id, foregroundNotification); } } } diff --git a/mobile/android/base/NotificationHelper.java b/mobile/android/base/NotificationHelper.java index 5d55b577e92..61b767a0cd1 100644 --- a/mobile/android/base/NotificationHelper.java +++ b/mobile/android/base/NotificationHelper.java @@ -106,8 +106,7 @@ public class NotificationHelper implements GeckoEventListener { PendingIntent pi = PendingIntent.getActivity(mContext, 0, notificationIntent, 0); builder.setContentIntent(pi); - NotificationManager manager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); - manager.notify(id.hashCode(), builder.build()); + GeckoAppShell.sNotificationClient.add(id.hashCode(), builder.build()); if (!mShowing.contains(id)) { mShowing.add(id); } @@ -126,8 +125,7 @@ public class NotificationHelper implements GeckoEventListener { } public void hideNotification(String id) { - NotificationManager manager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); - manager.cancel(id.hashCode()); + GeckoAppShell.sNotificationClient.remove(id.hashCode()); mShowing.remove(id); } diff --git a/mobile/android/base/NotificationService.java b/mobile/android/base/NotificationService.java index 73e7647fa83..838f64ef25f 100644 --- a/mobile/android/base/NotificationService.java +++ b/mobile/android/base/NotificationService.java @@ -5,6 +5,7 @@ package org.mozilla.gecko; +import android.app.Notification; import android.app.Service; import android.content.Intent; import android.os.Binder; @@ -12,18 +13,25 @@ import android.os.IBinder; public class NotificationService extends Service { private final IBinder mBinder = new NotificationBinder(); - private final NotificationHandler mHandler = new NotificationHandler(this) { - @Override - protected void setForegroundNotification(AlertNotification notification) { - super.setForegroundNotification(notification); + private NotificationHandler mHandler; - if (notification == null) { - stopForeground(true); - } else { - startForeground(notification.getId(), notification); + @Override + public void onCreate() { + // This has to be initialized in onCreate in order to ensure that the NotificationHandler can + // access the NotificationManager service. + mHandler = new NotificationHandler(this) { + @Override + protected void setForegroundNotification(int id, Notification notification) { + super.setForegroundNotification(id, notification); + + if (notification == null) { + stopForeground(true); + } else { + startForeground(id, notification); + } } - } - }; + }; + } public class NotificationBinder extends Binder { NotificationService getService() { From 2da4132fa4a8a8ecb157a6f837bf71b8b9a4376e Mon Sep 17 00:00:00 2001 From: Hannes Verschore Date: Fri, 19 Jul 2013 09:31:12 -0700 Subject: [PATCH 34/58] Bug 895019: Cleanup and make the tracelogger work again, r=jandem --- js/src/TraceLogging.cpp | 27 +++----- js/src/TraceLogging.h | 19 ++---- js/src/ion/BaselineBailouts.cpp | 10 +++ js/src/ion/BaselineCompiler.cpp | 10 +++ js/src/ion/BaselineJIT.cpp | 4 ++ js/src/ion/CodeGenerator.cpp | 20 ++++++ js/src/ion/Ion.cpp | 12 ---- js/src/ion/IonMacroAssembler.cpp | 68 +++++++++++++++++++ js/src/ion/IonMacroAssembler.h | 6 ++ js/src/ion/arm/CodeGenerator-arm.cpp | 3 + .../ion/shared/CodeGenerator-x86-shared.cpp | 4 ++ js/src/vm/Interpreter.cpp | 15 ++-- 12 files changed, 150 insertions(+), 48 deletions(-) diff --git a/js/src/TraceLogging.cpp b/js/src/TraceLogging.cpp index 7d6f8b09dd1..5c0e3a68eee 100644 --- a/js/src/TraceLogging.cpp +++ b/js/src/TraceLogging.cpp @@ -24,7 +24,7 @@ using namespace js; #if defined(__i386__) static __inline__ uint64_t -js::rdtsc(void) +rdtsc(void) { uint64_t x; __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); @@ -32,7 +32,7 @@ js::rdtsc(void) } #elif defined(__x86_64__) static __inline__ uint64_t -js::rdtsc(void) +rdtsc(void) { unsigned hi, lo; __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); @@ -40,7 +40,7 @@ js::rdtsc(void) } #elif defined(__powerpc__) static __inline__ uint64_t -js::rdtsc(void) +rdtsc(void) { uint64_t result=0; uint32_t upper, lower,tmp; @@ -62,26 +62,17 @@ js::rdtsc(void) #endif const char* const TraceLogging::type_name[] = { + "start,script", + "stop,script", "start,ion_compile", "stop,ion_compile", - "start,ion_cannon", - "stop,ion_cannon", - "stop,ion_cannon_bailout", - "start,ion_side_cannon", - "stop,ion_side_cannon", - "stop,ion_side_cannon_bailout", "start,yarr_jit_execute", "stop,yarr_jit_execute", - "start,jm_safepoint", - "stop,jm_safepoint", - "start,jm_normal", - "stop,jm_normal", - "start,jm_compile", - "stop,jm_compile", "start,gc", "stop,gc", - "start,interpreter", - "stop,interpreter" + "info,engine,interpreter", + "info,engine,baseline", + "info,engine,ionmonkey" }; TraceLogging* TraceLogging::_defaultLogger = NULL; @@ -157,7 +148,7 @@ TraceLogging::log(Type type, const char* file, unsigned int lineno) void TraceLogging::log(Type type, JSScript* script) { - this->log(type, script->filename, script->lineno); + this->log(type, script->filename(), script->lineno); } void diff --git a/js/src/TraceLogging.h b/js/src/TraceLogging.h index 99c6685a140..63052777a0d 100644 --- a/js/src/TraceLogging.h +++ b/js/src/TraceLogging.h @@ -15,26 +15,17 @@ class TraceLogging { public: enum Type { + SCRIPT_START, + SCRIPT_STOP, ION_COMPILE_START, ION_COMPILE_STOP, - ION_CANNON_START, - ION_CANNON_STOP, - ION_CANNON_BAIL, - ION_SIDE_CANNON_START, - ION_SIDE_CANNON_STOP, - ION_SIDE_CANNON_BAIL, YARR_JIT_START, YARR_JIT_STOP, - JM_SAFEPOINT_START, - JM_SAFEPOINT_STOP, - JM_START, - JM_STOP, - JM_COMPILE_START, - JM_COMPILE_STOP, GC_START, GC_STOP, - INTERPRETER_START, - INTERPRETER_STOP, + INFO_ENGINE_INTERPRETER, + INFO_ENGINE_BASELINE, + INFO_ENGINE_IONMONKEY, INFO }; diff --git a/js/src/ion/BaselineBailouts.cpp b/js/src/ion/BaselineBailouts.cpp index 7c9ac00b575..c65b38b9a3a 100644 --- a/js/src/ion/BaselineBailouts.cpp +++ b/js/src/ion/BaselineBailouts.cpp @@ -1032,6 +1032,10 @@ ion::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIt JS_ASSERT(bailoutInfo != NULL); JS_ASSERT(*bailoutInfo == NULL); +#if JS_TRACE_LOGGING + TraceLogging::defaultLogger()->log(TraceLogging::INFO_ENGINE_BASELINE); +#endif + // The caller of the top frame must be one of the following: // OptimizedJS - Ion calling into Ion. // BaselineStub - Baseline calling into Ion. @@ -1107,6 +1111,12 @@ ion::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIt RootedScript scr(cx, iter.script()); AutoValueVector startFrameFormals(cx); while (true) { +#if JS_TRACE_LOGGING + if (frameNo > 0) { + TraceLogging::defaultLogger()->log(TraceLogging::SCRIPT_START, scr); + TraceLogging::defaultLogger()->log(TraceLogging::INFO_ENGINE_BASELINE); + } +#endif IonSpew(IonSpew_BaselineBailouts, " FrameNo %d", frameNo); jsbytecode *callPC = NULL; RootedFunction nextCallee(cx, NULL); diff --git a/js/src/ion/BaselineCompiler.cpp b/js/src/ion/BaselineCompiler.cpp index e821d7641fb..bc883c79191 100644 --- a/js/src/ion/BaselineCompiler.cpp +++ b/js/src/ion/BaselineCompiler.cpp @@ -84,6 +84,7 @@ BaselineCompiler::compile() if (status != Method_Compiled) return status; + if (!emitEpilogue()) return Method_Error; @@ -224,6 +225,11 @@ BaselineCompiler::emitPrologue() masm.pushValue(R0); } +#if JS_TRACE_LOGGING + masm.tracelogStart(script.get()); + masm.tracelogLog(TraceLogging::INFO_ENGINE_BASELINE); +#endif + // Record the offset of the prologue, because Ion can bailout before // the scope chain is initialized. prologueOffset_ = masm.currentOffset(); @@ -256,6 +262,10 @@ BaselineCompiler::emitEpilogue() { masm.bind(&return_); +#if JS_TRACE_LOGGING + masm.tracelogStop(); +#endif + // Pop SPS frame if necessary emitSPSPop(); diff --git a/js/src/ion/BaselineJIT.cpp b/js/src/ion/BaselineJIT.cpp index d17d41583fa..42468ca98c2 100644 --- a/js/src/ion/BaselineJIT.cpp +++ b/js/src/ion/BaselineJIT.cpp @@ -185,6 +185,10 @@ ion::EnterBaselineAtBranch(JSContext *cx, StackFrame *fp, jsbytecode *pc) data.calleeToken = CalleeToToken(fp->script()); } +#if JS_TRACE_LOGGING + TraceLogging::defaultLogger()->log(TraceLogging::INFO_ENGINE_BASELINE); +#endif + IonExecStatus status = EnterBaseline(cx, data); if (status != IonExec_Ok) return status; diff --git a/js/src/ion/CodeGenerator.cpp b/js/src/ion/CodeGenerator.cpp index 1b6b5a9ef55..6fd0ead9f76 100644 --- a/js/src/ion/CodeGenerator.cpp +++ b/js/src/ion/CodeGenerator.cpp @@ -897,6 +897,10 @@ CodeGenerator::visitOsrEntry(LOsrEntry *lir) masm.flushBuffer(); setOsrEntryOffset(masm.size()); +#if JS_TRACE_LOGGING + masm.tracelogLog(TraceLogging::INFO_ENGINE_IONMONKEY); +#endif + // Allocate the full frame for this function. uint32_t size = frameSize(); if (size != 0) @@ -5421,6 +5425,11 @@ CodeGenerator::generate() if (!safepoints_.init(graph.totalSlotCount())) return false; +#if JS_TRACE_LOGGING + masm.tracelogStart(gen->info().script()); + masm.tracelogLog(TraceLogging::INFO_ENGINE_IONMONKEY); +#endif + // Before generating any code, we generate type checks for all parameters. // This comes before deoptTable_, because we can't use deopt tables without // creating the actual frame. @@ -5433,10 +5442,21 @@ CodeGenerator::generate() return false; } +#if JS_TRACE_LOGGING + Label skip; + masm.jump(&skip); +#endif + // Remember the entry offset to skip the argument check. masm.flushBuffer(); setSkipArgCheckEntryOffset(masm.size()); +#if JS_TRACE_LOGGING + masm.tracelogStart(gen->info().script()); + masm.tracelogLog(TraceLogging::INFO_ENGINE_IONMONKEY); + masm.bind(&skip); +#endif + if (!generatePrologue()) return false; if (!generateBody()) diff --git a/js/src/ion/Ion.cpp b/js/src/ion/Ion.cpp index d93afcaba1e..35f3cb849fa 100644 --- a/js/src/ion/Ion.cpp +++ b/js/src/ion/Ion.cpp @@ -1927,20 +1927,8 @@ ion::Cannon(JSContext *cx, RunState &state) if (!SetEnterJitData(cx, data, state, vals)) return IonExec_Error; -#if JS_TRACE_LOGGING - TraceLog(TraceLogging::defaultLogger(), - TraceLogging::ION_CANNON_START, - script); -#endif - IonExecStatus status = EnterIon(cx, data); -#if JS_TRACE_LOGGING - TraceLog(TraceLogging::defaultLogger(), - TraceLogging::ION_CANNON_STOP, - script); -#endif - if (status == IonExec_Ok) state.setReturnValue(data.result); diff --git a/js/src/ion/IonMacroAssembler.cpp b/js/src/ion/IonMacroAssembler.cpp index f8ce5309b69..050a4236332 100644 --- a/js/src/ion/IonMacroAssembler.cpp +++ b/js/src/ion/IonMacroAssembler.cpp @@ -1233,6 +1233,74 @@ MacroAssembler::printf(const char *output, Register value) PopRegsInMask(RegisterSet::Volatile()); } +#if JS_TRACE_LOGGING +void +MacroAssembler::tracelogStart(JSScript *script) +{ + void (&TraceLogStart)(TraceLogging*, TraceLogging::Type, JSScript*) = TraceLog; + RegisterSet regs = RegisterSet::Volatile(); + PushRegsInMask(regs); + + Register temp = regs.takeGeneral(); + Register logger = regs.takeGeneral(); + Register type = regs.takeGeneral(); + Register rscript = regs.takeGeneral(); + + setupUnalignedABICall(3, temp); + movePtr(ImmWord((void *)TraceLogging::defaultLogger()), logger); + passABIArg(logger); + move32(Imm32(TraceLogging::SCRIPT_START), type); + passABIArg(type); + movePtr(ImmGCPtr(script), rscript); + passABIArg(rscript); + callWithABI(JS_FUNC_TO_DATA_PTR(void *, TraceLogStart)); + + PopRegsInMask(RegisterSet::Volatile()); +} + +void +MacroAssembler::tracelogStop() +{ + void (&TraceLogStop)(TraceLogging*, TraceLogging::Type) = TraceLog; + RegisterSet regs = RegisterSet::Volatile(); + PushRegsInMask(regs); + + Register temp = regs.takeGeneral(); + Register logger = regs.takeGeneral(); + Register type = regs.takeGeneral(); + + setupUnalignedABICall(2, temp); + movePtr(ImmWord((void *)TraceLogging::defaultLogger()), logger); + passABIArg(logger); + move32(Imm32(TraceLogging::SCRIPT_STOP), type); + passABIArg(type); + callWithABI(JS_FUNC_TO_DATA_PTR(void *, TraceLogStop)); + + PopRegsInMask(RegisterSet::Volatile()); +} + +void +MacroAssembler::tracelogLog(TraceLogging::Type type) +{ + void (&TraceLogStop)(TraceLogging*, TraceLogging::Type) = TraceLog; + RegisterSet regs = RegisterSet::Volatile(); + PushRegsInMask(regs); + + Register temp = regs.takeGeneral(); + Register logger = regs.takeGeneral(); + Register rtype = regs.takeGeneral(); + + setupUnalignedABICall(2, temp); + movePtr(ImmWord((void *)TraceLogging::defaultLogger()), logger); + passABIArg(logger); + move32(Imm32(type), rtype); + passABIArg(rtype); + callWithABI(JS_FUNC_TO_DATA_PTR(void *, TraceLogStop)); + + PopRegsInMask(RegisterSet::Volatile()); +} +#endif + void MacroAssembler::convertInt32ValueToDouble(const Address &address, Register scratch, Label *done) { diff --git a/js/src/ion/IonMacroAssembler.h b/js/src/ion/IonMacroAssembler.h index cf6fca613f1..69024507d84 100644 --- a/js/src/ion/IonMacroAssembler.h +++ b/js/src/ion/IonMacroAssembler.h @@ -944,6 +944,12 @@ class MacroAssembler : public MacroAssemblerSpecific void printf(const char *output); void printf(const char *output, Register value); +#if JS_TRACE_LOGGING + void tracelogStart(JSScript *script); + void tracelogStop(); + void tracelogLog(TraceLogging::Type type); +#endif + void convertInt32ValueToDouble(const Address &address, Register scratch, Label *done); void convertValueToDouble(ValueOperand value, FloatRegister output, Label *fail); void convertValueToInt32(ValueOperand value, FloatRegister temp, Register output, Label *fail); diff --git a/js/src/ion/arm/CodeGenerator-arm.cpp b/js/src/ion/arm/CodeGenerator-arm.cpp index bacf2e23ff7..f299bc2ee1e 100644 --- a/js/src/ion/arm/CodeGenerator-arm.cpp +++ b/js/src/ion/arm/CodeGenerator-arm.cpp @@ -55,6 +55,9 @@ bool CodeGeneratorARM::generateEpilogue() { masm.bind(&returnLabel_); +#if JS_TRACE_LOGGING + masm.tracelogStop(); +#endif if (gen->compilingAsmJS()) { // Pop the stack we allocated at the start of the function. masm.freeStack(frameDepth_); diff --git a/js/src/ion/shared/CodeGenerator-x86-shared.cpp b/js/src/ion/shared/CodeGenerator-x86-shared.cpp index d161d820e33..41fb2cbce2b 100644 --- a/js/src/ion/shared/CodeGenerator-x86-shared.cpp +++ b/js/src/ion/shared/CodeGenerator-x86-shared.cpp @@ -49,6 +49,10 @@ CodeGeneratorX86Shared::generateEpilogue() { masm.bind(&returnLabel_); +#if JS_TRACE_LOGGING + masm.tracelogStop(); +#endif + // Pop the stack we allocated at the start of the function. masm.freeStack(frameSize()); JS_ASSERT(masm.framePushed() == 0); diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 0b83f5a0dad..30657738410 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -1373,10 +1373,8 @@ Interpret(JSContext *cx, RunState &state) SET_SCRIPT(regs.fp()->script()); #if JS_TRACE_LOGGING - AutoTraceLog logger(TraceLogging::defaultLogger(), - TraceLogging::INTERPRETER_START, - TraceLogging::INTERPRETER_STOP, - script); + TraceLogging::defaultLogger()->log(TraceLogging::SCRIPT_START, script); + TraceLogging::defaultLogger()->log(TraceLogging::INFO_ENGINE_INTERPRETER); #endif /* @@ -1689,6 +1687,10 @@ BEGIN_CASE(JSOP_STOP) */ CHECK_BRANCH(); +#if JS_TRACE_LOGGING + TraceLogging::defaultLogger()->log(TraceLogging::SCRIPT_STOP); +#endif + interpReturnOK = true; if (entryFrame != regs.fp()) inline_return: @@ -2551,6 +2553,11 @@ BEGIN_CASE(JSOP_FUNCALL) SET_SCRIPT(regs.fp()->script()); +#if JS_TRACE_LOGGING + TraceLogging::defaultLogger()->log(TraceLogging::SCRIPT_START, script); + TraceLogging::defaultLogger()->log(TraceLogging::INFO_ENGINE_INTERPRETER); +#endif + if (!regs.fp()->prologue(cx)) goto error; if (cx->compartment()->debugMode()) { From 76305364f5b3ead9671f98c801937895f04ceda4 Mon Sep 17 00:00:00 2001 From: Chris Lord Date: Fri, 19 Jul 2013 17:39:44 +0100 Subject: [PATCH 35/58] Bug 886576 - Fix scrolling cancelling locked dynamic toolbar animations. r=kats Move the margin animation-cancelling call into the margins-pinned check block in LayerMarginsAnimator to make sure margin animations aren't cancelled by scrolling when margins are locked. --- mobile/android/base/BrowserApp.java | 2 +- mobile/android/base/gfx/LayerMarginsAnimator.java | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mobile/android/base/BrowserApp.java b/mobile/android/base/BrowserApp.java index e29a212d3c3..31638eb5162 100644 --- a/mobile/android/base/BrowserApp.java +++ b/mobile/android/base/BrowserApp.java @@ -1209,8 +1209,8 @@ abstract public class BrowserApp extends GeckoApp // toolbar. if (mLayerView != null && isDynamicToolbarEnabled()) { if (width > 0 && height > 0) { - mLayerView.getLayerMarginsAnimator().showMargins(false); mLayerView.getLayerMarginsAnimator().setMarginsPinned(true); + mLayerView.getLayerMarginsAnimator().showMargins(false); } else { mLayerView.getLayerMarginsAnimator().setMarginsPinned(false); } diff --git a/mobile/android/base/gfx/LayerMarginsAnimator.java b/mobile/android/base/gfx/LayerMarginsAnimator.java index ad3f5acf899..ac170c6bbd8 100644 --- a/mobile/android/base/gfx/LayerMarginsAnimator.java +++ b/mobile/android/base/gfx/LayerMarginsAnimator.java @@ -226,17 +226,17 @@ public class LayerMarginsAnimator implements TouchEventInterceptor { * viewport origin and returns the modified metrics. */ ImmutableViewportMetrics scrollBy(ImmutableViewportMetrics aMetrics, float aDx, float aDy) { - // Make sure to cancel any margin animations when scrolling begins - if (mAnimationTimer != null) { - mAnimationTimer.cancel(); - mAnimationTimer = null; - } - float[] newMarginsX = { aMetrics.marginLeft, aMetrics.marginRight }; float[] newMarginsY = { aMetrics.marginTop, aMetrics.marginBottom }; // Only alter margins if the toolbar isn't pinned if (!mMarginsPinned) { + // Make sure to cancel any margin animations when margin-scrolling begins + if (mAnimationTimer != null) { + mAnimationTimer.cancel(); + mAnimationTimer = null; + } + // Reset the touch travel when changing direction if ((aDx >= 0) != (mTouchTravelDistance.x >= 0)) { mTouchTravelDistance.x = 0; From e9b8bc2c9e2626152e836cfeb2400acacad9dac9 Mon Sep 17 00:00:00 2001 From: Hannes Verschore Date: Fri, 19 Jul 2013 09:46:23 -0700 Subject: [PATCH 36/58] Bug 893853 - IonMonkey: Don't set typeset of |this| when type is unknown, r=bhackett --- js/src/ion/IonBuilder.cpp | 12 +++++++----- js/src/jit-test/tests/ion/bug893853.js | 9 +++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 js/src/jit-test/tests/ion/bug893853.js diff --git a/js/src/ion/IonBuilder.cpp b/js/src/ion/IonBuilder.cpp index 3499d02dbf2..ab879d07f1d 100644 --- a/js/src/ion/IonBuilder.cpp +++ b/js/src/ion/IonBuilder.cpp @@ -3469,11 +3469,13 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target) // Improve type information of |this| when not set. if (callInfo.constructing() && !callInfo.thisArg()->resultTypeSet()) { types::StackTypeSet *types = types::TypeScript::ThisTypes(calleeScript); - MTypeBarrier *barrier = MTypeBarrier::New(callInfo.thisArg(), cloneTypeSet(types), Bailout_Normal); - current->add(barrier); - MUnbox *unbox = MUnbox::New(barrier, MIRType_Object, MUnbox::Infallible); - current->add(unbox); - callInfo.setThis(unbox); + if (!types->unknown()) { + MTypeBarrier *barrier = MTypeBarrier::New(callInfo.thisArg(), cloneTypeSet(types), Bailout_Normal); + current->add(barrier); + MUnbox *unbox = MUnbox::New(barrier, MIRType_Object, MUnbox::Infallible); + current->add(unbox); + callInfo.setThis(unbox); + } } // Start inlining. diff --git a/js/src/jit-test/tests/ion/bug893853.js b/js/src/jit-test/tests/ion/bug893853.js new file mode 100644 index 00000000000..e07d7440e95 --- /dev/null +++ b/js/src/jit-test/tests/ion/bug893853.js @@ -0,0 +1,9 @@ + +function f() {} +new EvalTest(); +function EvalTest() { + with (this) { + f(EvalTest) + } +} +evaluate("var obj = new f(1, 'x');"); From c18627a32fb7b004c22a91e7585e41238fb86a99 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 17 Jul 2013 20:00:26 -0500 Subject: [PATCH 37/58] Bug 893670 - Part 1: Restore Emacs shortcuts in textareas. r=masayuki --HG-- extra : rebase_source : 14dc48ad891f41c38854fd1078971361d459e73a --- widget/cocoa/NativeKeyBindings.mm | 33 ++++++++++--------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/widget/cocoa/NativeKeyBindings.mm b/widget/cocoa/NativeKeyBindings.mm index 9516dda447f..70cb150e2a9 100644 --- a/widget/cocoa/NativeKeyBindings.mm +++ b/widget/cocoa/NativeKeyBindings.mm @@ -64,14 +64,9 @@ NativeKeyBindings::Init(NativeKeyBindingsType aType) // TODO: deleteTo* selectors are also supposed to add text to a kill buffer SEL_TO_COMMAND(deleteToBeginningOfLine:, "cmd_deleteToBeginningOfLine"); - if (aType == eNativeKeyBindingsType_Input) { - SEL_TO_COMMAND(deleteToBeginningOfParagraph:, - "cmd_deleteToBeginningOfLine"); - } + SEL_TO_COMMAND(deleteToBeginningOfParagraph:, "cmd_deleteToBeginningOfLine"); SEL_TO_COMMAND(deleteToEndOfLine:, "cmd_deleteToEndOfLine"); - if (aType == eNativeKeyBindingsType_Input) { - SEL_TO_COMMAND(deleteToEndOfParagraph:, "cmd_deleteToEndOfLine"); - } + SEL_TO_COMMAND(deleteToEndOfParagraph:, "cmd_deleteToEndOfLine"); // SEL_TO_COMMAND(deleteToMark:, ); SEL_TO_COMMAND(deleteWordBackward:, "cmd_deleteWordBackward"); @@ -100,12 +95,9 @@ NativeKeyBindings::Init(NativeKeyBindingsType aType) SEL_TO_COMMAND(moveForwardAndModifySelection:, "cmd_selectCharNext"); SEL_TO_COMMAND(moveLeft:, "cmd_charPrevious"); SEL_TO_COMMAND(moveLeftAndModifySelection:, "cmd_selectCharPrevious"); - if (aType == eNativeKeyBindingsType_Input) { - SEL_TO_COMMAND(moveParagraphBackwardAndModifySelection:, - "cmd_selectBeginLine"); - SEL_TO_COMMAND(moveParagraphForwardAndModifySelection:, - "cmd_selectEndLine"); - } + SEL_TO_COMMAND(moveParagraphBackwardAndModifySelection:, + "cmd_selectBeginLine"); + SEL_TO_COMMAND(moveParagraphForwardAndModifySelection:, "cmd_selectEndLine"); SEL_TO_COMMAND(moveRight:, "cmd_charNext"); SEL_TO_COMMAND(moveRightAndModifySelection:, "cmd_selectCharNext"); SEL_TO_COMMAND(moveToBeginningOfDocument:, "cmd_moveTop"); @@ -113,20 +105,15 @@ NativeKeyBindings::Init(NativeKeyBindingsType aType) SEL_TO_COMMAND(moveToBeginningOfLine:, "cmd_beginLine"); SEL_TO_COMMAND(moveToBeginningOfLineAndModifySelection:, "cmd_selectBeginLine"); - if (aType == eNativeKeyBindingsType_Input) { - SEL_TO_COMMAND(moveToBeginningOfParagraph:, "cmd_beginLine"); - SEL_TO_COMMAND(moveToBeginningOfParagraphAndModifySelection:, - "cmd_selectBeginLine"); - } + SEL_TO_COMMAND(moveToBeginningOfParagraph:, "cmd_beginLine"); + SEL_TO_COMMAND(moveToBeginningOfParagraphAndModifySelection:, + "cmd_selectBeginLine"); SEL_TO_COMMAND(moveToEndOfDocument:, "cmd_moveBottom"); SEL_TO_COMMAND(moveToEndOfDocumentAndModifySelection:, "cmd_selectBottom"); SEL_TO_COMMAND(moveToEndOfLine:, "cmd_endLine"); SEL_TO_COMMAND(moveToEndOfLineAndModifySelection:, "cmd_selectEndLine"); - if (aType == eNativeKeyBindingsType_Input) { - SEL_TO_COMMAND(moveToEndOfParagraph:, "cmd_endLine"); - SEL_TO_COMMAND(moveToEndOfParagraphAndModifySelection:, - "cmd_selectEndLine"); - } + SEL_TO_COMMAND(moveToEndOfParagraph:, "cmd_endLine"); + SEL_TO_COMMAND(moveToEndOfParagraphAndModifySelection:, "cmd_selectEndLine"); SEL_TO_COMMAND(moveToLeftEndOfLine:, "cmd_beginLine"); SEL_TO_COMMAND(moveToLeftEndOfLineAndModifySelection:, "cmd_selectBeginLine"); SEL_TO_COMMAND(moveToRightEndOfLine:, "cmd_endLine"); From e6ab16060bdaa52d5865c1a223bab0718b411f4d Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Thu, 18 Jul 2013 13:34:26 -0500 Subject: [PATCH 38/58] Bug 893670 - Part 2: Expand NativeKeyBindings tests. r=masayuki --HG-- extra : rebase_source : 9a4c15b3c2bb3631db9cf5f5b91aecefa9528db5 --- .../tests/test_native_key_bindings_mac.html | 311 +++++++++++++++--- 1 file changed, 259 insertions(+), 52 deletions(-) diff --git a/widget/tests/test_native_key_bindings_mac.html b/widget/tests/test_native_key_bindings_mac.html index 2817476e222..7bb4f38ad23 100644 --- a/widget/tests/test_native_key_bindings_mac.html +++ b/widget/tests/test_native_key_bindings_mac.html @@ -14,7 +14,6 @@
-

Stretching attack nullam stuck in a tree zzz, suspendisse cras nec suspendisse lick suscipit. Nunc egestas amet litter box, nullam climb the curtains biting I don't like that food tristique biting sleep on your @@ -46,14 +45,57 @@ Judging you rutrum bat sunbathe sleep on your face, jump on the table leap tincidunt a faucibus sleep in the sink. Stuck in a tree tristique zzz hiss in viverra nullam, quis tortor pharetra attack.

-
+ + + +