summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@wolfbeast.com>2019-03-26 18:41:32 +0100
committerwolfbeast <mcwerewolf@wolfbeast.com>2019-03-26 18:41:32 +0100
commit1e1525c44c23bde16102a64e685e02a9ab6825cc (patch)
treea2462a2f6278466e93ddedbf71983c325698933a
parente25ad543952b5afc13181aaebef9c5951fc27be0 (diff)
parenteb77e289bbe056b58051db0fa868e95da803aa0a (diff)
downloadUXP-1e1525c44c23bde16102a64e685e02a9ab6825cc.tar
UXP-1e1525c44c23bde16102a64e685e02a9ab6825cc.tar.gz
UXP-1e1525c44c23bde16102a64e685e02a9ab6825cc.tar.lz
UXP-1e1525c44c23bde16102a64e685e02a9ab6825cc.tar.xz
UXP-1e1525c44c23bde16102a64e685e02a9ab6825cc.zip
Merge commit 'eb77e289bbe056b58051db0fa868e95da803aa0a' into Basilisk-release
-rw-r--r--application/basilisk/branding/shared/uaoverrides.inc1
-rw-r--r--application/palemoon/app/profile/palemoon.js3
-rw-r--r--application/palemoon/base/content/aboutDialog.xul3
-rw-r--r--application/palemoon/base/content/baseMenuOverlay.xul2
-rw-r--r--application/palemoon/branding/shared/pref/uaoverrides.inc4
-rw-r--r--application/palemoon/components/preferences/preferences.xul2
-rw-r--r--application/palemoon/themes/linux/browser.css11
-rw-r--r--application/palemoon/themes/osx/browser.css11
-rw-r--r--application/palemoon/themes/windows/browser.css25
-rw-r--r--config/milestone.txt2
-rw-r--r--devtools/client/shared/curl.js1
-rw-r--r--dom/bindings/BindingUtils.cpp10
-rw-r--r--dom/bindings/BindingUtils.h101
-rw-r--r--dom/bindings/Codegen.py340
-rw-r--r--dom/bindings/Configuration.py2
-rw-r--r--dom/bindings/MozMap.h121
-rw-r--r--dom/bindings/Record.h91
-rw-r--r--dom/bindings/moz.build2
-rw-r--r--dom/bindings/parser/WebIDL.py152
-rw-r--r--dom/canvas/CanvasRenderingContext2D.cpp7
-rw-r--r--dom/canvas/CanvasRenderingContext2D.h4
-rw-r--r--dom/fetch/FetchDriver.cpp10
-rw-r--r--dom/fetch/Headers.cpp14
-rw-r--r--dom/fetch/Headers.h12
-rw-r--r--dom/fetch/InternalHeaders.cpp11
-rw-r--r--dom/fetch/InternalHeaders.h4
-rw-r--r--dom/html/HTMLTableElement.cpp15
-rw-r--r--dom/html/HTMLTableSectionElement.cpp2
-rw-r--r--dom/ipc/ContentChild.h4
-rw-r--r--dom/locales/en-US/chrome/security/security.properties2
-rw-r--r--dom/media/MediaManager.cpp11
-rw-r--r--dom/media/VideoFrameContainer.cpp12
-rw-r--r--dom/media/gmp/widevine-adapter/WidevineAdapter.cpp10
-rw-r--r--dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp101
-rw-r--r--dom/media/gmp/widevine-adapter/WidevineDecryptor.h24
-rw-r--r--dom/media/gmp/widevine-adapter/WidevineUtils.cpp4
-rw-r--r--dom/media/gmp/widevine-adapter/WidevineUtils.h10
-rw-r--r--dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h2
-rw-r--r--dom/media/gmp/widevine-adapter/content_decryption_module.h289
-rw-r--r--dom/media/gmp/widevine-adapter/content_decryption_module_export.h22
-rw-r--r--dom/media/gmp/widevine-adapter/content_decryption_module_ext.h64
-rw-r--r--dom/security/nsContentSecurityManager.cpp56
-rw-r--r--dom/security/nsContentSecurityManager.h1
-rw-r--r--dom/smil/nsSMILAnimationController.cpp2
-rw-r--r--dom/url/URLSearchParams.cpp51
-rw-r--r--dom/url/URLSearchParams.h19
-rw-r--r--dom/webidl/Headers.webidl2
-rw-r--r--dom/webidl/InstallTrigger.webidl2
-rw-r--r--dom/webidl/TestInterfaceJS.webidl2
-rw-r--r--dom/webidl/URLSearchParams.webidl3
-rw-r--r--dom/xslt/xslt/txMozillaStylesheetCompiler.cpp4
-rw-r--r--image/imgFrame.cpp2
-rw-r--r--js/public/Value.h7
-rw-r--r--js/src/gc/Nursery.cpp1
-rw-r--r--js/src/gc/Nursery.h1
-rw-r--r--js/src/jit/IonAnalysis.cpp21
-rw-r--r--js/src/jit/JitOptions.cpp2
-rw-r--r--js/src/jit/StupidAllocator.cpp1
-rw-r--r--js/src/jsapi.cpp3
-rw-r--r--js/src/jsapi.h25
-rw-r--r--js/src/jsfun.cpp58
-rw-r--r--js/src/vm/ObjectGroup.cpp1
-rw-r--r--js/xpconnect/src/XPCJSContext.cpp4
-rw-r--r--layout/base/nsLayoutUtils.h9
-rw-r--r--layout/base/nsPresShell.cpp10
-rw-r--r--layout/generic/nsAbsoluteContainingBlock.cpp28
-rw-r--r--layout/reftests/w3c-css/submitted/flexbox/position-absolute-containing-block-001-ref.html27
-rw-r--r--layout/reftests/w3c-css/submitted/flexbox/position-absolute-containing-block-001.html30
-rw-r--r--layout/reftests/w3c-css/submitted/flexbox/position-absolute-containing-block-002-ref.html27
-rw-r--r--layout/reftests/w3c-css/submitted/flexbox/position-absolute-containing-block-002.html38
-rw-r--r--layout/reftests/w3c-css/submitted/flexbox/reftest.list4
-rw-r--r--layout/style/Loader.cpp4
-rw-r--r--media/libcubeb/src/cubeb.c2
-rw-r--r--media/libcubeb/src/cubeb_audiounit.cpp2
-rw-r--r--mfbt/RangedPtr.h2
-rw-r--r--modules/libpref/init/all.js6
-rw-r--r--netwerk/base/security-prefs.js4
-rw-r--r--netwerk/protocol/ftp/FTPChannelChild.cpp41
-rw-r--r--netwerk/protocol/ftp/nsFtpConnectionThread.cpp81
-rw-r--r--netwerk/protocol/http/AlternateServices.cpp7
-rw-r--r--netwerk/protocol/http/HttpBaseChannel.cpp5
-rw-r--r--netwerk/protocol/http/HttpBaseChannel.h3
-rw-r--r--netwerk/protocol/http/TunnelUtils.cpp67
-rw-r--r--netwerk/protocol/http/TunnelUtils.h11
-rw-r--r--netwerk/protocol/http/nsHttpChannel.cpp14
-rw-r--r--netwerk/protocol/http/nsHttpChannel.h3
-rw-r--r--netwerk/protocol/http/nsHttpConnection.cpp21
-rw-r--r--netwerk/protocol/http/nsHttpConnection.h3
-rw-r--r--netwerk/protocol/http/nsHttpHandler.cpp67
-rw-r--r--netwerk/protocol/http/nsHttpHandler.h20
-rw-r--r--netwerk/sctp/datachannel/DataChannel.cpp11
-rw-r--r--netwerk/test/mochitests/mochitest.ini2
-rw-r--r--netwerk/test/mochitests/test_accept_header.html106
-rw-r--r--netwerk/test/mochitests/test_accept_header.sjs48
-rw-r--r--security/manager/ssl/nsSiteSecurityService.cpp2
-rw-r--r--toolkit/components/downloads/moz.build7
-rw-r--r--toolkit/content/widgets/browser.xml86
-rw-r--r--toolkit/xre/nsAppRunner.cpp14
-rw-r--r--uriloader/exthandler/win/nsOSHelperAppService.cpp192
-rw-r--r--xpcom/glue/nsTArray.h18
100 files changed, 1687 insertions, 1121 deletions
diff --git a/application/basilisk/branding/shared/uaoverrides.inc b/application/basilisk/branding/shared/uaoverrides.inc
index be713e9d3..307d889d9 100644
--- a/application/basilisk/branding/shared/uaoverrides.inc
+++ b/application/basilisk/branding/shared/uaoverrides.inc
@@ -37,6 +37,7 @@ pref("@GUAO_PREF@.dailymotion.com","Mozilla/5.0 (@OS_SLICE@ rv:52.0) @GK_SLICE@
// The following requires native mode. Or it blocks.. "too old firefox", breakage, etc.
// UA-Sniffing domains below have indicated no interest in supporting Pale Moon (BOO!)
+pref("@GUAO_PREF@.whatsapp.com","Mozilla/5.0 (@OS_SLICE@ rv:61.0) @GK_SLICE@ Firefox/61.0");
// UA-sniffing domains that are "app/vendor-specific" and do not like Pale Moon
diff --git a/application/palemoon/app/profile/palemoon.js b/application/palemoon/app/profile/palemoon.js
index 3df5d7194..85dc41c15 100644
--- a/application/palemoon/app/profile/palemoon.js
+++ b/application/palemoon/app/profile/palemoon.js
@@ -1121,6 +1121,9 @@ pref("security.csp.speccompliant", true);
// Block insecure active content on https pages
pref("security.mixed_content.block_active_content", true);
+// Disable Microsoft Family Safety MitM support
+pref("security.family_safety.mode", 0);
+
// Override the Gecko-default value of false for Pale Moon.
pref("plain_text.wrap_long_lines", true);
diff --git a/application/palemoon/base/content/aboutDialog.xul b/application/palemoon/base/content/aboutDialog.xul
index a34923a0a..6edfc2155 100644
--- a/application/palemoon/base/content/aboutDialog.xul
+++ b/application/palemoon/base/content/aboutDialog.xul
@@ -24,9 +24,6 @@
id="PMaboutDialog"
windowtype="Browser:About"
onload="init(event);"
-#ifdef MOZ_UPDATER
- onunload="onUnload(event);"
-#endif
#ifdef XP_MACOSX
inwindowmenu="false"
#else
diff --git a/application/palemoon/base/content/baseMenuOverlay.xul b/application/palemoon/base/content/baseMenuOverlay.xul
index d7c983671..a006ed5c6 100644
--- a/application/palemoon/base/content/baseMenuOverlay.xul
+++ b/application/palemoon/base/content/baseMenuOverlay.xul
@@ -66,7 +66,7 @@
accesskey="&helpSafeMode.accesskey;"
label="&helpSafeMode.label;"
oncommand="restart(true);"/>
- <menuseparator id="updateSeparator"/>
+ <menuseparator id="updatesSeparator"/>
<menuitem id="checkForUpdates" class="menuitem-iconic"
#ifdef MOZ_UPDATER
label="&updateCmd.label;"
diff --git a/application/palemoon/branding/shared/pref/uaoverrides.inc b/application/palemoon/branding/shared/pref/uaoverrides.inc
index 567956640..36a0ae145 100644
--- a/application/palemoon/branding/shared/pref/uaoverrides.inc
+++ b/application/palemoon/branding/shared/pref/uaoverrides.inc
@@ -57,12 +57,16 @@ pref("@GUAO_PREF@.www.amazon.com","Mozilla/5.0 (@OS_SLICE@ rv:45.9) @GK_SLICE@ F
pref("@GUAO_PREF@.soundcloud.com","Mozilla/5.0 (@OS_SLICE@ rv:@GRE_VERSION@) @GRE_DATE_SLICE@ @PM_SLICE@");
// Daily motion only likes strict Firefox UAs
pref("@GUAO_PREF@.dailymotion.com","Mozilla/5.0 (@OS_SLICE@ rv:52.0) @GK_SLICE@ Firefox/52.0");
+// Financial Times' polyfill.io breaks horribly on a Pale Moon UA. Send a strict Firefox UA instead.
+pref("@GUAO_PREF@.polyfill.io","Mozilla/5.0 (@OS_SLICE@ rv:60.9) @GK_SLICE@ Firefox/60.9");
+
// The following requires native mode. Or it blocks.. "too old firefox", breakage, etc.
pref("@GUAO_PREF@.deviantart.com","Mozilla/5.0 (@OS_SLICE@ rv:@GRE_VERSION@) @GRE_DATE_SLICE@ @PM_SLICE@");
pref("@GUAO_PREF@.deviantart.net","Mozilla/5.0 (@OS_SLICE@ rv:@GRE_VERSION@) @GRE_DATE_SLICE@ @PM_SLICE@");
pref("@GUAO_PREF@.altibox.dk","Mozilla/5.0 (@OS_SLICE@ rv:@GRE_VERSION@) @GRE_DATE_SLICE@ @PM_SLICE@");
pref("@GUAO_PREF@.altibox.no","Mozilla/5.0 (@OS_SLICE@ rv:@GRE_VERSION@) @GRE_DATE_SLICE@ @PM_SLICE@");
+pref("@GUAO_PREF@.firefox.com","Mozilla/5.0 (@OS_SLICE@ rv:@GRE_VERSION@) @GRE_DATE_SLICE@ @PM_SLICE@");
// UA-Sniffing domains below have indicated no interest in supporting Pale Moon (BOO!)
pref("@GUAO_PREF@.humblebundle.com","Mozilla/5.0 (@OS_SLICE@ rv:@GK_VERSION@) @GK_SLICE@ @FX_SLICE@ (Pale Moon)");
diff --git a/application/palemoon/components/preferences/preferences.xul b/application/palemoon/components/preferences/preferences.xul
index a1d9c8cf7..2b7fd9ded 100644
--- a/application/palemoon/components/preferences/preferences.xul
+++ b/application/palemoon/components/preferences/preferences.xul
@@ -56,7 +56,7 @@
#endif
#endif
onunload="if (typeof gSecurityPane != 'undefined') gSecurityPane.syncAddonSecurityLevel();"
- ondialogaccept="gNewtabUrl.writeNewtabUrl();">
+ ondialogaccept="if (typeof gTabsPane != 'undefined') gNewtabUrl.writeNewtabUrl();">
<script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/>
<script type="application/javascript" src="chrome://browser/content/preferences/newtaburl.js"/>
diff --git a/application/palemoon/themes/linux/browser.css b/application/palemoon/themes/linux/browser.css
index b545b06cb..933067c2b 100644
--- a/application/palemoon/themes/linux/browser.css
+++ b/application/palemoon/themes/linux/browser.css
@@ -1607,6 +1607,17 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
background-image: linear-gradient(to top, rgba(0,0,0,.3) 1px, rgba(0,0,0,.05) 1px, transparent 50%);
}
+/* When the tab bar is collapsed, show a 1px border in its place. */
+#TabsToolbar[collapsed="true"] {
+ visibility: visible;
+ height: 1px;
+ border-bottom-width: 1px;
+ /* !important here to override border-style: none on the toolbar */
+ border-bottom-style: solid !important;
+ border-bottom-color: ThreeDShadow;
+ overflow: hidden;
+}
+
.tabbrowser-tab,
.tabs-newtab-button {
position: static;
diff --git a/application/palemoon/themes/osx/browser.css b/application/palemoon/themes/osx/browser.css
index ddf050785..20e8c5eac 100644
--- a/application/palemoon/themes/osx/browser.css
+++ b/application/palemoon/themes/osx/browser.css
@@ -1630,6 +1630,17 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-
background-image: linear-gradient(to top, @toolbarShadowColor@ 1px, rgba(0,0,0,.05) 1px, transparent 50%);
}
+/* When the tab bar is collapsed, show a 1px border in its place. */
+#TabsToolbar[collapsed="true"] {
+ visibility: visible;
+ height: 1px;
+ border-bottom-width: 1px;
+ /* !important here to override border-style: none on the toolbar */
+ border-bottom-style: solid !important;
+ border-bottom-color: ThreeDShadow;
+ overflow: hidden;
+}
+
@media (-moz-mac-lion-theme) {
#main-window[sizemode=normal] #TabsToolbar {
padding-left: 2px;
diff --git a/application/palemoon/themes/windows/browser.css b/application/palemoon/themes/windows/browser.css
index 56a8318da..aae36c539 100644
--- a/application/palemoon/themes/windows/browser.css
+++ b/application/palemoon/themes/windows/browser.css
@@ -31,6 +31,8 @@
%endif
:root {
+ --toolbox-after-color: ThreeDShadow;
+
--toolbar-custom-color: hsl(210,75%,92%);
--toolbar-highlight-top: rgba(255,255,255,.5);
--toolbar-highlight-bottom: transparent;
@@ -91,7 +93,7 @@
display: -moz-box;
-moz-box-ordinal-group: 101; /* tabs toolbar is 100 */
height: 1px;
- background-color: ThreeDShadow;
+ background-color: var(--toolbox-after-color);
}
#navigator-toolbox[tabsontop=false]::after,
#main-window[disablechrome] #navigator-toolbox::after {
@@ -1841,6 +1843,17 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
background-image: linear-gradient(to top, @toolbarShadowColor@ 1px, rgba(0,0,0,.05) 1px, transparent 50%);
}
+/* When the tab bar is collapsed, show a 1px border in its place. */
+#TabsToolbar[collapsed="true"] {
+ visibility: visible;
+ height: 1px;
+ border-bottom-width: 1px;
+ /* !important here to override border-style: none on the toolbar */
+ border-bottom-style: solid !important;
+ border-bottom-color: var(--toolbox-after-color);
+ overflow: hidden;
+}
+
.tabbrowser-tab,
.tabs-newtab-button {
-moz-appearance: none;
@@ -3044,8 +3057,8 @@ toolbar[brighttext] #addonbar-closebutton {
@media (-moz-os-version: windows-vista),
(-moz-os-version: windows-win7) {
- #navigator-toolbox:not(:-moz-lwtheme)::after {
- background-color: #aabccf;
+ :root:not(:-moz-lwtheme) {
+ --toolbox-after-color: #aabccf;
}
}
@@ -3054,9 +3067,9 @@ toolbar[brighttext] #addonbar-closebutton {
:root {
--toolbar-custom-color: hsl(210,0%,92%);
}
-
- #navigator-toolbox:not(:-moz-lwtheme)::after {
- background-color: #bcbcbc;
+
+ :root:not(:-moz-lwtheme) {
+ --toolbox-after-color: #bcbcbc;
}
}
diff --git a/config/milestone.txt b/config/milestone.txt
index 219f85529..f525cbbb4 100644
--- a/config/milestone.txt
+++ b/config/milestone.txt
@@ -10,4 +10,4 @@
# hardcoded milestones in the tree from these two files.
#--------------------------------------------------------
-4.1.9
+4.1.10
diff --git a/devtools/client/shared/curl.js b/devtools/client/shared/curl.js
index 6d33ad971..967019746 100644
--- a/devtools/client/shared/curl.js
+++ b/devtools/client/shared/curl.js
@@ -375,6 +375,7 @@ const CurlUtils = {
.replace(/\'/g, "\\\'")
.replace(/\n/g, "\\n")
.replace(/\r/g, "\\r")
+ .replace(/!/g, "\\041")
.replace(/[^\x20-\x7E]/g, escapeCharacter) + "'";
}
diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp
index 323feca52..8d2bdaac6 100644
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -2558,7 +2558,7 @@ NonVoidByteStringToJsval(JSContext *cx, const nsACString &str,
template<typename T> static void
-NormalizeUSVStringInternal(JSContext* aCx, T& aString)
+NormalizeUSVStringInternal(T& aString)
{
char16_t* start = aString.BeginWriting();
// Must use const here because we can't pass char** to UTF16CharEnumerator as
@@ -2575,15 +2575,15 @@ NormalizeUSVStringInternal(JSContext* aCx, T& aString)
}
void
-NormalizeUSVString(JSContext* aCx, nsAString& aString)
+NormalizeUSVString(nsAString& aString)
{
- NormalizeUSVStringInternal(aCx, aString);
+ NormalizeUSVStringInternal(aString);
}
void
-NormalizeUSVString(JSContext* aCx, binding_detail::FakeString& aString)
+NormalizeUSVString(binding_detail::FakeString& aString)
{
- NormalizeUSVStringInternal(aCx, aString);
+ NormalizeUSVStringInternal(aString);
}
bool
diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h
index 24b47a545..a3ec70f47 100644
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -49,7 +49,7 @@ namespace mozilla {
enum UseCounter : int16_t;
namespace dom {
-template<typename DataType> class MozMap;
+template<typename KeyType, typename ValueType> class Record;
nsresult
UnwrapArgImpl(JS::Handle<JSObject*> src, const nsIID& iid, void** ppArg);
@@ -2127,11 +2127,30 @@ ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v,
return AssignJSString(cx, result, s);
}
+template<typename T>
+static inline bool
+ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v, T& result)
+{
+ return ConvertJSValueToString(cx, v, eStringify, eStringify, result);
+}
+
void
-NormalizeUSVString(JSContext* aCx, nsAString& aString);
+NormalizeUSVString(nsAString& aString);
void
-NormalizeUSVString(JSContext* aCx, binding_detail::FakeString& aString);
+NormalizeUSVString(binding_detail::FakeString& aString);
+
+template<typename T>
+static inline bool
+ConvertJSValueToUSVString(JSContext* cx, JS::Handle<JS::Value> v, T& result)
+{
+ if (!ConvertJSValueToString(cx, v, eStringify, eStringify, result)) {
+ return false;
+ }
+
+ NormalizeUSVString(result);
+ return true;
+}
template<typename T>
inline bool
@@ -2158,6 +2177,13 @@ bool
ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
bool nullable, nsACString& result);
+inline bool
+ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
+ nsACString& result)
+{
+ return ConvertJSValueToByteString(cx, v, false, result);
+}
+
template<typename T>
void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq);
template<typename T>
@@ -2293,31 +2319,26 @@ public:
}
};
-template<typename T>
-static void
-TraceMozMapValue(T* aValue, void* aClosure)
-{
- JSTracer* trc = static_cast<JSTracer*>(aClosure);
- // Act like it's a one-element sequence to leverage all that infrastructure.
- SequenceTracer<T>::TraceSequence(trc, aValue, aValue + 1);
-}
-
-template<typename T>
-void TraceMozMap(JSTracer* trc, MozMap<T>& map)
+template<typename K, typename V>
+void TraceRecord(JSTracer* trc, Record<K, V>& record)
{
- map.EnumerateValues(TraceMozMapValue<T>, trc);
+ for (auto& entry : record.Entries()) {
+ // Act like it's a one-element sequence to leverage all that infrastructure.
+ SequenceTracer<V>::TraceSequence(trc, &entry.mValue, &entry.mValue + 1);
+ }
}
-// sequence<MozMap>
-template<typename T>
-class SequenceTracer<MozMap<T>, false, false, false>
+// sequence<record>
+template<typename K, typename V>
+class SequenceTracer<Record<K, V>, false, false, false>
{
explicit SequenceTracer() = delete; // Should never be instantiated
public:
- static void TraceSequence(JSTracer* trc, MozMap<T>* seqp, MozMap<T>* end) {
+ static void TraceSequence(JSTracer* trc, Record<K, V>* seqp,
+ Record<K, V>* end) {
for (; seqp != end; ++seqp) {
- seqp->EnumerateValues(TraceMozMapValue<T>, trc);
+ TraceRecord(trc, *seqp);
}
}
};
@@ -2395,51 +2416,51 @@ public:
SequenceType mSequenceType;
};
-// Rooter class for MozMap; this is what we mostly use in the codegen.
-template<typename T>
-class MOZ_RAII MozMapRooter final : private JS::CustomAutoRooter
+// Rooter class for Record; this is what we mostly use in the codegen.
+template<typename K, typename V>
+class MOZ_RAII RecordRooter final : private JS::CustomAutoRooter
{
public:
- MozMapRooter(JSContext *aCx, MozMap<T>* aMozMap
+ RecordRooter(JSContext *aCx, Record<K, V>* aRecord
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
- mMozMap(aMozMap),
- mMozMapType(eMozMap)
+ mRecord(aRecord),
+ mRecordType(eRecord)
{
}
- MozMapRooter(JSContext *aCx, Nullable<MozMap<T>>* aMozMap
+ RecordRooter(JSContext *aCx, Nullable<Record<K, V>>* aRecord
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
- mNullableMozMap(aMozMap),
- mMozMapType(eNullableMozMap)
+ mNullableRecord(aRecord),
+ mRecordType(eNullableRecord)
{
}
private:
- enum MozMapType {
- eMozMap,
- eNullableMozMap
+ enum RecordType {
+ eRecord,
+ eNullableRecord
};
virtual void trace(JSTracer *trc) override
{
- if (mMozMapType == eMozMap) {
- TraceMozMap(trc, *mMozMap);
+ if (mRecordType == eRecord) {
+ TraceRecord(trc, *mRecord);
} else {
- MOZ_ASSERT(mMozMapType == eNullableMozMap);
- if (!mNullableMozMap->IsNull()) {
- TraceMozMap(trc, mNullableMozMap->Value());
+ MOZ_ASSERT(mRecordType == eNullableRecord);
+ if (!mNullableRecord->IsNull()) {
+ TraceRecord(trc, mNullableRecord->Value());
}
}
}
union {
- MozMap<T>* mMozMap;
- Nullable<MozMap<T>>* mNullableMozMap;
+ Record<K, V>* mRecord;
+ Nullable<Record<K, V>>* mNullableRecord;
};
- MozMapType mMozMapType;
+ RecordType mRecordType;
};
template<typename T>
diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py
index cb93e4897..74acb5918 100644
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -84,7 +84,7 @@ def idlTypeNeedsCycleCollection(type):
return True
elif type.isUnion():
return any(idlTypeNeedsCycleCollection(t) for t in type.flatMemberTypes)
- elif type.isMozMap():
+ elif type.isRecord():
if idlTypeNeedsCycleCollection(type.inner):
raise TypeError("Cycle collection for type %s is not supported" % type)
return False
@@ -996,6 +996,8 @@ class CGElseChain(CGThing):
class CGTemplatedType(CGWrapper):
def __init__(self, templateName, child, isConst=False, isReference=False):
+ if isinstance(child, list):
+ child = CGList(child, ", ")
const = "const " if isConst else ""
pre = "%s%s<" % (const, templateName)
ref = "&" if isReference else ""
@@ -1171,12 +1173,12 @@ class CGHeaders(CGWrapper):
declareIncludes.add(filename)
elif unrolled.isPrimitive():
bindingHeaders.add("mozilla/dom/PrimitiveConversions.h")
- elif unrolled.isMozMap():
+ elif unrolled.isRecord():
if dictionary or jsImplementedDescriptors:
- declareIncludes.add("mozilla/dom/MozMap.h")
+ declareIncludes.add("mozilla/dom/Record.h")
else:
- bindingHeaders.add("mozilla/dom/MozMap.h")
- # Also add headers for the type the MozMap is
+ bindingHeaders.add("mozilla/dom/Record.h")
+ # Also add headers for the type the record is
# parametrized over, if needed.
addHeadersForType((t.inner, dictionary))
@@ -1388,8 +1390,8 @@ def UnionTypes(unionTypes, config):
# the right header to be able to Release() in our inlined
# code.
headers.add(CGHeaders.getDeclarationFilename(f.callback))
- elif f.isMozMap():
- headers.add("mozilla/dom/MozMap.h")
+ elif f.isRecord():
+ headers.add("mozilla/dom/Record.h")
# And add headers for the type we're parametrized over
addHeadersForType(f.inner)
@@ -1448,9 +1450,9 @@ def UnionConversions(unionTypes, config):
headers.add(CGHeaders.getDeclarationFilename(f.inner))
elif f.isPrimitive():
headers.add("mozilla/dom/PrimitiveConversions.h")
- elif f.isMozMap():
- headers.add("mozilla/dom/MozMap.h")
- # And the internal type of the MozMap
+ elif f.isRecord():
+ headers.add("mozilla/dom/Record.h")
+ # And the internal type of the record
addHeadersForType(f.inner)
# We plan to include UnionTypes.h no matter what, so it's
@@ -4290,6 +4292,9 @@ class JSToNativeConversionInfo():
for whether we have a JS::Value. Only used when
defaultValue is not None or when True is passed for
checkForValue to instantiateJSToNativeConversion.
+ This expression may not be already-parenthesized, so if
+ you use it with && or || make sure to put parens
+ around it.
${passedToJSImpl} replaced by an expression that evaluates to a boolean
for whether this value is being passed to a JS-
implemented interface.
@@ -4355,7 +4360,9 @@ def handleDefaultStringValue(defaultValue, method):
passing as the second argument of handleDefault; in particular it does not
end with a ';'
"""
- assert defaultValue.type.isDOMString() or defaultValue.type.isByteString()
+ assert (defaultValue.type.isDOMString() or
+ defaultValue.type.isUSVString() or
+ defaultValue.type.isByteString())
return ("static const %(char_t)s data[] = { %(data)s };\n"
"%(method)s(data, ArrayLength(data) - 1)") % {
'char_t': "char" if defaultValue.type.isByteString() else "char16_t",
@@ -4365,6 +4372,17 @@ def handleDefaultStringValue(defaultValue, method):
}
+def recordKeyType(recordType):
+ assert recordType.keyType.isString()
+ if recordType.keyType.isByteString():
+ return "nsCString"
+ return "nsString"
+
+
+def recordKeyDeclType(recordType):
+ return CGGeneric(recordKeyType(recordType))
+
+
# If this function is modified, modify CGNativeMember.getArg and
# CGNativeMember.getRetvalInfo accordingly. The latter cares about the decltype
# and holdertype we end up using, because it needs to be able to return the code
@@ -4559,7 +4577,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
declArgs = "cx"
else:
assert (isMember in
- ("Sequence", "Variadic", "Dictionary", "OwningUnion", "MozMap"))
+ ("Sequence", "Variadic", "Dictionary", "OwningUnion", "Record"))
# We'll get traced by the sequence or dictionary or union tracer
declType = CGGeneric("JSObject*")
declArgs = None
@@ -4725,39 +4743,41 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
dealWithOptional=isOptional,
holderArgs=holderArgs)
- if type.isMozMap():
+ if type.isRecord():
assert not isEnforceRange and not isClamp
if failureCode is None:
- notMozMap = ('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n'
+ notRecord = ('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n'
"%s" % (firstCap(sourceDescription), exceptionCode))
else:
- notMozMap = failureCode
+ notRecord = failureCode
nullable = type.nullable()
# Be very careful not to change "type": we need it later
if nullable:
- valueType = type.inner.inner
+ recordType = type.inner
else:
- valueType = type.inner
+ recordType = type
+ valueType = recordType.inner
valueInfo = getJSToNativeConversionInfo(
- valueType, descriptorProvider, isMember="MozMap",
+ valueType, descriptorProvider, isMember="Record",
exceptionCode=exceptionCode, lenientFloatCode=lenientFloatCode,
isCallbackReturnValue=isCallbackReturnValue,
sourceDescription="value in %s" % sourceDescription,
nestingLevel=incrementNestingLevel())
if valueInfo.dealWithOptional:
- raise TypeError("Shouldn't have optional things in MozMap")
+ raise TypeError("Shouldn't have optional things in record")
if valueInfo.holderType is not None:
- raise TypeError("Shouldn't need holders for MozMap")
+ raise TypeError("Shouldn't need holders for record")
- typeName = CGTemplatedType("MozMap", valueInfo.declType)
- mozMapType = typeName.define()
+ declType = CGTemplatedType("Record", [recordKeyDeclType(recordType),
+ valueInfo.declType])
+ typeName = declType.define()
if nullable:
- typeName = CGTemplatedType("Nullable", typeName)
- mozMapRef = "${declName}.SetValue()"
+ declType = CGTemplatedType("Nullable", declType)
+ recordRef = "${declName}.SetValue()"
else:
- mozMapRef = "${declName}"
+ recordRef = "${declName}"
valueConversion = string.Template(valueInfo.template).substitute({
"val": "temp",
@@ -4770,68 +4790,122 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
"passedToJSImpl": "${passedToJSImpl}"
})
+ keyType = recordKeyType(recordType)
+ if recordType.keyType.isByteString():
+ keyConversionFunction = "ConvertJSValueToByteString"
+ hashKeyType = "nsCStringHashKey"
+ else:
+ hashKeyType = "nsStringHashKey"
+ if recordType.keyType.isDOMString():
+ keyConversionFunction = "ConvertJSValueToString"
+ else:
+ assert recordType.keyType.isUSVString()
+ keyConversionFunction = "ConvertJSValueToUSVString"
+
templateBody = fill(
"""
- ${mozMapType} &mozMap = ${mozMapRef};
+ auto& recordEntries = ${recordRef}.Entries();
- JS::Rooted<JSObject*> mozMapObj(cx, &$${val}.toObject());
- JS::Rooted<JS::IdVector> ids(cx, JS::IdVector(cx));
- if (!JS_Enumerate(cx, mozMapObj, &ids)) {
+ JS::Rooted<JSObject*> recordObj(cx, &$${val}.toObject());
+ JS::AutoIdVector ids(cx);
+ if (!js::GetPropertyKeys(cx, recordObj,
+ JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &ids)) {
+ $*{exceptionCode}
+ }
+ if (!recordEntries.SetCapacity(ids.length(), mozilla::fallible)) {
+ JS_ReportOutOfMemory(cx);
$*{exceptionCode}
}
JS::Rooted<JS::Value> propNameValue(cx);
JS::Rooted<JS::Value> temp(cx);
JS::Rooted<jsid> curId(cx);
+ JS::Rooted<JS::Value> idVal(cx);
+ // Use a hashset to keep track of ids seen, to avoid
+ // introducing nasty O(N^2) behavior scanning for them all the
+ // time. Ideally we'd use a data structure with O(1) lookup
+ // _and_ ordering for the MozMap, but we don't have one lying
+ // around.
+ nsTHashtable<${hashKeyType}> idsSeen;
for (size_t i = 0; i < ids.length(); ++i) {
- // Make sure we get the value before converting the name, since
- // getting the value can trigger GC but our name is a dependent
- // string.
curId = ids[i];
- binding_detail::FakeString propName;
- bool isSymbol;
- if (!ConvertIdToString(cx, curId, propName, isSymbol) ||
- (!isSymbol && !JS_GetPropertyById(cx, mozMapObj, curId, &temp))) {
+
+ JS::Rooted<JS::PropertyDescriptor> desc(cx);
+ if (!JS_GetOwnPropertyDescriptorById(cx, recordObj, curId,
+ &desc)) {
$*{exceptionCode}
}
- if (isSymbol) {
+
+ if (!desc.object() /* == undefined in spec terms */ ||
+ !desc.enumerable()) {
continue;
}
- ${valueType}* slotPtr = mozMap.AddEntry(propName);
- if (!slotPtr) {
- JS_ReportOutOfMemory(cx);
+ idVal = js::IdToValue(curId);
+ ${keyType} propName;
+ // This will just throw if idVal is a Symbol, like the spec says
+ // to do.
+ if (!${keyConversionFunction}(cx, idVal, propName)) {
$*{exceptionCode}
}
- ${valueType}& slot = *slotPtr;
+
+ if (!JS_GetPropertyById(cx, recordObj, curId, &temp)) {
+ $*{exceptionCode}
+ }
+
+ ${typeName}::EntryType* entry;
+ if (idsSeen.Contains(propName)) {
+ // Find the existing entry.
+ auto idx = recordEntries.IndexOf(propName);
+ MOZ_ASSERT(idx != recordEntries.NoIndex,
+ "Why is it not found?");
+ // Now blow it away to make it look like it was just added
+ // to the array, because it's not obvious that it's
+ // safe to write to its already-initialized mValue via our
+ // normal codegen conversions. For example, the value
+ // could be a union and this would change its type, but
+ // codegen assumes we won't do that.
+ entry = recordEntries.ReconstructElementAt(idx);
+ } else {
+ // Safe to do an infallible append here, because we did a
+ // SetCapacity above to the right capacity.
+ entry = recordEntries.AppendElement();
+ idsSeen.PutEntry(propName);
+ }
+ entry->mKey = propName;
+ ${valueType}& slot = entry->mValue;
$*{valueConversion}
}
""",
exceptionCode=exceptionCode,
- mozMapType=mozMapType,
- mozMapRef=mozMapRef,
+ recordRef=recordRef,
+ hashKeyType=hashKeyType,
+ keyType=keyType,
+ keyConversionFunction=keyConversionFunction,
+ typeName=typeName,
valueType=valueInfo.declType.define(),
valueConversion=valueConversion)
templateBody = wrapObjectTemplate(templateBody, type,
"${declName}.SetNull();\n",
- notMozMap)
+ notRecord)
- declType = typeName
declArgs = None
holderType = None
holderArgs = None
- # MozMap arguments that might contain traceable things need
+ # record arguments that might contain traceable things need
# to get traced
if not isMember and isCallbackReturnValue:
# Go ahead and just convert directly into our actual return value
declType = CGWrapper(declType, post="&")
declArgs = "aRetVal"
elif not isMember and typeNeedsRooting(valueType):
- holderType = CGTemplatedType("MozMapRooter", valueInfo.declType)
- # If our MozMap is nullable, this will set the Nullable to be
+ holderType = CGTemplatedType("RecordRooter",
+ [recordKeyDeclType(recordType),
+ valueInfo.declType])
+ # If our record is nullable, this will set the Nullable to be
# not-null, but that's ok because we make an explicit SetNull() call
# on it as needed if our JS value is actually null.
- holderArgs = "cx, &%s" % mozMapRef
+ holderArgs = "cx, &%s" % recordRef
return JSToNativeConversionInfo(templateBody, declType=declType,
declArgs=declArgs,
@@ -4914,16 +4988,16 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
else:
setDictionary = None
- mozMapMemberTypes = filter(lambda t: t.isMozMap(), memberTypes)
- if len(mozMapMemberTypes) > 0:
- assert len(mozMapMemberTypes) == 1
- name = getUnionMemberName(mozMapMemberTypes[0])
- mozMapObject = CGGeneric(
+ recordMemberTypes = filter(lambda t: t.isRecord(), memberTypes)
+ if len(recordMemberTypes) > 0:
+ assert len(recordMemberTypes) == 1
+ name = getUnionMemberName(recordMemberTypes[0])
+ recordObject = CGGeneric(
"done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
(unionArgumentObj, name))
names.append(name)
else:
- mozMapObject = None
+ recordObject = None
objectMemberTypes = filter(lambda t: t.isObject(), memberTypes)
if len(objectMemberTypes) > 0:
@@ -4939,10 +5013,10 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
else:
object = None
- hasObjectTypes = interfaceObject or sequenceObject or dateObject or callbackObject or object or mozMapObject
+ hasObjectTypes = interfaceObject or sequenceObject or dateObject or callbackObject or object or recordObject
if hasObjectTypes:
# "object" is not distinguishable from other types
- assert not object or not (interfaceObject or sequenceObject or dateObject or callbackObject or mozMapObject)
+ assert not object or not (interfaceObject or sequenceObject or dateObject or callbackObject or recordObject)
if sequenceObject or dateObject or callbackObject:
# An object can be both an sequence object and a callback or
# dictionary, but we shouldn't have both in the union's members
@@ -4962,9 +5036,9 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if dateObject:
templateBody.prepend(CGGeneric("JS::Rooted<JSObject*> argObj(cx, &${val}.toObject());\n"))
- if mozMapObject:
+ if recordObject:
templateBody = CGList([templateBody,
- CGIfWrapper(mozMapObject, "!done")])
+ CGIfWrapper(recordObject, "!done")])
templateBody = CGIfWrapper(templateBody, "${val}.isObject()")
else:
@@ -5144,7 +5218,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if isinstance(defaultValue, IDLNullValue):
extraConditionForNull = "!(${haveValue}) || "
else:
- extraConditionForNull = "${haveValue} && "
+ extraConditionForNull = "(${haveValue}) && "
else:
extraConditionForNull = ""
templateBody = handleNull(templateBody, declLoc,
@@ -5525,7 +5599,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
def getConversionCode(varName):
normalizeCode = ""
if type.isUSVString():
- normalizeCode = "NormalizeUSVString(cx, %s);\n" % varName
+ normalizeCode = "NormalizeUSVString(%s);\n" % varName
conversionCode = fill("""
if (!ConvertJSValueToString(cx, $${val}, ${nullBehavior}, ${undefinedBehavior}, ${varName})) {
@@ -5688,7 +5762,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
haveCallable = "${val}.isObject() && " + haveCallable
if defaultValue is not None:
assert(isinstance(defaultValue, IDLNullValue))
- haveCallable = "${haveValue} && " + haveCallable
+ haveCallable = "(${haveValue}) && " + haveCallable
template = (
("if (%s) {\n" % haveCallable) +
conversion +
@@ -5700,7 +5774,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
haveObject = "${val}.isObject()"
if defaultValue is not None:
assert(isinstance(defaultValue, IDLNullValue))
- haveObject = "${haveValue} && " + haveObject
+ haveObject = "(${haveValue}) && " + haveObject
template = CGIfElseWrapper(haveObject,
CGGeneric(conversion),
CGGeneric("${declName} = nullptr;\n")).define()
@@ -5724,7 +5798,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
assert not isEnforceRange and not isClamp
declArgs = None
- if isMember in ("Variadic", "Sequence", "Dictionary", "MozMap"):
+ if isMember in ("Variadic", "Sequence", "Dictionary", "Record"):
# Rooting is handled by the sequence and dictionary tracers.
declType = "JS::Value"
else:
@@ -5768,8 +5842,9 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription)
if type.isDictionary():
- # There are no nullable dictionaries
- assert not type.nullable() or isCallbackReturnValue
+ # There are no nullable dictionary arguments or dictionary members
+ assert(not type.nullable() or isCallbackReturnValue or
+ (isMember and isMember != "Dictionary"))
# All optional dictionaries always have default values, so we
# should be able to assume not isOptional here.
assert not isOptional
@@ -6256,7 +6331,7 @@ def getMaybeWrapValueFuncForType(type):
sequenceWrapLevel = 0
-mozMapWrapLevel = 0
+recordWrapLevel = 0
def getWrapTemplateForType(type, descriptorProvider, result, successCode,
@@ -6361,7 +6436,7 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
if type is None or type.isVoid():
return (setUndefined(), True)
- if (type.isSequence() or type.isMozMap()) and type.nullable():
+ if (type.isSequence() or type.isRecord()) and type.nullable():
# These are both wrapped in Nullable<>
recTemplate, recInfall = getWrapTemplateForType(type.inner, descriptorProvider,
"%s.Value()" % result, successCode,
@@ -6434,14 +6509,14 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
return (code, False)
- if type.isMozMap():
- # Now do non-nullable MozMap. Our success code is just to break to
+ if type.isRecord():
+ # Now do non-nullable record. Our success code is just to break to
# where we define the property on the object. Note that we bump the
- # mozMapWrapLevel around this call so that nested MozMap conversions
+ # recordWrapLevel around this call so that nested record conversions
# will use different temp value names.
- global mozMapWrapLevel
- valueName = "mozMapValue%d" % mozMapWrapLevel
- mozMapWrapLevel += 1
+ global recordWrapLevel
+ valueName = "recordValue%d" % recordWrapLevel
+ recordWrapLevel += 1
innerTemplate = wrapForType(
type.inner, descriptorProvider,
{
@@ -6454,12 +6529,22 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
'obj': "returnObj",
'typedArraysAreStructs': typedArraysAreStructs
})
- mozMapWrapLevel -= 1
+ recordWrapLevel -= 1
+ if type.keyType.isByteString():
+ # There is no length-taking JS_DefineProperty. So to keep
+ # things sane with embedded nulls, we want to byte-inflate
+ # to an nsAString. The only byte-inflation function we
+ # have around is AppendASCIItoUTF16, which luckily doesn't
+ # assert anything about the input being ASCII.
+ expandedKeyDecl = "NS_ConvertASCIItoUTF16 expandedKey(entry.mKey);\n"
+ keyName = "expandedKey"
+ else:
+ expandedKeyDecl = ""
+ keyName = "entry.mKey"
+
code = fill(
"""
- nsTArray<nsString> keys;
- ${result}.GetKeys(keys);
JS::Rooted<JSObject*> returnObj(cx, JS_NewPlainObject(cx));
if (!returnObj) {
$*{exceptionCode}
@@ -6467,15 +6552,17 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
// Scope for 'tmp'
{
JS::Rooted<JS::Value> tmp(cx);
- for (size_t idx = 0; idx < keys.Length(); ++idx) {
- auto& ${valueName} = ${result}.Get(keys[idx]);
+ for (auto& entry : ${result}.Entries()) {
+ auto& ${valueName} = entry.mValue;
// Control block to let us common up the JS_DefineUCProperty calls when there
// are different ways to succeed at wrapping the value.
do {
$*{innerTemplate}
} while (0);
- if (!JS_DefineUCProperty(cx, returnObj, keys[idx].get(),
- keys[idx].Length(), tmp,
+ $*{expandedKeyDecl}
+ if (!JS_DefineUCProperty(cx, returnObj,
+ ${keyName}.BeginReading(),
+ ${keyName}.Length(), tmp,
JSPROP_ENUMERATE)) {
$*{exceptionCode}
}
@@ -6487,6 +6574,8 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
exceptionCode=exceptionCode,
valueName=valueName,
innerTemplate=innerTemplate,
+ expandedKeyDecl=expandedKeyDecl,
+ keyName=keyName,
set=setObject("*returnObj"))
return (code, False)
@@ -6770,7 +6859,7 @@ def typeMatchesLambda(type, func):
return False
if type.nullable():
return typeMatchesLambda(type.inner, func)
- if type.isSequence() or type.isMozMap():
+ if type.isSequence() or type.isRecord():
return typeMatchesLambda(type.inner, func)
if type.isUnion():
return any(typeMatchesLambda(t, func) for t in
@@ -6866,20 +6955,21 @@ def getRetvalDeclarationForType(returnType, descriptorProvider,
if nullable:
result = CGTemplatedType("Nullable", result)
return result, "ref", rooter, None, None
- if returnType.isMozMap():
+ if returnType.isRecord():
nullable = returnType.nullable()
if nullable:
returnType = returnType.inner
result, _, _, _, _ = getRetvalDeclarationForType(returnType.inner,
descriptorProvider,
- isMember="MozMap")
+ isMember="Record")
# While we have our inner type, set up our rooter, if needed
if not isMember and typeNeedsRooting(returnType):
- rooter = CGGeneric("MozMapRooter<%s> resultRooter(cx, &result);\n" %
- result.define())
+ rooter = CGGeneric("RecordRooter<%s> resultRooter(cx, &result);\n" %
+ ("nsString, " + result.define()))
else:
rooter = None
- result = CGTemplatedType("MozMap", result)
+ result = CGTemplatedType("Record", [recordKeyDeclType(returnType),
+ result])
if nullable:
result = CGTemplatedType("Nullable", result)
return result, "ref", rooter, None, None
@@ -6976,7 +7066,7 @@ class CGCallGenerator(CGThing):
return True
if a.type.isSequence():
return True
- if a.type.isMozMap():
+ if a.type.isRecord():
return True
# isObject() types are always a JS::Rooted, whether
# nullable or not, and it turns out a const JS::Rooted
@@ -7138,7 +7228,7 @@ class MethodNotNewObjectError(Exception):
# nested sequences we don't use the same variable name to iterate over
# different sequences.
sequenceWrapLevel = 0
-mapWrapLevel = 0
+recordWrapLevel = 0
def wrapTypeIntoCurrentCompartment(type, value, isMember=True):
@@ -7199,29 +7289,27 @@ def wrapTypeIntoCurrentCompartment(type, value, isMember=True):
wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % origValue)
return wrapCode
- if type.isMozMap():
- origValue = value
+ if type.isRecord():
origType = type
if type.nullable():
type = type.inner
- value = "%s.Value()" % value
- global mapWrapLevel
- key = "mapName%d" % mapWrapLevel
- mapWrapLevel += 1
+ recordRef = "%s.Value()" % value
+ else:
+ recordRef = value
+ global recordWrapLevel
+ entryRef = "mapEntry%d" % recordWrapLevel
+ recordWrapLevel += 1
wrapElement = wrapTypeIntoCurrentCompartment(type.inner,
- "%s.Get(%sKeys[%sIndex])" % (value, key, key))
- mapWrapLevel -= 1
+ "%s.mValue" % entryRef)
+ recordWrapLevel -= 1
if not wrapElement:
return None
wrapCode = CGWrapper(CGIndenter(wrapElement),
- pre=("""
- nsTArray<nsString> %sKeys;
- %s.GetKeys(%sKeys);
- for (uint32_t %sIndex = 0; %sIndex < %sKeys.Length(); ++%sIndex) {
- """ % (key, value, key, key, key, key, key)),
+ pre=("for (auto& %s : %s.Entries()) {\n" %
+ (entryRef, recordRef)),
post="}\n")
if origType.nullable():
- wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % origValue)
+ wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % value)
return wrapCode
if type.isDictionary():
@@ -8110,11 +8198,11 @@ class CGMethodCall(CGThing):
if distinguishingType(s).isSequence())
# Now append all the overloads that take a dictionary or callback
- # interface or MozMap. There should be only one of these!
+ # interface or record. There should be only one of these!
genericObjectSigs = [
s for s in possibleSignatures
if (distinguishingType(s).isDictionary() or
- distinguishingType(s).isMozMap() or
+ distinguishingType(s).isRecord() or
distinguishingType(s).isCallbackInterface())]
assert len(genericObjectSigs) <= 1
objectSigs.extend(genericObjectSigs)
@@ -9408,7 +9496,7 @@ class CGMemberJITInfo(CGThing):
return "JSVAL_TYPE_UNDEFINED"
if t.isSequence():
return "JSVAL_TYPE_OBJECT"
- if t.isMozMap():
+ if t.isRecord():
return "JSVAL_TYPE_OBJECT"
if t.isGeckoInterface():
return "JSVAL_TYPE_OBJECT"
@@ -9669,17 +9757,22 @@ def getUnionAccessorSignatureType(type, descriptorProvider):
# Flat member types have already unwrapped nullables.
assert not type.nullable()
- if type.isSequence() or type.isMozMap():
+ if type.isSequence() or type.isRecord():
if type.isSequence():
wrapperType = "Sequence"
else:
- wrapperType = "MozMap"
+ wrapperType = "Record"
# We don't use the returned template here, so it's OK to just pass no
# sourceDescription.
elementInfo = getJSToNativeConversionInfo(type.inner,
descriptorProvider,
isMember=wrapperType)
- return CGTemplatedType(wrapperType, elementInfo.declType,
+ if wrapperType == "Sequence":
+ innerType = elementInfo.declType
+ else:
+ innerType = [recordKeyDeclType(type), elementInfo.declType]
+
+ return CGTemplatedType(wrapperType, innerType,
isConst=True, isReference=True)
# Nested unions are unwrapped automatically into our flatMemberTypes.
@@ -10040,10 +10133,10 @@ class CGUnionStruct(CGThing):
CGCase("e" + vars["name"],
CGGeneric("DoTraceSequence(trc, mValue.m%s.Value());\n" %
vars["name"])))
- elif t.isMozMap():
+ elif t.isRecord():
traceCases.append(
CGCase("e" + vars["name"],
- CGGeneric("TraceMozMap(trc, mValue.m%s.Value());\n" %
+ CGGeneric("TraceRecord(trc, mValue.m%s.Value());\n" %
vars["name"])))
else:
assert t.isSpiderMonkeyInterface()
@@ -13172,8 +13265,8 @@ class CGDictionary(CGThing):
trace = CGGeneric('%s.TraceSelf(trc);\n' % memberData)
if type.nullable():
trace = CGIfWrapper(trace, "!%s.IsNull()" % memberNullable)
- elif type.isMozMap():
- # If you implement this, add a MozMap<object> to
+ elif type.isRecord():
+ # If you implement this, add a record<DOMString, object> to
# TestInterfaceJSDictionary and test it in test_bug1036214.html
# to make sure we end up with the correct security properties.
assert False
@@ -13583,7 +13676,7 @@ class ForwardDeclarationBuilder:
# since we don't know which one we might want
self.addInMozillaDom(CGUnionStruct.unionTypeName(t, False))
self.addInMozillaDom(CGUnionStruct.unionTypeName(t, True))
- elif t.isMozMap():
+ elif t.isRecord():
self.forwardDeclareForType(t.inner, config)
# Don't need to do anything for void, primitive, string, any or object.
# There may be some other cases we are missing.
@@ -14089,9 +14182,9 @@ class CGNativeMember(ClassMethod):
else:
returnCode = "aRetVal.SwapElements(${declName});\n"
return "void", "", returnCode
- if type.isMozMap():
- # If we want to handle MozMap-of-MozMap return values, we're
- # going to need to fix example codegen to not produce MozMap<void>
+ if type.isRecord():
+ # If we want to handle record-of-record return values, we're
+ # going to need to fix example codegen to not produce record<void>
# for the relevant argument...
assert not isMember
# In this case we convert directly into our outparam to start with
@@ -14139,13 +14232,14 @@ class CGNativeMember(ClassMethod):
if nullable:
type = CGTemplatedType("Nullable", type)
args.append(Argument("%s&" % type.define(), "aRetVal"))
- elif returnType.isMozMap():
+ elif returnType.isRecord():
nullable = returnType.nullable()
if nullable:
returnType = returnType.inner
# And now the actual underlying type
elementDecl = self.getReturnType(returnType.inner, True)
- type = CGTemplatedType("MozMap", CGGeneric(elementDecl))
+ type = CGTemplatedType("Record", [recordKeyDeclType(returnType),
+ CGGeneric(elementDecl)])
if nullable:
type = CGTemplatedType("Nullable", type)
args.append(Argument("%s&" % type.define(), "aRetVal"))
@@ -14206,7 +14300,7 @@ class CGNativeMember(ClassMethod):
Nullable as needed.
isMember can be false or one of the strings "Sequence", "Variadic",
- "MozMap"
+ "Record"
"""
if type.isSequence():
nullable = type.nullable()
@@ -14217,13 +14311,13 @@ class CGNativeMember(ClassMethod):
decl = CGTemplatedType("Sequence", argType)
return decl.define(), True, True
- if type.isMozMap():
+ if type.isRecord():
nullable = type.nullable()
if nullable:
type = type.inner
elementType = type.inner
- argType = self.getArgType(elementType, False, "MozMap")[0]
- decl = CGTemplatedType("MozMap", argType)
+ argType = self.getArgType(elementType, False, "Record")[0]
+ decl = CGTemplatedType("Record", [recordKeyDeclType(type), argType])
return decl.define(), True, True
if type.isUnion():
diff --git a/dom/bindings/Configuration.py b/dom/bindings/Configuration.py
index 5c96580a1..f80c19c33 100644
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -115,7 +115,7 @@ class Configuration(DescriptorProvider):
for (t, _) in getAllTypes(self.descriptors, self.dictionaries, self.callbacks):
while True:
- if t.isMozMap():
+ if t.isRecord():
t = t.inner
elif t.unroll() != t:
t = t.unroll()
diff --git a/dom/bindings/MozMap.h b/dom/bindings/MozMap.h
deleted file mode 100644
index 1e920c098..000000000
--- a/dom/bindings/MozMap.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* 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/. */
-
-/**
- * Class for representing MozMap arguments. This is an nsTHashtable
- * under the hood, but we don't want to leak that implementation
- * detail.
- */
-
-#ifndef mozilla_dom_MozMap_h
-#define mozilla_dom_MozMap_h
-
-#include "nsTHashtable.h"
-#include "nsHashKeys.h"
-#include "nsStringGlue.h"
-#include "nsTArray.h"
-#include "mozilla/Attributes.h"
-#include "mozilla/Move.h"
-
-namespace mozilla {
-namespace dom {
-
-namespace binding_detail {
-template<typename DataType>
-class MozMapEntry : public nsStringHashKey
-{
-public:
- explicit MozMapEntry(const nsAString* aKeyTypePointer)
- : nsStringHashKey(aKeyTypePointer)
- {
- }
-
- // Move constructor so we can do MozMaps of MozMaps.
- MozMapEntry(MozMapEntry<DataType>&& aOther)
- : nsStringHashKey(aOther),
- mData(Move(aOther.mData))
- {
- }
-
- DataType mData;
-};
-
-} // namespace binding_detail
-
-template<typename DataType>
-class MozMap : protected nsTHashtable<binding_detail::MozMapEntry<DataType>>
-{
-public:
- typedef typename binding_detail::MozMapEntry<DataType> EntryType;
- typedef nsTHashtable<EntryType> Base;
- typedef MozMap<DataType> SelfType;
-
- MozMap()
- {
- }
-
- // Move constructor so we can do MozMap of MozMap.
- MozMap(SelfType&& aOther) :
- Base(Move(aOther))
- {
- }
-
- // The return value is only safe to use until an AddEntry call.
- const DataType& Get(const nsAString& aKey) const
- {
- const EntryType* ent = this->GetEntry(aKey);
- MOZ_ASSERT(ent, "Why are you using a key we didn't claim to have?");
- return ent->mData;
- }
-
- DataType& Get(const nsAString& aKey)
- {
- EntryType* ent = this->GetEntry(aKey);
- MOZ_ASSERT(ent, "Why are you using a key we didn't claim to have?");
- return ent->mData;
- }
-
- // The return value is only safe to use until an AddEntry call.
- const DataType* GetIfExists(const nsAString& aKey) const
- {
- const EntryType* ent = this->GetEntry(aKey);
- if (!ent) {
- return nullptr;
- }
- return &ent->mData;
- }
-
- void GetKeys(nsTArray<nsString>& aKeys) const {
- for (auto iter = this->ConstIter(); !iter.Done(); iter.Next()) {
- aKeys.AppendElement(iter.Get()->GetKey());
- }
- }
-
- // XXXbz we expose this generic enumerator for tracing. Otherwise we'd end up
- // with a dependency on BindingUtils.h here for the SequenceTracer bits.
- typedef void (* Enumerator)(DataType* aValue, void* aClosure);
- void EnumerateValues(Enumerator aEnumerator, void *aClosure)
- {
- for (auto iter = this->Iter(); !iter.Done(); iter.Next()) {
- aEnumerator(&iter.Get()->mData, aClosure);
- }
- }
-
- MOZ_MUST_USE
- DataType* AddEntry(const nsAString& aKey)
- {
- EntryType* ent = this->PutEntry(aKey, fallible);
- if (!ent) {
- return nullptr;
- }
- return &ent->mData;
- }
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_MozMap_h
diff --git a/dom/bindings/Record.h b/dom/bindings/Record.h
new file mode 100644
index 000000000..d6ab31699
--- /dev/null
+++ b/dom/bindings/Record.h
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/**
+ * Class for representing record arguments. Basically an array under the hood.
+ */
+
+#ifndef mozilla_dom_Record_h
+#define mozilla_dom_Record_h
+
+#include "nsTHashtable.h"
+#include "nsHashKeys.h"
+#include "nsStringGlue.h"
+#include "nsTArray.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/Move.h"
+
+namespace mozilla {
+namespace dom {
+
+namespace binding_detail {
+template<typename KeyType, typename ValueType>
+class RecordEntry
+{
+public:
+ RecordEntry()
+ {
+ }
+
+ // Move constructor so we can do Records of Records.
+ RecordEntry(RecordEntry<KeyType, ValueType>&& aOther)
+ : mKey(Move(aOther.mKey)),
+ mValue(Move(aOther.mValue))
+ {
+ }
+
+ KeyType mKey;
+ ValueType mValue;
+};
+
+} // namespace binding_detail
+
+template<typename KeyType, typename ValueType>
+class Record
+{
+public:
+ typedef typename binding_detail::RecordEntry<KeyType, ValueType> EntryType;
+ typedef Record<KeyType, ValueType> SelfType;
+
+ Record()
+ {
+ }
+
+ // Move constructor so we can do Record of Record.
+ Record(SelfType&& aOther) :
+ mEntries(Move(aOther.mEntries))
+ {
+ }
+
+ const nsTArray<EntryType>& Entries() const
+ {
+ return mEntries;
+ }
+
+ nsTArray<EntryType>& Entries()
+ {
+ return mEntries;
+ }
+
+private:
+ nsTArray<EntryType> mEntries;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+template<typename K, typename V>
+class nsDefaultComparator<mozilla::dom::binding_detail::RecordEntry<K, V>, K>
+{
+public:
+ bool Equals(const mozilla::dom::binding_detail::RecordEntry<K, V>& aEntry,
+ const K& aKey) const
+ {
+ return aEntry.mKey == aKey;
+ }
+};
+
+#endif // mozilla_dom_Record_h
diff --git a/dom/bindings/moz.build b/dom/bindings/moz.build
index f1ce9e276..7e1358e9c 100644
--- a/dom/bindings/moz.build
+++ b/dom/bindings/moz.build
@@ -32,10 +32,10 @@ EXPORTS.mozilla.dom += [
'FakeString.h',
'IterableIterator.h',
'JSSlots.h',
- 'MozMap.h',
'NonRefcountedDOMObject.h',
'Nullable.h',
'PrimitiveConversions.h',
+ 'Record.h',
'RootedDictionary.h',
'SimpleGlobalObject.h',
'StructuredClone.h',
diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py
index f668d7d62..8c32a8738 100644
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -1867,7 +1867,7 @@ class IDLDictionary(IDLObjectWithScope):
if (memberType.nullable() or
memberType.isSequence() or
- memberType.isMozMap()):
+ memberType.isRecord()):
return typeContainsDictionary(memberType.inner, dictionary)
if memberType.isDictionary():
@@ -1988,7 +1988,7 @@ class IDLType(IDLObject):
'callback',
'union',
'sequence',
- 'mozmap'
+ 'record'
)
def __init__(self, location, name):
@@ -2038,7 +2038,7 @@ class IDLType(IDLObject):
def isSequence(self):
return False
- def isMozMap(self):
+ def isRecord(self):
return False
def isArrayBuffer(self):
@@ -2263,8 +2263,8 @@ class IDLNullableType(IDLParameterizedType):
def isSequence(self):
return self.inner.isSequence()
- def isMozMap(self):
- return self.inner.isMozMap()
+ def isRecord(self):
+ return self.inner.isRecord()
def isArrayBuffer(self):
return self.inner.isArrayBuffer()
@@ -2321,8 +2321,10 @@ class IDLNullableType(IDLParameterizedType):
return self
def isDistinguishableFrom(self, other):
- if (other.nullable() or (other.isUnion() and other.hasNullableType) or
- other.isDictionary()):
+ if (other.nullable() or
+ other.isDictionary() or
+ (other.isUnion() and
+ (other.hasNullableType or other.hasDictionaryType()))):
# Can't tell which type null should become
return False
return self.inner.isDistinguishableFrom(other)
@@ -2397,34 +2399,38 @@ class IDLSequenceType(IDLParameterizedType):
return (other.isPrimitive() or other.isString() or other.isEnum() or
other.isDate() or other.isInterface() or
other.isDictionary() or
- other.isCallback() or other.isMozMap())
+ other.isCallback() or other.isRecord())
-class IDLMozMapType(IDLParameterizedType):
- def __init__(self, location, parameterType):
- assert not parameterType.isVoid()
+class IDLRecordType(IDLParameterizedType):
+ def __init__(self, location, keyType, valueType):
+ assert keyType.isString()
+ assert keyType.isComplete()
+ assert not valueType.isVoid()
+
+ IDLParameterizedType.__init__(self, location, valueType.name, valueType)
+ self.keyType = keyType
- IDLParameterizedType.__init__(self, location, parameterType.name, parameterType)
# Need to set self.name up front if our inner type is already complete,
# since in that case our .complete() won't be called.
if self.inner.isComplete():
- self.name = self.inner.name + "MozMap"
+ self.name = self.keyType.name + self.inner.name + "Record"
def __eq__(self, other):
- return isinstance(other, IDLMozMapType) and self.inner == other.inner
+ return isinstance(other, IDLRecordType) and self.inner == other.inner
def __str__(self):
- return self.inner.__str__() + "MozMap"
+ return self.keyType.__str__() + self.inner.__str__() + "Record"
- def isMozMap(self):
+ def isRecord(self):
return True
def tag(self):
- return IDLType.Tags.mozmap
+ return IDLType.Tags.record
def complete(self, scope):
self.inner = self.inner.complete(scope)
- self.name = self.inner.name + "MozMap"
+ self.name = self.keyType.name + self.inner.name + "Record"
return self
def unroll(self):
@@ -2614,8 +2620,8 @@ class IDLTypedefType(IDLType):
def isSequence(self):
return self.inner.isSequence()
- def isMozMap(self):
- return self.inner.isMozMap()
+ def isRecord(self):
+ return self.inner.isRecord()
def isDictionary(self):
return self.inner.isDictionary()
@@ -2798,7 +2804,7 @@ class IDLWrapperType(IDLType):
if self.isEnum():
return (other.isPrimitive() or other.isInterface() or other.isObject() or
other.isCallback() or other.isDictionary() or
- other.isSequence() or other.isMozMap() or other.isDate())
+ other.isSequence() or other.isRecord() or other.isDate())
if self.isDictionary() and other.nullable():
return False
if (other.isPrimitive() or other.isString() or other.isEnum() or
@@ -2820,7 +2826,7 @@ class IDLWrapperType(IDLType):
(self.isNonCallbackInterface() or
other.isNonCallbackInterface()))
if (other.isDictionary() or other.isCallback() or
- other.isMozMap()):
+ other.isRecord()):
return self.isNonCallbackInterface()
# Not much else |other| can be
@@ -3030,17 +3036,17 @@ class IDLBuiltinType(IDLType):
return (other.isNumeric() or other.isString() or other.isEnum() or
other.isInterface() or other.isObject() or
other.isCallback() or other.isDictionary() or
- other.isSequence() or other.isMozMap() or other.isDate())
+ other.isSequence() or other.isRecord() or other.isDate())
if self.isNumeric():
return (other.isBoolean() or other.isString() or other.isEnum() or
other.isInterface() or other.isObject() or
other.isCallback() or other.isDictionary() or
- other.isSequence() or other.isMozMap() or other.isDate())
+ other.isSequence() or other.isRecord() or other.isDate())
if self.isString():
return (other.isPrimitive() or other.isInterface() or
other.isObject() or
other.isCallback() or other.isDictionary() or
- other.isSequence() or other.isMozMap() or other.isDate())
+ other.isSequence() or other.isRecord() or other.isDate())
if self.isAny():
# Can't tell "any" apart from anything
return False
@@ -3050,7 +3056,7 @@ class IDLBuiltinType(IDLType):
return (other.isPrimitive() or other.isString() or other.isEnum() or
other.isInterface() or other.isCallback() or
other.isDictionary() or other.isSequence() or
- other.isMozMap())
+ other.isRecord())
if self.isVoid():
return not other.isVoid()
# Not much else we could be!
@@ -3058,7 +3064,7 @@ class IDLBuiltinType(IDLType):
# Like interfaces, but we know we're not a callback
return (other.isPrimitive() or other.isString() or other.isEnum() or
other.isCallback() or other.isDictionary() or
- other.isSequence() or other.isMozMap() or other.isDate() or
+ other.isSequence() or other.isRecord() or other.isDate() or
(other.isInterface() and (
# ArrayBuffer is distinguishable from everything
# that's not an ArrayBuffer or a callback interface
@@ -3843,6 +3849,9 @@ class IDLConst(IDLInterfaceMember):
if type.isDictionary():
raise WebIDLError("A constant cannot be of a dictionary type",
[self.location])
+ if type.isRecord():
+ raise WebIDLError("A constant cannot be of a record type",
+ [self.location])
self.type = type
self.value = value
@@ -3954,8 +3963,8 @@ class IDLAttribute(IDLInterfaceMember):
if self.type.isSequence() and not self.getExtendedAttribute("Cached"):
raise WebIDLError("A non-cached attribute cannot be of a sequence "
"type", [self.location])
- if self.type.isMozMap() and not self.getExtendedAttribute("Cached"):
- raise WebIDLError("A non-cached attribute cannot be of a MozMap "
+ if self.type.isRecord() and not self.getExtendedAttribute("Cached"):
+ raise WebIDLError("A non-cached attribute cannot be of a record "
"type", [self.location])
if self.type.isUnion():
for f in self.type.unroll().flatMemberTypes:
@@ -3971,11 +3980,11 @@ class IDLAttribute(IDLInterfaceMember):
"one of its member types's member "
"types, and so on) is a sequence "
"type", [self.location, f.location])
- if f.isMozMap():
+ if f.isRecord():
raise WebIDLError("An attribute cannot be of a union "
"type if one of its member types (or "
"one of its member types's member "
- "types, and so on) is a MozMap "
+ "types, and so on) is a record "
"type", [self.location, f.location])
if not self.type.isInterface() and self.getExtendedAttribute("PutForwards"):
raise WebIDLError("An attribute with [PutForwards] must have an "
@@ -3989,7 +3998,7 @@ class IDLAttribute(IDLInterfaceMember):
def typeContainsChromeOnlyDictionaryMember(type):
if (type.nullable() or
type.isSequence() or
- type.isMozMap()):
+ type.isRecord()):
return typeContainsChromeOnlyDictionaryMember(type.inner)
if type.isUnion():
@@ -4035,10 +4044,10 @@ class IDLAttribute(IDLInterfaceMember):
[self.location, location])
if self.getExtendedAttribute("Frozen"):
if (not self.type.isSequence() and not self.type.isDictionary() and
- not self.type.isMozMap()):
+ not self.type.isRecord()):
raise WebIDLError("[Frozen] is only allowed on "
"sequence-valued, dictionary-valued, and "
- "MozMap-valued attributes",
+ "record-valued attributes",
[self.location])
if not self.type.unroll().isExposedInAllOf(self.exposureSet):
raise WebIDLError("Attribute returns a type that is not exposed "
@@ -5147,7 +5156,7 @@ class Tokenizer(object):
"Promise": "PROMISE",
"required": "REQUIRED",
"sequence": "SEQUENCE",
- "MozMap": "MOZMAP",
+ "record": "RECORD",
"short": "SHORT",
"unsigned": "UNSIGNED",
"void": "VOID",
@@ -6276,7 +6285,7 @@ class Parser(Tokenizer):
| OCTET
| OPTIONAL
| SEQUENCE
- | MOZMAP
+ | RECORD
| SETTER
| SHORT
| STATIC
@@ -6355,7 +6364,7 @@ class Parser(Tokenizer):
def p_NonAnyType(self, p):
"""
- NonAnyType : PrimitiveOrStringType Null
+ NonAnyType : PrimitiveType Null
| ARRAYBUFFER Null
| SHAREDARRAYBUFFER Null
| OBJECT Null
@@ -6371,6 +6380,12 @@ class Parser(Tokenizer):
p[0] = self.handleNullable(type, p[2])
+ def p_NonAnyTypeStringType(self, p):
+ """
+ NonAnyType : StringType Null
+ """
+ p[0] = self.handleNullable(p[1], p[2])
+
def p_NonAnyTypeSequenceType(self, p):
"""
NonAnyType : SEQUENCE LT Type GT Null
@@ -6391,13 +6406,14 @@ class Parser(Tokenizer):
type = IDLUnresolvedType(self.getLocation(p, 1), promiseIdent, p[3])
p[0] = self.handleNullable(type, p[5])
- def p_NonAnyTypeMozMapType(self, p):
+ def p_NonAnyTypeRecordType(self, p):
"""
- NonAnyType : MOZMAP LT Type GT Null
+ NonAnyType : RECORD LT StringType COMMA Type GT Null
"""
- innerType = p[3]
- type = IDLMozMapType(self.getLocation(p, 1), innerType)
- p[0] = self.handleNullable(type, p[5])
+ keyType = p[3]
+ valueType = p[5]
+ type = IDLRecordType(self.getLocation(p, 1), keyType, valueType)
+ p[0] = self.handleNullable(type, p[7])
def p_NonAnyTypeScopedName(self, p):
"""
@@ -6440,7 +6456,7 @@ class Parser(Tokenizer):
def p_ConstType(self, p):
"""
- ConstType : PrimitiveOrStringType Null
+ ConstType : PrimitiveType Null
"""
type = BuiltinTypes[p[1]]
p[0] = self.handleNullable(type, p[2])
@@ -6454,69 +6470,75 @@ class Parser(Tokenizer):
type = IDLUnresolvedType(self.getLocation(p, 1), identifier)
p[0] = self.handleNullable(type, p[2])
- def p_PrimitiveOrStringTypeUint(self, p):
+ def p_PrimitiveTypeUint(self, p):
"""
- PrimitiveOrStringType : UnsignedIntegerType
+ PrimitiveType : UnsignedIntegerType
"""
p[0] = p[1]
- def p_PrimitiveOrStringTypeBoolean(self, p):
+ def p_PrimitiveTypeBoolean(self, p):
"""
- PrimitiveOrStringType : BOOLEAN
+ PrimitiveType : BOOLEAN
"""
p[0] = IDLBuiltinType.Types.boolean
- def p_PrimitiveOrStringTypeByte(self, p):
+ def p_PrimitiveTypeByte(self, p):
"""
- PrimitiveOrStringType : BYTE
+ PrimitiveType : BYTE
"""
p[0] = IDLBuiltinType.Types.byte
- def p_PrimitiveOrStringTypeOctet(self, p):
+ def p_PrimitiveTypeOctet(self, p):
"""
- PrimitiveOrStringType : OCTET
+ PrimitiveType : OCTET
"""
p[0] = IDLBuiltinType.Types.octet
- def p_PrimitiveOrStringTypeFloat(self, p):
+ def p_PrimitiveTypeFloat(self, p):
"""
- PrimitiveOrStringType : FLOAT
+ PrimitiveType : FLOAT
"""
p[0] = IDLBuiltinType.Types.float
- def p_PrimitiveOrStringTypeUnrestictedFloat(self, p):
+ def p_PrimitiveTypeUnrestictedFloat(self, p):
"""
- PrimitiveOrStringType : UNRESTRICTED FLOAT
+ PrimitiveType : UNRESTRICTED FLOAT
"""
p[0] = IDLBuiltinType.Types.unrestricted_float
- def p_PrimitiveOrStringTypeDouble(self, p):
+ def p_PrimitiveTypeDouble(self, p):
"""
- PrimitiveOrStringType : DOUBLE
+ PrimitiveType : DOUBLE
"""
p[0] = IDLBuiltinType.Types.double
- def p_PrimitiveOrStringTypeUnrestictedDouble(self, p):
+ def p_PrimitiveTypeUnrestictedDouble(self, p):
"""
- PrimitiveOrStringType : UNRESTRICTED DOUBLE
+ PrimitiveType : UNRESTRICTED DOUBLE
"""
p[0] = IDLBuiltinType.Types.unrestricted_double
- def p_PrimitiveOrStringTypeDOMString(self, p):
+ def p_StringType(self, p):
+ """
+ StringType : BuiltinStringType
+ """
+ p[0] = BuiltinTypes[p[1]]
+
+ def p_BuiltinStringTypeDOMString(self, p):
"""
- PrimitiveOrStringType : DOMSTRING
+ BuiltinStringType : DOMSTRING
"""
p[0] = IDLBuiltinType.Types.domstring
- def p_PrimitiveOrStringTypeBytestring(self, p):
+ def p_BuiltinStringTypeBytestring(self, p):
"""
- PrimitiveOrStringType : BYTESTRING
+ BuiltinStringType : BYTESTRING
"""
p[0] = IDLBuiltinType.Types.bytestring
- def p_PrimitiveOrStringTypeUSVString(self, p):
+ def p_BuiltinStringTypeUSVString(self, p):
"""
- PrimitiveOrStringType : USVSTRING
+ BuiltinStringType : USVSTRING
"""
p[0] = IDLBuiltinType.Types.usvstring
diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp
index a750c69b0..4849fda57 100644
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -6329,6 +6329,13 @@ CanvasRenderingContext2D::ShouldForceInactiveLayer(LayerManager* aManager)
return !aManager->CanUseCanvasLayerForSize(GetSize());
}
+void CanvasRenderingContext2D::SetWriteOnly() {
+ mWriteOnly = true;
+ if (mCanvasElement) {
+ mCanvasElement->SetWriteOnly();
+ }
+}
+
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(CanvasPath, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(CanvasPath, Release)
diff --git a/dom/canvas/CanvasRenderingContext2D.h b/dom/canvas/CanvasRenderingContext2D.h
index 46758ec88..d4f295a03 100644
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -1156,9 +1156,7 @@ protected:
// For the origin-clean algorithm (mWriteOnly == !origin-clean)
// See https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html
- void SetWriteOnly() {
- mWriteOnly = true;
- }
+ void SetWriteOnly();
bool IsWriteOnly() const {
return mWriteOnly;
diff --git a/dom/fetch/FetchDriver.cpp b/dom/fetch/FetchDriver.cpp
index 1791399b7..6294b0dc5 100644
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -903,11 +903,7 @@ FetchDriver::SetRequestHeaders(nsIHttpChannel* aChannel) const
AutoTArray<InternalHeaders::Entry, 5> headers;
mRequest->Headers()->GetEntries(headers);
- bool hasAccept = false;
for (uint32_t i = 0; i < headers.Length(); ++i) {
- if (!hasAccept && headers[i].mName.EqualsLiteral("accept")) {
- hasAccept = true;
- }
if (headers[i].mValue.IsEmpty()) {
aChannel->SetEmptyRequestHeader(headers[i].mName);
} else {
@@ -915,12 +911,6 @@ FetchDriver::SetRequestHeaders(nsIHttpChannel* aChannel) const
}
}
- if (!hasAccept) {
- aChannel->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
- NS_LITERAL_CSTRING("*/*"),
- false /* merge */);
- }
-
if (mRequest->ForceOriginHeader()) {
nsAutoString origin;
if (NS_SUCCEEDED(nsContentUtils::GetUTFOrigin(mPrincipal, origin))) {
diff --git a/dom/fetch/Headers.cpp b/dom/fetch/Headers.cpp
index 1e1a46c62..ca5aa57a6 100644
--- a/dom/fetch/Headers.cpp
+++ b/dom/fetch/Headers.cpp
@@ -25,7 +25,7 @@ NS_INTERFACE_MAP_END
// static
already_AddRefed<Headers>
Headers::Constructor(const GlobalObject& aGlobal,
- const Optional<HeadersOrByteStringSequenceSequenceOrByteStringMozMap>& aInit,
+ const Optional<HeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord>& aInit,
ErrorResult& aRv)
{
RefPtr<InternalHeaders> ih = new InternalHeaders();
@@ -39,8 +39,8 @@ Headers::Constructor(const GlobalObject& aGlobal,
ih->Fill(*aInit.Value().GetAsHeaders().mInternalHeaders, aRv);
} else if (aInit.Value().IsByteStringSequenceSequence()) {
ih->Fill(aInit.Value().GetAsByteStringSequenceSequence(), aRv);
- } else if (aInit.Value().IsByteStringMozMap()) {
- ih->Fill(aInit.Value().GetAsByteStringMozMap(), aRv);
+ } else if (aInit.Value().IsByteStringByteStringRecord()) {
+ ih->Fill(aInit.Value().GetAsByteStringByteStringRecord(), aRv);
}
if (aRv.Failed()) {
@@ -53,7 +53,7 @@ Headers::Constructor(const GlobalObject& aGlobal,
// static
already_AddRefed<Headers>
Headers::Constructor(const GlobalObject& aGlobal,
- const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit,
+ const OwningHeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord& aInit,
ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
@@ -62,7 +62,7 @@ Headers::Constructor(const GlobalObject& aGlobal,
/* static */ already_AddRefed<Headers>
Headers::Create(nsIGlobalObject* aGlobal,
- const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit,
+ const OwningHeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord& aInit,
ErrorResult& aRv)
{
RefPtr<InternalHeaders> ih = new InternalHeaders();
@@ -72,8 +72,8 @@ Headers::Create(nsIGlobalObject* aGlobal,
ih->Fill(*(aInit.GetAsHeaders().get()->mInternalHeaders), aRv);
} else if (aInit.IsByteStringSequenceSequence()) {
ih->Fill(aInit.GetAsByteStringSequenceSequence(), aRv);
- } else if (aInit.IsByteStringMozMap()) {
- ih->Fill(aInit.GetAsByteStringMozMap(), aRv);
+ } else if (aInit.IsByteStringByteStringRecord()) {
+ ih->Fill(aInit.GetAsByteStringByteStringRecord(), aRv);
}
if (NS_WARN_IF(aRv.Failed())) {
diff --git a/dom/fetch/Headers.h b/dom/fetch/Headers.h
index b603dc836..1dd92f779 100644
--- a/dom/fetch/Headers.h
+++ b/dom/fetch/Headers.h
@@ -20,9 +20,9 @@ class ErrorResult;
namespace dom {
-template<typename T> class MozMap;
-class HeadersOrByteStringSequenceSequenceOrByteStringMozMap;
-class OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap;
+template<typename K, typename V> class Record;
+class HeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord;
+class OwningHeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord;
/**
* This Headers class is only used to represent the content facing Headers
@@ -57,17 +57,17 @@ public:
static already_AddRefed<Headers>
Constructor(const GlobalObject& aGlobal,
- const Optional<HeadersOrByteStringSequenceSequenceOrByteStringMozMap>& aInit,
+ const Optional<HeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord>& aInit,
ErrorResult& aRv);
static already_AddRefed<Headers>
Constructor(const GlobalObject& aGlobal,
- const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit,
+ const OwningHeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord& aInit,
ErrorResult& aRv);
static already_AddRefed<Headers>
Create(nsIGlobalObject* aGlobalObject,
- const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit,
+ const OwningHeadersOrByteStringSequenceSequenceOrByteStringByteStringRecord& aInit,
ErrorResult& aRv);
void Append(const nsACString& aName, const nsACString& aValue,
diff --git a/dom/fetch/InternalHeaders.cpp b/dom/fetch/InternalHeaders.cpp
index 11585615e..f66221d42 100644
--- a/dom/fetch/InternalHeaders.cpp
+++ b/dom/fetch/InternalHeaders.cpp
@@ -314,12 +314,13 @@ InternalHeaders::Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& a
}
void
-InternalHeaders::Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv)
+InternalHeaders::Fill(const Record<nsCString, nsCString>& aInit, ErrorResult& aRv)
{
- nsTArray<nsString> keys;
- aInit.GetKeys(keys);
- for (uint32_t i = 0; i < keys.Length() && !aRv.Failed(); ++i) {
- Append(NS_ConvertUTF16toUTF8(keys[i]), aInit.Get(keys[i]), aRv);
+ for (auto& entry : aInit.Entries()) {
+ Append(entry.mKey, entry.mValue, aRv);
+ if (aRv.Failed()) {
+ return;
+ }
}
}
diff --git a/dom/fetch/InternalHeaders.h b/dom/fetch/InternalHeaders.h
index 9a6d6dae7..98046f0ef 100644
--- a/dom/fetch/InternalHeaders.h
+++ b/dom/fetch/InternalHeaders.h
@@ -20,7 +20,7 @@ class ErrorResult;
namespace dom {
-template<typename T> class MozMap;
+template<typename K, typename V> class Record;
class HeadersEntry;
class InternalHeaders final
@@ -113,7 +113,7 @@ public:
void Fill(const InternalHeaders& aInit, ErrorResult& aRv);
void Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& aRv);
- void Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv);
+ void Fill(const Record<nsCString, nsCString>& aInit, ErrorResult& aRv);
bool HasOnlySimpleHeaders() const;
diff --git a/dom/html/HTMLTableElement.cpp b/dom/html/HTMLTableElement.cpp
index ec1b7cecb..c5b7696cf 100644
--- a/dom/html/HTMLTableElement.cpp
+++ b/dom/html/HTMLTableElement.cpp
@@ -421,11 +421,10 @@ HTMLTableElement::CreateTHead()
void
HTMLTableElement::DeleteTHead()
{
- HTMLTableSectionElement* tHead = GetTHead();
+ RefPtr<HTMLTableSectionElement> tHead = GetTHead();
if (tHead) {
- mozilla::ErrorResult rv;
+ mozilla::IgnoredErrorResult rv;
nsINode::RemoveChild(*tHead, rv);
- MOZ_ASSERT(!rv.Failed());
}
}
@@ -452,11 +451,10 @@ HTMLTableElement::CreateTFoot()
void
HTMLTableElement::DeleteTFoot()
{
- HTMLTableSectionElement* tFoot = GetTFoot();
+ RefPtr<HTMLTableSectionElement> tFoot = GetTFoot();
if (tFoot) {
- mozilla::ErrorResult rv;
+ mozilla::IgnoredErrorResult rv;
nsINode::RemoveChild(*tFoot, rv);
- MOZ_ASSERT(!rv.Failed());
}
}
@@ -483,11 +481,10 @@ HTMLTableElement::CreateCaption()
void
HTMLTableElement::DeleteCaption()
{
- HTMLTableCaptionElement* caption = GetCaption();
+ RefPtr<HTMLTableCaptionElement> caption = GetCaption();
if (caption) {
- mozilla::ErrorResult rv;
+ mozilla::IgnoredErrorResult rv;
nsINode::RemoveChild(*caption, rv);
- MOZ_ASSERT(!rv.Failed());
}
}
diff --git a/dom/html/HTMLTableSectionElement.cpp b/dom/html/HTMLTableSectionElement.cpp
index c7b0665dd..e99597636 100644
--- a/dom/html/HTMLTableSectionElement.cpp
+++ b/dom/html/HTMLTableSectionElement.cpp
@@ -122,7 +122,7 @@ HTMLTableSectionElement::DeleteRow(int32_t aValue, ErrorResult& aError)
refIndex = (uint32_t)aValue;
}
- nsINode* row = rows->Item(refIndex);
+ nsCOMPtr<nsINode> row = rows->Item(refIndex);
if (!row) {
aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return;
diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h
index f29d17e7f..4c8f15cc0 100644
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -152,13 +152,13 @@ public:
RecvInitRendering(
Endpoint<PCompositorBridgeChild>&& aCompositor,
Endpoint<PImageBridgeChild>&& aImageBridge,
- Endpoint<PVideoDecoderManagerChild>&& aVideoManager);
+ Endpoint<PVideoDecoderManagerChild>&& aVideoManager) override;
bool
RecvReinitRendering(
Endpoint<PCompositorBridgeChild>&& aCompositor,
Endpoint<PImageBridgeChild>&& aImageBridge,
- Endpoint<PVideoDecoderManagerChild>&& aVideoManager);
+ Endpoint<PVideoDecoderManagerChild>&& aVideoManager) override;
PProcessHangMonitorChild*
AllocPProcessHangMonitorChild(Transport* aTransport,
diff --git a/dom/locales/en-US/chrome/security/security.properties b/dom/locales/en-US/chrome/security/security.properties
index 8efdb0a6d..2be56fb9d 100644
--- a/dom/locales/en-US/chrome/security/security.properties
+++ b/dom/locales/en-US/chrome/security/security.properties
@@ -85,3 +85,5 @@ BlockScriptWithWrongMimeType=Script from “%1$S” was blocked because of a dis
# LOCALIZATION NOTE: Do not translate "data: URI".
BlockTopLevelDataURINavigation=Navigation to toplevel data: URI not allowed (Blocked loading of: “%1$S”)
+
+BlockSubresourceFTP=Loading FTP subresource within http(s) page not allowed (Blocked loading of: “%1$S”)
diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp
index 288f2e74d..979cb64c7 100644
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -2049,6 +2049,16 @@ MediaManager::GetUserMedia(nsPIDOMWindowInner* aWindow,
return rv;
}
+ // Disallow access to null principal pages
+ nsCOMPtr<nsIPrincipal> principal = aWindow->GetExtantDoc()->NodePrincipal();
+ if (principal->GetIsNullPrincipal()) {
+ RefPtr<MediaStreamError> error =
+ new MediaStreamError(aWindow,
+ NS_LITERAL_STRING("NotAllowedError"));
+ onFailure->OnError(error);
+ return NS_OK;
+ }
+
if (!Preferences::GetBool("media.navigator.video.enabled", true)) {
c.mVideo.SetAsBoolean() = false;
}
@@ -2188,7 +2198,6 @@ MediaManager::GetUserMedia(nsPIDOMWindowInner* aWindow,
StreamListeners* listeners = AddWindowID(windowID);
// Create a disabled listener to act as a placeholder
- nsIPrincipal* principal = aWindow->GetExtantDoc()->NodePrincipal();
RefPtr<GetUserMediaCallbackMediaStreamListener> listener =
new GetUserMediaCallbackMediaStreamListener(mMediaThread, windowID,
MakePrincipalHandle(principal));
diff --git a/dom/media/VideoFrameContainer.cpp b/dom/media/VideoFrameContainer.cpp
index 2b1965766..56aea9d27 100644
--- a/dom/media/VideoFrameContainer.cpp
+++ b/dom/media/VideoFrameContainer.cpp
@@ -61,7 +61,7 @@ void VideoFrameContainer::UpdatePrincipalHandleForFrameIDLocked(const PrincipalH
mFrameIDForPendingPrincipalHandle = aFrameID;
}
-static void
+static bool
SetImageToBlackPixel(PlanarYCbCrImage* aImage)
{
uint8_t blackPixel[] = { 0x10, 0x80, 0x80 };
@@ -72,7 +72,7 @@ SetImageToBlackPixel(PlanarYCbCrImage* aImage)
data.mCrChannel = blackPixel + 2;
data.mYStride = data.mCbCrStride = 1;
data.mPicSize = data.mYSize = data.mCbCrSize = gfx::IntSize(1, 1);
- aImage->CopyData(data);
+ return aImage->CopyData(data);
}
class VideoFrameContainerInvalidateRunnable : public Runnable {
@@ -122,11 +122,13 @@ void VideoFrameContainer::SetCurrentFrames(const VideoSegment& aSegment)
if (frame->GetForceBlack()) {
if (!mBlackImage) {
- mBlackImage = GetImageContainer()->CreatePlanarYCbCrImage();
- if (mBlackImage) {
+ RefPtr<Image> blackImage = GetImageContainer()->CreatePlanarYCbCrImage();
+ if (blackImage) {
// Sets the image to a single black pixel, which will be scaled to
// fill the rendered size.
- SetImageToBlackPixel(mBlackImage->AsPlanarYCbCrImage());
+ if (SetImageToBlackPixel(blackImage->AsPlanarYCbCrImage())) {
+ mBlackImage = blackImage;
+ }
}
}
if (mBlackImage) {
diff --git a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
index 74b5c38e8..57d4ecec2 100644
--- a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
+++ b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
@@ -46,7 +46,7 @@ void* GetCdmHost(int aHostInterfaceVersion, void* aUserData)
Log("GetCdmHostFunc(%d, %p)", aHostInterfaceVersion, aUserData);
WidevineDecryptor* decryptor = reinterpret_cast<WidevineDecryptor*>(aUserData);
MOZ_ASSERT(decryptor);
- return static_cast<cdm::Host_8*>(decryptor);
+ return static_cast<cdm::Host_9*>(decryptor);
}
#define STRINGIFY(s) _STRINGIFY(s)
@@ -106,8 +106,8 @@ WidevineAdapter::GMPGetAPI(const char* aAPIName,
WidevineDecryptor* decryptor = new WidevineDecryptor();
- auto cdm = reinterpret_cast<cdm::ContentDecryptionModule*>(
- create(cdm::ContentDecryptionModule::kVersion,
+ auto cdm = reinterpret_cast<cdm::ContentDecryptionModule_9*>(
+ create(cdm::ContentDecryptionModule_9::kVersion,
kEMEKeySystemWidevine.get(),
kEMEKeySystemWidevine.Length(),
&GetCdmHost,
@@ -161,8 +161,8 @@ WidevineAdapter::Supports(int32_t aModuleVersion,
int32_t aHostVersion)
{
return aModuleVersion == CDM_MODULE_VERSION &&
- aInterfaceVersion == cdm::ContentDecryptionModule::kVersion &&
- aHostVersion == cdm::Host_8::kVersion;
+ aInterfaceVersion == cdm::ContentDecryptionModule_9::kVersion &&
+ aHostVersion == cdm::Host_9::kVersion;
}
} // namespace mozilla
diff --git a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
index 149fa1701..4d3408804 100644
--- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
+++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
@@ -102,7 +102,7 @@ WidevineDecryptor::CreateSession(uint32_t aCreateSessionToken,
} else {
// Invalid init data type
const char* errorMsg = "Invalid init data type when creating session.";
- OnRejectPromise(aPromiseId, kNotSupportedError, 0, errorMsg, sizeof(errorMsg));
+ OnRejectPromise(aPromiseId, kExceptionNotSupportedError, 0, errorMsg, sizeof(errorMsg));
return;
}
mPromiseIdToNewSessionTokens[aPromiseId] = aCreateSessionToken;
@@ -302,6 +302,12 @@ WidevineDecryptor::GetCurrentWallTime()
}
void
+WidevineDecryptor::OnResolveKeyStatusPromise(uint32_t aPromiseId,
+ cdm::KeyStatus aKeyStatus) {
+ //TODO: The callback of GetStatusForPolicy. See Mozilla bug 1404230.
+}
+
+void
WidevineDecryptor::OnResolveNewSessionPromise(uint32_t aPromiseId,
const char* aSessionId,
uint32_t aSessionIdSize)
@@ -333,41 +339,59 @@ WidevineDecryptor::OnResolvePromise(uint32_t aPromiseId)
}
static GMPDOMException
-ToGMPDOMException(cdm::Error aError)
-{
- switch (aError) {
- case kNotSupportedError: return kGMPNotSupportedError;
- case kInvalidStateError: return kGMPInvalidStateError;
- case kInvalidAccessError:
- // Note: Chrome converts kInvalidAccessError to TypeError, since the
- // Chromium CDM API doesn't have a type error enum value. The EME spec
- // requires TypeError in some places, so we do the same conversion.
- // See bug 1313202.
- return kGMPTypeError;
- case kQuotaExceededError: return kGMPQuotaExceededError;
+ConvertCDMExceptionToGMPDOMException(cdm::Exception aException)
+{
+ switch (aException) {
+ case kExceptionNotSupportedError: return kGMPNotSupportedError;
+ case kExceptionInvalidStateError: return kGMPInvalidStateError;
+ case kExceptionTypeError: return kGMPTypeError;
+ case kExceptionQuotaExceededError: return kGMPQuotaExceededError;
case kUnknownError: return kGMPInvalidModificationError; // Note: Unique placeholder.
case kClientError: return kGMPAbortError; // Note: Unique placeholder.
case kOutputError: return kGMPSecurityError; // Note: Unique placeholder.
};
- return kGMPTimeoutError; // Note: Unique placeholder.
+ return kGMPInvalidStateError; // Note: Unique placeholder.
+}
+
+// Align with spec, the Exceptions used by CDM to reject promises .
+// https://w3c.github.io/encrypted-media/#exceptions
+cdm::Exception
+ConvertCDMErrorToCDMException(cdm::Error error) {
+ switch (error) {
+ case cdm::kNotSupportedError:
+ return cdm::Exception::kExceptionNotSupportedError;
+ case cdm::kInvalidStateError:
+ return cdm::Exception::kExceptionInvalidStateError;
+ case cdm::kInvalidAccessError:
+ return cdm::Exception::kExceptionTypeError;
+ case cdm::kQuotaExceededError:
+ return cdm::Exception::kExceptionQuotaExceededError;
+
+ case cdm::kUnknownError:
+ case cdm::kClientError:
+ case cdm::kOutputError:
+ break;
+ }
+
+ return cdm::Exception::kExceptionInvalidStateError;
}
void
WidevineDecryptor::OnRejectPromise(uint32_t aPromiseId,
- Error aError,
+ cdm::Exception aException,
uint32_t aSystemCode,
const char* aErrorMessage,
uint32_t aErrorMessageSize)
{
if (!mCallback) {
Log("Decryptor::OnRejectPromise(aPromiseId=%d, err=%d, sysCode=%u, msg=%s) FAIL; !mCallback",
- aPromiseId, (int)aError, aSystemCode, aErrorMessage);
+ aPromiseId, (int)aException, aSystemCode, aErrorMessage);
return;
}
Log("Decryptor::OnRejectPromise(aPromiseId=%d, err=%d, sysCode=%u, msg=%s)",
- aPromiseId, (int)aError, aSystemCode, aErrorMessage);
+ aPromiseId, (int)aException, aSystemCode, aErrorMessage);
mCallback->RejectPromise(aPromiseId,
- ToGMPDOMException(aError),
+ ConvertCDMExceptionToGMPDOMException(aException),
!aErrorMessageSize ? "" : aErrorMessage,
aErrorMessageSize);
}
@@ -386,11 +410,9 @@ ToGMPMessageType(MessageType message_type)
void
WidevineDecryptor::OnSessionMessage(const char* aSessionId,
uint32_t aSessionIdSize,
- MessageType aMessageType,
+ cdm::MessageType aMessageType,
const char* aMessage,
- uint32_t aMessageSize,
- const char* aLegacyDestinationUrl,
- uint32_t aLegacyDestinationUrlLength)
+ uint32_t aMessageSize)
{
if (!mCallback) {
Log("Decryptor::OnSessionMessage() FAIL; !mCallback");
@@ -479,28 +501,6 @@ WidevineDecryptor::OnSessionClosed(const char* aSessionId,
}
void
-WidevineDecryptor::OnLegacySessionError(const char* aSessionId,
- uint32_t aSessionIdLength,
- Error aError,
- uint32_t aSystemCode,
- const char* aErrorMessage,
- uint32_t aErrorMessageLength)
-{
- if (!mCallback) {
- Log("Decryptor::OnLegacySessionError(sid=%s, error=%d) FAIL; !mCallback",
- aSessionId, (int)aError);
- return;
- }
- Log("Decryptor::OnLegacySessionError(sid=%s, error=%d)", aSessionId, (int)aError);
- mCallback->SessionError(aSessionId,
- aSessionIdLength,
- ToGMPDOMException(aError),
- aSystemCode,
- aErrorMessage,
- aErrorMessageLength);
-}
-
-void
WidevineDecryptor::SendPlatformChallenge(const char* aServiceId,
uint32_t aServiceIdSize,
const char* aChallenge,
@@ -538,4 +538,17 @@ WidevineDecryptor::CreateFileIO(FileIOClient* aClient)
return new WidevineFileIO(aClient);
}
+void
+WidevineDecryptor::RequestStorageId(uint32_t aVersion)
+{
+ Log("Decryptor::RequestStorageId() aVersion = %u", aVersion);
+ if (aVersion >= 0x80000000) {
+ mCDM->OnStorageId(aVersion, nullptr, 0);
+ return;
+ }
+
+ //TODO: Need to provide a menaingful buffer instead of a dummy one.
+ mCDM->OnStorageId(aVersion, new uint8_t[1024*1024], 1024 * 1024);
+}
+
} // namespace mozilla
diff --git a/dom/media/gmp/widevine-adapter/WidevineDecryptor.h b/dom/media/gmp/widevine-adapter/WidevineDecryptor.h
index d5185192b..f291c321d 100644
--- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.h
+++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.h
@@ -16,7 +16,7 @@
namespace mozilla {
class WidevineDecryptor : public GMPDecryptor
- , public cdm::Host_8
+ , public cdm::Host_9
{
public:
@@ -69,16 +69,19 @@ public:
void DecryptingComplete() override;
- // cdm::Host_8
+ // cdm::Host_9 implementation
cdm::Buffer* Allocate(uint32_t aCapacity) override;
void SetTimer(int64_t aDelayMs, void* aContext) override;
cdm::Time GetCurrentWallTime() override;
+ // cdm::Host_9 interface
+ void OnResolveKeyStatusPromise(uint32_t aPromiseId,
+ cdm::KeyStatus aKeyStatus) override;
void OnResolveNewSessionPromise(uint32_t aPromiseId,
const char* aSessionId,
uint32_t aSessionIdSize) override;
void OnResolvePromise(uint32_t aPromiseId) override;
void OnRejectPromise(uint32_t aPromiseId,
- cdm::Error aError,
+ cdm::Exception aException,
uint32_t aSystemCode,
const char* aErrorMessage,
uint32_t aErrorMessageSize) override;
@@ -86,9 +89,7 @@ public:
uint32_t aSessionIdSize,
cdm::MessageType aMessageType,
const char* aMessage,
- uint32_t aMessageSize,
- const char* aLegacyDestinationUrl,
- uint32_t aLegacyDestinationUrlLength) override;
+ uint32_t aMessageSize) override;
void OnSessionKeysChange(const char* aSessionId,
uint32_t aSessionIdSize,
bool aHasAdditionalUsableKey,
@@ -99,12 +100,6 @@ public:
cdm::Time aNewExpiryTime) override;
void OnSessionClosed(const char* aSessionId,
uint32_t aSessionIdSize) override;
- void OnLegacySessionError(const char* aSessionId,
- uint32_t aSessionId_length,
- cdm::Error aError,
- uint32_t aSystemCode,
- const char* aErrorMessage,
- uint32_t aErrorMessageLength) override;
void SendPlatformChallenge(const char* aServiceId,
uint32_t aServiceIdSize,
const char* aChallenge,
@@ -113,6 +108,9 @@ public:
void QueryOutputProtectionStatus() override;
void OnDeferredInitializationDone(cdm::StreamType aStreamType,
cdm::Status aDecoderStatus) override;
+ // cdm::Host_9 interface
+ // NOTE: the interface has changed upstream.
+ void RequestStorageId(uint32_t aVersion) override;
cdm::FileIO* CreateFileIO(cdm::FileIOClient* aClient) override;
GMPDecryptorCallback* Callback() const { return mCallback; }
@@ -120,7 +118,7 @@ public:
private:
~WidevineDecryptor();
RefPtr<CDMWrapper> mCDM;
- cdm::ContentDecryptionModule_8* CDM() { return mCDM->GetCDM(); }
+ cdm::ContentDecryptionModule_9* CDM() { return mCDM->GetCDM(); }
GMPDecryptorCallback* mCallback;
std::map<uint32_t, uint32_t> mPromiseIdToNewSessionTokens;
diff --git a/dom/media/gmp/widevine-adapter/WidevineUtils.cpp b/dom/media/gmp/widevine-adapter/WidevineUtils.cpp
index 925dfe1a1..10c6c2e18 100644
--- a/dom/media/gmp/widevine-adapter/WidevineUtils.cpp
+++ b/dom/media/gmp/widevine-adapter/WidevineUtils.cpp
@@ -43,7 +43,7 @@ ToGMPErr(cdm::Status aStatus)
case cdm::kSuccess: return GMPNoErr;
case cdm::kNeedMoreData: return GMPGenericErr;
case cdm::kNoKey: return GMPNoKeyErr;
- case cdm::kSessionError: return GMPGenericErr;
+ case cdm::kInitializationError: return GMPGenericErr;
case cdm::kDecryptError: return GMPCryptoErr;
case cdm::kDecodeError: return GMPDecodeErr;
case cdm::kDeferredInitialization: return GMPGenericErr;
@@ -77,7 +77,7 @@ void InitInputBuffer(const GMPEncryptedBufferMetadata* aCrypto,
aInputBuffer.timestamp = aTimestamp;
}
-CDMWrapper::CDMWrapper(cdm::ContentDecryptionModule_8* aCDM,
+CDMWrapper::CDMWrapper(cdm::ContentDecryptionModule_9* aCDM,
WidevineDecryptor* aDecryptor)
: mCDM(aCDM)
, mDecryptor(aDecryptor)
diff --git a/dom/media/gmp/widevine-adapter/WidevineUtils.h b/dom/media/gmp/widevine-adapter/WidevineUtils.h
index 57c004a87..2f6137fe3 100644
--- a/dom/media/gmp/widevine-adapter/WidevineUtils.h
+++ b/dom/media/gmp/widevine-adapter/WidevineUtils.h
@@ -48,12 +48,16 @@ class CDMWrapper {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CDMWrapper)
- explicit CDMWrapper(cdm::ContentDecryptionModule_8* aCDM,
+ explicit CDMWrapper(cdm::ContentDecryptionModule_9* aCDM,
WidevineDecryptor* aDecryptor);
- cdm::ContentDecryptionModule_8* GetCDM() const { return mCDM; }
+ cdm::ContentDecryptionModule_9* GetCDM() const { return mCDM; }
+ void OnStorageId(uint32_t aVersion, const uint8_t* aStorageId,
+ uint32_t aStorageIdSize) {
+ mCDM->OnStorageId(aVersion, aStorageId, aStorageIdSize);
+ }
private:
~CDMWrapper();
- cdm::ContentDecryptionModule_8* mCDM;
+ cdm::ContentDecryptionModule_9* mCDM;
RefPtr<WidevineDecryptor> mDecryptor;
};
diff --git a/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h b/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h
index b143f75f7..f5e63519b 100644
--- a/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h
+++ b/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h
@@ -45,7 +45,7 @@ private:
~WidevineVideoDecoder();
- cdm::ContentDecryptionModule_8* CDM() const {
+ cdm::ContentDecryptionModule_9* CDM() const {
// CDM should only be accessed before 'DecodingComplete'.
MOZ_ASSERT(mCDMWrapper);
// CDMWrapper ensure the CDM is non-null, no need to check again.
diff --git a/dom/media/gmp/widevine-adapter/content_decryption_module.h b/dom/media/gmp/widevine-adapter/content_decryption_module.h
index 512ca9768..0539135fb 100644
--- a/dom/media/gmp/widevine-adapter/content_decryption_module.h
+++ b/dom/media/gmp/widevine-adapter/content_decryption_module.h
@@ -5,6 +5,8 @@
#ifndef CDM_CONTENT_DECRYPTION_MODULE_H_
#define CDM_CONTENT_DECRYPTION_MODULE_H_
+#include "content_decryption_module_export.h"
+
#if defined(_MSC_VER)
typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
@@ -14,25 +16,21 @@ typedef __int64 int64_t;
#include <stdint.h>
#endif
-// Define CDM_EXPORT so that functionality implemented by the CDM module
-// can be exported to consumers.
-#if defined(WIN32)
-
-#if defined(CDM_IMPLEMENTATION)
-#define CDM_EXPORT __declspec(dllexport)
-#else
-#define CDM_EXPORT __declspec(dllimport)
-#endif // defined(CDM_IMPLEMENTATION)
-
-#else // defined(WIN32)
-
-#if defined(CDM_IMPLEMENTATION)
-#define CDM_EXPORT __attribute__((visibility("default")))
+// Define CDM_CLASS_API to export class types. We have to add visibility
+// attributes to make sure virtual tables in CDM consumer and CDM implementation
+// are the same. Generally, it was always a good idea, as there're no guarantees
+// about that for the internal symbols, but it has only become a practical issue
+// after introduction of LTO devirtualization. See more details on
+// https://crbug.com/609564#c35
+#if defined(_WIN32)
+#if defined(__clang__)
+#define CDM_CLASS_API [[clang::lto_visibility_public]]
#else
-#define CDM_EXPORT
+#define CDM_CLASS_API
#endif
-
-#endif // defined(WIN32)
+#else // defined(_WIN32)
+#define CDM_CLASS_API __attribute__((visibility("default")))
+#endif // defined(_WIN32)
// The version number must be rolled when the exported functions are updated!
// If the CDM and the adapter use different versions of these functions, the
@@ -48,9 +46,9 @@ typedef __int64 int64_t;
#define BUILD_ENTRYPOINT_NO_EXPANSION(name, version) name##_##version
extern "C" {
-CDM_EXPORT void INITIALIZE_CDM_MODULE();
+CDM_API void INITIALIZE_CDM_MODULE();
-CDM_EXPORT void DeinitializeCdmModule();
+CDM_API void DeinitializeCdmModule();
// Returns a pointer to the requested CDM Host interface upon success.
// Returns NULL if the requested CDM Host interface is not supported.
@@ -65,30 +63,30 @@ typedef void* (*GetCdmHostFunc)(int host_interface_version, void* user_data);
// |cdm_interface_version|.
// Caller retains ownership of arguments and must call Destroy() on the returned
// object.
-CDM_EXPORT void* CreateCdmInstance(
+CDM_API void* CreateCdmInstance(
int cdm_interface_version,
const char* key_system, uint32_t key_system_size,
GetCdmHostFunc get_cdm_host_func, void* user_data);
-CDM_EXPORT const char* GetCdmVersion();
+CDM_API const char* GetCdmVersion();
}
namespace cdm {
-class AudioFrames;
-class DecryptedBlock;
-class VideoFrame;
+class CDM_CLASS_API AudioFrames;
+class CDM_CLASS_API DecryptedBlock;
+class CDM_CLASS_API VideoFrame;
-class Host_7;
-class Host_8;
+class CDM_CLASS_API Host_8;
+class CDM_CLASS_API Host_9;
enum Status {
kSuccess = 0,
kNeedMoreData, // Decoder needs more data to produce a decoded frame/sample.
- kNoKey, // The required decryption key is not available.
- kSessionError, // Session management error.
- kDecryptError, // Decryption failed.
- kDecodeError, // Error decoding audio or video.
+ kNoKey, // The required decryption key is not available.
+ kInitializationError, // Initialization error.
+ kDecryptError, // Decryption failed.
+ kDecodeError, // Error decoding audio or video.
kDeferredInitialization // Decoder is not ready for initialization.
};
@@ -97,6 +95,7 @@ enum Status {
// The following starts with the list of DOM4 exceptions from:
// http://www.w3.org/TR/dom/#domexception
// Some DOM4 exceptions are not included as they are not expected to be used.
+// Should only be used on Host_8 and before.
enum Error {
kNotSupportedError = 9,
kInvalidStateError = 11,
@@ -113,8 +112,20 @@ enum Error {
kOutputError = 101
};
-// Time is defined as the number of seconds since the
-// Epoch (00:00:00 UTC, January 1, 1970).
+// Exceptions used by the CDM to reject promises.
+// https://w3c.github.io/encrypted-media/#exceptions
+enum Exception {
+ kExceptionTypeError,
+ kExceptionNotSupportedError,
+ kExceptionInvalidStateError,
+ kExceptionQuotaExceededError
+};
+
+// Time is defined as the number of seconds since the Epoch
+// (00:00:00 UTC, January 1, 1970), not including any added leap second.
+// Also see Time definition in spec: https://w3c.github.io/encrypted-media/#time
+// Note that Time is defined in millisecond accuracy in the spec but in second
+// accuracy here.
typedef double Time;
// An input buffer can be split into several continuous subsamples.
@@ -151,13 +162,13 @@ struct SubsampleEntry {
// unencrypted.
struct InputBuffer {
InputBuffer()
- : data(NULL),
+ : data(nullptr),
data_size(0),
- key_id(NULL),
+ key_id(nullptr),
key_id_size(0),
- iv(NULL),
+ iv(nullptr),
iv_size(0),
- subsamples(NULL),
+ subsamples(nullptr),
num_subsamples(0),
timestamp(0) {}
@@ -188,7 +199,7 @@ struct AudioDecoderConfig {
channel_count(0),
bits_per_channel(0),
samples_per_second(0),
- extra_data(NULL),
+ extra_data(nullptr),
extra_data_size(0) {}
AudioCodec codec;
@@ -214,10 +225,25 @@ enum AudioFormat {
};
// Surface formats based on FOURCC labels, see: http://www.fourcc.org/yuv.php
+// Values are chosen to be consistent with Chromium's VideoPixelFormat values.
enum VideoFormat {
kUnknownVideoFormat = 0, // Unknown format value. Used for error reporting.
- kYv12, // 12bpp YVU planar 1x1 Y, 2x2 VU samples.
- kI420 // 12bpp YVU planar 1x1 Y, 2x2 UV samples.
+ kYv12 = 1, // 12bpp YVU planar 1x1 Y, 2x2 VU samples.
+ kI420 = 2, // 12bpp YUV planar 1x1 Y, 2x2 UV samples.
+
+ // In the following formats, each sample uses 16-bit in storage, while the
+ // sample value is stored in the least significant N bits where N is
+ // specified by the number after "P". For example, for YUV420P9, each Y, U,
+ // and V sample is stored in the least significant 9 bits in a 2-byte block.
+ kYUV420P9 = 16,
+ kYUV420P10 = 17,
+ kYUV422P9 = 18,
+ kYUV422P10 = 19,
+ kYUV444P9 = 20,
+ kYUV444P10 = 21,
+ kYUV420P12 = 22,
+ kYUV422P12 = 23,
+ kYUV444P12 = 24,
};
struct Size {
@@ -245,14 +271,19 @@ struct VideoDecoderConfig {
kH264ProfileHigh,
kH264ProfileHigh10,
kH264ProfileHigh422,
- kH264ProfileHigh444Predictive
+ kH264ProfileHigh444Predictive,
+ // VP9 Profiles are only passed in starting from CDM_9.
+ kVP9Profile0,
+ kVP9Profile1,
+ kVP9Profile2,
+ kVP9Profile3
};
VideoDecoderConfig()
: codec(kUnknownVideoCodec),
profile(kUnknownVideoCodecProfile),
format(kUnknownVideoFormat),
- extra_data(NULL),
+ extra_data(nullptr),
extra_data_size(0) {}
VideoCodec codec;
@@ -294,7 +325,7 @@ struct PlatformChallengeResponse {
// Used when passing arrays of binary data. Does not own the referenced data.
struct BinaryData {
- BinaryData() : data(NULL), length(0) {}
+ BinaryData() : data(nullptr), length(0) {}
const uint8_t* data;
uint32_t length;
};
@@ -316,7 +347,10 @@ enum KeyStatus {
// should be 0 when |status| == kUsable.
struct KeyInformation {
KeyInformation()
- : key_id(NULL), key_id_size(0), status(kInternalError), system_code(0) {}
+ : key_id(nullptr),
+ key_id_size(0),
+ status(kInternalError),
+ system_code(0) {}
const uint8_t* key_id;
uint32_t key_id_size;
KeyStatus status;
@@ -372,6 +406,24 @@ enum MessageType {
kLicenseRelease = 2
};
+enum HdcpVersion {
+ kHdcpVersionNone,
+ kHdcpVersion1_0,
+ kHdcpVersion1_1,
+ kHdcpVersion1_2,
+ kHdcpVersion1_3,
+ kHdcpVersion1_4,
+ kHdcpVersion2_0,
+ kHdcpVersion2_1,
+ kHdcpVersion2_2
+};
+
+struct Policy {
+ Policy() : min_hdcp_version(kHdcpVersionNone) {}
+
+ HdcpVersion min_hdcp_version;
+};
+
// FileIO interface provides a way for the CDM to store data in a file in
// persistent storage. This interface aims only at providing basic read/write
// capabilities and should not be used as a full fledged file IO API.
@@ -381,7 +433,7 @@ enum MessageType {
// Note to implementors of this interface:
// Per-origin storage and the ability for users to clear it are important.
// See http://www.w3.org/TR/encrypted-media/#privacy-storedinfo.
-class FileIO {
+class CDM_CLASS_API FileIO {
public:
// Opens the file with |file_name| for read and write.
// FileIOClient::OnOpenComplete() will be called after the opening
@@ -389,8 +441,9 @@ class FileIO {
// - When the file is opened by a CDM instance, it will be classified as "in
// use". In this case other CDM instances in the same domain may receive
// kInUse status when trying to open it.
- // - |file_name| must not contain forward slash ('/') or backslash ('\'), and
- // must not start with an underscore ('_').
+ // - |file_name| must only contain letters (A-Za-z), digits(0-9), or "._-".
+ // It must not start with an underscore ('_'), and must be at least 1
+ // character and no more than 256 characters long.
virtual void Open(const char* file_name, uint32_t file_name_size) = 0;
// Reads the contents of the file. FileIOClient::OnReadComplete() will be
@@ -421,7 +474,7 @@ class FileIO {
// When kError is returned, the FileIO object could be in an error state. All
// following calls (other than Close()) could return kError. The CDM should
// still call Close() to destroy the FileIO object.
-class FileIOClient {
+class CDM_CLASS_API FileIOClient {
public:
enum Status {
kSuccess = 0,
@@ -462,10 +515,20 @@ class FileIOClient {
// provided in CreateCdmInstance() to allocate any Buffer that needs to
// be passed back to the caller. Implementations must call Buffer::Destroy()
// when a Buffer is created that will never be returned to the caller.
-class ContentDecryptionModule_7 {
+class CDM_CLASS_API ContentDecryptionModule_8 {
public:
- static const int kVersion = 7;
- typedef Host_7 Host;
+ static const int kVersion = 8;
+ typedef Host_8 Host;
+
+ // Initializes the CDM instance, providing information about permitted
+ // functionalities.
+ // If |allow_distinctive_identifier| is false, messages from the CDM,
+ // such as message events, must not contain a Distinctive Identifier,
+ // even in an encrypted form.
+ // If |allow_persistent_state| is false, the CDM must not attempt to
+ // persist state. Calls to CreateFileIO() will fail.
+ virtual void Initialize(bool allow_distinctive_identifier,
+ bool allow_persistent_state) = 0;
// SetServerCertificate(), CreateSessionAndGenerateRequest(), LoadSession(),
// UpdateSession(), CloseSession(), and RemoveSession() all accept a
@@ -484,8 +547,7 @@ class ContentDecryptionModule_7 {
// or Host::OnRejectPromise().
virtual void CreateSessionAndGenerateRequest(uint32_t promise_id,
SessionType session_type,
- const char* init_data_type,
- uint32_t init_data_type_size,
+ InitDataType init_data_type,
const uint8_t* init_data,
uint32_t init_data_size) = 0;
@@ -631,8 +693,8 @@ class ContentDecryptionModule_7 {
virtual void Destroy() = 0;
protected:
- ContentDecryptionModule_7() {}
- virtual ~ContentDecryptionModule_7() {}
+ ContentDecryptionModule_8() {}
+ virtual ~ContentDecryptionModule_8() {}
};
// ContentDecryptionModule interface that all CDMs need to implement.
@@ -641,10 +703,10 @@ class ContentDecryptionModule_7 {
// provided in CreateCdmInstance() to allocate any Buffer that needs to
// be passed back to the caller. Implementations must call Buffer::Destroy()
// when a Buffer is created that will never be returned to the caller.
-class ContentDecryptionModule_8 {
+class CDM_CLASS_API ContentDecryptionModule_9 {
public:
- static const int kVersion = 8;
- typedef Host_8 Host;
+ static const int kVersion = 9;
+ typedef Host_9 Host;
// Initializes the CDM instance, providing information about permitted
// functionalities.
@@ -656,6 +718,13 @@ class ContentDecryptionModule_8 {
virtual void Initialize(bool allow_distinctive_identifier,
bool allow_persistent_state) = 0;
+ // Gets the key status if the CDM has a hypothetical key with the |policy|.
+ // The CDM must respond by calling either Host::OnResolveKeyStatusPromise()
+ // with the result key status or Host::OnRejectPromise() if an unexpected
+ // error happened or this method is not supported.
+ virtual void GetStatusForPolicy(uint32_t promise_id,
+ const Policy& policy) = 0;
+
// SetServerCertificate(), CreateSessionAndGenerateRequest(), LoadSession(),
// UpdateSession(), CloseSession(), and RemoveSession() all accept a
// |promise_id|, which must be passed to the completion Host method
@@ -731,8 +800,8 @@ class ContentDecryptionModule_8 {
//
// Returns kSuccess if the |audio_decoder_config| is supported and the CDM
// audio decoder is successfully initialized.
- // Returns kSessionError if |audio_decoder_config| is not supported. The CDM
- // may still be able to do Decrypt().
+ // Returns kInitializationError if |audio_decoder_config| is not supported.
+ // The CDM may still be able to do Decrypt().
// Returns kDeferredInitialization if the CDM is not ready to initialize the
// decoder at this time. Must call Host::OnDeferredInitializationDone() once
// initialization is complete.
@@ -744,8 +813,8 @@ class ContentDecryptionModule_8 {
//
// Returns kSuccess if the |video_decoder_config| is supported and the CDM
// video decoder is successfully initialized.
- // Returns kSessionError if |video_decoder_config| is not supported. The CDM
- // may still be able to do Decrypt().
+ // Returns kInitializationError if |video_decoder_config| is not supported.
+ // The CDM may still be able to do Decrypt().
// Returns kDeferredInitialization if the CDM is not ready to initialize the
// decoder at this time. Must call Host::OnDeferredInitializationDone() once
// initialization is complete.
@@ -815,18 +884,30 @@ class ContentDecryptionModule_8 {
uint32_t link_mask,
uint32_t output_protection_mask) = 0;
+ // Called by the host after a call to Host::RequestStorageId(). If the
+ // version of the storage ID requested is available, |storage_id| and
+ // |storage_id_size| are set appropriately. |version| will be the same as
+ // what was requested, unless 0 (latest) was requested, in which case
+ // |version| will be the actual version number for the |storage_id| returned.
+ // If the requested version is not available, null/zero will be provided as
+ // |storage_id| and |storage_id_size|, respectively, and |version| should be
+ // ignored.
+ virtual void OnStorageId(uint32_t version,
+ const uint8_t* storage_id,
+ uint32_t storage_id_size) = 0;
+
// Destroys the object in the same context as it was created.
virtual void Destroy() = 0;
protected:
- ContentDecryptionModule_8() {}
- virtual ~ContentDecryptionModule_8() {}
+ ContentDecryptionModule_9() {}
+ virtual ~ContentDecryptionModule_9() {}
};
-typedef ContentDecryptionModule_8 ContentDecryptionModule;
+typedef ContentDecryptionModule_9 ContentDecryptionModule;
// Represents a buffer created by Allocator implementations.
-class Buffer {
+class CDM_CLASS_API Buffer {
public:
// Destroys the buffer in the same context as it was created.
virtual void Destroy() = 0;
@@ -845,9 +926,9 @@ class Buffer {
void operator=(const Buffer&);
};
-class Host_7 {
+class CDM_CLASS_API Host_8 {
public:
- static const int kVersion = 7;
+ static const int kVersion = 8;
// Returns a Buffer* containing non-zero members upon success, or NULL on
// failure. The caller owns the Buffer* after this call. The buffer is not
@@ -859,7 +940,7 @@ class Host_7 {
// from now with |context|.
virtual void SetTimer(int64_t delay_ms, void* context) = 0;
- // Returns the current wall time in seconds.
+ // Returns the current wall time.
virtual Time GetCurrentWallTime() = 0;
// Called by the CDM when a session is created or loaded and the value for the
@@ -917,8 +998,10 @@ class Host_7 {
// session |session_id|. This can happen as the result of an Update() call
// or some other event. If this happens as a result of a call to Update(),
// it must be called before resolving the Update() promise. |new_expiry_time|
- // can be 0 to represent "undefined". Size parameter should not include
- // null termination.
+ // represents the time after which the key(s) in the session will no longer
+ // be usable for decryption. It can be 0 if no such time exists or if the
+ // license explicitly never expires. Size parameter should not include null
+ // termination.
virtual void OnExpirationChange(const char* session_id,
uint32_t session_id_size,
Time new_expiry_time) = 0;
@@ -978,13 +1061,13 @@ class Host_7 {
virtual FileIO* CreateFileIO(FileIOClient* client) = 0;
protected:
- Host_7() {}
- virtual ~Host_7() {}
+ Host_8() {}
+ virtual ~Host_8() {}
};
-class Host_8 {
+class CDM_CLASS_API Host_9 {
public:
- static const int kVersion = 8;
+ static const int kVersion = 9;
// Returns a Buffer* containing non-zero members upon success, or NULL on
// failure. The caller owns the Buffer* after this call. The buffer is not
@@ -996,9 +1079,14 @@ class Host_8 {
// from now with |context|.
virtual void SetTimer(int64_t delay_ms, void* context) = 0;
- // Returns the current wall time in seconds.
+ // Returns the current wall time.
virtual Time GetCurrentWallTime() = 0;
+ // Called by the CDM when a key status is available in response to
+ // GetStatusForPolicy().
+ virtual void OnResolveKeyStatusPromise(uint32_t promise_id,
+ KeyStatus key_status) = 0;
+
// Called by the CDM when a session is created or loaded and the value for the
// MediaKeySession's sessionId attribute is available (|session_id|).
// This must be called before OnSessionMessage() or
@@ -1016,26 +1104,21 @@ class Host_8 {
// Called by the CDM when an error occurs as a result of one of the
// ContentDecryptionModule calls that accept a |promise_id|.
- // |error| must be specified, |error_message| and |system_code|
+ // |exception| must be specified. |error_message| and |system_code|
// are optional. |error_message_size| should not include null termination.
virtual void OnRejectPromise(uint32_t promise_id,
- Error error,
+ Exception exception,
uint32_t system_code,
const char* error_message,
uint32_t error_message_size) = 0;
// Called by the CDM when it has a message for session |session_id|.
// Size parameters should not include null termination.
- // |legacy_destination_url| is only for supporting the prefixed EME API and
- // is ignored by unprefixed EME. It should only be non-null if |message_type|
- // is kLicenseRenewal.
virtual void OnSessionMessage(const char* session_id,
uint32_t session_id_size,
MessageType message_type,
const char* message,
- uint32_t message_size,
- const char* legacy_destination_url,
- uint32_t legacy_destination_url_length) = 0;
+ uint32_t message_size) = 0;
// Called by the CDM when there has been a change in keys or their status for
// session |session_id|. |has_additional_usable_key| should be set if a
@@ -1054,8 +1137,10 @@ class Host_8 {
// session |session_id|. This can happen as the result of an Update() call
// or some other event. If this happens as a result of a call to Update(),
// it must be called before resolving the Update() promise. |new_expiry_time|
- // can be 0 to represent "undefined". Size parameter should not include
- // null termination.
+ // represents the time after which the key(s) in the session will no longer
+ // be usable for decryption. It can be 0 if no such time exists or if the
+ // license explicitly never expires. Size parameter should not include null
+ // termination.
virtual void OnExpirationChange(const char* session_id,
uint32_t session_id_size,
Time new_expiry_time) = 0;
@@ -1065,21 +1150,6 @@ class Host_8 {
virtual void OnSessionClosed(const char* session_id,
uint32_t session_id_size) = 0;
- // Called by the CDM when an error occurs in session |session_id|
- // unrelated to one of the ContentDecryptionModule calls that accept a
- // |promise_id|. |error| must be specified, |error_message| and
- // |system_code| are optional. Length parameters should not include null
- // termination.
- // Note:
- // - This method is only for supporting prefixed EME API.
- // - This method will be ignored by unprefixed EME. All errors reported
- // in this method should probably also be reported by one of other methods.
- virtual void OnLegacySessionError(
- const char* session_id, uint32_t session_id_length,
- Error error,
- uint32_t system_code,
- const char* error_message, uint32_t error_message_length) = 0;
-
// The following are optional methods that may not be implemented on all
// platforms.
@@ -1114,13 +1184,22 @@ class Host_8 {
// CDM can call this method multiple times to operate on different files.
virtual FileIO* CreateFileIO(FileIOClient* client) = 0;
+ // Requests a specific version of the storage ID. A storage ID is a stable,
+ // device specific ID used by the CDM to securely store persistent data. The
+ // ID will be returned by the host via ContentDecryptionModule::OnStorageId().
+ // If |version| is 0, the latest version will be returned. All |version|s
+ // that are greater than or equal to 0x80000000 are reserved for the CDM and
+ // should not be supported or returned by the host. The CDM must not expose
+ // the ID outside the client device, even in encrypted form.
+ virtual void RequestStorageId(uint32_t version) = 0;
+
protected:
- Host_8() {}
- virtual ~Host_8() {}
+ Host_9() {}
+ virtual ~Host_9() {}
};
// Represents a decrypted block that has not been decoded.
-class DecryptedBlock {
+class CDM_CLASS_API DecryptedBlock {
public:
virtual void SetDecryptedBuffer(Buffer* buffer) = 0;
virtual Buffer* DecryptedBuffer() = 0;
@@ -1135,7 +1214,7 @@ class DecryptedBlock {
virtual ~DecryptedBlock() {}
};
-class VideoFrame {
+class CDM_CLASS_API VideoFrame {
public:
enum VideoPlane {
kYPlane = 0,
@@ -1178,7 +1257,7 @@ class VideoFrame {
//
// |<----------------- AudioFrames ------------------>|
// | audio buffer 0 | audio buffer 1 | audio buffer 2 |
-class AudioFrames {
+class CDM_CLASS_API AudioFrames {
public:
virtual void SetFrameBuffer(Buffer* buffer) = 0;
virtual Buffer* FrameBuffer() = 0;
diff --git a/dom/media/gmp/widevine-adapter/content_decryption_module_export.h b/dom/media/gmp/widevine-adapter/content_decryption_module_export.h
new file mode 100644
index 000000000..51d485892
--- /dev/null
+++ b/dom/media/gmp/widevine-adapter/content_decryption_module_export.h
@@ -0,0 +1,22 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_
+#define CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_
+
+// Define CDM_API so that functionality implemented by the CDM module
+// can be exported to consumers.
+#if defined(_WIN32)
+
+#if defined(CDM_IMPLEMENTATION)
+#define CDM_API __declspec(dllexport)
+#else
+#define CDM_API __declspec(dllimport)
+#endif // defined(CDM_IMPLEMENTATION)
+
+#else // defined(_WIN32)
+#define CDM_API __attribute__((visibility("default")))
+#endif // defined(_WIN32)
+
+#endif // CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_
diff --git a/dom/media/gmp/widevine-adapter/content_decryption_module_ext.h b/dom/media/gmp/widevine-adapter/content_decryption_module_ext.h
new file mode 100644
index 000000000..5df8344e6
--- /dev/null
+++ b/dom/media/gmp/widevine-adapter/content_decryption_module_ext.h
@@ -0,0 +1,64 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CDM_CONTENT_DECRYPTION_MODULE_EXT_H_
+#define CDM_CONTENT_DECRYPTION_MODULE_EXT_H_
+
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
+#include "content_decryption_module_export.h"
+
+#if defined(_MSC_VER)
+typedef unsigned int uint32_t;
+#else
+#include <stdint.h>
+#endif
+
+namespace cdm {
+
+#if defined(_WIN32)
+typedef wchar_t FilePathCharType;
+typedef HANDLE PlatformFile;
+const PlatformFile kInvalidPlatformFile = INVALID_HANDLE_VALUE;
+#else
+typedef char FilePathCharType;
+typedef int PlatformFile;
+const PlatformFile kInvalidPlatformFile = -1;
+#endif // defined(_WIN32)
+
+struct HostFile {
+ HostFile(const FilePathCharType* file_path,
+ PlatformFile file,
+ PlatformFile sig_file)
+ : file_path(file_path), file(file), sig_file(sig_file) {}
+
+ // File that is part of the host of the CDM.
+ const FilePathCharType* file_path = nullptr;
+ PlatformFile file = kInvalidPlatformFile;
+
+ // Signature file for |file|.
+ PlatformFile sig_file = kInvalidPlatformFile;
+};
+
+} // namespace cdm
+
+extern "C" {
+
+// Functions in this file are dynamically retrieved by their versioned function
+// names. Increment the version number for any backward incompatible API
+// changes.
+
+// Verifies CDM host. All files in |host_files| are opened in read-only mode.
+//
+// Returns false and closes all files if there is an immediate failure.
+// Otherwise returns true as soon as possible and processes the files
+// asynchronously. All files MUST be closed by the CDM after this one-time
+// processing is finished.
+CDM_API bool VerifyCdmHost_0(const cdm::HostFile* host_files,
+ uint32_t num_files);
+}
+
+#endif // CDM_CONTENT_DECRYPTION_MODULE_EXT_H_
diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp
index 570730312..f2cbc8fcf 100644
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -92,6 +92,55 @@ nsContentSecurityManager::AllowTopLevelNavigationToDataURI(nsIChannel* aChannel)
return false;
}
+/* static */ nsresult
+nsContentSecurityManager::CheckFTPSubresourceLoad(nsIChannel* aChannel)
+{
+ // We dissallow using FTP resources as a subresource everywhere.
+ // The only valid way to use FTP resources is loading it as
+ // a top level document.
+
+ nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
+ if (!loadInfo) {
+ return NS_OK;
+ }
+
+ nsContentPolicyType type = loadInfo->GetExternalContentPolicyType();
+ if (type == nsIContentPolicy::TYPE_DOCUMENT) {
+ return NS_OK;
+ }
+
+ nsCOMPtr<nsIURI> uri;
+ nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (!uri) {
+ return NS_OK;
+ }
+
+ bool isFtpURI = (NS_SUCCEEDED(uri->SchemeIs("ftp", &isFtpURI)) && isFtpURI);
+ if (!isFtpURI) {
+ return NS_OK;
+ }
+
+ nsCOMPtr<nsIDocument> doc;
+ if (nsINode* node = loadInfo->LoadingNode()) {
+ doc = node->OwnerDoc();
+ }
+
+ nsAutoCString spec;
+ uri->GetSpec(spec);
+ NS_ConvertUTF8toUTF16 specUTF16(NS_UnescapeURL(spec));
+ const char16_t* params[] = { specUTF16.get() };
+
+ nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
+ NS_LITERAL_CSTRING("FTP_URI_BLOCKED"),
+ doc,
+ nsContentUtils::eSECURITY_PROPERTIES,
+ "BlockSubresourceFTP",
+ params, ArrayLength(params));
+
+ return NS_ERROR_CONTENT_BLOCKED;
+}
+
static nsresult
ValidateSecurityFlags(nsILoadInfo* aLoadInfo)
{
@@ -574,6 +623,10 @@ nsContentSecurityManager::doContentSecurityCheck(nsIChannel* aChannel,
rv = DoContentSecurityChecks(aChannel, loadInfo);
NS_ENSURE_SUCCESS(rv, rv);
+ // Apply this after CSP checks to allow CSP reporting.
+ rv = CheckFTPSubresourceLoad(aChannel);
+ NS_ENSURE_SUCCESS(rv, rv);
+
// now lets set the initalSecurityFlag for subsequent calls
loadInfo->SetInitialSecurityCheckDone(true);
@@ -591,6 +644,9 @@ nsContentSecurityManager::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
// Are we enforcing security using LoadInfo?
if (loadInfo && loadInfo->GetEnforceSecurity()) {
nsresult rv = CheckChannel(aNewChannel);
+ if (NS_SUCCEEDED(rv)) {
+ rv = CheckFTPSubresourceLoad(aNewChannel);
+ }
if (NS_FAILED(rv)) {
aOldChannel->Cancel(rv);
return rv;
diff --git a/dom/security/nsContentSecurityManager.h b/dom/security/nsContentSecurityManager.h
index bab847743..750dd8803 100644
--- a/dom/security/nsContentSecurityManager.h
+++ b/dom/security/nsContentSecurityManager.h
@@ -36,6 +36,7 @@ public:
private:
static nsresult CheckChannel(nsIChannel* aChannel);
+ static nsresult CheckFTPSubresourceLoad(nsIChannel* aChannel);
virtual ~nsContentSecurityManager() {}
diff --git a/dom/smil/nsSMILAnimationController.cpp b/dom/smil/nsSMILAnimationController.cpp
index 0dd616346..69956203e 100644
--- a/dom/smil/nsSMILAnimationController.cpp
+++ b/dom/smil/nsSMILAnimationController.cpp
@@ -233,7 +233,7 @@ void
nsSMILAnimationController::NotifyRefreshDriverCreated(
nsRefreshDriver* aRefreshDriver)
{
- if (!mPauseState) {
+ if (!mPauseState && mChildContainerTable.Count()) {
MaybeStartSampling(aRefreshDriver);
}
}
diff --git a/dom/url/URLSearchParams.cpp b/dom/url/URLSearchParams.cpp
index d9492f81c..f762299f8 100644
--- a/dom/url/URLSearchParams.cpp
+++ b/dom/url/URLSearchParams.cpp
@@ -314,14 +314,6 @@ URLSearchParams::URLSearchParams(nsISupports* aParent,
{
}
-URLSearchParams::URLSearchParams(nsISupports* aParent,
- const URLSearchParams& aOther)
- : mParams(new URLParams(*aOther.mParams.get()))
- , mParent(aParent)
- , mObserver(nullptr)
-{
-}
-
URLSearchParams::~URLSearchParams()
{
DeleteAll();
@@ -335,34 +327,43 @@ URLSearchParams::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
/* static */ already_AddRefed<URLSearchParams>
URLSearchParams::Constructor(const GlobalObject& aGlobal,
- const nsAString& aInit,
+ const USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString& aInit,
ErrorResult& aRv)
{
RefPtr<URLSearchParams> sp =
new URLSearchParams(aGlobal.GetAsSupports(), nullptr);
- NS_ConvertUTF16toUTF8 input(aInit);
-
- if (StringBeginsWith(input, NS_LITERAL_CSTRING("?"))) {
- sp->ParseInput(Substring(input, 1, input.Length() - 1));
+ if (aInit.IsUSVString()) {
+ NS_ConvertUTF16toUTF8 input(aInit.GetAsUSVString());
+ if (StringBeginsWith(input, NS_LITERAL_CSTRING("?"))) {
+ sp->ParseInput(Substring(input, 1, input.Length() - 1));
+ } else {
+ sp->ParseInput(input);
+ }
+ } else if (aInit.IsUSVStringSequenceSequence()) {
+ const Sequence<Sequence<nsString>>& list =
+ aInit.GetAsUSVStringSequenceSequence();
+ for (uint32_t i = 0; i < list.Length(); ++i) {
+ const Sequence<nsString>& item = list[i];
+ if (item.Length() != 2) {
+ aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
+ return nullptr;
+ }
+ sp->Append(item[0], item[1]);
+ }
+ } else if (aInit.IsUSVStringUSVStringRecord()) {
+ const Record<nsString, nsString>& record =
+ aInit.GetAsUSVStringUSVStringRecord();
+ for (auto& entry : record.Entries()) {
+ sp->Append(entry.mKey, entry.mValue);
+ }
} else {
- sp->ParseInput(input);
+ MOZ_CRASH("URLSearchParams: Invalid string");
}
return sp.forget();
}
-/* static */ already_AddRefed<URLSearchParams>
-URLSearchParams::Constructor(const GlobalObject& aGlobal,
- URLSearchParams& aInit,
- ErrorResult& aRv)
-{
- RefPtr<URLSearchParams> sp =
- new URLSearchParams(aGlobal.GetAsSupports(), aInit);
-
- return sp.forget();
-}
-
void
URLSearchParams::ParseInput(const nsACString& aInput)
{
diff --git a/dom/url/URLSearchParams.h b/dom/url/URLSearchParams.h
index 4b0aaa991..9fefd78dd 100644
--- a/dom/url/URLSearchParams.h
+++ b/dom/url/URLSearchParams.h
@@ -20,6 +20,7 @@ namespace mozilla {
namespace dom {
class URLSearchParams;
+class USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString;
class URLSearchParamsObserver : public nsISupports
{
@@ -43,14 +44,6 @@ public:
DeleteAll();
}
- explicit URLParams(const URLParams& aOther)
- : mParams(aOther.mParams)
- {}
-
- URLParams(const URLParams&& aOther)
- : mParams(Move(aOther.mParams))
- {}
-
class ForEachIterator
{
public:
@@ -144,9 +137,6 @@ public:
explicit URLSearchParams(nsISupports* aParent,
URLSearchParamsObserver* aObserver=nullptr);
- URLSearchParams(nsISupports* aParent,
- const URLSearchParams& aOther);
-
// WebIDL methods
nsISupports* GetParentObject() const
{
@@ -157,11 +147,8 @@ public:
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
static already_AddRefed<URLSearchParams>
- Constructor(const GlobalObject& aGlobal, const nsAString& aInit,
- ErrorResult& aRv);
-
- static already_AddRefed<URLSearchParams>
- Constructor(const GlobalObject& aGlobal, URLSearchParams& aInit,
+ Constructor(const GlobalObject& aGlobal,
+ const USVStringSequenceSequenceOrUSVStringUSVStringRecordOrUSVString& aInit,
ErrorResult& aRv);
void ParseInput(const nsACString& aInput);
diff --git a/dom/webidl/Headers.webidl b/dom/webidl/Headers.webidl
index 205ab9f9e..eef552a7f 100644
--- a/dom/webidl/Headers.webidl
+++ b/dom/webidl/Headers.webidl
@@ -8,7 +8,7 @@
* http://fetch.spec.whatwg.org/#headers-class
*/
-typedef (Headers or sequence<sequence<ByteString>> or MozMap<ByteString>) HeadersInit;
+typedef (Headers or sequence<sequence<ByteString>> or record<ByteString, ByteString>) HeadersInit;
enum HeadersGuardEnum {
"none",
diff --git a/dom/webidl/InstallTrigger.webidl b/dom/webidl/InstallTrigger.webidl
index 789fb2bc4..68f48ddc6 100644
--- a/dom/webidl/InstallTrigger.webidl
+++ b/dom/webidl/InstallTrigger.webidl
@@ -57,7 +57,7 @@ interface InstallTriggerImpl {
* A callback to call as each installation succeeds or fails
* @return true if the installations were successfully started
*/
- boolean install(MozMap<(DOMString or InstallTriggerData)> installs,
+ boolean install(record<DOMString, (DOMString or InstallTriggerData)> installs,
optional InstallTriggerCallback callback);
/**
diff --git a/dom/webidl/TestInterfaceJS.webidl b/dom/webidl/TestInterfaceJS.webidl
index 1ca629c39..2cf8d701a 100644
--- a/dom/webidl/TestInterfaceJS.webidl
+++ b/dom/webidl/TestInterfaceJS.webidl
@@ -24,7 +24,7 @@ interface TestInterfaceJS : EventTarget {
any pingPongObjectOrString((object or DOMString) objOrString);
TestInterfaceJSDictionary pingPongDictionary(optional TestInterfaceJSDictionary dict);
long pingPongDictionaryOrLong(optional (TestInterfaceJSUnionableDictionary or long) dictOrLong);
- DOMString pingPongMap(MozMap<any> map);
+ DOMString pingPongMap(record<DOMString, any> map);
long objectSequenceLength(sequence<object> seq);
long anySequenceLength(sequence<any> seq);
diff --git a/dom/webidl/URLSearchParams.webidl b/dom/webidl/URLSearchParams.webidl
index 93e846071..b93f4e8b1 100644
--- a/dom/webidl/URLSearchParams.webidl
+++ b/dom/webidl/URLSearchParams.webidl
@@ -13,8 +13,7 @@
* http://www.openwebfoundation.org/legal/the-owf-1-0-agreements/owfa-1-0.
*/
-[Constructor(optional USVString init = ""),
- Constructor(URLSearchParams init),
+[Constructor(optional (sequence<sequence<USVString>> or record<USVString, USVString> or USVString) init = ""),
Exposed=(Window,Worker,WorkerDebugger,System)]
interface URLSearchParams {
void append(USVString name, USVString value);
diff --git a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
index 726441757..c9bcc31ff 100644
--- a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
+++ b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
@@ -462,10 +462,6 @@ txCompileObserver::startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler,
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
if (httpChannel) {
- httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
- NS_LITERAL_CSTRING("*/*"),
- false);
-
nsCOMPtr<nsIURI> referrerURI;
aReferrerPrincipal->GetURI(getter_AddRefs(referrerURI));
if (referrerURI) {
diff --git a/image/imgFrame.cpp b/image/imgFrame.cpp
index c9f44181d..d982c17c4 100644
--- a/image/imgFrame.cpp
+++ b/image/imgFrame.cpp
@@ -161,13 +161,13 @@ imgFrame::imgFrame()
: mMonitor("imgFrame")
, mDecoded(0, 0, 0, 0)
, mLockCount(0)
+ , mHasNoAlpha(false)
, mAborted(false)
, mFinished(false)
, mOptimizable(false)
, mTimeout(FrameTimeout::FromRawMilliseconds(100))
, mDisposalMethod(DisposalMethod::NOT_SPECIFIED)
, mBlendMethod(BlendMethod::OVER)
- , mHasNoAlpha(false)
, mPalettedImageData(nullptr)
, mPaletteDepth(0)
, mNonPremult(false)
diff --git a/js/public/Value.h b/js/public/Value.h
index 01666ed4e..7c4f833e3 100644
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -567,8 +567,11 @@ class MOZ_NON_PARAM alignas(8) Value
}
bool isMagic(JSWhyMagic why) const {
- MOZ_ASSERT_IF(isMagic(), data.s.payload.why == why);
- return isMagic();
+ if (!isMagic()) {
+ return false;
+ }
+ MOZ_RELEASE_ASSERT(data.s.payload.why == why);
+ return true;
}
JS::TraceKind traceKind() const {
diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp
index ea4350fb8..93a0eb6a8 100644
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -210,6 +210,7 @@ js::Nursery::disable()
return;
updateNumChunks(0);
currentEnd_ = 0;
+ position_ = 0;
runtime()->gc.storeBuffer.disable();
}
diff --git a/js/src/gc/Nursery.h b/js/src/gc/Nursery.h
index 0d215d997..a839a4979 100644
--- a/js/src/gc/Nursery.h
+++ b/js/src/gc/Nursery.h
@@ -245,6 +245,7 @@ class Nursery
// Free space remaining, not counting chunk trailers.
MOZ_ALWAYS_INLINE size_t freeSpace() const {
+ MOZ_ASSERT(isEnabled());
MOZ_ASSERT(currentEnd_ - position_ <= NurseryChunkUsableSize);
return (currentEnd_ - position_) +
(numChunks() - currentChunk_ - 1) * NurseryChunkUsableSize;
diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp
index b163d5818..d255c32a8 100644
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -3127,6 +3127,15 @@ ExtractMathSpace(MDefinition* ins)
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unknown TruncateKind");
}
+static bool MonotoneAdd(int32_t lhs, int32_t rhs) {
+ return (lhs >= 0 && rhs >= 0) || (lhs <= 0 && rhs <= 0);
+}
+
+static bool MonotoneSub(int32_t lhs, int32_t rhs) {
+ return (lhs >= 0 && rhs <= 0) || (lhs <= 0 && rhs >= 0);
+}
+
+
// Extract a linear sum from ins, if possible (otherwise giving the sum 'ins + 0').
SimpleLinearSum
jit::ExtractLinearSum(MDefinition* ins, MathSpace space)
@@ -3168,10 +3177,12 @@ jit::ExtractLinearSum(MDefinition* ins, MathSpace space)
// Check if this is of the form <SUM> + n or n + <SUM>.
if (ins->isAdd()) {
int32_t constant;
- if (space == MathSpace::Modulo)
+ if (space == MathSpace::Modulo) {
constant = lsum.constant + rsum.constant;
- else if (!SafeAdd(lsum.constant, rsum.constant, &constant))
+ } else if (!SafeAdd(lsum.constant, rsum.constant, &constant) ||
+ !MonotoneAdd(lsum.constant, rsum.constant)) {
return SimpleLinearSum(ins, 0);
+ }
return SimpleLinearSum(lsum.term ? lsum.term : rsum.term, constant);
}
@@ -3179,10 +3190,12 @@ jit::ExtractLinearSum(MDefinition* ins, MathSpace space)
// Check if this is of the form <SUM> - n.
if (lsum.term) {
int32_t constant;
- if (space == MathSpace::Modulo)
+ if (space == MathSpace::Modulo) {
constant = lsum.constant - rsum.constant;
- else if (!SafeSub(lsum.constant, rsum.constant, &constant))
+ } else if (!SafeSub(lsum.constant, rsum.constant, &constant) ||
+ !MonotoneSub(lsum.constant, rsum.constant)) {
return SimpleLinearSum(ins, 0);
+ }
return SimpleLinearSum(lsum.term, constant);
}
diff --git a/js/src/jit/JitOptions.cpp b/js/src/jit/JitOptions.cpp
index eb5a6c1c2..b9a7c7b27 100644
--- a/js/src/jit/JitOptions.cpp
+++ b/js/src/jit/JitOptions.cpp
@@ -222,7 +222,7 @@ DefaultJitOptions::DefaultJitOptions()
}
// Toggles whether unboxed plain objects can be created by the VM.
- SET_DEFAULT(disableUnboxedObjects, false);
+ SET_DEFAULT(disableUnboxedObjects, true);
// Test whether Atomics are allowed in asm.js code.
SET_DEFAULT(asmJSAtomicsEnable, false);
diff --git a/js/src/jit/StupidAllocator.cpp b/js/src/jit/StupidAllocator.cpp
index 8e3ea6286..55431e8e0 100644
--- a/js/src/jit/StupidAllocator.cpp
+++ b/js/src/jit/StupidAllocator.cpp
@@ -407,7 +407,6 @@ StupidAllocator::allocateForDefinition(LInstruction* ins, LDefinition* def)
{
uint32_t vreg = def->virtualRegister();
- CodePosition from;
if ((def->output()->isRegister() && def->policy() == LDefinition::FIXED) ||
def->policy() == LDefinition::MUST_REUSE_INPUT)
{
diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
index 37d023bd4..6114b8157 100644
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -6410,6 +6410,9 @@ JS_SetGlobalJitCompilerOption(JSContext* cx, JSJitCompilerOption opt, uint32_t v
}
jit::JitOptions.jumpThreshold = value;
break;
+ case JSJITCOMPILER_UNBOXED_OBJECTS:
+ jit::JitOptions.disableUnboxedObjects = !value;
+ break;
case JSJITCOMPILER_ASMJS_ATOMICS_ENABLE:
jit::JitOptions.asmJSAtomicsEnable = !!value;
break;
diff --git a/js/src/jsapi.h b/js/src/jsapi.h
index 005d2278e..1f726f2e5 100644
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -5783,19 +5783,20 @@ JS_SetParallelParsingEnabled(JSContext* cx, bool enabled);
extern JS_PUBLIC_API(void)
JS_SetOffthreadIonCompilationEnabled(JSContext* cx, bool enabled);
-#define JIT_COMPILER_OPTIONS(Register) \
- Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \
- Register(ION_WARMUP_TRIGGER, "ion.warmup.trigger") \
- Register(ION_GVN_ENABLE, "ion.gvn.enable") \
- Register(ION_FORCE_IC, "ion.forceinlineCaches") \
- Register(ION_ENABLE, "ion.enable") \
+#define JIT_COMPILER_OPTIONS(Register) \
+ Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \
+ Register(ION_WARMUP_TRIGGER, "ion.warmup.trigger") \
+ Register(ION_GVN_ENABLE, "ion.gvn.enable") \
+ Register(ION_FORCE_IC, "ion.forceinlineCaches") \
+ Register(ION_ENABLE, "ion.enable") \
Register(ION_INTERRUPT_WITHOUT_SIGNAL, "ion.interrupt-without-signals") \
- Register(ION_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis") \
- Register(BASELINE_ENABLE, "baseline.enable") \
- Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \
- Register(JUMP_THRESHOLD, "jump-threshold") \
- Register(ASMJS_ATOMICS_ENABLE, "asmjs.atomics.enable") \
- Register(WASM_TEST_MODE, "wasm.test-mode") \
+ Register(ION_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis") \
+ Register(BASELINE_ENABLE, "baseline.enable") \
+ Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \
+ Register(JUMP_THRESHOLD, "jump-threshold") \
+ Register(UNBOXED_OBJECTS, "unboxed_objects") \
+ Register(ASMJS_ATOMICS_ENABLE, "asmjs.atomics.enable") \
+ Register(WASM_TEST_MODE, "wasm.test-mode") \
Register(WASM_FOLD_OFFSETS, "wasm.fold-offsets")
typedef enum JSJitCompilerOption {
diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp
index 863871df9..98311be2f 100644
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -288,6 +288,12 @@ CallerGetterImpl(JSContext* cx, const CallArgs& args)
return true;
}
+ if (JS_IsDeadWrapper(callerObj)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_DEAD_OBJECT);
+ return false;
+ }
+
JSFunction* callerFun = &callerObj->as<JSFunction>();
MOZ_ASSERT(!callerFun->isBuiltin(), "non-builtin iterator returned a builtin?");
@@ -314,54 +320,14 @@ CallerSetterImpl(JSContext* cx, const CallArgs& args)
{
MOZ_ASSERT(IsFunction(args.thisv()));
- // Beware! This function can be invoked on *any* function! It can't
- // assume it'll never be invoked on natives, strict mode functions, bound
- // functions, or anything else that ordinarily has immutable .caller
- // defined with [[ThrowTypeError]].
- RootedFunction fun(cx, &args.thisv().toObject().as<JSFunction>());
- if (!CallerRestrictions(cx, fun))
- return false;
-
- // Return |undefined| unless an error must be thrown.
- args.rval().setUndefined();
-
- // We can almost just return |undefined| here -- but if the caller function
- // was strict mode code, we still have to throw a TypeError. This requires
- // computing the caller, checking that no security boundaries are crossed,
- // and throwing a TypeError if the resulting caller is strict.
-
- NonBuiltinScriptFrameIter iter(cx);
- if (!AdvanceToActiveCallLinear(cx, iter, fun))
- return true;
-
- ++iter;
- while (!iter.done() && iter.isEvalFrame())
- ++iter;
-
- if (iter.done() || !iter.isFunctionFrame())
- return true;
-
- RootedObject caller(cx, iter.callee(cx));
- if (!cx->compartment()->wrap(cx, &caller)) {
- cx->clearPendingException();
- return true;
- }
-
- // If we don't have full access to the caller, or the caller is not strict,
- // return undefined. Otherwise throw a TypeError.
- JSObject* callerObj = CheckedUnwrap(caller);
- if (!callerObj)
- return true;
-
- JSFunction* callerFun = &callerObj->as<JSFunction>();
- MOZ_ASSERT(!callerFun->isBuiltin(), "non-builtin iterator returned a builtin?");
-
- if (callerFun->strict()) {
- JS_ReportErrorFlagsAndNumberASCII(cx, JSREPORT_ERROR, GetErrorMessage, nullptr,
- JSMSG_CALLER_IS_STRICT);
- return false;
+ // We just have to return |undefined|, but first we call CallerGetterImpl
+ // because we need the same strict-mode and security checks.
+
+ if (!CallerGetterImpl(cx, args)) {
+ return false;
}
+ args.rval().setUndefined();
return true;
}
diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp
index 1fbf8976b..46159a972 100644
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -495,7 +495,6 @@ ObjectGroup::defaultNewGroup(ExclusiveContext* cx, const Class* clasp,
if (associated->is<JSFunction>()) {
// Canonicalize new functions to use the original one associated with its script.
- JSFunction* fun = &associated->as<JSFunction>();
associated = associated->as<JSFunction>().maybeCanonicalFunction();
// If we have previously cleared the 'new' script information for this
diff --git a/js/xpconnect/src/XPCJSContext.cpp b/js/xpconnect/src/XPCJSContext.cpp
index 0243d80e3..bde949a96 100644
--- a/js/xpconnect/src/XPCJSContext.cpp
+++ b/js/xpconnect/src/XPCJSContext.cpp
@@ -1427,6 +1427,8 @@ ReloadPrefsCallback(const char* pref, void* data)
bool extraWarnings = Preferences::GetBool(JS_OPTIONS_DOT_STR "strict");
+ bool unboxedObjects = Preferences::GetBool(JS_OPTIONS_DOT_STR "unboxed_objects");
+
sSharedMemoryEnabled = Preferences::GetBool(JS_OPTIONS_DOT_STR "shared_memory");
#ifdef DEBUG
@@ -1455,6 +1457,8 @@ ReloadPrefsCallback(const char* pref, void* data)
useBaselineEager ? 0 : -1);
JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_ION_WARMUP_TRIGGER,
useIonEager ? 0 : -1);
+ JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_UNBOXED_OBJECTS,
+ unboxedObjects);
}
XPCJSContext::~XPCJSContext()
diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h
index 63253fd10..0a82dbf6a 100644
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1439,13 +1439,14 @@ public:
/**
* This function increases an initial intrinsic size, 'aCurrent', according
* to the given 'aPercent', such that the size-increase makes up exactly
- * 'aPercent' percent of the returned value. If 'aPercent' is less than
- * or equal to zero the original 'aCurrent' value is returned. If 'aPercent'
- * is greater than or equal to 1.0 the value nscoord_MAX is returned.
+ * 'aPercent' percent of the returned value. If 'aPercent' or 'aCurrent' are
+ * less than or equal to zero the original 'aCurrent' value is returned.
+ * If 'aPercent' is greater than or equal to 1.0 the value nscoord_MAX is
+ * returned.
*/
static nscoord AddPercents(nscoord aCurrent, float aPercent)
{
- if (aPercent > 0.0f) {
+ if (aPercent > 0.0f && aCurrent > 0) {
return MOZ_UNLIKELY(aPercent >= 1.0f) ? nscoord_MAX
: NSToCoordRound(float(aCurrent) / (1.0f - aPercent));
}
diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp
index 969ebc962..5dfbb8dba 100644
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -7296,11 +7296,11 @@ PresShell::HandleEvent(nsIFrame* aFrame,
return NS_OK;
}
- nsIContent* capturingContent = ((aEvent->mClass == ePointerEventClass ||
- aEvent->mClass == eWheelEventClass ||
- aEvent->HasMouseEventMessage())
- ? GetCapturingContent()
- : nullptr);
+ nsCOMPtr<nsIContent> capturingContent = ((aEvent->mClass == ePointerEventClass ||
+ aEvent->mClass == eWheelEventClass ||
+ aEvent->HasMouseEventMessage())
+ ? GetCapturingContent()
+ : nullptr);
nsCOMPtr<nsIDocument> retargetEventDoc;
if (!aDontRetargetEvents) {
diff --git a/layout/generic/nsAbsoluteContainingBlock.cpp b/layout/generic/nsAbsoluteContainingBlock.cpp
index 7c48aae92..e3c847d01 100644
--- a/layout/generic/nsAbsoluteContainingBlock.cpp
+++ b/layout/generic/nsAbsoluteContainingBlock.cpp
@@ -409,14 +409,30 @@ OffsetToAlignedStaticPos(const ReflowInput& aKidReflowInput,
? GetOrthogonalAxis(aAbsPosCBAxis)
: aAbsPosCBAxis);
+ const bool placeholderContainerIsContainingBlock =
+ aPlaceholderContainer == aKidReflowInput.mCBReflowInput->mFrame;
+
nsIAtom* parentType = aPlaceholderContainer->GetType();
LogicalSize alignAreaSize(pcWM);
if (parentType == nsGkAtoms::flexContainerFrame) {
- // The alignment container is the flex container's content box:
- alignAreaSize = aPlaceholderContainer->GetLogicalSize(pcWM);
- LogicalMargin pcBorderPadding =
- aPlaceholderContainer->GetLogicalUsedBorderAndPadding(pcWM);
- alignAreaSize -= pcBorderPadding.Size(pcWM);
+ // We store the frame rect in FinishAndStoreOverflow, which runs _after_
+ // reflowing the absolute frames, so handle the special case of the frame
+ // being the actual containing block here, by getting the size from
+ // aAbsPosCBSize.
+ //
+ // The alignment container is the flex container's content box.
+ if (placeholderContainerIsContainingBlock) {
+ alignAreaSize = aAbsPosCBSize.ConvertTo(pcWM, aAbsPosCBWM);
+ // aAbsPosCBSize is the padding-box, so substract the padding to get the
+ // content box.
+ alignAreaSize -=
+ aPlaceholderContainer->GetLogicalUsedPadding(pcWM).Size(pcWM);
+ } else {
+ alignAreaSize = aPlaceholderContainer->GetLogicalSize(pcWM);
+ LogicalMargin pcBorderPadding =
+ aPlaceholderContainer->GetLogicalUsedBorderAndPadding(pcWM);
+ alignAreaSize -= pcBorderPadding.Size(pcWM);
+ }
} else if (parentType == nsGkAtoms::gridContainerFrame) {
// This abspos elem's parent is a grid container. Per CSS Grid 10.1 & 10.2:
// - If the grid container *also* generates the abspos containing block (a
@@ -424,7 +440,7 @@ OffsetToAlignedStaticPos(const ReflowInput& aKidReflowInput,
// the alignment container, too. (And its size is aAbsPosCBSize.)
// - Otherwise, we use the grid's padding box as the alignment container.
// https://drafts.csswg.org/css-grid/#static-position
- if (aPlaceholderContainer == aKidReflowInput.mCBReflowInput->mFrame) {
+ if (placeholderContainerIsContainingBlock) {
// The alignment container is the grid area that we're using as the
// absolute containing block.
alignAreaSize = aAbsPosCBSize.ConvertTo(pcWM, aAbsPosCBWM);
diff --git a/layout/reftests/w3c-css/submitted/flexbox/position-absolute-containing-block-001-ref.html b/layout/reftests/w3c-css/submitted/flexbox/position-absolute-containing-block-001-ref.html
new file mode 100644
index 000000000..08eec8691
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/flexbox/position-absolute-containing-block-001-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8"><title>CSS Test Reference</title>
+<meta charset="utf-8">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<style>
+.parent {
+ position: fixed;
+ top: 0;
+ left: 0;
+ display: block;
+ width: 200px;
+ height: 200px;
+ background: yellow;
+}
+
+.child {
+ position: absolute;
+ left: 50px;
+ top: 50px;
+ width: 100px;
+ height: 100px;
+ background: green;
+}
+</style>
+</head><body><div class="parent"><div class="child"></div></div>
+</body></html> \ No newline at end of file
diff --git a/layout/reftests/w3c-css/submitted/flexbox/position-absolute-containing-block-001.html b/layout/reftests/w3c-css/submitted/flexbox/position-absolute-containing-block-001.html
new file mode 100644
index 000000000..5f623cb84
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/flexbox/position-absolute-containing-block-001.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8"><title>CSS Test: Absolutely positioned children of flex container with CSS align</title>
+<meta charset="utf-8">
+<link rel="help" href="https://drafts.csswg.org/css-flexbox/#abspos-items">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1386654">
+<link rel="match" href="https://hg.mozilla.org/mozilla-central/raw-file/6538de3b6137/layout/reftests/w3c-css/submitted/flexbox/position-absolute-containing-block-001-ref.html">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<style>
+.parent {
+ position: fixed;
+ top: 0;
+ left: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 200px;
+ height: 200px;
+ background: yellow;
+}
+
+.child {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ background: green;
+}
+</style>
+</head><body><div class="parent"><div class="child"></div></div>
+</body></html> \ No newline at end of file
diff --git a/layout/reftests/w3c-css/submitted/flexbox/position-absolute-containing-block-002-ref.html b/layout/reftests/w3c-css/submitted/flexbox/position-absolute-containing-block-002-ref.html
new file mode 100644
index 000000000..df730047b
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/flexbox/position-absolute-containing-block-002-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8"><title>CSS Test Reference</title>
+<meta charset="utf-8">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<style>
+.parent {
+ position: fixed;
+ top: 0;
+ left: 0;
+ display: block;
+ width: 200px;
+ height: 200px;
+ background: yellow;
+}
+
+.child {
+ position: absolute;
+ left: 60px;
+ top: 60px;
+ width: 100px;
+ height: 100px;
+ background: green;
+}
+</style>
+</head><body><div class="parent"><div class="child"></div></div>
+</body></html> \ No newline at end of file
diff --git a/layout/reftests/w3c-css/submitted/flexbox/position-absolute-containing-block-002.html b/layout/reftests/w3c-css/submitted/flexbox/position-absolute-containing-block-002.html
new file mode 100644
index 000000000..9e89c5ad0
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/flexbox/position-absolute-containing-block-002.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8"><title>CSS Test: Absolutely positioned children of flex container with CSS align</title>
+<meta charset="utf-8">
+<link rel="help" href="https://drafts.csswg.org/css-flexbox/#abspos-items">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1386654">
+<link rel="match" href="https://hg.mozilla.org/mozilla-central/raw-file/6538de3b6137/layout/reftests/w3c-css/submitted/flexbox/position-absolute-containing-block-002-ref.html">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<style>
+.parent {
+ position: fixed;
+ top: 0;
+ left: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 180px;
+ height: 180px;
+
+ /* Expand the background area to 200px, without touching the content-box,
+ which is what flex absolute children should be aligned relative to. */
+ border-top: 5px solid yellow;
+ padding-top: 15px;
+ border-left: 5px solid yellow;
+ padding-left: 15px;
+
+ background: yellow;
+}
+
+.child {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ background: green;
+}
+</style>
+</head><body><div class="parent"><div class="child"></div></div>
+</body></html> \ No newline at end of file
diff --git a/layout/reftests/w3c-css/submitted/flexbox/reftest.list b/layout/reftests/w3c-css/submitted/flexbox/reftest.list
index fd8bfccc9..3df75aee6 100644
--- a/layout/reftests/w3c-css/submitted/flexbox/reftest.list
+++ b/layout/reftests/w3c-css/submitted/flexbox/reftest.list
@@ -211,3 +211,7 @@ fails == flexbox-min-height-auto-002b.html flexbox-min-height-auto-002-ref.html
== flexbox-single-line-clamp-1.html flexbox-single-line-clamp-1-ref.html
== flexbox-single-line-clamp-2.html flexbox-single-line-clamp-2-ref.html
== flexbox-single-line-clamp-3.html flexbox-single-line-clamp-3-ref.html
+
+# Flexbox as an absolute containing block.
+== position-absolute-containing-block-001.html position-absolute-containing-block-001-ref.html
+== position-absolute-containing-block-002.html position-absolute-containing-block-002-ref.html
diff --git a/layout/style/Loader.cpp b/layout/style/Loader.cpp
index a1a0fcfd9..0ce337e29 100644
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -1677,10 +1677,6 @@ Loader::LoadSheet(SheetLoadData* aLoadData,
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
if (httpChannel) {
- // Send a minimal Accept header for text/css
- httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
- NS_LITERAL_CSTRING("text/css,*/*;q=0.1"),
- false);
nsCOMPtr<nsIURI> referrerURI = aLoadData->GetReferrerURI();
if (referrerURI)
httpChannel->SetReferrerWithPolicy(referrerURI,
diff --git a/media/libcubeb/src/cubeb.c b/media/libcubeb/src/cubeb.c
index e0375c394..eb22a9b94 100644
--- a/media/libcubeb/src/cubeb.c
+++ b/media/libcubeb/src/cubeb.c
@@ -562,7 +562,7 @@ int cubeb_set_log_callback(cubeb_log_level log_level,
void
cubeb_crash()
{
- abort();
*((volatile int *) NULL) = 0;
+ abort();
}
diff --git a/media/libcubeb/src/cubeb_audiounit.cpp b/media/libcubeb/src/cubeb_audiounit.cpp
index f24dfbff2..9483c2795 100644
--- a/media/libcubeb/src/cubeb_audiounit.cpp
+++ b/media/libcubeb/src/cubeb_audiounit.cpp
@@ -1443,12 +1443,12 @@ audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, set_buff
buffer_size_changed_callback,
stm);
if (r != noErr) {
- return CUBEB_ERROR;
if (set_side == INPUT) {
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/input/kAudioDevicePropertyBufferFrameSize", r);
} else {
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/output/kAudioDevicePropertyBufferFrameSize", r);
}
+ return CUBEB_ERROR;
}
if (!stm->buffer_size_change_state && count >= 30) {
diff --git a/mfbt/RangedPtr.h b/mfbt/RangedPtr.h
index a07c1f4f8..a3d4ec103 100644
--- a/mfbt/RangedPtr.h
+++ b/mfbt/RangedPtr.h
@@ -212,7 +212,7 @@ public:
return *this;
}
- T& operator[](int aIndex) const
+ T& operator[](ptrdiff_t aIndex) const
{
MOZ_ASSERT(size_t(aIndex > 0 ? aIndex : -aIndex) <= size_t(-1) / sizeof(T));
return *create(mPtr + aIndex);
diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js
index 3666ca425..aed20c854 100644
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1264,6 +1264,7 @@ pref("javascript.options.strict", false);
#ifdef DEBUG
pref("javascript.options.strict.debug", false);
#endif
+pref("javascript.options.unboxed_objects", false);
pref("javascript.options.baselinejit", true);
pref("javascript.options.ion", true);
pref("javascript.options.asmjs", true);
@@ -1474,7 +1475,10 @@ pref("network.http.request.max-start-delay", 10);
pref("network.http.request.max-attempts", 10);
// Headers
-pref("network.http.accept.default", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
+pref("network.http.accept.default", "*/*");
+pref("network.http.accept.navigation", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
+pref("network.http.accept.image", "image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5");
+pref("network.http.accept.style", "text/css,*/*;q=0.1");
// Prefs allowing granular control of referers
// 0=don't send any, 1=send only on clicks, 2=send on image requests as well
diff --git a/netwerk/base/security-prefs.js b/netwerk/base/security-prefs.js
index ea0b2236d..ef78ddccb 100644
--- a/netwerk/base/security-prefs.js
+++ b/netwerk/base/security-prefs.js
@@ -117,10 +117,6 @@ pref("security.webauth.u2f", false);
pref("security.webauth.u2f_enable_softtoken", false);
pref("security.webauth.u2f_enable_usbtoken", false);
-pref("security.ssl.errorReporting.enabled", true);
-pref("security.ssl.errorReporting.url", "https://incoming.telemetry.mozilla.org/submit/sslreports/");
-pref("security.ssl.errorReporting.automatic", false);
-
// OCSP must-staple
pref("security.ssl.enable_ocsp_must_staple", true);
diff --git a/netwerk/protocol/ftp/FTPChannelChild.cpp b/netwerk/protocol/ftp/FTPChannelChild.cpp
index f8284aae3..f52586744 100644
--- a/netwerk/protocol/ftp/FTPChannelChild.cpp
+++ b/netwerk/protocol/ftp/FTPChannelChild.cpp
@@ -516,33 +516,6 @@ FTPChannelChild::RecvOnStopRequest(const nsresult& aChannelStatus,
return true;
}
-class nsFtpChildAsyncAlert : public Runnable
-{
-public:
- nsFtpChildAsyncAlert(nsIPrompt *aPrompter, nsString aResponseMsg)
- : mPrompter(aPrompter)
- , mResponseMsg(aResponseMsg)
- {
- MOZ_COUNT_CTOR(nsFtpChildAsyncAlert);
- }
-protected:
- virtual ~nsFtpChildAsyncAlert()
- {
- MOZ_COUNT_DTOR(nsFtpChildAsyncAlert);
- }
-public:
- NS_IMETHOD Run() override
- {
- if (mPrompter) {
- mPrompter->Alert(nullptr, mResponseMsg.get());
- }
- return NS_OK;
- }
-private:
- nsCOMPtr<nsIPrompt> mPrompter;
- nsString mResponseMsg;
-};
-
class MaybeDivertOnStopFTPEvent : public ChannelEvent
{
public:
@@ -600,19 +573,7 @@ FTPChannelChild::DoOnStopRequest(const nsresult& aChannelStatus,
(void)mListener->OnStopRequest(this, mListenerContext, aChannelStatus);
if (NS_FAILED(aChannelStatus) && !aErrorMsg.IsEmpty()) {
- nsCOMPtr<nsIPrompt> prompter;
- GetCallback(prompter);
- if (prompter) {
- nsCOMPtr<nsIRunnable> alertEvent;
- if (aUseUTF8) {
- alertEvent = new nsFtpChildAsyncAlert(prompter,
- NS_ConvertUTF8toUTF16(aErrorMsg));
- } else {
- alertEvent = new nsFtpChildAsyncAlert(prompter,
- NS_ConvertASCIItoUTF16(aErrorMsg));
- }
- NS_DispatchToMainThread(alertEvent);
- }
+ NS_ERROR("FTP error on stop request.");
}
mListener = nullptr;
diff --git a/netwerk/protocol/ftp/nsFtpConnectionThread.cpp b/netwerk/protocol/ftp/nsFtpConnectionThread.cpp
index 2ae12846a..0dae7ca92 100644
--- a/netwerk/protocol/ftp/nsFtpConnectionThread.cpp
+++ b/netwerk/protocol/ftp/nsFtpConnectionThread.cpp
@@ -29,7 +29,6 @@
#include "nsIStreamListenerTee.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
-#include "nsIStringBundle.h"
#include "nsAuthInformationHolder.h"
#include "nsIProtocolProxyService.h"
#include "nsICancelable.h"
@@ -926,38 +925,7 @@ nsFtpState::R_syst() {
mServerType = FTP_VMS_TYPE;
} else {
NS_ERROR("Server type list format unrecognized.");
- // Guessing causes crashes.
- // (Of course, the parsing code should be more robust...)
- nsCOMPtr<nsIStringBundleService> bundleService =
- do_GetService(NS_STRINGBUNDLE_CONTRACTID);
- if (!bundleService)
- return FTP_ERROR;
-
- nsCOMPtr<nsIStringBundle> bundle;
- nsresult rv = bundleService->CreateBundle(NECKO_MSGS_URL,
- getter_AddRefs(bundle));
- if (NS_FAILED(rv))
- return FTP_ERROR;
-
- char16_t* ucs2Response = ToNewUnicode(mResponseMsg);
- const char16_t *formatStrings[1] = { ucs2Response };
- NS_NAMED_LITERAL_STRING(name, "UnsupportedFTPServer");
-
- nsXPIDLString formattedString;
- rv = bundle->FormatStringFromName(name.get(), formatStrings, 1,
- getter_Copies(formattedString));
- free(ucs2Response);
- if (NS_FAILED(rv))
- return FTP_ERROR;
-
- // TODO(darin): this code should not be dictating UI like this!
- nsCOMPtr<nsIPrompt> prompter;
- mChannel->GetCallback(prompter);
- if (prompter)
- prompter->Alert(nullptr, formattedString.get());
-
- // since we just alerted the user, clear mResponseMsg,
- // which is displayed to the user.
+ // clear mResponseMsg, which is displayed to the user.
mResponseMsg = "";
return FTP_ERROR;
}
@@ -1779,34 +1747,6 @@ nsFtpState::KillControlConnection()
mControlConnection = nullptr;
}
-class nsFtpAsyncAlert : public Runnable
-{
-public:
- nsFtpAsyncAlert(nsIPrompt *aPrompter, nsString aResponseMsg)
- : mPrompter(aPrompter)
- , mResponseMsg(aResponseMsg)
- {
- MOZ_COUNT_CTOR(nsFtpAsyncAlert);
- }
-protected:
- virtual ~nsFtpAsyncAlert()
- {
- MOZ_COUNT_DTOR(nsFtpAsyncAlert);
- }
-public:
- NS_IMETHOD Run() override
- {
- if (mPrompter) {
- mPrompter->Alert(nullptr, mResponseMsg.get());
- }
- return NS_OK;
- }
-private:
- nsCOMPtr<nsIPrompt> mPrompter;
- nsString mResponseMsg;
-};
-
-
nsresult
nsFtpState::StopProcessing()
{
@@ -1818,23 +1758,8 @@ nsFtpState::StopProcessing()
LOG_INFO(("FTP:(%x) nsFtpState stopping", this));
if (NS_FAILED(mInternalError) && !mResponseMsg.IsEmpty()) {
- // check to see if the control status is bad.
- // web shell wont throw an alert. we better:
-
- // XXX(darin): this code should not be dictating UI like this!
- nsCOMPtr<nsIPrompt> prompter;
- mChannel->GetCallback(prompter);
- if (prompter) {
- nsCOMPtr<nsIRunnable> alertEvent;
- if (mUseUTF8) {
- alertEvent = new nsFtpAsyncAlert(prompter,
- NS_ConvertUTF8toUTF16(mResponseMsg));
- } else {
- alertEvent = new nsFtpAsyncAlert(prompter,
- NS_ConvertASCIItoUTF16(mResponseMsg));
- }
- NS_DispatchToMainThread(alertEvent);
- }
+ NS_ERROR("FTP: bad control status.");
+ // check to see if the control status is bad; forward the error message.
nsCOMPtr<nsIFTPChannelParentInternal> ftpChanP;
mChannel->GetCallback(ftpChanP);
if (ftpChanP) {
diff --git a/netwerk/protocol/http/AlternateServices.cpp b/netwerk/protocol/http/AlternateServices.cpp
index b3e6babe3..ee2fa9331 100644
--- a/netwerk/protocol/http/AlternateServices.cpp
+++ b/netwerk/protocol/http/AlternateServices.cpp
@@ -654,8 +654,13 @@ private:
{
nsID channelId;
nsLoadFlags flags;
+
+ nsContentPolicyType contentPolicyType =
+ loadInfo ? loadInfo->GetExternalContentPolicyType()
+ : nsIContentPolicy::TYPE_OTHER;
+
if (NS_FAILED(gHttpHandler->NewChannelId(&channelId)) ||
- NS_FAILED(chan->Init(uri, caps, nullptr, 0, nullptr, channelId)) ||
+ NS_FAILED(chan->Init(uri, caps, nullptr, 0, nullptr, channelId, contentPolicyType)) ||
NS_FAILED(chan->SetAllowAltSvc(false)) ||
NS_FAILED(chan->SetRedirectMode(nsIHttpChannelInternal::REDIRECT_MODE_ERROR)) ||
NS_FAILED(chan->SetLoadInfo(loadInfo)) ||
diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp
index 9e43d89e0..86e177e71 100644
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -151,7 +151,8 @@ HttpBaseChannel::Init(nsIURI *aURI,
nsProxyInfo *aProxyInfo,
uint32_t aProxyResolveFlags,
nsIURI *aProxyURI,
- const nsID& aChannelId)
+ const nsID& aChannelId,
+ nsContentPolicyType aContentPolicyType)
{
LOG(("HttpBaseChannel::Init [this=%p]\n", this));
@@ -200,7 +201,7 @@ HttpBaseChannel::Init(nsIURI *aURI,
rv = mRequestHead.SetHeader(nsHttp::Host, hostLine);
if (NS_FAILED(rv)) return rv;
- rv = gHttpHandler->AddStandardRequestHeaders(&mRequestHead, isHTTPS);
+ rv = gHttpHandler->AddStandardRequestHeaders(&mRequestHead, isHTTPS, aContentPolicyType);
if (NS_FAILED(rv)) return rv;
nsAutoCString type;
diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h
index 9aa696a70..8def0f23c 100644
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -99,7 +99,8 @@ public:
virtual nsresult Init(nsIURI *aURI, uint32_t aCaps, nsProxyInfo *aProxyInfo,
uint32_t aProxyResolveFlags,
nsIURI *aProxyURI,
- const nsID& aChannelId);
+ const nsID& aChannelId,
+ nsContentPolicyType aContentPolicyType);
// nsIRequest
NS_IMETHOD GetName(nsACString& aName) override;
diff --git a/netwerk/protocol/http/TunnelUtils.cpp b/netwerk/protocol/http/TunnelUtils.cpp
index 4cc24a07f..6880e0187 100644
--- a/netwerk/protocol/http/TunnelUtils.cpp
+++ b/netwerk/protocol/http/TunnelUtils.cpp
@@ -23,6 +23,7 @@
#include "nsNetCID.h"
#include "nsServiceManagerUtils.h"
#include "nsComponentManagerUtils.h"
+#include "nsSocketTransport2.h"
namespace mozilla {
namespace net {
@@ -42,6 +43,7 @@ TLSFilterTransaction::TLSFilterTransaction(nsAHttpTransaction *aWrapped,
, mSegmentReader(aReader)
, mSegmentWriter(aWriter)
, mForce(false)
+ , mReadSegmentReturnValue(NS_OK)
, mNudgeCounter(0)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
@@ -130,6 +132,19 @@ TLSFilterTransaction::Close(nsresult aReason)
}
mTransaction->Close(aReason);
mTransaction = nullptr;
+
+ RefPtr<NullHttpTransaction> baseTrans(do_QueryReferent(mWeakTrans));
+ SpdyConnectTransaction *trans = baseTrans
+ ? baseTrans->QuerySpdyConnectTransaction()
+ : nullptr;
+
+ LOG(("TLSFilterTransaction::Close %p aReason=%" PRIx32 " trans=%p\n",
+ this, static_cast<uint32_t>(aReason), trans));
+
+ if (trans) {
+ trans->Close(aReason);
+ trans = nullptr;
+ }
}
nsresult
@@ -140,7 +155,7 @@ TLSFilterTransaction::OnReadSegment(const char *aData,
LOG(("TLSFilterTransaction %p OnReadSegment %d (buffered %d)\n",
this, aCount, mEncryptedTextUsed));
- mReadSegmentBlocked = false;
+ mReadSegmentReturnValue = NS_OK;
MOZ_ASSERT(mSegmentReader);
if (!mSecInfo) {
return NS_ERROR_FAILURE;
@@ -188,10 +203,12 @@ TLSFilterTransaction::OnReadSegment(const char *aData,
return NS_OK;
}
// mTransaction ReadSegments actually obscures this code, so
- // keep it in a member var for this::ReadSegments to insepct. Similar
+ // keep it in a member var for this::ReadSegments to inspect. Similar
// to nsHttpConnection::mSocketOutCondition
- mReadSegmentBlocked = (PR_GetError() == PR_WOULD_BLOCK_ERROR);
- return mReadSegmentBlocked ? NS_BASE_STREAM_WOULD_BLOCK : NS_ERROR_FAILURE;
+ PRErrorCode code = PR_GetError();
+ mReadSegmentReturnValue = ErrorAccordingToNSPR(code);
+
+ return mReadSegmentReturnValue;
}
aCount -= written;
aData += written;
@@ -273,10 +290,18 @@ TLSFilterTransaction::OnWriteSegment(char *aData,
mFilterReadCode = NS_OK;
int32_t bytesRead = PR_Read(mFD, aData, aCount);
if (bytesRead == -1) {
- if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
+ PRErrorCode code = PR_GetError();
+ if (code == PR_WOULD_BLOCK_ERROR) {
return NS_BASE_STREAM_WOULD_BLOCK;
}
- return NS_ERROR_FAILURE;
+ // If reading from the socket succeeded (NS_SUCCEEDED(mFilterReadCode)),
+ // but the nss layer encountered an error remember the error.
+ if (NS_SUCCEEDED(mFilterReadCode)) {
+ mFilterReadCode = ErrorAccordingToNSPR(code);
+ LOG(("TLSFilterTransaction::OnWriteSegment %p nss error %" PRIx32 ".\n",
+ this, static_cast<uint32_t>(mFilterReadCode)));
+ }
+ return mFilterReadCode;
}
*outCountRead = bytesRead;
@@ -303,7 +328,7 @@ TLSFilterTransaction::FilterInput(char *aBuf, int32_t aAmount)
if (NS_SUCCEEDED(mFilterReadCode) && outCountRead) {
LOG(("TLSFilterTransaction::FilterInput rv=%x read=%d input from net "
"1 layer stripped, 1 still on\n", mFilterReadCode, outCountRead));
- if (mReadSegmentBlocked) {
+ if (mReadSegmentReturnValue == NS_BASE_STREAM_WOULD_BLOCK) {
mNudgeCounter = 0;
}
}
@@ -325,19 +350,18 @@ TLSFilterTransaction::ReadSegments(nsAHttpSegmentReader *aReader,
return NS_ERROR_UNEXPECTED;
}
- mReadSegmentBlocked = false;
+ mReadSegmentReturnValue = NS_OK;
mSegmentReader = aReader;
nsresult rv = mTransaction->ReadSegments(this, aCount, outCountRead);
LOG(("TLSFilterTransaction %p called trans->ReadSegments rv=%x %d\n",
this, rv, *outCountRead));
- if (NS_SUCCEEDED(rv) && mReadSegmentBlocked) {
- rv = NS_BASE_STREAM_WOULD_BLOCK;
+ if (NS_SUCCEEDED(rv) && (mReadSegmentReturnValue == NS_BASE_STREAM_WOULD_BLOCK)) {
LOG(("TLSFilterTransaction %p read segment blocked found rv=%x\n",
- this, rv));
+ this, static_cast<uint32_t>(rv)));
Connection()->ForceSend();
}
- return rv;
+ return NS_SUCCEEDED(rv) ? mReadSegmentReturnValue : rv;
}
nsresult
@@ -442,7 +466,10 @@ TLSFilterTransaction::Notify(nsITimer *timer)
if (timer != mTimer) {
return NS_ERROR_UNEXPECTED;
}
- StartTimerCallback();
+ nsresult rv = StartTimerCallback();
+ if (NS_FAILED(rv)) {
+ Close(rv);
+ }
return NS_OK;
}
@@ -456,7 +483,7 @@ TLSFilterTransaction::StartTimerCallback()
// This class can be called re-entrantly, so cleanup m* before ->on()
RefPtr<NudgeTunnelCallback> cb(mNudgeCallback);
mNudgeCallback = nullptr;
- cb->OnTunnelNudged(this);
+ return cb->OnTunnelNudged(this);
}
return NS_OK;
}
@@ -675,10 +702,12 @@ TLSFilterTransaction::TakeSubTransactions(
}
nsresult
-TLSFilterTransaction::SetProxiedTransaction(nsAHttpTransaction *aTrans)
+TLSFilterTransaction::SetProxiedTransaction(nsAHttpTransaction *aTrans,
+ nsAHttpTransaction *aSpdyConnectTransaction)
{
- LOG(("TLSFilterTransaction::SetProxiedTransaction [this=%p] aTrans=%p\n",
- this, aTrans));
+ LOG(("TLSFilterTransaction::SetProxiedTransaction [this=%p] aTrans=%p, "
+ "aSpdyConnectTransaction=%p\n",
+ this, aTrans, aSpdyConnectTransaction));
mTransaction = aTrans;
nsCOMPtr<nsIInterfaceRequestor> callbacks;
@@ -688,6 +717,8 @@ TLSFilterTransaction::SetProxiedTransaction(nsAHttpTransaction *aTrans)
secCtrl->SetNotificationCallbacks(callbacks);
}
+ mWeakTrans = do_GetWeakReference(aSpdyConnectTransaction);
+
return NS_OK;
}
@@ -1075,7 +1106,7 @@ SpdyConnectTransaction::MapStreamToHttpConnection(nsISocketTransport *aTransport
if (mForcePlainText) {
mTunneledConn->ForcePlainText();
} else {
- mTunneledConn->SetupSecondaryTLS();
+ mTunneledConn->SetupSecondaryTLS(this);
mTunneledConn->SetInSpdyTunnel(true);
}
diff --git a/netwerk/protocol/http/TunnelUtils.h b/netwerk/protocol/http/TunnelUtils.h
index 20cfaf7ee..4a003082e 100644
--- a/netwerk/protocol/http/TunnelUtils.h
+++ b/netwerk/protocol/http/TunnelUtils.h
@@ -93,10 +93,11 @@ class TLSFilterTransaction;
class NudgeTunnelCallback : public nsISupports
{
public:
- virtual void OnTunnelNudged(TLSFilterTransaction *) = 0;
+ virtual nsresult OnTunnelNudged(TLSFilterTransaction *) = 0;
};
-#define NS_DECL_NUDGETUNNELCALLBACK void OnTunnelNudged(TLSFilterTransaction *) override;
+#define NS_DECL_NUDGETUNNELCALLBACK \
+ nsresult OnTunnelNudged(TLSFilterTransaction *) override;
class TLSFilterTransaction final
: public nsAHttpTransaction
@@ -121,7 +122,8 @@ public:
nsresult CommitToSegmentSize(uint32_t size, bool forceCommitment) override;
nsresult GetTransactionSecurityInfo(nsISupports **) override;
nsresult NudgeTunnel(NudgeTunnelCallback *callback);
- nsresult SetProxiedTransaction(nsAHttpTransaction *aTrans);
+ MOZ_MUST_USE nsresult SetProxiedTransaction(nsAHttpTransaction *aTrans,
+ nsAHttpTransaction *aSpdyConnectTransaction = nullptr);
void newIODriver(nsIAsyncInputStream *aSocketIn,
nsIAsyncOutputStream *aSocketOut,
nsIAsyncInputStream **outSocketIn,
@@ -153,6 +155,7 @@ private:
private:
RefPtr<nsAHttpTransaction> mTransaction;
+ nsWeakPtr mWeakTrans; // SpdyConnectTransaction *
nsCOMPtr<nsISupports> mSecInfo;
nsCOMPtr<nsITimer> mTimer;
RefPtr<NudgeTunnelCallback> mNudgeCallback;
@@ -168,7 +171,7 @@ private:
nsresult mFilterReadCode;
bool mForce;
- bool mReadSegmentBlocked;
+ nsresult mReadSegmentReturnValue;
uint32_t mNudgeCounter;
};
diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp
index a890c51b3..481df5ff0 100644
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -324,10 +324,16 @@ nsHttpChannel::Init(nsIURI *uri,
nsProxyInfo *proxyInfo,
uint32_t proxyResolveFlags,
nsIURI *proxyURI,
- const nsID& channelId)
-{
- nsresult rv = HttpBaseChannel::Init(uri, caps, proxyInfo,
- proxyResolveFlags, proxyURI, channelId);
+ const nsID& channelId,
+ nsContentPolicyType aContentPolicyType)
+{
+ nsresult rv = HttpBaseChannel::Init(uri,
+ caps,
+ proxyInfo,
+ proxyResolveFlags,
+ proxyURI,
+ channelId,
+ aContentPolicyType);
if (NS_FAILED(rv))
return rv;
diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h
index 554875b1c..0038e1f71 100644
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -123,7 +123,8 @@ public:
virtual nsresult Init(nsIURI *aURI, uint32_t aCaps, nsProxyInfo *aProxyInfo,
uint32_t aProxyResolveFlags,
nsIURI *aProxyURI,
- const nsID& aChannelId) override;
+ const nsID& aChannelId,
+ nsContentPolicyType aContentPolicyType) override;
nsresult OnPush(const nsACString &uri, Http2PushedStream *pushedStream);
diff --git a/netwerk/protocol/http/nsHttpConnection.cpp b/netwerk/protocol/http/nsHttpConnection.cpp
index 8ccba76e2..505d849c0 100644
--- a/netwerk/protocol/http/nsHttpConnection.cpp
+++ b/netwerk/protocol/http/nsHttpConnection.cpp
@@ -535,16 +535,16 @@ npnComplete:
return true;
}
-void
+nsresult
nsHttpConnection::OnTunnelNudged(TLSFilterTransaction *trans)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
LOG(("nsHttpConnection::OnTunnelNudged %p\n", this));
if (trans != mTLSFilter) {
- return;
+ return NS_OK;
}
LOG(("nsHttpConnection::OnTunnelNudged %p Calling OnSocketWritable\n", this));
- OnSocketWritable();
+ return OnSocketWritable();
}
// called on the socket thread
@@ -639,7 +639,9 @@ nsHttpConnection::Activate(nsAHttpTransaction *trans, uint32_t caps, int32_t pri
}
if (mTLSFilter) {
- mTLSFilter->SetProxiedTransaction(trans);
+ RefPtr<NullHttpTransaction> baseTrans(do_QueryReferent(mWeakTrans));
+ rv = mTLSFilter->SetProxiedTransaction(trans, baseTrans);
+ NS_ENSURE_SUCCESS(rv, rv);
mTransaction = mTLSFilter;
}
@@ -1979,7 +1981,7 @@ nsHttpConnection::OnSocketReadable()
// negotiation are known (which is determined from the write path).
// If the server speaks SPDY it is likely the readable data here is
// a spdy settings frame and without NPN it would be misinterpreted
- // as HTTP/*
+ // as HTTP
LOG(("nsHttpConnection::OnSocketReadable %p return due to inactive "
"tunnel setup but incomplete NPN state\n", this));
@@ -2019,12 +2021,14 @@ nsHttpConnection::OnSocketReadable()
}
void
-nsHttpConnection::SetupSecondaryTLS()
+nsHttpConnection::SetupSecondaryTLS(nsAHttpTransaction *aSpdyConnectTransaction)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
MOZ_ASSERT(!mTLSFilter);
- LOG(("nsHttpConnection %p SetupSecondaryTLS %s %d\n",
- this, mConnInfo->Origin(), mConnInfo->OriginPort()));
+ LOG(("nsHttpConnection %p SetupSecondaryTLS %s %d "
+ "aSpdyConnectTransaction=%p\n",
+ this, mConnInfo->Origin(), mConnInfo->OriginPort(),
+ aSpdyConnectTransaction));
nsHttpConnectionInfo *ci = nullptr;
if (mTransaction) {
@@ -2041,6 +2045,7 @@ nsHttpConnection::SetupSecondaryTLS()
if (mTransaction) {
mTransaction = mTLSFilter;
}
+ mWeakTrans = do_GetWeakReference(aSpdyConnectTransaction);
}
void
diff --git a/netwerk/protocol/http/nsHttpConnection.h b/netwerk/protocol/http/nsHttpConnection.h
index 08eea1de2..ce7523eb5 100644
--- a/netwerk/protocol/http/nsHttpConnection.h
+++ b/netwerk/protocol/http/nsHttpConnection.h
@@ -202,7 +202,7 @@ public:
static nsresult MakeConnectString(nsAHttpTransaction *trans,
nsHttpRequestHead *request,
nsACString &result);
- void SetupSecondaryTLS();
+ void SetupSecondaryTLS(nsAHttpTransaction *aSpdyConnectTransaction = nullptr);
void SetInSpdyTunnel(bool arg);
// Check active connections for traffic (or not). SPDY connections send a
@@ -281,6 +281,7 @@ private:
// transaction is open, otherwise it is null.
RefPtr<nsAHttpTransaction> mTransaction;
RefPtr<TLSFilterTransaction> mTLSFilter;
+ nsWeakPtr mWeakTrans; // SpdyConnectTransaction *
RefPtr<nsHttpHandler> mHttpHandler; // keep gHttpHandler alive
diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp
index 477961454..0f4c94202 100644
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -468,7 +468,9 @@ nsHttpHandler::InitConnectionMgr()
}
nsresult
-nsHttpHandler::AddStandardRequestHeaders(nsHttpRequestHead *request, bool isSecure)
+nsHttpHandler::AddStandardRequestHeaders(nsHttpRequestHead *request,
+ bool isSecure,
+ nsContentPolicyType aContentPolicyType)
{
nsresult rv;
@@ -481,7 +483,20 @@ nsHttpHandler::AddStandardRequestHeaders(nsHttpRequestHead *request, bool isSecu
// Add the "Accept" header. Note, this is set as an override because the
// service worker expects to see it. The other "default" headers are
// hidden from service worker interception.
- rv = request->SetHeader(nsHttp::Accept, mAccept,
+ nsAutoCString accept;
+ if (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
+ aContentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT) {
+ accept.Assign(mAcceptNavigation);
+ } else if (aContentPolicyType == nsIContentPolicy::TYPE_IMAGE ||
+ aContentPolicyType == nsIContentPolicy::TYPE_IMAGESET) {
+ accept.Assign(mAcceptImage);
+ } else if (aContentPolicyType == nsIContentPolicy::TYPE_STYLESHEET) {
+ accept.Assign(mAcceptStyle);
+ } else {
+ accept.Assign(mAcceptDefault);
+ }
+
+ rv = request->SetHeader(nsHttp::Accept, accept,
false, nsHttpHeaderArray::eVarietyRequestOverride);
if (NS_FAILED(rv)) return rv;
@@ -1268,12 +1283,36 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
mQoSBits = (uint8_t) clamped(val, 0, 0xff);
}
+ if (PREF_CHANGED(HTTP_PREF("accept.navigation"))) {
+ nsXPIDLCString accept;
+ rv = prefs->GetCharPref(HTTP_PREF("accept.navigation"),
+ getter_Copies(accept));
+ if (NS_SUCCEEDED(rv))
+ SetAccept(accept, ACCEPT_NAVIGATION);
+ }
+
+ if (PREF_CHANGED(HTTP_PREF("accept.image"))) {
+ nsXPIDLCString accept;
+ rv = prefs->GetCharPref(HTTP_PREF("accept.image"),
+ getter_Copies(accept));
+ if (NS_SUCCEEDED(rv))
+ SetAccept(accept, ACCEPT_IMAGE);
+ }
+
+ if (PREF_CHANGED(HTTP_PREF("accept.style"))) {
+ nsXPIDLCString accept;
+ rv = prefs->GetCharPref(HTTP_PREF("accept.style"),
+ getter_Copies(accept));
+ if (NS_SUCCEEDED(rv))
+ SetAccept(accept, ACCEPT_STYLE);
+ }
+
if (PREF_CHANGED(HTTP_PREF("accept.default"))) {
nsXPIDLCString accept;
rv = prefs->GetCharPref(HTTP_PREF("accept.default"),
getter_Copies(accept));
if (NS_SUCCEEDED(rv))
- SetAccept(accept);
+ SetAccept(accept, ACCEPT_DEFAULT);
}
if (PREF_CHANGED(HTTP_PREF("accept-encoding"))) {
@@ -1897,9 +1936,21 @@ nsHttpHandler::SetAcceptLanguages()
}
nsresult
-nsHttpHandler::SetAccept(const char *aAccept)
+nsHttpHandler::SetAccept(const char *aAccept, AcceptType aType)
{
- mAccept = aAccept;
+ switch (aType) {
+ case ACCEPT_NAVIGATION:
+ mAcceptNavigation = aAccept;
+ break;
+ case ACCEPT_IMAGE:
+ mAcceptImage = aAccept;
+ break;
+ case ACCEPT_STYLE:
+ mAcceptStyle = aAccept;
+ break;
+ case ACCEPT_DEFAULT:
+ mAcceptDefault = aAccept;
+ }
return NS_OK;
}
@@ -2057,7 +2108,11 @@ nsHttpHandler::NewProxiedChannel2(nsIURI *uri,
rv = NewChannelId(&channelId);
NS_ENSURE_SUCCESS(rv, rv);
- rv = httpChannel->Init(uri, caps, proxyInfo, proxyResolveFlags, proxyURI, channelId);
+ nsContentPolicyType contentPolicyType =
+ aLoadInfo ? aLoadInfo->GetExternalContentPolicyType()
+ : nsIContentPolicy::TYPE_OTHER;
+
+ rv = httpChannel->Init(uri, caps, proxyInfo, proxyResolveFlags, proxyURI, channelId, contentPolicyType);
if (NS_FAILED(rv))
return rv;
diff --git a/netwerk/protocol/http/nsHttpHandler.h b/netwerk/protocol/http/nsHttpHandler.h
index f1ec0f947..67b9ebe0e 100644
--- a/netwerk/protocol/http/nsHttpHandler.h
+++ b/netwerk/protocol/http/nsHttpHandler.h
@@ -15,6 +15,7 @@
#include "nsCOMPtr.h"
#include "nsWeakReference.h"
+#include "nsIContentPolicy.h"
#include "nsIHttpProtocolHandler.h"
#include "nsIObserver.h"
#include "nsISpeculativeConnect.h"
@@ -50,6 +51,14 @@ enum FrameCheckLevel {
FRAMECHECK_STRICT
};
+// Fetch spec different http Accept types
+enum AcceptType {
+ ACCEPT_NAVIGATION,
+ ACCEPT_IMAGE,
+ ACCEPT_STYLE,
+ ACCEPT_DEFAULT,
+};
+
//-----------------------------------------------------------------------------
// nsHttpHandler - protocol handler for HTTP and HTTPS
//-----------------------------------------------------------------------------
@@ -70,7 +79,7 @@ public:
nsHttpHandler();
nsresult Init();
- nsresult AddStandardRequestHeaders(nsHttpRequestHead *, bool isSecure);
+ nsresult AddStandardRequestHeaders(nsHttpRequestHead *, bool isSecure, nsContentPolicyType aContentPolicyType);
nsresult AddConnectionHeader(nsHttpRequestHead *,
uint32_t capabilities);
bool IsAcceptableEncoding(const char *encoding, bool isSecure);
@@ -385,7 +394,7 @@ private:
void InitUserAgentComponents();
void PrefsChanged(nsIPrefBranch *prefs, const char *pref);
- nsresult SetAccept(const char *);
+ nsresult SetAccept(const char *, AcceptType aType);
nsresult SetAcceptLanguages();
nsresult SetAcceptEncodings(const char *, bool mIsSecure);
@@ -394,8 +403,8 @@ private:
void NotifyObservers(nsIHttpChannel *chan, const char *event);
static void TimerCallback(nsITimer * aTimer, void * aClosure);
+
private:
-
// cached services
nsMainThreadPtrHandle<nsIIOService> mIOService;
nsMainThreadPtrHandle<nsIStreamConverterService> mStreamConvSvc;
@@ -460,7 +469,10 @@ private:
bool mPipeliningOverSSL;
bool mEnforceAssocReq;
- nsCString mAccept;
+ nsCString mAcceptNavigation;
+ nsCString mAcceptImage;
+ nsCString mAcceptStyle;
+ nsCString mAcceptDefault;
nsCString mAcceptLanguages;
nsCString mHttpAcceptEncodings;
nsCString mHttpsAcceptEncodings;
diff --git a/netwerk/sctp/datachannel/DataChannel.cpp b/netwerk/sctp/datachannel/DataChannel.cpp
index ebc430f8c..19be43d1c 100644
--- a/netwerk/sctp/datachannel/DataChannel.cpp
+++ b/netwerk/sctp/datachannel/DataChannel.cpp
@@ -1928,12 +1928,21 @@ DataChannelConnection::ReceiveCallback(struct socket* sock, void *data, size_t d
if (!data) {
usrsctp_close(sock); // SCTP has finished shutting down
} else {
- mLock.AssertCurrentThreadOwns();
+ bool locked = false;
+ if (!IsSTSThread()) {
+ mLock.Lock();
+ locked = true;
+ } else {
+ mLock.AssertCurrentThreadOwns();
+ }
if (flags & MSG_NOTIFICATION) {
HandleNotification(static_cast<union sctp_notification *>(data), datalen);
} else {
HandleMessage(data, datalen, ntohl(rcv.rcv_ppid), rcv.rcv_sid);
}
+ if (locked) {
+ mLock.Unlock();
+ }
}
// sctp allocates 'data' with malloc(), and expects the receiver to free
// it (presumably with free).
diff --git a/netwerk/test/mochitests/mochitest.ini b/netwerk/test/mochitests/mochitest.ini
index f8a919031..3cd5a674b 100644
--- a/netwerk/test/mochitests/mochitest.ini
+++ b/netwerk/test/mochitests/mochitest.ini
@@ -25,3 +25,5 @@ support-files =
[test_viewsource_unlinkable.html]
[test_xhr_method_case.html]
[test_1396395.html]
+[test_accept_header.html]
+support-files = test_accept_header.sjs
diff --git a/netwerk/test/mochitests/test_accept_header.html b/netwerk/test/mochitests/test_accept_header.html
new file mode 100644
index 000000000..b8434230f
--- /dev/null
+++ b/netwerk/test/mochitests/test_accept_header.html
@@ -0,0 +1,106 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Accept header</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script>
+
+// All the requests are sent to test_accept_header.sjs which will return
+// different content based on the queryString. When the queryString is 'get',
+// test_accept_header.sjs returns a JSON object with the latest request and its
+// accept header value.
+
+function test_last_request_and_continue(query, expected) {
+ fetch("test_accept_header.sjs?get").then(r => r.json()).then(json => {
+ is(json.type, query, "Expected: " + query);
+ is(json.accept, expected, "Accept header: " + expected);
+ next();
+ });
+}
+
+function test_iframe() {
+ let observer = new PerformanceObserver(function(list, obj) {
+ obj.disconnect();
+
+ list.getEntries().forEach(entry => {
+ if (entry.name.endsWith("test_accept_header.sjs?iframe")) {
+ obj.disconnect();
+ test_last_request_and_continue("iframe", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
+ }
+ });
+ });
+
+ observer.observe({entryTypes: ["resource"]});
+
+ let ifr = document.createElement("iframe");
+ ifr.src = "test_accept_header.sjs?iframe";
+ document.body.appendChild(ifr);
+}
+
+function test_image() {
+ let i = new Image();
+ i.src = "test_accept_header.sjs?image";
+ i.onload = function() {
+ // Fetch spec says we should have: "image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5"
+ test_last_request_and_continue("image", "image/webp,image/png,image/*;q=0.8,*/*;q=0.5");
+ }
+}
+
+function test_style() {
+ let observer = new PerformanceObserver(function(list, obj) {
+ obj.disconnect();
+
+ list.getEntries().forEach(entry => {
+ if (entry.name.endsWith("test_accept_header.sjs?style")) {
+ obj.disconnect();
+ test_last_request_and_continue("style", "text/css,*/*;q=0.1");
+ }
+ });
+ });
+
+ observer.observe({entryTypes: ["resource"]});
+
+ let head = document.getElementsByTagName("head")[0];
+ let link = document.createElement("link");
+ link.rel = "stylesheet";
+ link.type = "text/css";
+ link.href = "test_accept_header.sjs?style";
+ head.appendChild(link);
+}
+
+function test_worker() {
+ let w = new Worker("test_accept_header.sjs?worker");
+ w.onmessage = function() {
+ test_last_request_and_continue("worker", "*/*");
+ }
+}
+
+let tests = [
+ test_iframe,
+ test_image,
+ test_style,
+ test_worker,
+];
+
+function next() {
+ if (tests.length == 0) {
+ SimpleTest.finish();
+ return;
+ }
+
+ let test = tests.shift();
+ test();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+SpecialPowers.pushPrefEnv({ "set": [
+ [ "dom.enable_performance_observer", true ]
+]}, next);
+
+</script>
+</body>
+</html>
diff --git a/netwerk/test/mochitests/test_accept_header.sjs b/netwerk/test/mochitests/test_accept_header.sjs
new file mode 100644
index 000000000..035c886aa
--- /dev/null
+++ b/netwerk/test/mochitests/test_accept_header.sjs
@@ -0,0 +1,48 @@
+function handleRequest(request, response) {
+ response.setStatusLine(request.httpVersion, "200", "OK");
+
+ if (request.queryString == "worker") {
+ response.setHeader("Content-Type", "application/json", false);
+ response.write("postMessage(42)");
+
+ setState("data", JSON.stringify({type: "worker", accept: request.getHeader("Accept") }));
+ return;
+ }
+
+ if (request.queryString == "image") {
+ // A 1x1 PNG image.
+ // Source: https://commons.wikimedia.org/wiki/File:1x1.png (Public Domain)
+ const IMAGE = atob("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAA" +
+ "ACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=");
+
+ response.setHeader("Content-Type", "image/png", false);
+ response.write(IMAGE);
+
+ setState("data", JSON.stringify({type: "image", accept: request.getHeader("Accept") }));
+ return;
+ }
+
+ if (request.queryString == "style") {
+ response.setHeader("Content-Type", "text/css", false);
+ response.write("");
+
+ setState("data", JSON.stringify({type: "style", accept: request.getHeader("Accept") }));
+ return;
+ }
+
+ if (request.queryString == "iframe") {
+ response.setHeader("Content-Type", "text/html", false);
+ response.write("<h1>Hello world!</h1>");
+
+ setState("data", JSON.stringify({type: "iframe", accept: request.getHeader("Accept") }));
+ return;
+ }
+
+ if (request.queryString == "get") {
+ response.setHeader("Content-Type", "text/javascript", false);
+ response.write(getState("data"));
+
+ setState("data", "");
+ return;
+ }
+}
diff --git a/security/manager/ssl/nsSiteSecurityService.cpp b/security/manager/ssl/nsSiteSecurityService.cpp
index fc38f4e64..cfee79d8d 100644
--- a/security/manager/ssl/nsSiteSecurityService.cpp
+++ b/security/manager/ssl/nsSiteSecurityService.cpp
@@ -210,8 +210,8 @@ const uint64_t kSixtyDaysInSeconds = 60 * 24 * 60 * 60;
nsSiteSecurityService::nsSiteSecurityService()
: mMaxMaxAge(kSixtyDaysInSeconds)
, mUsePreloadList(true)
- , mPreloadListTimeOffset(0)
, mUseStsService(true)
+ , mPreloadListTimeOffset(0)
{
}
diff --git a/toolkit/components/downloads/moz.build b/toolkit/components/downloads/moz.build
index 20394a70d..e611f4010 100644
--- a/toolkit/components/downloads/moz.build
+++ b/toolkit/components/downloads/moz.build
@@ -53,9 +53,10 @@ if CONFIG['OS_ARCH'] == 'WINNT':
'nsDownloadScanner.cpp',
]
-# XXX - Until Suite builds off XULRunner we can't guarantee our implementation
-# of nsIDownloadManagerUI overrides toolkit's.
-if not CONFIG['MOZ_SUITE']:
+# The Communicator Downloads Manager uses its own DownloadManagerUI
+# component and it can't be guaranteed that its implimentation will override
+# toolkit's so don't include toolkit's
+if not CONFIG['MOZ_SUITE'] and not CONFIG['BINOC_COMM_DLMGR']:
EXTRA_COMPONENTS += [
'nsDownloadManagerUI.js',
'nsDownloadManagerUI.manifest',
diff --git a/toolkit/content/widgets/browser.xml b/toolkit/content/widgets/browser.xml
index 5a0a99bf8..9c72e86d8 100644
--- a/toolkit/content/widgets/browser.xml
+++ b/toolkit/content/widgets/browser.xml
@@ -43,15 +43,11 @@
<parameter name="fn"/>
<body>
<![CDATA[
- if (!this.isRemoteBrowser) {
- this.inLoadURI = true;
- try {
- fn();
- } finally {
- this.inLoadURI = false;
- }
- } else {
+ this.inLoadURI = true;
+ try {
fn();
+ } finally {
+ this.inLoadURI = false;
}
]]>
</body>
@@ -307,7 +303,7 @@
<method name="preserveLayers">
<parameter name="preserve"/>
<body>
- // Only useful for remote browsers.
+ <!-- Only useful for remote browsers. -->
</body>
</method>
@@ -338,8 +334,9 @@
</getter>
</property>
+ <!-- stubbed to false until all callers are removed -->
<property name="isRemoteBrowser"
- onget="return (this.getAttribute('remote') == 'true');"
+ onget="return false;"
readonly="true"/>
<property name="messageManager"
@@ -920,7 +917,7 @@
os.addObserver(this, "browser:purge-session-history", true);
// enable global history if we weren't told otherwise
- if (!this.hasAttribute("disableglobalhistory") && !this.isRemoteBrowser) {
+ if (!this.hasAttribute("disableglobalhistory")) {
try {
this.docShell.useGlobalHistory = true;
} catch (ex) {
@@ -949,9 +946,7 @@
this.relatedBrowser = relatedBrowser;
}
- if (!this.isRemoteBrowser) {
- this.addEventListener("pagehide", this.onPageHide, true);
- }
+ this.addEventListener("pagehide", this.onPageHide, true);
if (this.messageManager) {
this.messageManager.addMessageListener("PopupBlocking:UpdateBlockedPopups", this);
@@ -1000,9 +995,7 @@
this.lastURI = null;
- if (!this.isRemoteBrowser) {
- this.removeEventListener("pagehide", this.onPageHide, true);
- }
+ this.removeEventListener("pagehide", this.onPageHide, true);
if (this._autoScrollNeedsCleanup) {
// we polluted the global scope, so clean it up
@@ -1288,9 +1281,6 @@
<parameter name="aOtherBrowser"/>
<body>
<![CDATA[
- if (this.isRemoteBrowser != aOtherBrowser.isRemoteBrowser)
- throw new Error("Can only swap docshells between browsers in the same process.");
-
// Give others a chance to swap state.
// IMPORTANT: Since a swapDocShells call does not swap the messageManager
// instances attached to a browser to aOtherBrowser, others
@@ -1324,28 +1314,6 @@
"_webNavigation"
];
- if (this.isRemoteBrowser) {
- fieldsToSwap.push(...[
- "_remoteWebNavigation",
- "_remoteWebNavigationImpl",
- "_remoteWebProgressManager",
- "_remoteWebProgress",
- "_remoteFinder",
- "_securityUI",
- "_documentURI",
- "_documentContentType",
- "_contentTitle",
- "_characterSet",
- "_contentPrincipal",
- "_imageDocument",
- "_fullZoom",
- "_textZoom",
- "_isSyntheticDocument",
- "_innerWindowID",
- "_manifestURI",
- ]);
- }
-
var ourFieldValues = {};
var otherFieldValues = {};
for (let field of fieldsToSwap) {
@@ -1368,27 +1336,10 @@
aOtherBrowser[field] = ourFieldValues[field];
}
- if (!this.isRemoteBrowser) {
- // Null the current nsITypeAheadFind instances so that they're
- // lazily re-created on access. We need to do this because they
- // might have attached the wrong docShell.
- this._fastFind = aOtherBrowser._fastFind = null;
- }
- else {
- // Rewire the remote listeners
- this._remoteWebNavigationImpl.swapBrowser(this);
- aOtherBrowser._remoteWebNavigationImpl.swapBrowser(aOtherBrowser);
-
- if (this._remoteWebProgressManager && aOtherBrowser._remoteWebProgressManager) {
- this._remoteWebProgressManager.swapBrowser(this);
- aOtherBrowser._remoteWebProgressManager.swapBrowser(aOtherBrowser);
- }
-
- if (this._remoteFinder)
- this._remoteFinder.swapBrowser(this);
- if (aOtherBrowser._remoteFinder)
- aOtherBrowser._remoteFinder.swapBrowser(aOtherBrowser);
- }
+ // Null the current nsITypeAheadFind instances so that they're
+ // lazily re-created on access. We need to do this because they
+ // might have attached the wrong docShell.
+ this._fastFind = aOtherBrowser._fastFind = null;
event = new CustomEvent("EndSwapDocShells", {"detail": aOtherBrowser});
this.dispatchEvent(event);
@@ -1540,11 +1491,6 @@
event.preventDefault();
}
- // No need to handle "dragover" in e10s, since nsDocShellTreeOwner.cpp in the child process
- // handles that case using "@mozilla.org/content/dropped-link-handler;1" service.
- if (this.isRemoteBrowser)
- return;
-
let linkHandler = Components.classes["@mozilla.org/content/dropped-link-handler;1"].
getService(Components.interfaces.nsIDroppedLinkHandler);
if (linkHandler.canDropLink(event, false))
@@ -1553,9 +1499,7 @@
</handler>
<handler event="drop" group="system">
<![CDATA[
- // No need to handle "drop" in e10s, since nsDocShellTreeOwner.cpp in the child process
- // handles that case using "@mozilla.org/content/dropped-link-handler;1" service.
- if (!this.droppedLinkHandler || event.defaultPrevented || this.isRemoteBrowser)
+ if (!this.droppedLinkHandler || event.defaultPrevented)
return;
let name = { };
diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
index 59a72c432..26e432b3c 100644
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -4130,9 +4130,12 @@ XRE_InitCommandLine(int aArgc, char* aArgv[])
#endif
const char *path = nullptr;
- ArgResult ar = CheckArg("greomni", false, &path);
+ ArgResult ar = CheckArg("greomni", true, &path);
if (ar == ARG_BAD) {
- PR_fprintf(PR_STDERR, "Error: argument --greomni requires a path argument\n");
+ PR_fprintf(PR_STDERR,
+ "Error: argument --greomni requires a path argument or the "
+ "--osint argument was specified with the --greomni argument "
+ "which is invalid.\n");
return NS_ERROR_FAILURE;
}
@@ -4146,9 +4149,12 @@ XRE_InitCommandLine(int aArgc, char* aArgv[])
return rv;
}
- ar = CheckArg("appomni", false, &path);
+ ar = CheckArg("appomni", true, &path);
if (ar == ARG_BAD) {
- PR_fprintf(PR_STDERR, "Error: argument --appomni requires a path argument\n");
+ PR_fprintf(PR_STDERR,
+ "Error: argument --appomni requires a path argument or the "
+ "--osint argument was specified with the --appomni argument "
+ "which is invalid.\n");
return NS_ERROR_FAILURE;
}
diff --git a/uriloader/exthandler/win/nsOSHelperAppService.cpp b/uriloader/exthandler/win/nsOSHelperAppService.cpp
index f01f3b49b..48b6f1795 100644
--- a/uriloader/exthandler/win/nsOSHelperAppService.cpp
+++ b/uriloader/exthandler/win/nsOSHelperAppService.cpp
@@ -29,8 +29,6 @@
#define LOG(args) MOZ_LOG(mLog, mozilla::LogLevel::Debug, args)
// helper methods: forward declarations...
-static nsresult GetExtensionFrom4xRegistryInfo(const nsACString& aMimeType,
- nsString& aFileExtension);
static nsresult GetExtensionFromWindowsMimeDatabase(const nsACString& aMimeType,
nsString& aFileExtension);
@@ -77,79 +75,45 @@ static nsresult GetExtensionFromWindowsMimeDatabase(const nsACString& aMimeType,
return NS_OK;
}
-// We have a serious problem!! I have this content type and the windows registry only gives me
-// helper apps based on extension. Right now, we really don't have a good place to go for
-// trying to figure out the extension for a particular mime type....One short term hack is to look
-// this information in 4.x (it's stored in the windows regsitry).
-static nsresult GetExtensionFrom4xRegistryInfo(const nsACString& aMimeType,
- nsString& aFileExtension)
-{
- nsCOMPtr<nsIWindowsRegKey> regKey =
- do_CreateInstance("@mozilla.org/windows-registry-key;1");
- if (!regKey)
- return NS_ERROR_NOT_AVAILABLE;
-
- nsresult rv = regKey->
- Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
- NS_LITERAL_STRING("Software\\Netscape\\Netscape Navigator\\Suffixes"),
- nsIWindowsRegKey::ACCESS_QUERY_VALUE);
- if (NS_FAILED(rv))
- return NS_ERROR_NOT_AVAILABLE;
-
- rv = regKey->ReadStringValue(NS_ConvertASCIItoUTF16(aMimeType),
- aFileExtension);
- if (NS_FAILED(rv))
- return NS_OK;
-
- aFileExtension.Insert(char16_t('.'), 0);
-
- // this may be a comma separated list of extensions...just take the
- // first one for now...
-
- int32_t pos = aFileExtension.FindChar(char16_t(','));
- if (pos > 0) {
- // we have a comma separated list of types...
- // truncate everything after the first comma (including the comma)
- aFileExtension.Truncate(pos);
- }
-
- return NS_OK;
-}
-
nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char * aProtocolScheme, bool * aHandlerExists)
{
// look up the protocol scheme in the windows registry....if we find a match then we have a handler for it...
*aHandlerExists = false;
if (aProtocolScheme && *aProtocolScheme)
{
- // Vista: use new application association interface
- if (mAppAssoc) {
- wchar_t * pResult = nullptr;
- NS_ConvertASCIItoUTF16 scheme(aProtocolScheme);
- // We are responsible for freeing returned strings.
- HRESULT hr = mAppAssoc->QueryCurrentDefault(scheme.get(),
- AT_URLPROTOCOL, AL_EFFECTIVE,
- &pResult);
- if (SUCCEEDED(hr)) {
- CoTaskMemFree(pResult);
- *aHandlerExists = true;
+ NS_ENSURE_TRUE(mAppAssoc, NS_ERROR_NOT_AVAILABLE);
+ wchar_t * pResult = nullptr;
+ NS_ConvertASCIItoUTF16 scheme(aProtocolScheme);
+ // We are responsible for freeing returned strings.
+ HRESULT hr = mAppAssoc->QueryCurrentDefault(scheme.get(),
+ AT_URLPROTOCOL, AL_EFFECTIVE,
+ &pResult);
+ if (SUCCEEDED(hr)) {
+ CoTaskMemFree(pResult);
+ // Check the registry to see if it's a valid handler.
+ nsCOMPtr<nsIWindowsRegKey> regKey = do_CreateInstance("@mozilla.org/windows-registry-key;1");
+ if (!regKey) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
+ nsDependentString(scheme.get()),
+ nsIWindowsRegKey::ACCESS_QUERY_VALUE);
+ if (NS_FAILED(rv)) {
+ // Open will fail if the registry key path doesn't exist.
+ return NS_OK;
+ }
+
+ bool hasValue;
+ rv = regKey->HasValue(NS_LITERAL_STRING("URL Protocol"), &hasValue);
+ if (NS_FAILED(rv)) {
+ return NS_ERROR_FAILURE;
+ }
+ if (!hasValue) {
+ return NS_OK;
}
- return NS_OK;
- }
- HKEY hKey;
- LONG err = ::RegOpenKeyExW(HKEY_CLASSES_ROOT,
- NS_ConvertASCIItoUTF16(aProtocolScheme).get(),
- 0,
- KEY_QUERY_VALUE,
- &hKey);
- if (err == ERROR_SUCCESS)
- {
- err = ::RegQueryValueExW(hKey, L"URL Protocol",
- nullptr, nullptr, nullptr, nullptr);
- *aHandlerExists = (err == ERROR_SUCCESS);
- // close the key
- ::RegCloseKey(hKey);
+ *aHandlerExists = true;
}
}
@@ -180,40 +144,21 @@ NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(const nsACString&
}
}
- if (mAppAssoc) {
- // Vista: use new application association interface
- wchar_t * pResult = nullptr;
- // We are responsible for freeing returned strings.
- HRESULT hr = mAppAssoc->QueryCurrentDefault(buf.get(),
- AT_URLPROTOCOL, AL_EFFECTIVE,
- &pResult);
- if (SUCCEEDED(hr)) {
- nsCOMPtr<nsIFile> app;
- nsAutoString appInfo(pResult);
- CoTaskMemFree(pResult);
- if (NS_SUCCEEDED(GetDefaultAppInfo(appInfo, _retval, getter_AddRefs(app))))
- return NS_OK;
- }
- return NS_ERROR_NOT_AVAILABLE;
+ NS_ENSURE_TRUE(mAppAssoc, NS_ERROR_NOT_AVAILABLE);
+ wchar_t * pResult = nullptr;
+ // We are responsible for freeing returned strings.
+ HRESULT hr = mAppAssoc->QueryCurrentDefault(buf.get(),
+ AT_URLPROTOCOL, AL_EFFECTIVE,
+ &pResult);
+ if (SUCCEEDED(hr)) {
+ nsCOMPtr<nsIFile> app;
+ nsAutoString appInfo(pResult);
+ CoTaskMemFree(pResult);
+ if (NS_SUCCEEDED(GetDefaultAppInfo(appInfo, _retval, getter_AddRefs(app))))
+ return NS_OK;
}
- nsCOMPtr<nsIFile> app;
- GetDefaultAppInfo(buf, _retval, getter_AddRefs(app));
-
- if (!_retval.Equals(buf))
- return NS_OK;
-
- // Fall back to full path
- buf.AppendLiteral("\\shell\\open\\command");
- nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
- buf,
- nsIWindowsRegKey::ACCESS_QUERY_VALUE);
- if (NS_FAILED(rv))
- return NS_ERROR_NOT_AVAILABLE;
-
- rv = regKey->ReadStringValue(EmptyString(), _retval);
-
- return NS_SUCCEEDED(rv) ? NS_OK : NS_ERROR_NOT_AVAILABLE;
+ return NS_ERROR_NOT_AVAILABLE;
}
// GetMIMEInfoFromRegistry: This function obtains the values of some of the nsIMIMEInfo
@@ -421,36 +366,18 @@ already_AddRefed<nsMIMEInfoWin> nsOSHelperAppService::GetByExtension(const nsAFl
bool found;
// Retrieve the default application for this extension
- if (mAppAssoc) {
- // Vista: use the new application association COM interfaces
- // for resolving helpers.
- nsString assocType(fileExtToUse);
- wchar_t * pResult = nullptr;
- HRESULT hr = mAppAssoc->QueryCurrentDefault(assocType.get(),
- AT_FILEEXTENSION, AL_EFFECTIVE,
- &pResult);
- if (SUCCEEDED(hr)) {
- found = true;
- appInfo.Assign(pResult);
- CoTaskMemFree(pResult);
- }
- else {
- found = false;
- }
- }
- else
- {
- nsCOMPtr<nsIWindowsRegKey> regKey =
- do_CreateInstance("@mozilla.org/windows-registry-key;1");
- if (!regKey)
- return nullptr;
- nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
- fileExtToUse,
- nsIWindowsRegKey::ACCESS_QUERY_VALUE);
- if (NS_SUCCEEDED(rv)) {
- found = NS_SUCCEEDED(regKey->ReadStringValue(EmptyString(),
- appInfo));
- }
+ NS_ENSURE_TRUE(mAppAssoc, nullptr);
+ nsString assocType(fileExtToUse);
+ wchar_t * pResult = nullptr;
+ HRESULT hr = mAppAssoc->QueryCurrentDefault(assocType.get(),
+ AT_FILEEXTENSION, AL_EFFECTIVE,
+ &pResult);
+ if (SUCCEEDED(hr)) {
+ found = true;
+ appInfo.Assign(pResult);
+ CoTaskMemFree(pResult);
+ } else {
+ found = false;
}
// Bug 358297 - ignore the default handler, force the user to choose app
@@ -496,14 +423,9 @@ already_AddRefed<nsIMIMEInfo> nsOSHelperAppService::GetMIMEInfoFromOS(const nsAC
* We'll do extension-based lookup for this type later in this function.
*/
if (!aMIMEType.LowerCaseEqualsLiteral(APPLICATION_OCTET_STREAM)) {
- // (1) try to use the windows mime database to see if there is a mapping to a file extension
- // (2) try to see if we have some left over 4.x registry info we can peek at...
+ // try to use the windows mime database to see if there is a mapping to a file extension
GetExtensionFromWindowsMimeDatabase(aMIMEType, fileExtension);
LOG(("Windows mime database: extension '%s'\n", fileExtension.get()));
- if (fileExtension.IsEmpty()) {
- GetExtensionFrom4xRegistryInfo(aMIMEType, fileExtension);
- LOG(("4.x Registry: extension '%s'\n", fileExtension.get()));
- }
}
// If we found an extension for the type, do the lookup
RefPtr<nsMIMEInfoWin> mi;
diff --git a/xpcom/glue/nsTArray.h b/xpcom/glue/nsTArray.h
index 82586a79a..64af17bbb 100644
--- a/xpcom/glue/nsTArray.h
+++ b/xpcom/glue/nsTArray.h
@@ -1503,6 +1503,24 @@ public:
mozilla::Forward<Item>(aItem));
}
+ // Reconstruct the element at the given index, and return a pointer to the
+ // reconstructed element. This will destroy the existing element and
+ // default-construct a new one, giving you a state much like what single-arg
+ // InsertElementAt(), or no-arg AppendElement() does, but without changing the
+ // length of the array.
+ //
+ // array[idx] = T()
+ //
+ // would accomplish the same thing as long as T has the appropriate moving
+ // operator=, but some types don't for various reasons.
+ elem_type* ReconstructElementAt(index_type aIndex)
+ {
+ elem_type* elem = &ElementAt(aIndex);
+ elem_traits::Destruct(elem);
+ elem_traits::Construct(elem);
+ return elem;
+ }
+
// This method searches for the smallest index of an element that is strictly
// greater than |aItem|. If |aItem| is inserted at this index, the array will
// remain sorted and |aItem| would come after all elements that are equal to