--- a/.clang-format
+++ b/.clang-format
@@ -1,4 +1,30 @@
BasedOnStyle: Mozilla
# Ignore all comments because they aren't reflowed properly.
CommentPragmas: "^"
+
+# Force pointers to the type for C++.
+DerivePointerAlignment: false
+PointerAlignment: Left
+
+# Prevent the loss of indentation with these macros
+MacroBlockBegin: "^\
+NS_INTERFACE_MAP_BEGIN|\
+NS_INTERFACE_TABLE_HEAD|\
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION|\
+NS_IMPL_CYCLE_COLLECTION_.*_BEGIN|\
+NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED|\
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED|\
+NS_INTERFACE_TABLE_BEGIN|\
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED|\
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED$"
+MacroBlockEnd: "^\
+NS_INTERFACE_MAP_END|\
+NS_IMPL_CYCLE_COLLECTION_.*_END|\
+NS_INTERFACE_TABLE_END|\
+NS_INTERFACE_MAP_END_INHERITING|\
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END_INHERITED|\
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED$"
+
+SortIncludes: false
+
--- a/.clang-format-ignore
+++ b/.clang-format-ignore
@@ -1,3 +1,70 @@
-^mfbt/.*
-^js/.*
-^media/.*
+^build/clang-plugin/tests/.*
+^config/gcc-stl-wrapper.template.h
+^config/msvc-stl-wrapper.template.h
+^js/src/jsapi-tests/.*
+
+# Generated from ./tools/rewriting/ThirdPartyPaths.txt
+# awk '{print "^"$1".*"}' ./tools/rewriting/ThirdPartyPaths.txt
+^browser/components/translation/cld2/.*
+^build/stlport/.*
+^db/sqlite3/src/.*
+^dom/media/platforms/ffmpeg/libav.*
+^extensions/spellcheck/hunspell/src/.*
+^gfx/2d/convolver.*
+^gfx/2d/image_operations.*
+^gfx/angle/.*
+^gfx/cairo/.*
+^gfx/graphite2/.*
+^gfx/harfbuzz/.*
+^gfx/ots/.*
+^gfx/qcms/.*
+^gfx/skia/.*
+^gfx/ycbcr/.*
+^intl/hyphenation/hyphen/.*
+^intl/icu/.*
+^ipc/chromium/.*
+^js/src/ctypes/libffi/.*
+^js/src/dtoa.c.*
+^js/src/jit/arm64/vixl/.*
+^media/gmp-clearkey/0.1/openaes/.*
+^media/kiss_fft/.*
+^media/libav/.*
+^media/libcubeb/.*
+^media/libjpeg/.*
+^media/libmkv/.*
+^media/libnestegg/.*
+^media/libogg/.*
+^media/libopus/.*
+^media/libpng/.*
+^media/libsoundtouch/.*
+^media/libspeex_resampler/.*
+^media/libstagefright/.*
+^media/libtheora/.*
+^media/libtremor/.*
+^media/libvorbis/.*
+^media/libvpx/.*
+^media/libyuv/.*
+^media/mtransport/.*
+^media/openmax_dl/.*
+^media/pocketsphinx/.*
+^media/sphinxbase/.*
+^media/webrtc/trunk/.*
+^memory/jemalloc/src/.*
+^mfbt/decimal/.*
+^mfbt/double-conversion/.*
+^mfbt/lz4.*
+^mobile/android/thirdparty/.*
+^modules/brotli/.*
+^modules/freetype2/.*
+^modules/libbz2/.*
+^modules/libmar/.*
+^modules/zlib/.*
+^netwerk/sctp/src/.*
+^netwerk/srtp/src/.*
+^nsprpub/.*
+^other-licenses/.*
+^security/sandbox/chromium/.*
+^testing/gtest/gmock/.*
+^testing/gtest/gtest/.*
+^toolkit/components/protobuf/.*
+^toolkit/crashreporter/google-breakpad/.*
--- a/.eslintignore
+++ b/.eslintignore
@@ -90,17 +90,16 @@ devtools/client/netmonitor/har/test/**
devtools/client/projecteditor/**
devtools/client/promisedebugger/**
devtools/client/responsivedesign/**
devtools/client/scratchpad/**
devtools/client/shadereditor/**
devtools/client/shared/*.jsm
devtools/client/shared/webgl-utils.js
devtools/client/shared/widgets/*.jsm
-devtools/client/sourceeditor/test/*.js
devtools/client/webaudioeditor/**
devtools/client/webconsole/**
!devtools/client/webconsole/panel.js
!devtools/client/webconsole/jsterm.js
!devtools/client/webconsole/console-commands.js
devtools/client/webide/**
!devtools/client/webide/components/webideCli.js
devtools/server/*.js
@@ -167,16 +166,17 @@ devtools/shared/pretty-fast/*
devtools/shared/sourcemap/*
devtools/shared/sprintfjs/*
devtools/shared/qrcode/decoder/*
devtools/shared/qrcode/encoder/*
devtools/client/shared/demangle.js
devtools/client/shared/vendor/*
devtools/client/sourceeditor/codemirror/*.js
devtools/client/sourceeditor/codemirror/**/*.js
+devtools/client/sourceeditor/test/cm_mode_ruby.js
devtools/client/sourceeditor/test/codemirror/*
devtools/client/inspector/markup/test/lib_*
devtools/client/jsonview/lib/require.js
devtools/server/actors/utils/automation-timeline.js
# Ignore devtools files testing sourcemaps / code style
devtools/client/debugger/test/mochitest/code_binary_search.js
devtools/client/debugger/test/mochitest/code_math.min.js
--- a/.hgtags
+++ b/.hgtags
@@ -124,8 +124,9 @@ fcef8ded82219c89298b4e376cfbdfba79a1d35a
67a788db9f07822cfef52351bbbe3745dff8bd7f FIREFOX_AURORA_44_BASE
99137d6d4061f408ae0869122649d8bdf489cc30 FIREFOX_AURORA_45_BASE
67c66c2878aed17ae3096d7db483ddbb2293c503 FIREFOX_AURORA_46_BASE
68d3781deda0d4d58ec9877862830db89669b3a5 FIREFOX_AURORA_47_BASE
1c6385ae1fe7e37d8f23f958ce14582f07af729e FIREFOX_AURORA_48_BASE
d98f20c25feeac4dd7ebbd1c022957df1ef58af4 FIREFOX_AURORA_49_BASE
465d150bc8be5bbf9f02a8607d4552b6a5e1697c FIREFOX_AURORA_50_BASE
fc69febcbf6c0dcc4b3dfc7a346d8d348798a65f FIREFOX_AURORA_51_BASE
+1196bf3032e1bce1fb07a01fd9082a767426c5fb FIREFOX_AURORA_52_BASE
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
#
# Modifying this file will now automatically clobber the buildbot machines \o/
#
# Are you updating CLOBBER because you think it's needed for your WebIDL
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
-Bug 1277704 - jemalloc may need a clobber
+Merge day clobber
\ No newline at end of file
--- a/accessible/html/HTMLFormControlAccessible.cpp
+++ b/accessible/html/HTMLFormControlAccessible.cpp
@@ -458,21 +458,16 @@ HTMLTextFieldAccessible::DoAction(uint8_
already_AddRefed<nsIEditor>
HTMLTextFieldAccessible::GetEditor() const
{
nsCOMPtr<nsIDOMNSEditableElement> editableElt(do_QueryInterface(mContent));
if (!editableElt)
return nullptr;
- // nsGenericHTMLElement::GetEditor has a security check.
- // Make sure we're not restricted by the permissions of
- // whatever script is currently running.
- mozilla::dom::AutoNoJSAPI nojsapi;
-
nsCOMPtr<nsIEditor> editor;
editableElt->GetEditor(getter_AddRefs(editor));
return editor.forget();
}
////////////////////////////////////////////////////////////////////////////////
// HTMLTextFieldAccessible: Widgets
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,10 +1,10 @@
<?xml version='1.0' encoding='UTF-8'?>
-<blocklist lastupdate="1479042428179" xmlns="http://www.mozilla.org/2006/addons-blocklist">
+<blocklist lastupdate="1479128827245" xmlns="http://www.mozilla.org/2006/addons-blocklist">
<emItems>
<emItem blockID="i988" id="{b12785f5-d8d0-4530-a3ea-5c4263b85bef}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i398" id="{377e5d4d-77e5-476a-8716-7e70a9272da0}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
@@ -346,18 +346,18 @@
<emItem blockID="i618" id="toolbar@ask.com">
<prefs/>
<versionRange minVersion="3.15.24" maxVersion="3.15.24.*" severity="1"/>
<versionRange minVersion="3.15.13" maxVersion="3.15.13.*" severity="1"/>
<versionRange minVersion="3.15.28" maxVersion="3.15.28.*" severity="1"/>
<versionRange minVersion="3.15.22" maxVersion="3.15.22.*" severity="1"/>
<versionRange minVersion="3.15.8" maxVersion="3.15.8.*" severity="1"/>
<versionRange minVersion="3.15.10" maxVersion="3.15.11.*" severity="1"/>
+ <versionRange minVersion="3.15.18" maxVersion="3.15.20.*" severity="1"/>
<versionRange minVersion="3.15.5" maxVersion="3.15.5.*" severity="1"/>
- <versionRange minVersion="3.15.18" maxVersion="3.15.20.*" severity="1"/>
<versionRange minVersion="3.15.31" maxVersion="3.15.31.*" severity="1"/>
<versionRange minVersion="3.15.26" maxVersion="3.15.26.*" severity="1"/>
</emItem>
<emItem blockID="i15" id="personas@christopher.beard">
<prefs/>
<versionRange minVersion="1.6" maxVersion="1.6">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange maxVersion="3.6.*" minVersion="3.6"/>
@@ -451,28 +451,28 @@
<emItem blockID="i1232" id="nosquint@urandom.ca">
<prefs/>
<versionRange minVersion="0" maxVersion="2.1.9.1-signed.1-signed" severity="1">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange maxVersion="*" minVersion="47"/>
</targetApplication>
</versionRange>
</emItem>
- <emItem blockID="i650" id="jid1-qj0w91o64N7Eeg@jetpack">
- <prefs/>
- <versionRange minVersion="39.5.1" maxVersion="47.0.4" severity="3"/>
- </emItem>
<emItem blockID="i748" id="{32da2f20-827d-40aa-a3b4-2fc4a294352e}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i544" id="/^(93abedcf-8e3a-4d02-b761-d1441e437c09@243f129d-aee2-42c2-bcd1-48858e1c22fd\.com|9acfc440-ac2d-417a-a64c-f6f14653b712@09f9a966-9258-4b12-af32-da29bdcc28c5\.com|58ad0086-1cfb-48bb-8ad2-33a8905572bc@5715d2be-69b9-4930-8f7e-64bdeb961cfd\.com)$/">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
+ <emItem blockID="i650" id="jid1-qj0w91o64N7Eeg@jetpack">
+ <prefs/>
+ <versionRange minVersion="39.5.1" maxVersion="47.0.4" severity="3"/>
+ </emItem>
<emItem blockID="i640" id="jid0-l9BxpNUhx1UUgRfKigWzSfrZqAc@jetpack">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i628" id="ffxtlbr@iminent.com">
<prefs>
<pref>browser.startup.homepage</pref>
<pref>browser.search.defaultenginename</pref>
@@ -593,28 +593,28 @@
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i730" id="25p@9eAkaLq.net">
<prefs>
<pref>browser.startup.homepage</pref>
</prefs>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
+ <emItem blockID="i400" id="{dd6b651f-dfb9-4142-b0bd-09912ad22674}">
+ <prefs/>
+ <versionRange minVersion="0" maxVersion="*" severity="1"/>
+ </emItem>
<emItem blockID="i1227" id="{A34CAF42-A3E3-11E5-945F-18C31D5D46B0}">
<prefs>
<pref>security.csp.enable</pref>
<pref>security.fileuri.strict_origin_policy</pref>
<pref>security.mixed_content.block_active_content</pref>
</prefs>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
- <emItem blockID="i400" id="{dd6b651f-dfb9-4142-b0bd-09912ad22674}">
- <prefs/>
- <versionRange minVersion="0" maxVersion="*" severity="1"/>
- </emItem>
<emItem blockID="i11" id="yslow@yahoo-inc.com">
<prefs/>
<versionRange minVersion="2.0.5" maxVersion="2.0.5">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange maxVersion="*" minVersion="3.5.7"/>
</targetApplication>
</versionRange>
</emItem>
@@ -665,21 +665,21 @@
<emItem blockID="i396" id="/@(ft|putlocker|clickmovie|m2k|sharerepo|smarter-?)downloader\.com$/">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i560" id="adsremoval@adsremoval.net">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
- <emItem blockID="i968" id="{184AA5E6-741D-464a-820E-94B3ABC2F3B4}">
+ <emItem blockID="i538" id="{354dbb0a-71d5-4e9f-9c02-6c88b9d387ba}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
- <emItem blockID="i538" id="{354dbb0a-71d5-4e9f-9c02-6c88b9d387ba}">
+ <emItem blockID="i968" id="{184AA5E6-741D-464a-820E-94B3ABC2F3B4}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i792" id="{8f894ed3-0bf2-498e-a103-27ef6e88899f}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i742" id="{f894a29a-f065-40c3-bb19-da6057778493}">
@@ -858,53 +858,53 @@
<emItem blockID="i1022" id="g99hiaoekjoasiijdkoleabsy278djasi@jetpack">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i499" id="{babb9931-ad56-444c-b935-38bffe18ad26}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
+ <emItem blockID="i718" id="G4Ce4@w.net">
+ <prefs>
+ <pref>browser.startup.homepage</pref>
+ </prefs>
+ <versionRange minVersion="0" maxVersion="*" severity="1"/>
+ </emItem>
+ <emItem blockID="i21" id="support@update-firefox.com">
+ <prefs/>
+ </emItem>
<emItem blockID="i75" id="firebug@software.joehewitt.com" os="Darwin,Linux">
<prefs/>
<versionRange minVersion="1.9.0" maxVersion="1.9.0" severity="1">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange maxVersion="9.*" minVersion="9.0a1"/>
</targetApplication>
</versionRange>
</emItem>
- <emItem blockID="i718" id="G4Ce4@w.net">
- <prefs>
- <pref>browser.startup.homepage</pref>
- </prefs>
- <versionRange minVersion="0" maxVersion="*" severity="1"/>
- </emItem>
- <emItem blockID="i21" id="support@update-firefox.com">
- <prefs/>
- </emItem>
<emItem blockID="i491" id="{515b2424-5911-40bd-8a2c-bdb20286d8f5}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i65" id="activity@facebook.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*"/>
</emItem>
- <emItem blockID="i476" id="mbroctone@facebook.com">
- <prefs/>
- <versionRange minVersion="0" maxVersion="*" severity="3"/>
- </emItem>
<emItem blockID="i532" id="249911bc-d1bd-4d66-8c17-df533609e6d8@c76f3de9-939e-4922-b73c-5d7a3139375d.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i1264" id="suchpony@suchpony.de">
<prefs/>
<versionRange minVersion="0" maxVersion="1.6.7" severity="3"/>
</emItem>
+ <emItem blockID="i476" id="mbroctone@facebook.com">
+ <prefs/>
+ <versionRange minVersion="0" maxVersion="*" severity="3"/>
+ </emItem>
<emItem blockID="i722" id="{9802047e-5a84-4da3-b103-c55995d147d1}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="i656" id="hdv@vovcacik.addons.mozilla.org">
<prefs/>
<versionRange minVersion="102.0" maxVersion="102.0" severity="3"/>
</emItem>
@@ -1155,48 +1155,48 @@
<pref>browser.search.defaultenginename</pref>
</prefs>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i972" id="831778-poidjao88DASfsAnindsd@jetpack">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
- <emItem blockID="i515" id="/^({bf9194c2-b86d-4ebc-9b53-1c08b6ff779e}|{61a83e16-7198-49c6-8874-3e4e8faeb4f3}|{f0af464e-5167-45cf-9cf0-66b396d1918c}|{5d9968c3-101c-4944-ba71-72d77393322d}|{01e86e69-a2f8-48a0-b068-83869bdba3d0})$/">
- <prefs/>
- <versionRange minVersion="0" maxVersion="*" severity="1"/>
- </emItem>
<emItem blockID="i844" id="e9d197d59f2f45f382b1aa5c14d82@8706aaed9b904554b5cb7984e9.com">
<prefs>
<pref>browser.startup.homepage</pref>
<pref>browser.search.defaultenginename</pref>
</prefs>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
+ <emItem blockID="i515" id="/^({bf9194c2-b86d-4ebc-9b53-1c08b6ff779e}|{61a83e16-7198-49c6-8874-3e4e8faeb4f3}|{f0af464e-5167-45cf-9cf0-66b396d1918c}|{5d9968c3-101c-4944-ba71-72d77393322d}|{01e86e69-a2f8-48a0-b068-83869bdba3d0})$/">
+ <prefs/>
+ <versionRange minVersion="0" maxVersion="*" severity="1"/>
+ </emItem>
<emItem blockID="i216" id="fdm_ffext@freedownloadmanager.org">
<prefs/>
<versionRange minVersion="1.0" maxVersion="1.3.1">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange maxVersion="*" minVersion="3.0a1"/>
</targetApplication>
</versionRange>
<versionRange minVersion="1.5.7.5" maxVersion="1.5.7.5" severity="1"/>
</emItem>
<emItem blockID="i596" id="{b99c8534-7800-48fa-bd71-519a46cdc7e1}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
+ <emItem blockID="i461" id="{8E9E3331-D360-4f87-8803-52DE43566502}">
+ <prefs/>
+ <versionRange minVersion="0" maxVersion="*" severity="1"/>
+ </emItem>
<emItem blockID="i818" id="contentarget@maildrop.cc">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
- <emItem blockID="i461" id="{8E9E3331-D360-4f87-8803-52DE43566502}">
- <prefs/>
- <versionRange minVersion="0" maxVersion="*" severity="1"/>
- </emItem>
<emItem blockID="i23" id="firefox@bandoo.com">
<prefs/>
<versionRange minVersion="5.0" maxVersion="5.0" severity="1">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange maxVersion="*" minVersion="3.7a1pre"/>
</targetApplication>
</versionRange>
</emItem>
@@ -1226,28 +1226,28 @@
<pref>browser.search.defaultenginename</pref>
</prefs>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
<emItem blockID="i448" id="{0134af61-7a0c-4649-aeca-90d776060cb3}">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
+ <emItem blockID="i92" id="play5@vide04flash.com">
+ <prefs/>
+ <versionRange minVersion="0" maxVersion="*"/>
+ </emItem>
<emItem blockID="i45" id="{22119944-ED35-4ab1-910B-E619EA06A115}">
<prefs/>
<versionRange minVersion="0.1" maxVersion="7.9.20.6" severity="1">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange maxVersion="*" minVersion="8.0a1"/>
</targetApplication>
</versionRange>
</emItem>
- <emItem blockID="i92" id="play5@vide04flash.com">
- <prefs/>
- <versionRange minVersion="0" maxVersion="*"/>
- </emItem>
<emItem blockID="i220" id="pricepeep@getpricepeep.com">
<prefs/>
<versionRange minVersion="0" maxVersion="2.1.0.19.99" severity="1"/>
</emItem>
<emItem blockID="i518" id="/^({d6e79525-4524-4707-9b97-1d70df8e7e59}|{ddb4644d-1a37-4e6d-8b6e-8e35e2a8ea6c}|{e55007f4-80c5-418e-ac33-10c4d60db01e}|{e77d8ca6-3a60-4ae9-8461-53b22fa3125b}|{e89a62b7-248e-492f-9715-43bf8c507a2f}|{5ce3e0cb-aa83-45cb-a7da-a2684f05b8f3})$/">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="1"/>
</emItem>
@@ -1888,28 +1888,28 @@
<versionRange maxVersion="*" minVersion="3.7a1pre"/>
</targetApplication>
</versionRange>
</emItem>
<emItem blockID="i1129" id="youtubeunblocker__web@unblocker.yt">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
+ <emItem blockID="i808" id="{c96d1ae6-c4cf-4984-b110-f5f561b33b5a}">
+ <prefs/>
+ <versionRange minVersion="0" maxVersion="*" severity="3"/>
+ </emItem>
<emItem blockID="i1214" id="firefoxdav@icloud.com">
<prefs/>
<versionRange minVersion="0" maxVersion="1.4.22" severity="1"/>
</emItem>
<emItem blockID="i66" id="youtubeer@youtuber.com">
<prefs/>
<versionRange minVersion="0" maxVersion="*"/>
</emItem>
- <emItem blockID="i808" id="{c96d1ae6-c4cf-4984-b110-f5f561b33b5a}">
- <prefs/>
- <versionRange minVersion="0" maxVersion="*" severity="3"/>
- </emItem>
<emItem blockID="i4" id="{4B3803EA-5230-4DC3-A7FC-33638F3D3542}">
<prefs/>
<versionRange minVersion="1.2" maxVersion="1.2">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange maxVersion="*" minVersion="3.0a1"/>
</targetApplication>
</versionRange>
</emItem>
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -634,16 +634,22 @@ toolbar:not(#TabsToolbar) > #personal-bo
#back-button > .toolbarbutton-menu-dropmarker,
#forward-button > .toolbarbutton-menu-dropmarker {
display: none;
}
.unified-nav-current {
font-weight: bold;
}
+.bookmark-item > label {
+ /* ensure we use the direction of the bookmarks label instead of the
+ * browser locale */
+ unicode-bidi: plaintext;
+}
+
toolbarbutton.bookmark-item {
max-width: 13em;
}
/* Apply crisp rendering for favicons at exactly 2dppx resolution */
@media (resolution: 2dppx) {
#alltabs-popup > .menuitem-iconic > .menu-iconic-left > .menu-iconic-icon,
.menuitem-with-favicon > .menu-iconic-left > .menu-iconic-icon {
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -794,19 +794,16 @@
if (this.mTabBrowser.isFindBarInitialized(this.mTab)) {
let findBar = this.mTabBrowser.getFindBar(this.mTab);
// Close the Find toolbar if we're in old-style TAF mode
if (findBar.findMode != findBar.FIND_NORMAL) {
findBar.close();
}
-
- // fix bug 253793 - turn off highlight when page changes
- findBar.getElement("highlight").checked = false;
}
// Don't clear the favicon if this onLocationChange was
// triggered by a pushState or a replaceState (bug 550565) or
// a hash change (bug 408415).
if (aWebProgress.isLoadingDocument && !isSameDocument) {
this.mBrowser.mIconURL = null;
}
@@ -2128,38 +2125,40 @@
var aSkipAnimation;
var aAllowMixedContent;
var aForceNotRemote;
var aNoReferrer;
var aUserContextId;
var aEventDetail;
var aRelatedBrowser;
var aOriginPrincipal;
+ var aDisallowInheritPrincipal;
var aOpener;
if (arguments.length == 2 &&
typeof arguments[1] == "object" &&
!(arguments[1] instanceof Ci.nsIURI)) {
let params = arguments[1];
- aReferrerURI = params.referrerURI;
- aReferrerPolicy = params.referrerPolicy;
- aCharset = params.charset;
- aPostData = params.postData;
- aOwner = params.ownerTab;
- aAllowThirdPartyFixup = params.allowThirdPartyFixup;
- aFromExternal = params.fromExternal;
- aRelatedToCurrent = params.relatedToCurrent;
- aSkipAnimation = params.skipAnimation;
- aAllowMixedContent = params.allowMixedContent;
- aForceNotRemote = params.forceNotRemote;
- aNoReferrer = params.noReferrer;
- aUserContextId = params.userContextId;
- aEventDetail = params.eventDetail;
- aRelatedBrowser = params.relatedBrowser;
- aOriginPrincipal = params.originPrincipal;
- aOpener = params.opener;
+ aReferrerURI = params.referrerURI;
+ aReferrerPolicy = params.referrerPolicy;
+ aCharset = params.charset;
+ aPostData = params.postData;
+ aOwner = params.ownerTab;
+ aAllowThirdPartyFixup = params.allowThirdPartyFixup;
+ aFromExternal = params.fromExternal;
+ aRelatedToCurrent = params.relatedToCurrent;
+ aSkipAnimation = params.skipAnimation;
+ aAllowMixedContent = params.allowMixedContent;
+ aForceNotRemote = params.forceNotRemote;
+ aNoReferrer = params.noReferrer;
+ aUserContextId = params.userContextId;
+ aEventDetail = params.eventDetail;
+ aRelatedBrowser = params.relatedBrowser;
+ aOriginPrincipal = params.originPrincipal;
+ aDisallowInheritPrincipal = params.disallowInheritPrincipal;
+ aOpener = params.opener;
}
// if we're adding tabs, we're past interrupt mode, ditch the owner
if (this.mCurrentTab.owner)
this.mCurrentTab.owner = null;
var t = document.createElementNS(NS_XUL, "tab");
@@ -2236,31 +2235,33 @@
t.dispatchEvent(evt);
if (!usingPreloadedContent && aOriginPrincipal) {
b.createAboutBlankContentViewer(aOriginPrincipal);
}
// If we didn't swap docShells with a preloaded browser
// then let's just continue loading the page normally.
- if (!usingPreloadedContent && !uriIsAboutBlank) {
+ if (!usingPreloadedContent && (!uriIsAboutBlank || aDisallowInheritPrincipal)) {
// pretend the user typed this so it'll be available till
// the document successfully loads
if (aURI && gInitialPages.indexOf(aURI) == -1)
b.userTypedValue = aURI;
let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
if (aAllowThirdPartyFixup) {
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FIXUP_SCHEME_TYPOS;
}
if (aFromExternal)
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL;
if (aAllowMixedContent)
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_MIXED_CONTENT;
+ if (aDisallowInheritPrincipal)
+ flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL;
try {
b.loadURIWithFlags(aURI, {
flags,
referrerURI: aNoReferrer ? null: aReferrerURI,
referrerPolicy: aReferrerPolicy,
charset: aCharset,
postData: aPostData,
});
--- a/browser/base/content/test/general/browser_aboutCertError.js
+++ b/browser/base/content/test/general/browser_aboutCertError.js
@@ -140,18 +140,17 @@ add_task(function* checkWrongSystemTimeW
let formatter = new Intl.DateTimeFormat();
// pretend we have a positively skewed (ahead) system time
let serverDate = new Date("2015/10/27");
let serverDateFmt = formatter.format(serverDate);
let localDateFmt = formatter.format(new Date());
let skew = Math.floor((Date.now() - serverDate.getTime()) / 1000);
- yield new Promise(r => SpecialPowers.pushPrefEnv({set:
- [[PREF_BLOCKLIST_CLOCK_SKEW_SECONDS, skew]]}, r));
+ yield SpecialPowers.pushPrefEnv({set: [[PREF_BLOCKLIST_CLOCK_SKEW_SECONDS, skew]]});
info("Loading a bad cert page with a skewed clock");
let message = yield Task.spawn(setUpPage);
isnot(message.divDisplay, "none", "Wrong time message information is visible");
ok(message.text.includes("because your clock appears to show the wrong time"),
"Correct error message found");
ok(message.text.includes("expired.example.com"), "URL found in error message");
@@ -162,47 +161,44 @@ add_task(function* checkWrongSystemTimeW
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
// pretend we have a negatively skewed (behind) system time
serverDate = new Date();
serverDate.setYear(serverDate.getFullYear() + 1);
serverDateFmt = formatter.format(serverDate);
skew = Math.floor((Date.now() - serverDate.getTime()) / 1000);
- yield new Promise(r => SpecialPowers.pushPrefEnv({set:
- [[PREF_BLOCKLIST_CLOCK_SKEW_SECONDS, skew]]}, r));
+ yield SpecialPowers.pushPrefEnv({set: [[PREF_BLOCKLIST_CLOCK_SKEW_SECONDS, skew]]});
info("Loading a bad cert page with a skewed clock");
message = yield Task.spawn(setUpPage);
isnot(message.divDisplay, "none", "Wrong time message information is visible");
ok(message.text.includes("because your clock appears to show the wrong time"),
"Correct error message found");
ok(message.text.includes("expired.example.com"), "URL found in error message");
ok(message.systemDate.includes(localDateFmt), "correct local date displayed");
ok(message.actualDate.includes(serverDateFmt), "correct server date displayed");
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
// pretend we only have a slightly skewed system time, four hours
skew = 60 * 60 * 4;
- yield new Promise(r => SpecialPowers.pushPrefEnv({set:
- [[PREF_BLOCKLIST_CLOCK_SKEW_SECONDS, skew]]}, r));
+ yield SpecialPowers.pushPrefEnv({set: [[PREF_BLOCKLIST_CLOCK_SKEW_SECONDS, skew]]});
info("Loading a bad cert page with an only slightly skewed clock");
message = yield Task.spawn(setUpPage);
is(message.divDisplay, "none", "Wrong time message information is not visible");
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
// now pretend we have no skewed system time
skew = 0;
- yield new Promise(r => SpecialPowers.pushPrefEnv({set:
- [[PREF_BLOCKLIST_CLOCK_SKEW_SECONDS, skew]]}, r));
+ yield SpecialPowers.pushPrefEnv({set: [[PREF_BLOCKLIST_CLOCK_SKEW_SECONDS, skew]]});
info("Loading a bad cert page with no skewed clock");
message = yield Task.spawn(setUpPage);
is(message.divDisplay, "none", "Wrong time message information is not visible");
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
});
--- a/browser/base/content/test/general/browser_bug537013.js
+++ b/browser/base/content/test/general/browser_bug537013.js
@@ -40,17 +40,17 @@ function test() {
});
texts.forEach(aText => addTabWithText(aText));
// Set up the first tab
gBrowser.selectedTab = tabs[0];
setFindString(texts[0]);
// Turn on highlight for testing bug 891638
- gFindBar.getElement("highlight").checked = true;
+ gFindBar.toggleHighlight(true);
// Make sure the second tab is correct, then set it up
gBrowser.selectedTab = tabs[1];
gBrowser.selectedTab.addEventListener("TabFindInitialized", continueTests1);
// Initialize the findbar
gFindBar;
}
function continueTests1() {
@@ -67,30 +67,29 @@ function continueTests1() {
gBrowser.selectedTab = tabs[0];
ok(!gFindBar.hidden, "First tab shows find bar!");
// When the Find Clipboard is supported, this test not relevant.
if (!HasFindClipboard)
is(gFindBar._findField.value, texts[0], "First tab persists find value!");
ok(gFindBar.getElement("highlight").checked,
"Highlight button state persists!");
- // While we're here, let's test bug 253793
+ // While we're here, let's test the backout of bug 253793.
gBrowser.reload();
gBrowser.addEventListener("DOMContentLoaded", continueTests2, true);
}
function continueTests2() {
gBrowser.removeEventListener("DOMContentLoaded", continueTests2, true);
- waitForCondition(() => !gFindBar.getElement("highlight").checked,
- continueTests3,
- "Highlight never reset!");
+ ok(gFindBar.getElement("highlight").checked, "Highlight never reset!");
+ continueTests3();
}
function continueTests3() {
- ok(!gFindBar.getElement("highlight").checked, "Highlight button reset!");
+ ok(gFindBar.getElement("highlight").checked, "Highlight button reset!");
gFindBar.close();
ok(gFindBar.hidden, "First tab doesn't show find bar!");
gBrowser.selectedTab = tabs[1];
ok(!gFindBar.hidden, "Second tab shows find bar!");
// Test for bug 892384
is(gFindBar._findField.getAttribute("focused"), "true",
"Open findbar refocused on tab change!");
gURLBar.focus();
@@ -124,13 +123,13 @@ function continueTests3() {
// Test that findbar gets restored when a tab is moved to a new window.
function checkNewWindow() {
ok(!newWindow.gFindBar.hidden, "New window shows find bar!");
// Disabled the following assertion due to intermittent failure on OSX 10.6 Debug.
if (!HasFindClipboard) {
is(newWindow.gFindBar._findField.value, texts[1],
"New window find bar has correct find value!");
}
- ok(!newWindow.gFindBar.getElement("find-next").disabled,
- "New window findbar has enabled buttons!");
+ ok(newWindow.gFindBar.getElement("find-next").disabled,
+ "New window findbar has disabled buttons!");
newWindow.close();
finish();
}
--- a/browser/base/content/test/general/browser_bug719271.js
+++ b/browser/base/content/test/general/browser_bug719271.js
@@ -19,16 +19,22 @@ function test() {
yield FullZoomHelper.load(gTab1, TEST_PAGE);
yield FullZoomHelper.load(gTab2, TEST_VIDEO);
}).then(zoomTab1, FullZoomHelper.failAndContinue(finish));
}
function zoomTab1() {
Task.spawn(function* () {
is(gBrowser.selectedTab, gTab1, "Tab 1 is selected");
+
+ // Reset zoom level if we run this test > 1 time in same browser session.
+ var level1 = ZoomManager.getZoomForBrowser(gBrowser.getBrowserForTab(gTab1));
+ if (level1 > 1)
+ FullZoom.reduce();
+
FullZoomHelper.zoomTest(gTab1, 1, "Initial zoom of tab 1 should be 1");
FullZoomHelper.zoomTest(gTab2, 1, "Initial zoom of tab 2 should be 1");
FullZoom.enlarge();
gLevel1 = ZoomManager.getZoomForBrowser(gBrowser.getBrowserForTab(gTab1));
ok(gLevel1 > 1, "New zoom for tab 1 should be greater than 1");
FullZoomHelper.zoomTest(gTab2, 1, "Zooming tab 1 should not affect tab 2");
--- a/browser/base/content/test/general/browser_sanitize-passwordDisabledHosts.js
+++ b/browser/base/content/test/general/browser_sanitize-passwordDisabledHosts.js
@@ -2,16 +2,19 @@
// clearing site-specific settings in Clear Recent History dialog
var tempScope = {};
Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
.loadSubScript("chrome://browser/content/sanitize.js", tempScope);
var Sanitizer = tempScope.Sanitizer;
add_task(function*() {
+ // getLoginSavingEnabled always returns false if password capture is disabled.
+ yield SpecialPowers.pushPrefEnv({"set": [["signon.rememberSignons", true]]});
+
var pwmgr = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
// Add a disabled host
pwmgr.setLoginSavingEnabled("http://example.com", false);
// Sanity check
is(pwmgr.getLoginSavingEnabled("http://example.com"), false,
"example.com should be disabled for password saving since we haven't cleared that yet.");
@@ -31,9 +34,11 @@ add_task(function*() {
itemPrefs.setBoolPref("siteSettings", true);
// Clear it
yield s.sanitize();
// Make sure it's gone
is(pwmgr.getLoginSavingEnabled("http://example.com"), true,
"example.com should be enabled for password saving again now that we've cleared.");
+
+ yield SpecialPowers.popPrefEnv();
});
--- a/browser/components/extensions/ext-tabs.js
+++ b/browser/components/extensions/ext-tabs.js
@@ -543,16 +543,20 @@ extensions.registerSchemaAPI("tabs", "ad
if (!containerId) {
return Promise.reject({message: `No cookie store exists with ID ${createProperties.cookieStoreId}`});
}
options.userContextId = containerId;
}
}
+ // Make sure things like about:blank and data: URIs never inherit,
+ // and instead always get a NullPrincipal.
+ options.disallowInheritPrincipal = true;
+
tabListener.initTabReady();
let tab = window.gBrowser.addTab(url || window.BROWSER_NEW_TAB_URL, options);
let active = true;
if (createProperties.active !== null) {
active = createProperties.active;
}
if (active) {
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_popup_resize.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_popup_resize.js
@@ -1,16 +1,16 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
-function* openPanel(extension, win = window) {
+function* openPanel(extension, win = window, awaitLoad = false) {
clickBrowserAction(extension, win);
- return yield awaitExtensionPanel(extension, win, false);
+ return yield awaitExtensionPanel(extension, win, awaitLoad);
}
add_task(function* testBrowserActionPopupResize() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"browser_action": {
"default_popup": "popup.html",
"browser_style": true,
@@ -108,17 +108,17 @@ function* testPopupSize(standardsMode, b
});
yield extension.startup();
/* eslint-disable mozilla/no-cpows-in-tests */
if (arrowSide == "top") {
// Test the standalone panel for a toolbar button.
- let browser = yield openPanel(extension, browserWin);
+ let browser = yield openPanel(extension, browserWin, true);
let dims = yield promiseContentDimensions(browser);
is(dims.isStandards, standardsMode, "Document has the expected compat mode");
let {innerWidth, innerHeight} = dims.window;
dims = yield alterContent(browser, () => {
--- a/browser/components/extensions/test/browser/browser_ext_tabs_executeScript.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_executeScript.js
@@ -83,16 +83,30 @@ add_task(function* testExecuteScript() {
browser.test.assertEq(2, result.length, "Result has correct length");
browser.test.assertTrue(/\/file_iframe_document\.html$/.test(result[0]), "First result is correct");
browser.test.assertEq("http://mochi.test:8888/", result[1], "Second result is correct");
}),
browser.tabs.executeScript({
code: "location.href;",
+ allFrames: true,
+ matchAboutBlank: true,
+ }).then(result => {
+ browser.test.assertTrue(Array.isArray(result), "Result is an array");
+
+ browser.test.assertEq(3, result.length, "Result has correct length");
+
+ browser.test.assertTrue(/\/file_iframe_document\.html$/.test(result[0]), "First result is correct");
+ browser.test.assertEq("http://mochi.test:8888/", result[1], "Second result is correct");
+ browser.test.assertEq("about:blank", result[2], "Thirds result is correct");
+ }),
+
+ browser.tabs.executeScript({
+ code: "location.href;",
runAt: "document_end",
}).then(result => {
browser.test.assertEq(1, result.length, "Expected callback result");
browser.test.assertEq("string", typeof result[0], "Result is a string");
browser.test.assertTrue(/\/file_iframe_document\.html$/.test(result[0]), "Result is correct");
}),
@@ -182,16 +196,22 @@ add_task(function* testExecuteScript() {
browser.tabs.create({url: "http://example.com/"}).then(async tab => {
let result = await browser.tabs.executeScript(tab.id, {code: "location.href"});
browser.test.assertEq("http://example.com/", result[0], "Script executed correctly in new tab");
await browser.tabs.remove(tab.id);
}),
+ browser.tabs.create({url: "about:blank"}).then(async tab => {
+ const result = await browser.tabs.executeScript(tab.id, {code: "location.href", matchAboutBlank: true});
+ browser.test.assertEq("about:blank", result[0], "Script executed correctly in new tab");
+ await browser.tabs.remove(tab.id);
+ }),
+
new Promise(resolve => {
browser.runtime.onMessage.addListener(message => {
browser.test.assertEq("script ran", message, "Expected runtime message");
resolve();
});
}),
]);
--- a/browser/components/extensions/test/browser/file_iframe_document.html
+++ b/browser/components/extensions/test/browser/file_iframe_document.html
@@ -1,10 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<iframe src="/"></iframe>
+ <iframe src="about:blank"></iframe>
</body>
</html>
--- a/browser/components/places/content/places.css
+++ b/browser/components/places/content/places.css
@@ -1,16 +1,22 @@
/* 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/. */
tree[type="places"] {
-moz-binding: url("chrome://browser/content/places/tree.xml#places-tree");
}
+tree[type="places"] > treechildren::-moz-tree-cell {
+ /* ensure we use the direction of the website title / url instead of the
+ * browser locale */
+ unicode-bidi: plaintext;
+}
+
.toolbar-drop-indicator {
position: relative;
z-index: 1;
}
menupopup[placespopup="true"] {
-moz-binding: url("chrome://browser/content/places/menu.xml#places-popup-base");
}
--- a/browser/components/places/content/placesOverlay.xul
+++ b/browser/components/places/content/placesOverlay.xul
@@ -37,17 +37,17 @@
<script type="application/javascript"
src="chrome://browser/content/places/treeView.js"/>
<!-- Bookmarks and history tooltip -->
<tooltip id="bhTooltip" noautohide="true"
onpopupshowing="return window.top.BookmarksEventHandler.fillInBHTooltip(document, event)">
<vbox id="bhTooltipTextBox" flex="1">
<label id="bhtTitleText" class="tooltip-label" />
- <label id="bhtUrlText" crop="center" class="tooltip-label" />
+ <label id="bhtUrlText" crop="center" class="tooltip-label uri-element" />
</vbox>
</tooltip>
<commandset id="placesCommands"
commandupdater="true"
events="focus,sort,places"
oncommandupdate="goUpdatePlacesCommands();">
<command id="placesCmd_open"
--- a/browser/components/shell/nsWindowsShellService.cpp
+++ b/browser/components/shell/nsWindowsShellService.cpp
@@ -641,35 +641,36 @@ nsWindowsShellService::LaunchControlPane
pAARUI->Release();
}
return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
}
nsresult
nsWindowsShellService::LaunchControlPanelDefaultPrograms()
{
- // Default Programs is a Vista+ feature
- if (!IsVistaOrLater()) {
+ // This Default Programs feature is Win7+ only.
+ if (!IsWin7OrLater()) {
return NS_ERROR_FAILURE;
}
// Build the path control.exe path safely
WCHAR controlEXEPath[MAX_PATH + 1] = { '\0' };
if (!GetSystemDirectoryW(controlEXEPath, MAX_PATH)) {
return NS_ERROR_FAILURE;
}
LPCWSTR controlEXE = L"control.exe";
if (wcslen(controlEXEPath) + wcslen(controlEXE) >= MAX_PATH) {
return NS_ERROR_FAILURE;
}
if (!PathAppendW(controlEXEPath, controlEXE)) {
return NS_ERROR_FAILURE;
}
- WCHAR params[] = L"control.exe /name Microsoft.DefaultPrograms /page pageDefaultProgram";
+ WCHAR params[] = L"control.exe /name Microsoft.DefaultPrograms /page "
+ "pageDefaultProgram\\pageAdvancedSettings?pszAppName=" APP_REG_NAME;
STARTUPINFOW si = {sizeof(si), 0};
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWDEFAULT;
PROCESS_INFORMATION pi = {0};
if (!CreateProcessW(controlEXEPath, params, nullptr, nullptr, FALSE,
0, nullptr, nullptr, &si, &pi)) {
return NS_ERROR_FAILURE;
}
@@ -723,18 +724,20 @@ SettingsAppBelievesConnected()
}
return !!value;
}
nsresult
nsWindowsShellService::LaunchModernSettingsDialogDefaultApps()
{
- if (!IsWindowsLogonConnected() && SettingsAppBelievesConnected()) {
- // Use the classic Control Panel to work around a bug of Windows 10.
+ if (!IsWindowsBuildOrLater(14965) &&
+ !IsWindowsLogonConnected() && SettingsAppBelievesConnected()) {
+ // Use the classic Control Panel to work around a bug of older
+ // builds of Windows 10.
return LaunchControlPanelDefaultPrograms();
}
IApplicationActivationManager* pActivator;
HRESULT hr = CoCreateInstance(CLSID_ApplicationActivationManager,
nullptr,
CLSCTX_INPROC,
IID_IApplicationActivationManager,
--- a/browser/config/version.txt
+++ b/browser/config/version.txt
@@ -1,1 +1,1 @@
-52.0a1
+53.0a1
--- a/browser/config/version_display.txt
+++ b/browser/config/version_display.txt
@@ -1,1 +1,1 @@
-52.0a1
+53.0a1
--- a/browser/themes/shared/controlcenter/panel.inc.css
+++ b/browser/themes/shared/controlcenter/panel.inc.css
@@ -378,16 +378,26 @@ description#identity-popup-content-verif
.identity-popup-permission-icon.in-use {
animation: 1.5s ease in-use-blink infinite;
}
@keyframes in-use-blink {
50% { opacity: 0; }
}
+.identity-popup-permission-label,
+.identity-popup-permission-state-label {
+ /* We need to align the action buttons and permission icons with the text.
+ This is tricky because the icon height is defined in pixels, while the
+ font height can vary with platform and system settings, and at least on
+ Windows the default font metrics reserve more extra space for accents.
+ This value is a good compromise for different platforms and font sizes. */
+ margin-top: -0.1em;
+}
+
.identity-popup-permission-label {
margin-inline-start: 1em;
}
.identity-popup-permission-state-label {
margin-inline-end: 5px;
text-align: end;
color: graytext;
--- a/build/moz.configure/compile-checks.configure
+++ b/build/moz.configure/compile-checks.configure
@@ -70,22 +70,22 @@ def check_header(header, language='C++',
@template
def check_headers(*headers, **kwargs):
checks = []
for header in headers:
checks.append(check_header(header, **kwargs))
return checks
-@depends(c_compiler)
-def warnings_cflags(c_compiler):
+@dependable
+def warnings_cflags():
return []
-@depends(cxx_compiler)
-def warnings_cxxflags(cxx_compiler):
+@dependable
+def warnings_cxxflags():
return []
# Tests whether GCC or clang support the given warning flag, and if it is,
# add it to the list of warning flags for the build.
# - `warning` is the warning flag (e.g. -Wfoo)
# - `compiler` (optional) is the compiler to test against (c_compiler or
# cxx_compiler, from toolchain.configure). When omitted, both compilers
--- a/build/moz.configure/init.configure
+++ b/build/moz.configure/init.configure
@@ -487,18 +487,18 @@ add_old_configure_assignment('HAVE_64BIT
# Autoconf needs these set
@depends(host)
def host_for_old_configure(host):
return '--host=%s' % host.alias
add_old_configure_arg(host_for_old_configure)
-@depends(host, target)
-def target_for_old_configure(host, target):
+@depends(target)
+def target_for_old_configure(target):
target_alias = target.alias
# old-configure does plenty of tests against $target and $target_os
# and expects darwin for iOS, so make it happy.
if target.os == 'iOS':
target_alias = target_alias.replace('-ios', '-darwin')
return '--target=%s' % target_alias
add_old_configure_arg(target_for_old_configure)
@@ -754,20 +754,20 @@ def project_flag(env=None, set_for_old_c
# milestone.is_nightly corresponds to cases NIGHTLY_BUILD is set.
@depends(milestone, '--help')
def enabled_in_nightly(milestone, _):
return milestone.is_nightly
# Set the MOZ_CONFIGURE_OPTIONS variable with all the options that
# were passed somehow (environment, command line, mozconfig)
-@depends(mozconfig_options)
+@dependable
@imports(_from='mozbuild.shellutil', _import='quote')
@imports('__sandbox__')
-def all_configure_options(_):
+def all_configure_options():
result = []
previous = None
for option in __sandbox__._options.itervalues():
# __sandbox__._options contains items for both option.name and
# option.env. But it's also an OrderedDict, meaning both are
# consecutive.
# Also ignore OLD_CONFIGURE and MOZCONFIG because they're not
# interesting.
--- a/build/moz.configure/rust.configure
+++ b/build/moz.configure/rust.configure
@@ -66,23 +66,23 @@ def rust_compiler(value, rustc, rustc_in
version {} of the 'rustc' toolchain and make sure it is
first in your path.
You can verify this by typing 'rustc --version'.
'''.format(version, min_version)))
return True
set_config('MOZ_RUST', rust_compiler)
-@depends(rust_compiler, rustc, target, cross_compiling)
+@depends(rust_compiler, rustc, target)
@imports('os')
@imports('subprocess')
@imports(_from='mozbuild.configure.util', _import='LineIO')
@imports(_from='mozbuild.shellutil', _import='quote')
@imports(_from='tempfile', _import='mkstemp')
-def rust_target(rust_compiler, rustc, target, cross_compiling):
+def rust_target(rust_compiler, rustc, target):
if rust_compiler:
# Rust's --target options are similar to, but not exactly the same
# as, the autoconf-derived targets we use. An example would be that
# Rust uses distinct target triples for targetting the GNU C++ ABI
# and the MSVC C++ ABI on Win32, whereas autoconf has a single
# triple and relies on the user to ensure that everything is
# compiled for the appropriate ABI. We need to perform appropriate
# munging to get the correct option to rustc.
--- a/build/moz.configure/toolchain.configure
+++ b/build/moz.configure/toolchain.configure
@@ -151,18 +151,18 @@ def using_compiler_wrapper(compiler_wrap
set_config('MOZ_USING_COMPILER_WRAPPER', using_compiler_wrapper)
# Cross-compilation related things.
# ==============================================================
js_option('--with-toolchain-prefix', env='TOOLCHAIN_PREFIX', nargs=1,
help='Prefix for the target toolchain')
-@depends('--with-toolchain-prefix', target, host, cross_compiling)
-def toolchain_prefix(value, target, host, cross_compiling):
+@depends('--with-toolchain-prefix', target, cross_compiling)
+def toolchain_prefix(value, target, cross_compiling):
if value:
return tuple(value)
if cross_compiling:
return ('%s-' % target.toolchain, '%s-' % target.alias)
@depends(toolchain_prefix, target)
def first_toolchain_prefix(toolchain_prefix, target):
# Pass TOOLCHAIN_PREFIX down to the build system if it was given from the
@@ -878,18 +878,18 @@ add_old_configure_assignment('MOZ_DEBUG_
@depends(c_compiler, target)
def libcxx_inline_visibility(c_compiler, target):
if c_compiler.type == 'clang' and target.os == 'Android':
return ''
set_define('_LIBCPP_INLINE_VISIBILITY', libcxx_inline_visibility)
set_define('_LIBCPP_INLINE_VISIBILITY_EXCEPT_GCC49', libcxx_inline_visibility)
-@depends(c_compiler, target, check_build_environment)
-def visibility_flags(c_compiler, target, env):
+@depends(target, check_build_environment)
+def visibility_flags(target, env):
if target.os != 'WINNT':
if target.kernel == 'Darwin':
return ('-fvisibility=hidden', '-fvisibility-inlines-hidden')
return ('-I%s/system_wrappers' % os.path.join(env.dist),
'-include',
'%s/config/gcc_hidden.h' % env.topsrcdir)
@depends(target, visibility_flags)
--- a/build/sanitizers/asan_blacklist_win.txt
+++ b/build/sanitizers/asan_blacklist_win.txt
@@ -1,15 +1,15 @@
# This is originally copied from Chromium tools/memory/asan/blacklist_win.txt.
# The rules in this file are only applied at compile time. If you can modify the
# source in question, consider function attributes to disable instrumentation.
# Bug 1200740 - ASan crash due to child process function interceptions
# Sandbox executes some of its code before the ASan RTL gets initialized and
-# maps shadow memory. As a result, instrmented code tries to access unavailable
+# maps shadow memory. As a result, instrumented code tries to access unavailable
# shadow memory and faults.
fun:*TargetNtSetInformationThread@20
fun:*TargetNtOpenThreadToken@20
fun:*TargetNtOpenThreadTokenEx@24
fun:*TargetNtMapViewOfSection@44
fun:*AutoProtectMemory*sandbox*
fun:*EatResolverThunk*sandbox*
fun:*InterceptionAgent*sandbox*
@@ -19,8 +19,9 @@ fun:*ProcessState*sandbox*
src:*pe_image.h
src:*pe_image.cc
src:*resolver_32.cc
src:*filesystem_interception.cc
src:*process_thread_interception.cc
src:*registry_interception.cc
src:*sandbox_nt_util.cc
src:*sync_interception.cc
+src:*interceptors_64.cc
--- a/config/external/nss/nss.symbols
+++ b/config/external/nss/nss.symbols
@@ -685,16 +685,17 @@ SSL_ResetHandshake
SSL_SendAdditionalKeyShares
SSL_SetCanFalseStartCallback
SSL_SetDowngradeCheckVersion
SSL_SetNextProtoNego
SSL_SetPKCS11PinArg
SSL_SetSockPeerID
SSL_SetSRTPCiphers
SSL_SetStapledOCSPResponses
+SSL_SetTrustAnchors
SSL_SetURL
SSL_ShutdownServerSessionIDCache
SSL_SignatureSchemePrefSet
SSL_SNISocketConfigHook
SSL_VersionRangeGet
SSL_VersionRangeGetDefault
SSL_VersionRangeGetSupported
SSL_VersionRangeSet
--- a/config/milestone.txt
+++ b/config/milestone.txt
@@ -5,9 +5,9 @@
# x.x.x.x
# x.x.x+
#
# Referenced by milestone.py.
# Hopefully I'll be able to automate replacement of *all*
# hardcoded milestones in the tree from these two files.
#--------------------------------------------------------
-52.0a1
+53.0a1
--- a/devtools/client/animationinspector/test/browser.ini
+++ b/devtools/client/animationinspector/test/browser.ini
@@ -56,15 +56,16 @@ skip-if = os == "linux" && !debug # Bug
[browser_animation_timeline_rewind_button.js]
[browser_animation_timeline_scrubber_exists.js]
[browser_animation_timeline_scrubber_movable.js]
[browser_animation_timeline_scrubber_moves.js]
[browser_animation_timeline_setCurrentTime.js]
[browser_animation_timeline_shows_delay.js]
[browser_animation_timeline_shows_endDelay.js]
[browser_animation_timeline_shows_iterations.js]
+[browser_animation_timeline_shows_name_label.js]
[browser_animation_timeline_shows_time_info.js]
[browser_animation_timeline_takes_rate_into_account.js]
[browser_animation_timeline_ui.js]
[browser_animation_toggle_button_resets_on_navigate.js]
[browser_animation_toggle_button_toggles_animations.js]
[browser_animation_toolbar_exists.js]
[browser_animation_ui_updates_when_animation_data_changes.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_shows_name_label.js
@@ -0,0 +1,46 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+// Check the text content and width of name label.
+
+add_task(function* () {
+ yield addTab(URL_ROOT + "doc_simple_animation.html");
+ let {inspector, panel} = yield openAnimationInspector();
+
+ info("Selecting 'simple-animation' animation which is running on compositor");
+ yield selectNodeAndWaitForAnimations(".animated", inspector);
+ checkNameLabel(panel.animationsTimelineComponent.rootWrapperEl, "simple-animation");
+
+ info("Selecting 'no-compositor' animation which is not running on compositor");
+ yield selectNodeAndWaitForAnimations(".no-compositor", inspector);
+ checkNameLabel(panel.animationsTimelineComponent.rootWrapperEl, "no-compositor");
+});
+
+function checkNameLabel(rootWrapperEl, expectedLabelContent) {
+ const timeblockEl = rootWrapperEl.querySelector(".time-block");
+ const labelEl = rootWrapperEl.querySelector(".name div");
+ is(labelEl.textContent, expectedLabelContent,
+ `Text content of labelEl sould be ${ expectedLabelContent }`);
+
+ // Expand timeblockEl to avoid max-width of the label.
+ timeblockEl.style.width = "10000px";
+ const originalLabelWidth = labelEl.clientWidth;
+ ok(originalLabelWidth < timeblockEl.clientWidth / 2,
+ "Label width should be less than 50%");
+
+ // Set timeblockEl width to double of original label width.
+ timeblockEl.style.width = `${ originalLabelWidth * 2 }px`;
+ is(labelEl.clientWidth + labelEl.offsetLeft, originalLabelWidth,
+ `Label width + offsetLeft should be ${ originalLabelWidth }px`);
+
+ // Shrink timeblockEl to enable max-width.
+ timeblockEl.style.width = `${ originalLabelWidth }px`;
+ is(labelEl.clientWidth + labelEl.offsetLeft,
+ Math.round(timeblockEl.clientWidth / 2),
+ "Label width + offsetLeft should be half of timeblockEl");
+}
--- a/devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js
+++ b/devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js
@@ -10,16 +10,19 @@
* As part of bug 1077403, the leaking uncaught rejection should be fixed.
*/
thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Shader Editor is " +
"still waiting for a WebGL context to be created.");
const { DebuggerServer } = require("devtools/server/main");
const { DebuggerClient } = require("devtools/shared/client/main");
+// Bug 1277805: Too slow for debug runs
+requestLongerTimeout(2);
+
/**
* Bug 979536: Ensure fronts are destroyed after toolbox close.
*
* The fronts need to be destroyed manually to unbind their onPacket handlers.
*
* When you initialize a front and call |this.manage|, it adds a client actor
* pool that the DebuggerClient uses to route packet replies to that actor.
*
--- a/devtools/client/inspector/inspector.js
+++ b/devtools/client/inspector/inspector.js
@@ -3,16 +3,18 @@
/* 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/. */
/* global window */
"use strict";
+var Cu = Components.utils;
+var { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
var Services = require("Services");
var promise = require("promise");
var defer = require("devtools/shared/defer");
var EventEmitter = require("devtools/shared/event-emitter");
const {executeSoon} = require("devtools/shared/DevToolsUtils");
var {KeyShortcuts} = require("devtools/client/shared/key-shortcuts");
var {Task} = require("devtools/shared/task");
const {initCssProperties} = require("devtools/shared/fronts/css-properties");
@@ -408,31 +410,36 @@ Inspector.prototype = {
str = INSPECTOR_L10N.getStr("inspector.searchResultsNone");
}
}
this.searchResultsLabel.textContent = str;
},
get React() {
- return require("devtools/client/shared/vendor/react");
+ return this._toolbox.React;
},
get ReactDOM() {
- return require("devtools/client/shared/vendor/react-dom");
+ return this._toolbox.ReactDOM;
},
get ReactRedux() {
- return require("devtools/client/shared/vendor/react-redux");
+ return this._toolbox.ReactRedux;
+ },
+
+ get browserRequire() {
+ return this._toolbox.browserRequire;
},
get InspectorTabPanel() {
if (!this._InspectorTabPanel) {
this._InspectorTabPanel =
- this.React.createFactory(require("devtools/client/inspector/components/inspector-tab-panel"));
+ this.React.createFactory(this.browserRequire(
+ "devtools/client/inspector/components/inspector-tab-panel"));
}
return this._InspectorTabPanel;
},
/**
* Check if the inspector should use the landscape mode.
*
* @return {Boolean} true if the inspector should be in landscape mode.
@@ -442,17 +449,18 @@ Inspector.prototype = {
return clientWidth > PORTRAIT_MODE_WIDTH;
},
/**
* Build Splitter located between the main and side area of
* the Inspector panel.
*/
setupSplitter: function () {
- let SplitBox = this.React.createFactory(require("devtools/client/shared/components/splitter/split-box"));
+ let SplitBox = this.React.createFactory(this.browserRequire(
+ "devtools/client/shared/components/splitter/split-box"));
let splitter = SplitBox({
className: "inspector-sidebar-splitter",
initialWidth: INITIAL_SIDEBAR_SIZE,
initialHeight: INITIAL_SIDEBAR_SIZE,
splitterSize: 1,
endPanelControl: true,
startPanel: this.InspectorTabPanel({
@@ -555,17 +563,17 @@ Inspector.prototype = {
"computedview",
INSPECTOR_L10N.getStr("inspector.sidebar.computedViewTitle"),
defaultTab == "computedview");
this.ruleview = new RuleViewTool(this, this.panelWin);
this.computedview = new ComputedViewTool(this, this.panelWin);
if (Services.prefs.getBoolPref("devtools.layoutview.enabled")) {
- const {LayoutView} = require("devtools/client/inspector/layout/layout");
+ const {LayoutView} = this.browserRequire("devtools/client/inspector/layout/layout");
this.layoutview = new LayoutView(this, this.panelWin);
}
if (this.target.form.animationsActor) {
this.sidebar.addFrameTab(
"animationinspector",
INSPECTOR_L10N.getStr("inspector.sidebar.animationInspectorTitle"),
"chrome://devtools/content/animationinspector/animation-inspector.xhtml",
@@ -603,17 +611,18 @@ Inspector.prototype = {
addSidebarTab: function (id, title, panel, selected) {
this.sidebar.addTab(id, title, panel, selected);
},
setupToolbar: function () {
this.teardownToolbar();
// Setup the sidebar toggle button.
- let SidebarToggle = this.React.createFactory(require("devtools/client/shared/components/sidebar-toggle"));
+ let SidebarToggle = this.React.createFactory(this.browserRequire(
+ "devtools/client/shared/components/sidebar-toggle"));
let sidebarToggle = SidebarToggle({
onClick: this.onPaneToggleButtonClicked,
collapsed: false,
expandPaneTitle: INSPECTOR_L10N.getStr("inspector.expandPane"),
collapsePaneTitle: INSPECTOR_L10N.getStr("inspector.collapsePane"),
});
@@ -1842,17 +1851,16 @@ Inspector.prototype = {
// URL constructor doesn't support chrome: scheme
let href = window.location.href.replace(/chrome:/, "http://");
let url = new window.URL(href);
// Only use this method to attach the toolbox if some query parameters are given
if (url.search.length > 1) {
const { targetFromURL } = require("devtools/client/framework/target-from-url");
const { attachThread } = require("devtools/client/framework/attach-thread");
- const Cu = Components.utils;
const { BrowserLoader } =
Cu.import("resource://devtools/client/shared/browser-loader.js", {});
const { Selection } = require("devtools/client/framework/selection");
const { InspectorFront } = require("devtools/shared/fronts/inspector");
const { getHighlighterUtils } = require("devtools/client/framework/toolbox-highlighter-utils");
Task.spawn(function* () {
--- a/devtools/client/inspector/inspector.xhtml
+++ b/devtools/client/inspector/inspector.xhtml
@@ -21,23 +21,16 @@
<link rel="stylesheet" href="resource://devtools/client/shared/components/tabs/tabs.css"/>
<link rel="stylesheet" href="resource://devtools/client/shared/components/tabs/tabbar.css"/>
<link rel="stylesheet" href="resource://devtools/client/inspector/components/inspector-tab-panel.css"/>
<link rel="stylesheet" href="resource://devtools/client/shared/components/splitter/split-box.css"/>
<link rel="stylesheet" href="resource://devtools/client/inspector/layout/components/Accordion.css"/>
<script type="application/javascript;version=1.8"
src="chrome://devtools/content/shared/theme-switching.js"></script>
- <script type="application/javascript;version=1.8">
- const { BrowserLoader } = Components.utils.import("resource://devtools/client/shared/browser-loader.js", {});
- const { require } = BrowserLoader({
- window,
- baseURI: "resource://devtools/client/inspector/",
- });
- </script>
<script type="application/javascript;version=1.8" src="inspector.js" defer="true"></script>
</head>
<body class="theme-body" role="application">
<div class="inspector-responsive-container theme-body inspector">
<!-- Main Panel Content -->
<div id="inspector-main-content" class="devtools-main-content">
<div id="inspector-toolbar" class="devtools-toolbar" nowindowdrag="true"
--- a/devtools/client/inspector/shared/test/browser_styleinspector_context-menu-copy-urls.js
+++ b/devtools/client/inspector/shared/test/browser_styleinspector_context-menu-copy-urls.js
@@ -63,17 +63,17 @@ function* startTest() {
}
function* testCopyUrlToClipboard({view, inspector}, type, selector, expected) {
info("Select node in inspector panel");
yield selectNode(selector, inspector);
info("Retrieve background-image link for selected node in current " +
"styleinspector view");
- let property = getBackgroundImageProperty(inspector, view, selector);
+ let property = getBackgroundImageProperty(view, selector);
let imageLink = property.valueSpan.querySelector(".theme-link");
ok(imageLink, "Background-image link element found");
info("Simulate right click on the background-image URL");
let allMenuItems = openStyleContextMenuAndGetAllItems(view, imageLink);
let menuitemCopyUrl = allMenuItems.find(item => item.label ===
STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyUrl"));
let menuitemCopyImageDataUrl = allMenuItems.find(item => item.label ===
@@ -95,15 +95,15 @@ function* testCopyUrlToClipboard({view,
yield waitForClipboardPromise(() => {
return menuitemCopyUrl.click();
}, expected);
}
info("Hide context menu");
}
-function getBackgroundImageProperty(inspector, view, selector) {
- let isRuleView = view === inspector.ruleview.view;
+function getBackgroundImageProperty(view, selector) {
+ let isRuleView = view instanceof CssRuleView;
if (isRuleView) {
return getRuleViewProperty(view, selector, "background-image");
}
return getComputedViewProperty(view, "background-image");
}
--- a/devtools/client/inspector/shared/test/head.js
+++ b/devtools/client/inspector/shared/test/head.js
@@ -5,16 +5,17 @@
/* import-globals-from ../../test/head.js */
"use strict";
// Import the inspector's head.js first (which itself imports shared-head.js).
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/inspector/test/head.js",
this);
+var {CssRuleView} = require("devtools/client/inspector/rules/rules");
var {getInplaceEditorForSpan: inplaceEditor} =
require("devtools/client/shared/inplace-editor");
const {getColor: getThemeColor} = require("devtools/client/shared/theme");
const TEST_URL_ROOT =
"http://example.com/browser/devtools/client/inspector/shared/test/";
const TEST_URL_ROOT_SSL =
"https://example.com/browser/devtools/client/inspector/shared/test/";
--- a/devtools/client/inspector/toolsidebar.js
+++ b/devtools/client/inspector/toolsidebar.js
@@ -56,24 +56,29 @@ ToolSidebar.prototype = {
get React() {
return this._toolPanel.React;
},
get ReactDOM() {
return this._toolPanel.ReactDOM;
},
+ get browserRequire() {
+ return this._toolPanel.browserRequire;
+ },
+
get InspectorTabPanel() {
return this._toolPanel.InspectorTabPanel;
},
// Rendering
render: function () {
- let Tabbar = this.React.createFactory(require("devtools/client/shared/components/tabs/tabbar"));
+ let Tabbar = this.React.createFactory(this.browserRequire(
+ "devtools/client/shared/components/tabs/tabbar"));
let sidebar = Tabbar({
toolbox: this._toolPanel._toolbox,
showAllTabsMenu: true,
onSelect: this.handleSelectionChange.bind(this),
});
this._tabbar = this.ReactDOM.render(sidebar, this._tabbox);
--- a/devtools/client/preferences/devtools.js
+++ b/devtools/client/preferences/devtools.js
@@ -236,16 +236,17 @@ sticky_pref("devtools.theme", "light");
#endif
// Web console filters
pref("devtools.webconsole.filter.error", true);
pref("devtools.webconsole.filter.warn", true);
pref("devtools.webconsole.filter.info", true);
pref("devtools.webconsole.filter.log", true);
pref("devtools.webconsole.filter.debug", true);
+pref("devtools.webconsole.filter.css", false);
pref("devtools.webconsole.filter.net", false);
pref("devtools.webconsole.filter.netxhr", false);
// Deprecated - old console frontend
pref("devtools.webconsole.filter.network", true);
pref("devtools.webconsole.filter.networkinfo", false);
pref("devtools.webconsole.filter.netwarn", true);
pref("devtools.webconsole.filter.csserror", true);
pref("devtools.webconsole.filter.cssparser", false);
--- a/devtools/client/shared/components/reps/element-node.js
+++ b/devtools/client/shared/components/reps/element-node.js
@@ -82,24 +82,41 @@ define(function (require, exports, modul
"<",
nodeNameElement,
...attributeElements,
">",
];
},
render: function () {
- let {object, mode} = this.props;
+ let {
+ object,
+ mode,
+ onDOMNodeMouseOver,
+ onDOMNodeMouseOut
+ } = this.props;
let elements = this.getElements(object, mode);
- const baseElement = span({className: "objectBox"}, ...elements);
+ let objectLink = this.props.objectLink || span;
- if (this.props.objectLink) {
- return this.props.objectLink({object}, baseElement);
+ let baseConfig = {className: "objectBox objectBox-node"};
+ if (onDOMNodeMouseOver) {
+ Object.assign(baseConfig, {
+ onMouseOver: _ => onDOMNodeMouseOver(object)
+ });
}
- return baseElement;
+
+ if (onDOMNodeMouseOut) {
+ Object.assign(baseConfig, {
+ onMouseOut: onDOMNodeMouseOut
+ });
+ }
+
+ return objectLink({object},
+ span(baseConfig, ...elements)
+ );
},
});
// Registration
function supportsObject(object, type) {
if (!isGrip(object)) {
return false;
}
new file mode 100644
--- /dev/null
+++ b/devtools/client/shared/components/reps/error.js
@@ -0,0 +1,68 @@
+/* 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/. */
+"use strict";
+
+// Make this available to both AMD and CJS environments
+define(function (require, exports, module) {
+ // ReactJS
+ const React = require("devtools/client/shared/vendor/react");
+ // Dependencies
+ const { isGrip } = require("./rep-utils");
+ // Shortcuts
+ const { span } = React.DOM;
+
+ /**
+ * Renders Error objects.
+ */
+ const ErrorRep = React.createClass({
+ displayName: "Error",
+
+ propTypes: {
+ object: React.PropTypes.object.isRequired,
+ mode: React.PropTypes.string
+ },
+
+ render: function () {
+ let object = this.props.object;
+ let preview = object.preview;
+ let name = preview && preview.name
+ ? preview.name
+ : "Error";
+
+ let content = this.props.mode === "tiny"
+ ? name
+ : `${name}: ${preview.message}`;
+
+ if (preview.stack && this.props.mode !== "tiny") {
+ /*
+ * Since Reps are used in the JSON Viewer, we can't localize
+ * the "Stack trace" label (defined in debugger.properties as
+ * "variablesViewErrorStacktrace" property), until Bug 1317038 lands.
+ */
+ content = `${content}\nStack trace:\n${preview.stack}`;
+ }
+
+ let objectLink = this.props.objectLink || span;
+ return (
+ objectLink({object, className: "objectBox-stackTrace"},
+ span({}, content)
+ )
+ );
+ },
+ });
+
+ // Registration
+ function supportsObject(object, type) {
+ if (!isGrip(object)) {
+ return false;
+ }
+ return (object.preview && type === "Error");
+ }
+
+ // Exports from this module
+ exports.ErrorRep = {
+ rep: ErrorRep,
+ supportsObject: supportsObject
+ };
+});
--- a/devtools/client/shared/components/reps/moz.build
+++ b/devtools/client/shared/components/reps/moz.build
@@ -7,16 +7,17 @@
DevToolsModules(
'array.js',
'attribute.js',
'caption.js',
'comment-node.js',
'date-time.js',
'document.js',
'element-node.js',
+ 'error.js',
'event.js',
'function.js',
'grip-array.js',
'grip-map.js',
'grip.js',
'infinity.js',
'long-string.js',
'nan.js',
--- a/devtools/client/shared/components/reps/rep.js
+++ b/devtools/client/shared/components/reps/rep.js
@@ -32,16 +32,17 @@ define(function (require, exports, modul
const { Event } = require("./event");
const { Func } = require("./function");
const { PromiseRep } = require("./promise");
const { RegExp } = require("./regexp");
const { StyleSheet } = require("./stylesheet");
const { CommentNode } = require("./comment-node");
const { ElementNode } = require("./element-node");
const { TextNode } = require("./text-node");
+ const { ErrorRep } = require("./error");
const { Window } = require("./window");
const { ObjectWithText } = require("./object-with-text");
const { ObjectWithURL } = require("./object-with-url");
const { GripArray } = require("./grip-array");
const { GripMap } = require("./grip-map");
const { Grip } = require("./grip");
// List of all registered template.
@@ -59,16 +60,17 @@ define(function (require, exports, modul
LongStringRep,
Func,
PromiseRep,
ArrayRep,
Document,
Window,
ObjectWithText,
ObjectWithURL,
+ ErrorRep,
GripArray,
GripMap,
Grip,
Undefined,
Null,
StringRep,
Number,
SymbolRep,
--- a/devtools/client/shared/components/reps/text-node.js
+++ b/devtools/client/shared/components/reps/text-node.js
@@ -39,30 +39,43 @@ define(function (require, exports, modul
}
return "";
},
render: function () {
let grip = this.props.object;
let mode = this.props.mode || "short";
+ let baseConfig = {className: "objectBox objectBox-textNode"};
+ if (this.props.onDOMNodeMouseOver) {
+ Object.assign(baseConfig, {
+ onMouseOver: _ => this.props.onDOMNodeMouseOver(grip)
+ });
+ }
+
+ if (this.props.onDOMNodeMouseOut) {
+ Object.assign(baseConfig, {
+ onMouseOut: this.props.onDOMNodeMouseOut
+ });
+ }
+
if (mode == "short" || mode == "tiny") {
return (
- DOM.span({className: "objectBox objectBox-textNode"},
+ DOM.span(baseConfig,
this.getTitle(grip),
DOM.span({className: "nodeValue"},
"\"" + this.getTextContent(grip) + "\""
)
)
);
}
let objectLink = this.props.objectLink || DOM.span;
return (
- DOM.span({className: "objectBox objectBox-textNode"},
+ DOM.span(baseConfig,
this.getTitle(grip),
objectLink({
object: grip
}, "<"),
DOM.span({className: "nodeTag"}, "TextNode"),
" textContent=\"",
DOM.span({className: "nodeValue"},
this.getTextContent(grip)
--- a/devtools/client/shared/components/test/mochitest/chrome.ini
+++ b/devtools/client/shared/components/test/mochitest/chrome.ini
@@ -8,16 +8,17 @@ support-files =
[test_notification_box_02.html]
[test_notification_box_03.html]
[test_reps_array.html]
[test_reps_attribute.html]
[test_reps_comment-node.html]
[test_reps_date-time.html]
[test_reps_document.html]
[test_reps_element-node.html]
+[test_reps_error.html]
[test_reps_event.html]
[test_reps_function.html]
[test_reps_grip.html]
[test_reps_grip-array.html]
[test_reps_grip-map.html]
[test_reps_infinity.html]
[test_reps_long-string.html]
[test_reps_nan.html]
--- a/devtools/client/shared/components/test/mochitest/test_reps_element-node.html
+++ b/devtools/client/shared/components/test/mochitest/test_reps_element-node.html
@@ -26,16 +26,19 @@ window.onload = Task.async(function* ()
yield testBodyNode();
yield testDocumentElement();
yield testNode();
yield testNodeWithLeadingAndTrailingSpacesClassName();
yield testNodeWithoutAttributes();
yield testLotsOfAttributes();
yield testSvgNode();
yield testSvgNodeInXHTML();
+
+ yield testOnMouseOver();
+ yield testOnMouseOut();
} catch (e) {
ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
} finally {
SimpleTest.finish();
}
function testBodyNode() {
const stub = getGripStub("testBodyNode");
@@ -166,16 +169,49 @@ window.onload = Task.async(function* ()
"Element node rep has expected text content for XHTML SVG element node");
const tinyRenderedComponent = renderComponent(
ElementNode.rep, { object: stub, mode: "tiny" });
is(tinyRenderedComponent.textContent, `svg:circle.svg-element`,
"Element node rep has expected text content for XHTML SVG element in tiny mode");
}
+ function testOnMouseOver() {
+ const stub = getGripStub("testNode");
+
+ let mouseOverValue;
+ let onDOMNodeMouseOver = (object) => {
+ mouseOverValue = object;
+ };
+ const renderedComponent = renderComponent(
+ ElementNode.rep, {object: stub, onDOMNodeMouseOver});
+
+ const node = renderedComponent.querySelector(".objectBox-node");
+ TestUtils.Simulate.mouseOver(node);
+
+ is(mouseOverValue, stub, "onDOMNodeMouseOver is called with the expected argument " +
+ "when mouseover is fired on the Rep");
+ }
+
+ function testOnMouseOut() {
+ const stub = getGripStub("testNode");
+
+ let called = false;
+ let onDOMNodeMouseOut = (object) => {
+ called = true;
+ };
+ const renderedComponent = renderComponent(
+ ElementNode.rep, {object: stub, onDOMNodeMouseOut});
+
+ const node = renderedComponent.querySelector(".objectBox-node");
+ TestUtils.Simulate.mouseOut(node);
+
+ is(called, true, "onDOMNodeMouseOut is called when mouseout is fired on the Rep");
+ }
+
function getGripStub(name) {
switch (name) {
case "testBodyNode":
return {
"type": "object",
"actor": "server1.conn1.child1/obj30",
"class": "HTMLBodyElement",
"ownPropertyLength": 0,
new file mode 100644
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_reps_error.html
@@ -0,0 +1,421 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test Error rep
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Rep test - Error</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+"use strict";
+
+window.onload = Task.async(function* () {
+ let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
+ let { ErrorRep } = browserRequire("devtools/client/shared/components/reps/error");
+
+ try {
+ // Test errors with different properties
+ yield testSimpleError();
+ yield testMultilineStackError();
+ yield testErrorWithoutStacktrace();
+
+ // Test different kind of errors
+ yield testEvalError();
+ yield testInternalError();
+ yield testRangeError();
+ yield testReferenceError();
+ yield testSyntaxError();
+ yield testTypeError();
+ yield testURIError();
+ } catch (e) {
+ ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+ } finally {
+ SimpleTest.finish();
+ }
+
+ function testSimpleError() {
+ // Test object = `new Error("Error message")`
+ const stub = getGripStub("testSimpleError");
+ const renderedRep = shallowRenderComponent(Rep, {object: stub});
+ is(renderedRep.type, ErrorRep.rep,
+ `Rep correctly selects ${ErrorRep.rep.displayName} for Error object`);
+
+ const renderedComponent = renderComponent(ErrorRep.rep, {object: stub});
+ is(renderedComponent.textContent,
+ "Error: Error message\n" +
+ "Stack trace:\n" +
+ "@debugger eval code:1:13\n",
+ "Error Rep has expected text content for a simple error");
+
+ const tinyRenderedComponent = renderComponent(ErrorRep.rep, {object: stub, mode: "tiny"});
+ is(tinyRenderedComponent.textContent,
+ "Error",
+ "Error Rep has expected text content for a simple error in tiny mode");
+ }
+
+ function testMultilineStackError() {
+ /*
+ * Test object = `
+ * function errorFoo() {
+ * errorBar();
+ * }
+ * function errorBar() {
+ * console.log(new Error("bar"));
+ * }
+ * errorFoo();`
+ */
+ const stub = getGripStub("testMultilineStackError");
+ const renderedRep = shallowRenderComponent(Rep, {object: stub});
+ is(renderedRep.type, ErrorRep.rep,
+ `Rep correctly selects ${ErrorRep.rep.displayName} for Error object`);
+
+ const renderedComponent = renderComponent(ErrorRep.rep, {object: stub});
+ is(renderedComponent.textContent,
+ "Error: bar\n" +
+ "Stack trace:\n" +
+ "errorBar@debugger eval code:6:15\n" +
+ "errorFoo@debugger eval code:3:3\n" +
+ "@debugger eval code:8:1\n",
+ "Error Rep has expected text content for an error with a multiple line");
+
+ const tinyRenderedComponent = renderComponent(ErrorRep.rep, {object: stub, mode: "tiny"});
+ is(tinyRenderedComponent.textContent,
+ "Error",
+ "Error Rep has expected text content for an error with a multiple line in tiny mode");
+ }
+
+ function testErrorWithoutStacktrace() {
+ const stub = getGripStub("testErrorWithoutStacktrace");
+ const renderedRep = shallowRenderComponent(Rep, {object: stub});
+ is(renderedRep.type, ErrorRep.rep,
+ `Rep correctly selects ${ErrorRep.rep.displayName} for Error object`);
+
+ const renderedComponent = renderComponent(ErrorRep.rep, {object: stub});
+ is(renderedComponent.textContent,
+ "Error: Error message",
+ "Error Rep has expected text content for an error without stacktrace");
+
+ const tinyRenderedComponent = renderComponent(ErrorRep.rep, {object: stub, mode: "tiny"});
+ is(tinyRenderedComponent.textContent,
+ "Error",
+ "Error Rep has expected text content for an error without stacktrace in tiny mode");
+ }
+
+ function testEvalError() {
+ // Test object = `new EvalError("EvalError message")`
+ const stub = getGripStub("testEvalError");
+ const renderedRep = shallowRenderComponent(Rep, {object: stub});
+ is(renderedRep.type, ErrorRep.rep,
+ `Rep correctly selects ${ErrorRep.rep.displayName} for EvalError object`);
+
+ const renderedComponent = renderComponent(ErrorRep.rep, {object: stub});
+ is(renderedComponent.textContent,
+ "EvalError: EvalError message\n" +
+ "Stack trace:\n" +
+ "@debugger eval code:10:13\n",
+ "Error Rep has expected text content for an EvalError");
+
+ const tinyRenderedComponent = renderComponent(ErrorRep.rep, {object: stub, mode: "tiny"});
+ is(tinyRenderedComponent.textContent,
+ "EvalError",
+ "Error Rep has expected text content for an EvalError in tiny mode");
+ }
+
+ function testInternalError() {
+ // Test object = `new InternalError("InternalError message")`
+ const stub = getGripStub("testInternalError");
+ const renderedRep = shallowRenderComponent(Rep, {object: stub});
+ is(renderedRep.type, ErrorRep.rep,
+ `Rep correctly selects ${ErrorRep.rep.displayName} for InternalError object`);
+
+ const renderedComponent = renderComponent(ErrorRep.rep, {object: stub});
+ is(renderedComponent.textContent,
+ "InternalError: InternalError message\n" +
+ "Stack trace:\n" +
+ "@debugger eval code:11:13\n",
+ "Error Rep has expected text content for an InternalError");
+
+ const tinyRenderedComponent = renderComponent(ErrorRep.rep, {object: stub, mode: "tiny"});
+ is(tinyRenderedComponent.textContent,
+ "InternalError",
+ "Error Rep has expected text content for an InternalError in tiny mode");
+ }
+
+ function testRangeError() {
+ // Test object = `new RangeError("RangeError message")`
+ const stub = getGripStub("testRangeError");
+ const renderedRep = shallowRenderComponent(Rep, {object: stub});
+ is(renderedRep.type, ErrorRep.rep,
+ `Rep correctly selects ${ErrorRep.rep.displayName} for RangeError object`);
+
+ const renderedComponent = renderComponent(ErrorRep.rep, {object: stub});
+ is(renderedComponent.textContent,
+ "RangeError: RangeError message\n" +
+ "Stack trace:\n" +
+ "@debugger eval code:12:13\n",
+ "Error Rep has expected text content for RangeError");
+
+ const tinyRenderedComponent = renderComponent(ErrorRep.rep, {object: stub, mode: "tiny"});
+ is(tinyRenderedComponent.textContent,
+ "RangeError",
+ "Error Rep has expected text content for RangeError in tiny mode");
+ }
+
+ function testReferenceError() {
+ // Test object = `new ReferenceError("ReferenceError message"`
+ const stub = getGripStub("testReferenceError");
+ const renderedRep = shallowRenderComponent(Rep, {object: stub});
+ is(renderedRep.type, ErrorRep.rep,
+ `Rep correctly selects ${ErrorRep.rep.displayName} for ReferenceError object`);
+
+ const renderedComponent = renderComponent(ErrorRep.rep, {object: stub});
+ is(renderedComponent.textContent,
+ "ReferenceError: ReferenceError message\n" +
+ "Stack trace:\n" +
+ "@debugger eval code:13:13\n",
+ "Error Rep has expected text content for ReferenceError");
+
+ const tinyRenderedComponent = renderComponent(ErrorRep.rep, {object: stub, mode: "tiny"});
+ is(tinyRenderedComponent.textContent,
+ "ReferenceError",
+ "Error Rep has expected text content for ReferenceError in tiny mode");
+ }
+
+ function testSyntaxError() {
+ // Test object = `new SyntaxError("SyntaxError message"`
+ const stub = getGripStub("testSyntaxError");
+ const renderedRep = shallowRenderComponent(Rep, {object: stub});
+ is(renderedRep.type, ErrorRep.rep,
+ `Rep correctly selects ${ErrorRep.rep.displayName} for SyntaxError object`);
+
+ const renderedComponent = renderComponent(ErrorRep.rep, {object: stub});
+ is(renderedComponent.textContent,
+ "SyntaxError: SyntaxError message\n" +
+ "Stack trace:\n" +
+ "@debugger eval code:14:13\n",
+ "Error Rep has expected text content for SyntaxError");
+
+ const tinyRenderedComponent = renderComponent(ErrorRep.rep, {object: stub, mode: "tiny"});
+ is(tinyRenderedComponent.textContent,
+ "SyntaxError",
+ "SyntaxError Rep has expected text content for SyntaxError in tiny mode");
+ }
+
+ function testTypeError() {
+ // Test object = `new TypeError("TypeError message"`
+ const stub = getGripStub("testTypeError");
+ const renderedRep = shallowRenderComponent(Rep, {object: stub});
+ is(renderedRep.type, ErrorRep.rep,
+ `Rep correctly selects ${ErrorRep.rep.displayName} for TypeError`);
+
+ const renderedComponent = renderComponent(ErrorRep.rep, {object: stub});
+ is(renderedComponent.textContent,
+ "TypeError: TypeError message\n" +
+ "Stack trace:\n" +
+ "@debugger eval code:15:13\n",
+ "Error Rep has expected text content for TypeError");
+
+ const tinyRenderedComponent = renderComponent(ErrorRep.rep, {object: stub, mode: "tiny"});
+ is(tinyRenderedComponent.textContent,
+ "TypeError",
+ "Error Rep has expected text content for a TypeError in tiny mode");
+ }
+
+ function testURIError() {
+ // Test object = `new URIError("URIError message")`
+ const stub = getGripStub("testURIError");
+ const renderedRep = shallowRenderComponent(Rep, {object: stub});
+ is(renderedRep.type, ErrorRep.rep,
+ `Rep correctly selects ${ErrorRep.rep.displayName} for URIError object`);
+
+ const renderedComponent = renderComponent(ErrorRep.rep, {object: stub});
+ is(renderedComponent.textContent,
+ "URIError: URIError message\n" +
+ "Stack trace:\n" +
+ "@debugger eval code:16:13\n",
+ "Error Rep has expected text content for URIError");
+
+ const tinyRenderedComponent = renderComponent(ErrorRep.rep, {object: stub, mode: "tiny"});
+ is(tinyRenderedComponent.textContent,
+ "URIError",
+ "Error Rep has expected text content for URIError in tiny mode");
+ }
+
+ function getGripStub(name) {
+ switch (name) {
+ case "testSimpleError":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj1020",
+ "class": "Error",
+ "ownPropertyLength": 4,
+ "preview": {
+ "kind": "Error",
+ "name": "Error",
+ "message": "Error message",
+ "stack": "@debugger eval code:1:13\n",
+ "fileName": "debugger eval code",
+ "lineNumber": 1,
+ "columnNumber": 13
+ }
+ };
+ case "testMultilineStackError":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj1021",
+ "class": "Error",
+ "ownPropertyLength": 4,
+ "preview": {
+ "kind": "Error",
+ "name": "Error",
+ "message": "bar",
+ "stack": "errorBar@debugger eval code:6:15\n" +
+ "errorFoo@debugger eval code:3:3\n" +
+ "@debugger eval code:8:1\n",
+ "fileName": "debugger eval code",
+ "lineNumber": 6,
+ "columnNumber": 15
+ }
+ };
+ case "testErrorWithoutStacktrace":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj1020",
+ "class": "Error",
+ "ownPropertyLength": 4,
+ "preview": {
+ "kind": "Error",
+ "name": "Error",
+ "message": "Error message",
+ }
+ };
+ case "testEvalError":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj1022",
+ "class": "Error",
+ "ownPropertyLength": 4,
+ "preview": {
+ "kind": "Error",
+ "name": "EvalError",
+ "message": "EvalError message",
+ "stack": "@debugger eval code:10:13\n",
+ "fileName": "debugger eval code",
+ "lineNumber": 10,
+ "columnNumber": 13
+ }
+ };
+ case "testInternalError":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj1023",
+ "class": "Error",
+ "ownPropertyLength": 4,
+ "preview": {
+ "kind": "Error",
+ "name": "InternalError",
+ "message": "InternalError message",
+ "stack": "@debugger eval code:11:13\n",
+ "fileName": "debugger eval code",
+ "lineNumber": 11,
+ "columnNumber": 13
+ }
+ };
+ case "testRangeError":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj1024",
+ "class": "Error",
+ "ownPropertyLength": 4,
+ "preview": {
+ "kind": "Error",
+ "name": "RangeError",
+ "message": "RangeError message",
+ "stack": "@debugger eval code:12:13\n",
+ "fileName": "debugger eval code",
+ "lineNumber": 12,
+ "columnNumber": 13
+ }
+ };
+ case "testReferenceError":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj1025",
+ "class": "Error",
+ "ownPropertyLength": 4,
+ "preview": {
+ "kind": "Error",
+ "name": "ReferenceError",
+ "message": "ReferenceError message",
+ "stack": "@debugger eval code:13:13\n",
+ "fileName": "debugger eval code",
+ "lineNumber": 13,
+ "columnNumber": 13
+ }
+ };
+ case "testSyntaxError":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj1026",
+ "class": "Error",
+ "ownPropertyLength": 4,
+ "preview": {
+ "kind": "Error",
+ "name": "SyntaxError",
+ "message": "SyntaxError message",
+ "stack": "@debugger eval code:14:13\n",
+ "fileName": "debugger eval code",
+ "lineNumber": 14,
+ "columnNumber": 13
+ }
+ };
+ case "testTypeError":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj1027",
+ "class": "Error",
+ "ownPropertyLength": 4,
+ "preview": {
+ "kind": "Error",
+ "name": "TypeError",
+ "message": "TypeError message",
+ "stack": "@debugger eval code:15:13\n",
+ "fileName": "debugger eval code",
+ "lineNumber": 15,
+ "columnNumber": 13
+ }
+ };
+ case "testURIError":
+ return {
+ "type": "object",
+ "actor": "server1.conn1.child1/obj1028",
+ "class": "Error",
+ "ownPropertyLength": 4,
+ "preview": {
+ "kind": "Error",
+ "name": "URIError",
+ "message": "URIError message",
+ "stack": "@debugger eval code:16:13\n",
+ "fileName": "debugger eval code",
+ "lineNumber": 16,
+ "columnNumber": 13
+ }
+ };
+ }
+
+ return null;
+ }
+});
+</script>
+</pre>
+</body>
+</html>
--- a/devtools/client/shared/components/test/mochitest/test_reps_grip-array.html
+++ b/devtools/client/shared/components/test/mochitest/test_reps_grip-array.html
@@ -33,16 +33,21 @@ window.onload = Task.async(function* ()
yield testMaxProps();
yield testMoreThanShortMaxProps();
yield testMoreThanLongMaxProps();
yield testRecursiveArray();
yield testPreviewLimit();
yield testNamedNodeMap();
yield testNodeList();
yield testDocumentFragment();
+
+ yield testOnMouseOver();
+ yield testOnMouseOut();
+
+
} catch(e) {
ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
} finally {
SimpleTest.finish();
}
function testBasic() {
// Test array: `[]`
@@ -300,16 +305,53 @@ window.onload = Task.async(function* ()
mode: "long",
expectedOutput: longOutput,
}
];
testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
}
+
+
+ function testOnMouseOver() {
+ const stub = getGripStub("testNodeList");
+
+ let mouseOverValue;
+ let onDOMNodeMouseOver = (object) => {
+ mouseOverValue = object;
+ };
+ const renderedComponent = renderComponent(
+ GripArray.rep, {object: stub, onDOMNodeMouseOver});
+
+ const nodes = renderedComponent.querySelectorAll(".objectBox-node");
+ nodes.forEach((node, index) => {
+ TestUtils.Simulate.mouseOver(node);
+
+ is(mouseOverValue, stub.preview.items[index], "onDOMNodeMouseOver is called with " +
+ "the expected argument when mouseover is fired on the Rep");
+ });
+ }
+
+ function testOnMouseOut() {
+ const stub = getGripStub("testNodeList");
+
+ let called = false;
+ let onDOMNodeMouseOut = (object) => {
+ called = true;
+ };
+ const renderedComponent = renderComponent(
+ GripArray.rep, {object: stub, onDOMNodeMouseOut});
+
+ const node = renderedComponent.querySelector(".objectBox-node");
+ TestUtils.Simulate.mouseOut(node);
+
+ is(called, true, "onDOMNodeMouseOut is called when mouseout is fired on the Rep");
+ }
+
function getGripStub(functionName) {
switch (functionName) {
case "testBasic":
return {
"type": "object",
"class": "Array",
"actor": "server1.conn0.obj35",
"extensible": true,
--- a/devtools/client/shared/components/test/mochitest/test_reps_text-node.html
+++ b/devtools/client/shared/components/test/mochitest/test_reps_text-node.html
@@ -44,16 +44,19 @@ window.onload = Task.async(function* ()
object: gripStubs.get("testRendering")
});
is(renderedRep.type, TextNode.rep,
`Rep correctly selects ${TextNode.rep.displayName}`);
yield testRendering();
yield testRenderingWithEOL();
+
+ yield testOnMouseOver();
+ yield testOnMouseOut();
} catch (e) {
ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
} finally {
SimpleTest.finish();
}
function testRendering() {
const stub = gripStubs.get("testRendering");
@@ -103,13 +106,42 @@ window.onload = Task.async(function* ()
{
mode: "long",
expectedOutput: defaultLongOutput,
}
];
testRepRenderModes(modeTests, "testRenderingWithEOL", TextNode, stub);
}
+
+ function testOnMouseOver() {
+ const stub = gripStubs.get("testRendering");
+
+ let mouseOverValue;
+ let onDOMNodeMouseOver = (object) => {
+ mouseOverValue = object;
+ };
+ const renderedComponent = renderComponent(
+ TextNode.rep, {object: stub, onDOMNodeMouseOver});
+
+ TestUtils.Simulate.mouseOver(renderedComponent);
+ is(mouseOverValue, stub, "onDOMNodeMouseOver is called with the expected argument " +
+ "when mouseover is fired on the Rep");
+ }
+
+ function testOnMouseOut() {
+ const stub = gripStubs.get("testRendering");
+
+ let called = false;
+ let onDOMNodeMouseOut = (object) => {
+ called = true;
+ };
+ const renderedComponent = renderComponent(
+ TextNode.rep, {object: stub, onDOMNodeMouseOut});
+
+ TestUtils.Simulate.mouseOut(renderedComponent);
+ is(called, true, "onDOMNodeMouseOut is called when mouseout is fired on the Rep");
+ }
});
</script>
</pre>
</body>
</html>
--- a/devtools/client/sourceeditor/test/.eslintrc.js
+++ b/devtools/client/sourceeditor/test/.eslintrc.js
@@ -1,6 +1,10 @@
"use strict";
module.exports = {
// Extend from the shared list of defined globals for mochitests.
- "extends": "../../../.eslintrc.mochitests.js"
+ "extends": "../../../.eslintrc.mochitests.js",
+ "globals": {
+ "runCodeMirrorTest": true,
+ "gBrowser": true
+ }
};
--- a/devtools/client/sourceeditor/test/browser_css_autocompletion.js
+++ b/devtools/client/sourceeditor/test/browser_css_autocompletion.js
@@ -8,17 +8,17 @@ const CSSCompleter = require("devtools/c
const {InspectorFront} = require("devtools/shared/fronts/inspector");
const CSS_URI = "http://mochi.test:8888/browser/devtools/client/sourceeditor" +
"/test/css_statemachine_testcases.css";
const TESTS_URI = "http://mochi.test:8888/browser/devtools/client" +
"/sourceeditor/test/css_autocompletion_tests.json";
const source = read(CSS_URI);
-const tests = eval(read(TESTS_URI));
+const {tests} = JSON.parse(read(TESTS_URI));
const TEST_URI = "data:text/html;charset=UTF-8," + encodeURIComponent(
["<!DOCTYPE html>",
"<html>",
" <head>",
" <title>CSS State machine tests.</title>",
" <style type='text/css'>",
"#progress {",
@@ -55,17 +55,19 @@ const TEST_URI = "data:text/html;charset
" <div id='devtools-toolbarbutton' class='devtools-menulist'></div>",
" <div id='devtools-anotherone'></div>",
" <div id='devtools-yetagain'></div>",
" <div id='devtools-itjustgoeson'></div>",
" <div id='devtools-okstopitnow'></div>",
" <div class='hidden-labels-box devtools-toolbarbutton devtools-menulist'></div>",
" <div class='devtools-menulist'></div>",
" <div class='devtools-menulist'></div>",
+ /* eslint-disable max-len */
" <tabs class='devtools-toolbarbutton'><tab></tab><tab></tab><tab></tab></tabs><tabs></tabs>",
+ /* eslint-enable max-len */
" <button class='category-name visible'></button>",
" <div class='devtools-toolbarbutton' label='true'>",
" <hbox class='toolbarbutton-menubutton-button'></hbox></div>",
" </body>",
" </html>"
].join("\n"));
let doc = null;
@@ -73,17 +75,19 @@ let index = 0;
let completer = null;
let progress;
let progressDiv;
let inspector;
function test() {
waitForExplicitFinish();
addTab(TEST_URI).then(function () {
+ /* eslint-disable mozilla/no-cpows-in-tests */
doc = content.document;
+ /* eslint-enable mozilla/no-cpows-in-tests */
runTests();
});
}
function runTests() {
progress = doc.getElementById("progress");
progressDiv = doc.querySelector("#progress > div");
let target = TargetFactory.forTab(gBrowser.selectedTab);
--- a/devtools/client/sourceeditor/test/browser_css_getInfo.js
+++ b/devtools/client/sourceeditor/test/browser_css_getInfo.js
@@ -51,16 +51,18 @@ const source = [
// Format of test cases :
// [
// {line, ch}, - The caret position at which the getInfo call should be made
// expectedState, - The expected state at the caret
// expectedSelector, - The expected selector for the state
// expectedProperty, - The expected property name for states value and property
// expectedValue, - If state is value, then the expected value
// ]
+
+/* eslint-disable max-len */
const tests = [
[{line: 0, ch: 13}, "selector", ".devtools-toolbar"],
[{line: 8, ch: 13}, "property", ["#devtools-menu.devtools-menulist",
".devtools-toolbarbutton#devtools-menu "], "-moz-appearance"],
[{line: 28, ch: 25}, "value", [".devtools-menulist:active",
"#devtools-toolbarbutton:focus "], "outline-offset", "-4px"],
[{line: 4, ch: 1}, "null"],
[{line: 5, ch: 0}, "null"],
@@ -74,16 +76,17 @@ const tests = [
"linear-gradient(hsla(212,7%,57%,.35),\n hsla(212,7%,57%,.1)) padding-box"],
[{line: 16, ch: 3}, "value", ["#devtools-menu.devtools-menulist",
".devtools-toolbarbutton#devtools-menu "], "background",
"linear-gradient(hsla(212,7%,57%,.35),\n hsla(212,7%,57%,.1)) padding-box"],
[{line: 15, ch: 25}, "value", ["#devtools-menu.devtools-menulist",
".devtools-toolbarbutton#devtools-menu "], "background",
"linear-gradient(hsla(212,7%,57%,.35),\n hsla(212,7%,57%,.1)) padding-box"],
];
+/* eslint-enable max-len */
const TEST_URI = "data:text/html;charset=UTF-8," + encodeURIComponent(
["<!DOCTYPE html>",
"<html>",
" <head>",
" <title>CSS contextual information tests.</title>",
" <style type='text/css'>",
"#progress {",
@@ -120,24 +123,28 @@ const TEST_URI = "data:text/html;charset
" </html>"
].join("\n"));
let doc = null;
function test() {
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(() => {
+ /* eslint-disable mozilla/no-cpows-in-tests */
doc = content.document;
+ /* eslint-enable mozilla/no-cpows-in-tests */
runTests();
});
gBrowser.loadURI(TEST_URI);
}
function runTests() {
- let completer = new CSSCompleter({cssProperties: getClientCssProperties()});
+ let completer = new CSSCompleter({
+ cssProperties: getClientCssProperties()
+ });
let matches = (arr, toCheck) => !arr.some((x, i) => x != toCheck[i]);
let checkState = (expected, actual) => {
if (expected[0] == "null" && actual == null) {
return true;
} else if (expected[0] == actual.state && expected[0] == "selector" &&
expected[1] == actual.selector) {
return true;
} else if (expected[0] == actual.state && expected[0] == "property" &&
--- a/devtools/client/sourceeditor/test/browser_css_statemachine.js
+++ b/devtools/client/sourceeditor/test/browser_css_statemachine.js
@@ -7,17 +7,17 @@
const CSSCompleter = require("devtools/client/sourceeditor/css-autocompleter");
const CSS_URI = "http://mochi.test:8888/browser/devtools/client/sourceeditor" +
"/test/css_statemachine_testcases.css";
const TESTS_URI = "http://mochi.test:8888/browser/devtools/client" +
"/sourceeditor/test/css_statemachine_tests.json";
const source = read(CSS_URI);
-const tests = eval(read(TESTS_URI));
+const {tests} = JSON.parse(read(TESTS_URI));
const TEST_URI = "data:text/html;charset=UTF-8," + encodeURIComponent(
["<!DOCTYPE html>",
"<html>",
" <head>",
" <title>CSS State machine tests.</title>",
" <style type='text/css'>",
"#progress {",
@@ -54,23 +54,27 @@ const TEST_URI = "data:text/html;charset
" </html>"
].join("\n"));
var doc = null;
function test() {
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab(TEST_URI);
BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(() => {
+ /* eslint-disable mozilla/no-cpows-in-tests */
doc = content.document;
+ /* eslint-enable mozilla/no-cpows-in-tests */
runTests();
});
}
function runTests() {
- let completer = new CSSCompleter({cssProperties: getClientCssProperties()});
+ let completer = new CSSCompleter({
+ cssProperties: getClientCssProperties()
+ });
let checkState = state => {
if (state[0] == "null" && (!completer.state || completer.state == "null")) {
return true;
} else if (state[0] == completer.state && state[0] == "selector" &&
state[1] == completer.selectorState &&
state[2] == completer.completing &&
state[3] == completer.selector) {
return true;
@@ -84,25 +88,25 @@ function runTests() {
return true;
}
return false;
};
let progress = doc.getElementById("progress");
let progressDiv = doc.querySelector("#progress > div");
let i = 0;
- for (let test of tests) {
+ for (let testcase of tests) {
progress.dataset.progress = ++i;
progressDiv.style.width = 100 * i / tests.length + "%";
- completer.resolveState(limit(source, test[0]),
- {line: test[0][0], ch: test[0][1]});
- if (checkState(test[1])) {
+ completer.resolveState(limit(source, testcase[0]),
+ {line: testcase[0][0], ch: testcase[0][1]});
+ if (checkState(testcase[1])) {
ok(true, "Test " + i + " passed. ");
} else {
- ok(false, "Test " + i + " failed. Expected state : [" + test[1] + "] " +
+ ok(false, "Test " + i + " failed. Expected state : [" + testcase[1] + "] " +
"but found [" + completer.state + ", " + completer.selectorState +
", " + completer.completing + ", " +
(completer.propertyName || completer.selector) + "].");
progress.classList.add("failed");
}
}
gBrowser.removeCurrentTab();
finish();
--- a/devtools/client/sourceeditor/test/browser_editor_autocomplete_events.js
+++ b/devtools/client/sourceeditor/test/browser_editor_autocomplete_events.js
@@ -1,16 +1,15 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const {InspectorFront} = require("devtools/shared/fronts/inspector");
-const AUTOCOMPLETION_PREF = "devtools.editor.autocomplete";
const TEST_URI = "data:text/html;charset=UTF-8,<html><body><bar></bar>" +
"<div id='baz'></div><body></html>";
add_task(function* () {
yield addTab(TEST_URI);
yield runTests();
});
@@ -94,17 +93,19 @@ function* testKeyboardCycleForPrefixedSt
function* testKeyboardCSSComma(ed, win) {
ed.focus();
ed.setText("b");
ed.setCursor({line: 1, ch: 1});
let isPopupOpened = false;
let popupOpened = ed.getAutocompletionPopup().once("popup-opened");
- popupOpened.then(() => isPopupOpened = true);
+ popupOpened.then(() => {
+ isPopupOpened = true;
+ });
EventUtils.synthesizeKey(",", { }, win);
yield wait(500);
ok(!isPopupOpened, "Autocompletion shouldn't be opened");
}
--- a/devtools/client/sourceeditor/test/browser_editor_find_again.js
+++ b/devtools/client/sourceeditor/test/browser_editor_find_again.js
@@ -10,17 +10,18 @@ const L10N = new LocalizationHelper("dev
const { OS } = Services.appinfo;
// On linux, getting immediately the selection's range here fails, returning
const FIND_KEY = L10N.getStr("find.key");
const FINDNEXT_KEY = L10N.getStr("findNext.key");
const FINDPREV_KEY = L10N.getStr("findPrev.key");
// the replace's key with the appropriate modifiers based on OS
-const REPLACE_KEY = OS == "Darwin" ? L10N.getStr("replaceAllMac.key") : L10N.getStr("replaceAll.key");
+const REPLACE_KEY = OS == "Darwin" ? L10N.getStr("replaceAllMac.key")
+ : L10N.getStr("replaceAll.key");
// values like it's not selected – even if the selection is visible.
// For the record, setting the selection's range immediately doesn't have
// any effect.
// It's like the <input> is not ready yet.
// Therefore, we trigger the UI focus event to the <input>, waiting for the
// response.
// Using a timeout could also work, but that is more precise, ensuring also
--- a/devtools/client/sourceeditor/test/cm_script_injection_test.js
+++ b/devtools/client/sourceeditor/test/cm_script_injection_test.js
@@ -1,8 +1,10 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
+/* global editor */
+
"use strict";
window.addEventListener("editorReady", function () {
editor.setText("Script successfully injected!");
});
--- a/devtools/client/sourceeditor/test/css_autocompletion_tests.json
+++ b/devtools/client/sourceeditor/test/css_autocompletion_tests.json
@@ -1,39 +1,43 @@
-// Test states to be tested for css state machine in css-autocompelter.js file.
-// Test cases are of the following format:
-// [
-// [
-// line, // The line location of the cursor
-// ch // The column locaiton of the cursor
-// ],
-// suggestions // Array of expected results
-// ]
-[
- [[0, 10], []],
- [[4, 7], ['.devtools-menulist', '.devtools-toolbarbutton']],
- [[5, 8], ['-moz-animation', '-moz-animation-delay', '-moz-animation-direction',
- '-moz-animation-duration', '-moz-animation-fill-mode',
- '-moz-animation-iteration-count', '-moz-animation-name',
- '-moz-animation-play-state', '-moz-animation-timing-function',
- '-moz-appearance']],
- [[12, 20], ['none', 'number-input']],
- [[12, 22], ['none']],
- [[17, 22], ['hsl', 'hsla']],
- [[19, 10], ['background', 'background-attachment', 'background-blend-mode',
- 'background-clip', 'background-color', 'background-image',
- 'background-origin', 'background-position', 'background-position-x',
- 'background-position-y', 'background-repeat', 'background-size']],
- [[21, 9], ["-moz-calc", "auto", "calc", "inherit", "initial","unset"]],
- [[25, 26], ['.devtools-toolbarbutton > tab',
- '.devtools-toolbarbutton > hbox',
- '.devtools-toolbarbutton > .toolbarbutton-menubutton-button']],
- [[25, 31], ['.devtools-toolbarbutton > hbox.toolbarbutton-menubutton-button']],
- [[29, 20], ['.devtools-menulist:after', '.devtools-menulist:active']],
- [[30, 10], ['#devtools-anotherone', '#devtools-itjustgoeson', '#devtools-menu',
- '#devtools-okstopitnow', '#devtools-toolbarbutton', '#devtools-yetagain']],
- [[39, 39], ['.devtools-toolbarbutton:not([label]) > tab']],
- [[43, 51], ['.devtools-toolbarbutton:not([checked=true]):hover:after',
- '.devtools-toolbarbutton:not([checked=true]):hover:active']],
- [[58, 36], ['!important;']],
- [[73, 42], [':lang(', ':last-of-type', ':link', ':last-child']],
- [[77, 25], ['.visible']],
-]
+{
+ "description": [
+ "Test states to be tested for css state machine in css-autocompelter.js file.",
+ "Test cases are of the following format:",
+ "[",
+ " [",
+ " line, # The line location of the cursor",
+ " ch # The column locaiton of the cursor",
+ " ],",
+ " suggestions # Array of expected results",
+ "]"
+ ],
+ "tests": [
+ [[0, 10], []],
+ [[4, 7], [".devtools-menulist", ".devtools-toolbarbutton"]],
+ [[5, 8], ["-moz-animation", "-moz-animation-delay", "-moz-animation-direction",
+ "-moz-animation-duration", "-moz-animation-fill-mode",
+ "-moz-animation-iteration-count", "-moz-animation-name",
+ "-moz-animation-play-state", "-moz-animation-timing-function",
+ "-moz-appearance"]],
+ [[12, 20], ["none", "number-input"]],
+ [[12, 22], ["none"]],
+ [[17, 22], ["hsl", "hsla"]],
+ [[19, 10], ["background", "background-attachment", "background-blend-mode",
+ "background-clip", "background-color", "background-image",
+ "background-origin", "background-position", "background-position-x",
+ "background-position-y", "background-repeat", "background-size"]],
+ [[21, 9], ["-moz-calc", "auto", "calc", "inherit", "initial","unset"]],
+ [[25, 26], [".devtools-toolbarbutton > tab",
+ ".devtools-toolbarbutton > hbox",
+ ".devtools-toolbarbutton > .toolbarbutton-menubutton-button"]],
+ [[25, 31], [".devtools-toolbarbutton > hbox.toolbarbutton-menubutton-button"]],
+ [[29, 20], [".devtools-menulist:after", ".devtools-menulist:active"]],
+ [[30, 10], ["#devtools-anotherone", "#devtools-itjustgoeson", "#devtools-menu",
+ "#devtools-okstopitnow", "#devtools-toolbarbutton", "#devtools-yetagain"]],
+ [[39, 39], [".devtools-toolbarbutton:not([label]) > tab"]],
+ [[43, 51], [".devtools-toolbarbutton:not([checked=true]):hover:after",
+ ".devtools-toolbarbutton:not([checked=true]):hover:active"]],
+ [[58, 36], ["!important;"]],
+ [[73, 42], [":lang(", ":last-of-type", ":link", ":last-child"]],
+ [[77, 25], [".visible"]]
+ ]
+}
--- a/devtools/client/sourceeditor/test/css_statemachine_tests.json
+++ b/devtools/client/sourceeditor/test/css_statemachine_tests.json
@@ -1,84 +1,88 @@
-// Test states to be tested for css state machine in css-autocompelter.js file.
-// Test cases are of the following format:
-// [
-// [
-// line, // The line location of the cursor
-// ch // The column locaiton of the cursor
-// ],
-// [
-// state, // one of CSS_STATES
-// selectorState, // one of SELECTOR_STATES
-// completing, // what is being completed
-// propertyName, // what property is being completed in case of value state
-// // or the current selector that is being completed
-// ]
-// ]
-[
- [[0, 10], ['null', '', '', '']],
- [[4, 3], ['selector', 'class', 'de', '.de']],
- [[5, 8], ['property', 'null', '-moz-a']],
- [[5, 21], ['value', 'null', 'no', '-moz-appearance']],
- [[6, 18], ['property', 'null', 'padding']],
- [[6, 24], ['value', 'null', '3', 'padding']],
- [[6, 29], ['property', 'null', 'bo']],
- [[6, 50], ['value', 'null', '1p', 'border-bottom-width']],
- [[7, 24], ['value', 'null', 's', 'border-bottom-style']],
- [[9, 0], ['null', 'null', '', '']],
- [[10, 6], ['selector', 'id', 'devto', '#devto']],
- [[10, 17], ['selector', 'class', 'de', '#devtools-menu.de']],
- [[11, 5], ['selector', 'class', 'devt', '.devt']],
- [[11, 30], ['selector', 'id', 'devtoo', '.devtools-toolbarbutton#devtoo']],
- [[12, 10], ['property', 'null', '-moz-app']],
- [[16, 27], ['value', 'null', 'hsl', 'text-shadow']],
- [[19, 24], ['value', 'null', 'linear-gra', 'background']],
- [[19, 55], ['value', 'null', 'hsl', 'background']],
- [[19, 79], ['value', 'null', 'paddin', 'background']],
- [[20, 47], ['value', 'null', 'ins', 'box-shadow']],
- [[22, 15], ['value', 'null', 'inheri', 'color']],
- [[25, 26], ['selector', 'null', '', '.devtools-toolbarbutton > ']],
- [[25, 28], ['selector', 'tag', 'hb', '.devtools-toolbarbutton > hb']],
- [[25, 41], ['selector', 'class', 'toolbarbut', '.devtools-toolbarbutton > hbox.toolbarbut']],
- [[29, 21], ['selector', 'pseudo', 'ac', '.devtools-menulist:ac']],
- [[30, 27], ['selector', 'pseudo', 'foc', '#devtools-toolbarbutton:foc']],
- [[31, 18], ['value', 'null', 'dot', 'outline']],
- [[32, 25], ['value', 'null', '-4p', 'outline-offset']],
- [[35, 26], ['selector', 'pseudo', 'no', '.devtools-toolbarbutton:no']],
- [[35, 28], ['selector', 'null', 'not', '']],
- [[35, 30], ['selector', 'attribute', 'l', '[l']],
- [[39, 46], ['selector', 'class', 'toolba', '.devtools-toolbarbutton:not([label]) > .toolba']],
- [[43, 39], ['selector', 'value', 'tr', '[checked=tr']],
- [[43, 47], ['selector', 'pseudo', 'hov', '.devtools-toolbarbutton:not([checked=true]):hov']],
- [[43, 53], ['selector', 'pseudo', 'act', '.devtools-toolbarbutton:not([checked=true]):hover:act']],
- [[47, 22], ['selector', 'attribute', 'op', '.devtools-menulist[op']],
- [[47, 33], ['selector', 'value', 'tr', '.devtools-menulist[open =tr']],
- [[48, 38], ['selector', 'value', 'tr', '.devtools-toolbarbutton[open = tr']],
- [[49, 40], ['selector', 'value', 'true', '.devtools-toolbarbutton[checked= true']],
- [[53, 34], ['selector', 'value', '=', '.devtools-toolbarbutton[checked=']],
- [[58, 38], ['value', 'null', '!impor', 'background-color']],
- [[61, 41], ['selector', 'pseudo', 'hov', '.devtools-toolbarbutton[checked=true]:hov']],
- [[65, 47], ['selector', 'class', 'to', '.devtools-toolbarbutton[type=menu-button] > .to']],
- [[69, 44], ['selector', 'pseudo', 'first-of', '.devtools-sidebar-tabs > tabs > tab:first-of']],
- [[73, 45], ['selector', 'pseudo', 'last', ':last']],
- [[77, 27], ['selector', 'class', 'vis', '.vis']],
- [[78, 34], ['selector', 'class', 'hidd', '.hidden-labels-box.visible ~ .hidd']],
- [[83, 5], ['media', 'null', 'medi']],
- [[83, 22], ['media', 'null', '800']],
- [[84, 9], ['selector', 'class', 'catego', '.catego']],
- [[89, 9], ['media', 'null', 'al']],
- [[90, 6], ['selector', 'id', 'err', '#err']],
- [[93, 11], ['property', 'null', 'backgro']],
- [[98, 6], ['selector', 'tag', 'butt', 'butt']],
- [[99, 22], ['value', 'null', '!impor', 'width']],
- [[103, 5], ['keyframes', 'null', 'ke']],
- [[104, 7], ['frame', 'null', 'fro']],
- [[104, 15], ['property', 'null', 'opac']],
- [[104, 29], ['property', 'null', 'transf']],
- [[104, 38], ['value', 'null', 'scal', 'transform']],
- [[105, 8], ['frame', 'null', '']],
- [[113, 6], ['keyframes', 'null', 'keyfr']],
- [[114, 4], ['frame', 'null', 'fr']],
- [[115, 3], ['frame', 'null', '2']],
- [[117, 8], ['property', 'null', 'opac']],
- [[117, 16], ['value', 'null', '0', 'opacity']],
- [[121, 0], ['null', '', '']],
-]
+{
+ "description": [
+ "Test states to be tested for css state machine in css-autocompleter.js file.",
+ "Test cases are of the following format:",
+ "[",
+ " [",
+ " line, // The line location of the cursor",
+ " ch // The column locaiton of the cursor",
+ " ],",
+ " [",
+ " state, // one of CSS_STATES",
+ " selectorState, // one of SELECTOR_STATES",
+ " completing, // what is being completed",
+ " propertyName, // what property is being completed in case of value state",
+ " // or the current selector that is being completed",
+ " ]",
+ "]"
+ ],
+ "tests": [
+ [[0, 10], ["null", "", "", ""]],
+ [[4, 3], ["selector", "class", "de", ".de"]],
+ [[5, 8], ["property", "null", "-moz-a"]],
+ [[5, 21], ["value", "null", "no", "-moz-appearance"]],
+ [[6, 18], ["property", "null", "padding"]],
+ [[6, 24], ["value", "null", "3", "padding"]],
+ [[6, 29], ["property", "null", "bo"]],
+ [[6, 50], ["value", "null", "1p", "border-bottom-width"]],
+ [[7, 24], ["value", "null", "s", "border-bottom-style"]],
+ [[9, 0], ["null", "null", "", ""]],
+ [[10, 6], ["selector", "id", "devto", "#devto"]],
+ [[10, 17], ["selector", "class", "de", "#devtools-menu.de"]],
+ [[11, 5], ["selector", "class", "devt", ".devt"]],
+ [[11, 30], ["selector", "id", "devtoo", ".devtools-toolbarbutton#devtoo"]],
+ [[12, 10], ["property", "null", "-moz-app"]],
+ [[16, 27], ["value", "null", "hsl", "text-shadow"]],
+ [[19, 24], ["value", "null", "linear-gra", "background"]],
+ [[19, 55], ["value", "null", "hsl", "background"]],
+ [[19, 79], ["value", "null", "paddin", "background"]],
+ [[20, 47], ["value", "null", "ins", "box-shadow"]],
+ [[22, 15], ["value", "null", "inheri", "color"]],
+ [[25, 26], ["selector", "null", "", ".devtools-toolbarbutton > "]],
+ [[25, 28], ["selector", "tag", "hb", ".devtools-toolbarbutton > hb"]],
+ [[25, 41], ["selector", "class", "toolbarbut", ".devtools-toolbarbutton > hbox.toolbarbut"]],
+ [[29, 21], ["selector", "pseudo", "ac", ".devtools-menulist:ac"]],
+ [[30, 27], ["selector", "pseudo", "foc", "#devtools-toolbarbutton:foc"]],
+ [[31, 18], ["value", "null", "dot", "outline"]],
+ [[32, 25], ["value", "null", "-4p", "outline-offset"]],
+ [[35, 26], ["selector", "pseudo", "no", ".devtools-toolbarbutton:no"]],
+ [[35, 28], ["selector", "null", "not", ""]],
+ [[35, 30], ["selector", "attribute", "l", "[l"]],
+ [[39, 46], ["selector", "class", "toolba", ".devtools-toolbarbutton:not([label]) > .toolba"]],
+ [[43, 39], ["selector", "value", "tr", "[checked=tr"]],
+ [[43, 47], ["selector", "pseudo", "hov", ".devtools-toolbarbutton:not([checked=true]):hov"]],
+ [[43, 53], ["selector", "pseudo", "act", ".devtools-toolbarbutton:not([checked=true]):hover:act"]],
+ [[47, 22], ["selector", "attribute", "op", ".devtools-menulist[op"]],
+ [[47, 33], ["selector", "value", "tr", ".devtools-menulist[open =tr"]],
+ [[48, 38], ["selector", "value", "tr", ".devtools-toolbarbutton[open = tr"]],
+ [[49, 40], ["selector", "value", "true", ".devtools-toolbarbutton[checked= true"]],
+ [[53, 34], ["selector", "value", "=", ".devtools-toolbarbutton[checked="]],
+ [[58, 38], ["value", "null", "!impor", "background-color"]],
+ [[61, 41], ["selector", "pseudo", "hov", ".devtools-toolbarbutton[checked=true]:hov"]],
+ [[65, 47], ["selector", "class", "to", ".devtools-toolbarbutton[type=menu-button] > .to"]],
+ [[69, 44], ["selector", "pseudo", "first-of", ".devtools-sidebar-tabs > tabs > tab:first-of"]],
+ [[73, 45], ["selector", "pseudo", "last", ":last"]],
+ [[77, 27], ["selector", "class", "vis", ".vis"]],
+ [[78, 34], ["selector", "class", "hidd", ".hidden-labels-box.visible ~ .hidd"]],
+ [[83, 5], ["media", "null", "medi"]],
+ [[83, 22], ["media", "null", "800"]],
+ [[84, 9], ["selector", "class", "catego", ".catego"]],
+ [[89, 9], ["media", "null", "al"]],
+ [[90, 6], ["selector", "id", "err", "#err"]],
+ [[93, 11], ["property", "null", "backgro"]],
+ [[98, 6], ["selector", "tag", "butt", "butt"]],
+ [[99, 22], ["value", "null", "!impor", "width"]],
+ [[103, 5], ["keyframes", "null", "ke"]],
+ [[104, 7], ["frame", "null", "fro"]],
+ [[104, 15], ["property", "null", "opac"]],
+ [[104, 29], ["property", "null", "transf"]],
+ [[104, 38], ["value", "null", "scal", "transform"]],
+ [[105, 8], ["frame", "null", ""]],
+ [[113, 6], ["keyframes", "null", "keyfr"]],
+ [[114, 4], ["frame", "null", "fr"]],
+ [[115, 3], ["frame", "null", "2"]],
+ [[117, 8], ["property", "null", "opac"]],
+ [[117, 16], ["value", "null", "0", "opacity"]],
+ [[121, 0], ["null", "", ""]]
+ ]
+}
\ No newline at end of file
--- a/devtools/client/sourceeditor/test/head.js
+++ b/devtools/client/sourceeditor/test/head.js
@@ -1,12 +1,15 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from ../../framework/test/shared-head.js */
+/* exported promiseWaitForFocus, setup, ch, teardown, loadHelperScript,
+ limit, ch, read, codemirrorSetStatus */
+
"use strict";
// shared-head.js handles imports, constants, and utility functions
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
this);
const { NetUtil } = require("resource://gre/modules/NetUtil.jsm");
@@ -99,26 +102,26 @@ function loadHelperScript(filePath) {
let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
Services.scriptloader.loadSubScript(testDir + "/" + filePath, this);
}
/**
* This method returns the portion of the input string `source` up to the
* [line, ch] location.
*/
-function limit(source, [line, ch]) {
+function limit(source, [line, char]) {
line++;
let list = source.split("\n");
if (list.length < line) {
return source;
}
if (line == 1) {
- return list[0].slice(0, ch);
+ return list[0].slice(0, char);
}
- return [...list.slice(0, line - 1), list[line - 1].slice(0, ch)].join("\n");
+ return [...list.slice(0, line - 1), list[line - 1].slice(0, char)].join("\n");
}
function read(url) {
let scriptableStream = Cc["@mozilla.org/scriptableinputstream;1"]
.getService(Ci.nsIScriptableInputStream);
let channel = NetUtil.newChannel({
uri: url,
--- a/devtools/client/sourceeditor/test/helper_codemirror_runner.js
+++ b/devtools/client/sourceeditor/test/helper_codemirror_runner.js
@@ -1,11 +1,13 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/* exported runCodeMirrorTest */
/* globals codemirrorSetStatus */
"use strict";
function runCodeMirrorTest(browser) {
let mm = browser.messageManager;
mm.addMessageListener("setStatus", function listener({data}) {
let {statusMsg, type, customMsg} = data;
@@ -19,20 +21,22 @@ function runCodeMirrorTest(browser) {
mm = null;
finish();
});
// Interact with the content iframe, giving it a function to
// 1) Proxy CM test harness calls into ok() calls
// 2) Detecting when it finishes by checking the DOM and
// setting a timeout to check again if not.
+ /* eslint-disable max-len */
mm.loadFrameScript("data:," +
"content.wrappedJSObject.mozilla_setStatus = function(statusMsg, type, customMsg) {" +
" sendSyncMessage('setStatus', {statusMsg: statusMsg, type: type, customMsg: customMsg});" +
"};" +
"function check() { " +
" var doc = content.document; var out = doc.getElementById('status'); " +
" if (!out || !out.classList.contains('done')) { return setTimeout(check, 100); }" +
" sendAsyncMessage('done', { failed: content.wrappedJSObject.failed });" +
"}" +
"check();"
, true);
+ /* eslint-enable max-len */
}
--- a/devtools/client/themes/animationinspector.css
+++ b/devtools/client/themes/animationinspector.css
@@ -392,20 +392,16 @@ body {
/* Flex items don't support text-overflow, so a child div is used */
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
background-color: rgba(255, 255, 255, 0.7);
max-width: 50%;
}
-.animation-timeline .fast-track .name div {
- width: calc(100% - var(--fast-track-icon-width));
-}
-
.animation-timeline .fast-track .name::after {
/* Animations running on the compositor have the fast-track background image*/
content: "";
display: block;
position: absolute;
top: 1px;
right: 0;
height: 100%;
--- a/devtools/client/webconsole/new-console-output/components/filter-bar.js
+++ b/devtools/client/webconsole/new-console-output/components/filter-bar.js
@@ -111,16 +111,22 @@ const FilterBar = createClass({
label: "Debug",
filterKey: MESSAGE_LEVEL.DEBUG,
dispatch
}),
dom.span({
className: "devtools-separator",
}),
FilterButton({
+ active: filter.css,
+ label: "CSS",
+ filterKey: "css",
+ dispatch
+ }),
+ FilterButton({
active: filter.netxhr,
label: "XHR",
filterKey: "netxhr",
dispatch
}),
FilterButton({
active: filter.net,
label: "Requests",
--- a/devtools/client/webconsole/new-console-output/components/grip-message-body.js
+++ b/devtools/client/webconsole/new-console-output/components/grip-message-body.js
@@ -40,28 +40,37 @@ GripMessageBody.propTypes = {
function GripMessageBody(props) {
const { grip, userProvidedStyle, serviceContainer } = props;
let styleObject;
if (userProvidedStyle && userProvidedStyle !== "") {
styleObject = cleanupStyle(userProvidedStyle, serviceContainer.createElement);
}
+ let onDOMNodeMouseOver;
+ let onDOMNodeMouseOut;
+ if (serviceContainer) {
+ onDOMNodeMouseOver = (object) => serviceContainer.highlightDomElement(object);
+ onDOMNodeMouseOut = serviceContainer.unHighlightDomElement;
+ }
+
return (
// @TODO once there is a longString rep, also turn off quotes for those.
typeof grip === "string"
? StringRep({
object: grip,
useQuotes: false,
mode: props.mode,
style: styleObject
})
: Rep({
object: grip,
objectLink: VariablesViewLink,
+ onDOMNodeMouseOver,
+ onDOMNodeMouseOut,
defaultRep: Grip,
mode: props.mode,
})
);
}
function cleanupStyle(userProvidedStyle, createElement) {
// Regular expression that matches the allowed CSS property names.
--- a/devtools/client/webconsole/new-console-output/components/message-container.js
+++ b/devtools/client/webconsole/new-console-output/components/message-container.js
@@ -61,16 +61,17 @@ const MessageContainer = createClass({
});
function getMessageComponent(message) {
switch (message.source) {
case MESSAGE_SOURCE.CONSOLE_API:
return componentMap.get("ConsoleApiCall");
case MESSAGE_SOURCE.NETWORK:
return componentMap.get("NetworkEventMessage");
+ case MESSAGE_SOURCE.CSS:
case MESSAGE_SOURCE.JAVASCRIPT:
switch (message.type) {
case MESSAGE_TYPE.COMMAND:
return componentMap.get("ConsoleCommand");
case MESSAGE_TYPE.RESULT:
return componentMap.get("EvaluationResult");
// @TODO this is probably not the right behavior, but works for now.
// Chrome doesn't distinguish between page errors and log messages. We
--- a/devtools/client/webconsole/new-console-output/components/message-types/evaluation-result.js
+++ b/devtools/client/webconsole/new-console-output/components/message-types/evaluation-result.js
@@ -35,17 +35,17 @@ function EvaluationResult(props) {
exceptionDocURL,
frame,
} = message;
let messageBody;
if (message.messageText) {
messageBody = message.messageText;
} else {
- messageBody = GripMessageBody({grip: message.parameters});
+ messageBody = GripMessageBody({grip: message.parameters, serviceContainer});
}
const topLevelClasses = ["cm-s-mozilla"];
const childProps = {
source,
type,
level,
--- a/devtools/client/webconsole/new-console-output/components/variables-view-link.js
+++ b/devtools/client/webconsole/new-console-output/components/variables-view-link.js
@@ -15,20 +15,20 @@ const {openVariablesView} = require("dev
VariablesViewLink.displayName = "VariablesViewLink";
VariablesViewLink.propTypes = {
object: PropTypes.object.isRequired
};
function VariablesViewLink(props) {
- const { object, children } = props;
+ const { className, object, children } = props;
return (
dom.a({
onClick: openVariablesView.bind(null, object),
- className: "cm-variable",
+ className: className || "cm-variable",
draggable: false,
}, children)
);
}
module.exports = VariablesViewLink;
--- a/devtools/client/webconsole/new-console-output/constants.js
+++ b/devtools/client/webconsole/new-console-output/constants.js
@@ -21,28 +21,30 @@ const actionTypes = {
const prefs = {
PREFS: {
FILTER: {
ERROR: "devtools.webconsole.filter.error",
WARN: "devtools.webconsole.filter.warn",
INFO: "devtools.webconsole.filter.info",
LOG: "devtools.webconsole.filter.log",
DEBUG: "devtools.webconsole.filter.debug",
+ CSS: "devtools.webconsole.filter.css",
NET: "devtools.webconsole.filter.net",
NETXHR: "devtools.webconsole.filter.netxhr",
},
UI: {
FILTER_BAR: "devtools.webconsole.ui.filterbar"
}
}
};
const chromeRDPEnums = {
MESSAGE_SOURCE: {
XML: "xml",
+ CSS: "css",
JAVASCRIPT: "javascript",
NETWORK: "network",
CONSOLE_API: "console-api",
STORAGE: "storage",
APPCACHE: "appcache",
RENDERING: "rendering",
SECURITY: "security",
OTHER: "other",
--- a/devtools/client/webconsole/new-console-output/new-console-output-wrapper.js
+++ b/devtools/client/webconsole/new-console-output/new-console-output-wrapper.js
@@ -53,17 +53,27 @@ NewConsoleOutputWrapper.prototype = {
return this.toolbox.selectTool("netmonitor").then(panel => {
return panel.panelWin.NetMonitorController.inspectRequest(requestId);
});
},
sourceMapService: this.toolbox ? this.toolbox._sourceMapService : null,
openLink: url => this.jsterm.hud.owner.openLink.call(this.jsterm.hud.owner, url),
createElement: nodename => {
return this.document.createElementNS("http://www.w3.org/1999/xhtml", nodename);
- }
+ },
+ highlightDomElement: (grip, options = {}) => {
+ return this.toolbox && this.toolbox.highlighterUtils
+ ? this.toolbox.highlighterUtils.highlightDomValueGrip(grip, options)
+ : null;
+ },
+ unHighlightDomElement: (forceHide = false) => {
+ return this.toolbox && this.toolbox.highlighterUtils
+ ? this.toolbox.highlighterUtils.unhighlight(forceHide)
+ : null;
+ },
}
});
let filterBar = FilterBar({
serviceContainer: {
attachRefToHud
}
});
let provider = React.createElement(
--- a/devtools/client/webconsole/new-console-output/reducers/filters.js
+++ b/devtools/client/webconsole/new-console-output/reducers/filters.js
@@ -4,16 +4,17 @@
* 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/. */
"use strict";
const Immutable = require("devtools/client/shared/vendor/immutable");
const constants = require("devtools/client/webconsole/new-console-output/constants");
const FilterState = Immutable.Record({
+ css: false,
debug: true,
error: true,
info: true,
log: true,
net: false,
netxhr: false,
text: "",
warn: true,
--- a/devtools/client/webconsole/new-console-output/selectors/messages.js
+++ b/devtools/client/webconsole/new-console-output/selectors/messages.js
@@ -24,16 +24,17 @@ function getAllMessages(state) {
return prune(
messages.filter(message => {
return (
isInOpenedGroup(message, groups, messagesUI)
&& (
isUnfilterable(message)
|| (
matchLevelFilters(message, filters)
+ && matchCssFilters(message, filters)
&& matchNetworkFilters(message, filters)
&& matchSearchFilters(message, filters)
)
)
);
}),
logLimit
);
@@ -91,16 +92,23 @@ function matchLevelFilters(message, filt
function matchNetworkFilters(message, filters) {
return (
message.source !== MESSAGE_SOURCE.NETWORK
|| (filters.get("net") === true && message.isXHR === false)
|| (filters.get("netxhr") === true && message.isXHR === true)
);
}
+function matchCssFilters(message, filters) {
+ return (
+ message.source != MESSAGE_SOURCE.CSS
+ || filters.get("css") === true
+ );
+}
+
function matchSearchFilters(message, filters) {
let text = filters.text || "";
return (
text === ""
// @TODO currently we return true for any object grip. We should find a way to
// search object grips.
|| (message.parameters !== null && !Array.isArray(message.parameters))
// Look for a match in location.
--- a/devtools/client/webconsole/new-console-output/store.js
+++ b/devtools/client/webconsole/new-console-output/store.js
@@ -25,16 +25,17 @@ function configureStore() {
prefs: new PrefState({
logLimit: Math.max(Services.prefs.getIntPref("devtools.hud.loglimit"), 1),
}),
filters: new FilterState({
error: Services.prefs.getBoolPref(PREFS.FILTER.ERROR),
warn: Services.prefs.getBoolPref(PREFS.FILTER.WARN),
info: Services.prefs.getBoolPref(PREFS.FILTER.INFO),
log: Services.prefs.getBoolPref(PREFS.FILTER.LOG),
+ css: Services.prefs.getBoolPref(PREFS.FILTER.CSS),
net: Services.prefs.getBoolPref(PREFS.FILTER.NET),
netxhr: Services.prefs.getBoolPref(PREFS.FILTER.NETXHR),
}),
ui: new UiState({
filterBarVisible: Services.prefs.getBoolPref(PREFS.UI.FILTER_BAR),
})
};
--- a/devtools/client/webconsole/new-console-output/test/components/message-container.test.js
+++ b/devtools/client/webconsole/new-console-output/test/components/message-container.test.js
@@ -34,16 +34,22 @@ describe("MessageContainer component:",
},
{
component: EvaluationResult,
message: stubPreparedMessages.get("new Date(0)")
},
{
component: PageError,
message: stubPreparedMessages.get("ReferenceError: asdf is not defined")
+ },
+ {
+ component: PageError,
+ message: stubPreparedMessages.get(
+ "Unknown property ‘such-unknown-property’. Declaration dropped."
+ )
}
];
messageTypes.forEach(info => {
const { component, message } = info;
const rendered = shallowRenderComponent(MessageContainer, {
message,
serviceContainer,
--- a/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/browser.ini
+++ b/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/browser.ini
@@ -1,18 +1,22 @@
[DEFAULT]
tags = devtools
subsuite = devtools
support-files =
head.js
!/devtools/client/framework/test/shared-head.js
test-console-api.html
+ test-css-message.html
test-network-event.html
+ test-tempfile.css
test-tempfile.js
[browser_webconsole_update_stubs_console_api.js]
skip-if=true # This is only used to update stubs. It is not an actual test.
+[browser_webconsole_update_stubs_css_message.js]
+skip-if=true # This is only used to update stubs. It is not an actual test.
[browser_webconsole_update_stubs_evaluation_result.js]
skip-if=true # This is only used to update stubs. It is not an actual test.
[browser_webconsole_update_stubs_network_event.js]
skip-if=true # This is only used to update stubs. It is not an actual test.
[browser_webconsole_update_stubs_page_error.js]
skip-if=true # This is only used to update stubs. It is not an actual test.
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/browser_webconsole_update_stubs_css_message.js
@@ -0,0 +1,48 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+Cu.import("resource://gre/modules/osfile.jsm");
+const TEST_URI = "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-css-message.html";
+
+const { cssMessage: snippets} = require("devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/stub-snippets.js");
+
+let stubs = {
+ preparedMessages: [],
+ packets: [],
+};
+
+add_task(function* () {
+ let toolbox = yield openNewTabAndToolbox(TEST_URI, "webconsole");
+ ok(true, "make the test not fail");
+
+ for (let [key, code] of snippets) {
+ OS.File.writeAtomic(TEMP_CSS_FILE_PATH, code);
+ let received = new Promise(resolve => {
+ /* CSS errors are considered as pageError on the server */
+ toolbox.target.client.addListener("pageError", function onPacket(e, packet) {
+ toolbox.target.client.removeListener("pageError", onPacket);
+ info("Received css message:" + e + " " + JSON.stringify(packet, null, "\t"));
+
+ let message = prepareMessage(packet, {getNextId: () => 1});
+ stubs.packets.push(formatPacket(message.messageText, packet));
+ stubs.preparedMessages.push(formatStub(message.messageText, packet));
+ resolve();
+ });
+ });
+
+ yield ContentTask.spawn(gBrowser.selectedBrowser, key, function (snippetKey) {
+ let stylesheet = content.document.createElement("link");
+ stylesheet.rel = "stylesheet";
+ stylesheet.href = "test-tempfile.css?key=" + encodeURIComponent(snippetKey);
+ content.document.body.appendChild(stylesheet);
+ });
+
+ yield received;
+ }
+
+ let filePath = OS.Path.join(`${BASE_PATH}/stubs`, "cssMessage.js");
+ OS.File.writeAtomic(filePath, formatFile(stubs));
+ OS.File.writeAtomic(TEMP_CSS_FILE_PATH, "");
+});
--- a/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/head.js
+++ b/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/head.js
@@ -17,16 +17,18 @@ registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.webconsole.new-frontend-enabled");
});
const { prepareMessage } = require("devtools/client/webconsole/new-console-output/utils/messages");
const { stubPackets } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs/index.js");
const BASE_PATH = "../../../../devtools/client/webconsole/new-console-output/test/fixtures";
const TEMP_FILE_PATH = OS.Path.join(`${BASE_PATH}/stub-generators`, "test-tempfile.js");
+const TEMP_CSS_FILE_PATH = OS.Path.join(`${BASE_PATH}/stub-generators`,
+ "test-tempfile.css");
let cachedPackets = {};
function getCleanedPacket(key, packet) {
if(Object.keys(cachedPackets).includes(key)) {
return cachedPackets[key];
}
--- a/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/stub-snippets.js
+++ b/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/stub-snippets.js
@@ -84,16 +84,31 @@ consoleApi.set("console.log(%cfoobar)",
keys: ["console.log(%cfoobar)"],
code: `
console.log(
"%cfoo%cbar",
"color:blue;font-size:1.3em;background:url('http://example.com/test');position:absolute;top:10px",
"color:red;background:\\165rl('http://example.com/test')");
`});
+// CSS messages
+const cssMessage = new Map();
+
+cssMessage.set("Unknown property", `
+p {
+ such-unknown-property: wow;
+}
+`);
+
+cssMessage.set("Invalid property value", `
+p {
+ padding-top: invalid value;
+}
+`);
+
// Evaluation Result
const evaluationResultCommands = [
"new Date(0)",
"asdf()",
"1 + @"
];
let evaluationResult = new Map(evaluationResultCommands.map(cmd => [cmd, cmd]));
@@ -137,12 +152,13 @@ pageError.set("Reference Error", `
bar()
}
foo()
`);
module.exports = {
consoleApi,
+ cssMessage,
evaluationResult,
networkEvent,
pageError,
};
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-css-message.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Stub generator</title>
+ </head>
+ <body>
+ <p>Stub generator</p>
+ <link rel="stylesheet" href="test-tempfile.css"/>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/new-console-output/test/fixtures/stubs/cssMessage.js
@@ -0,0 +1,105 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/*
+ * THIS FILE IS AUTOGENERATED. DO NOT MODIFY BY HAND. RUN TESTS IN FIXTURES/ TO UPDATE.
+ */
+
+const { ConsoleMessage, NetworkEventMessage } = require("devtools/client/webconsole/new-console-output/types");
+
+let stubPreparedMessages = new Map();
+let stubPackets = new Map();
+
+
+stubPreparedMessages.set("Unknown property ‘such-unknown-property’. Declaration dropped.", new ConsoleMessage({
+ "id": "1",
+ "allowRepeating": true,
+ "source": "css",
+ "type": "log",
+ "level": "warn",
+ "messageText": "Unknown property ‘such-unknown-property’. Declaration dropped.",
+ "parameters": null,
+ "repeat": 1,
+ "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"css\",\"type\":\"log\",\"level\":\"warn\",\"messageText\":\"Unknown property ‘such-unknown-property’. Declaration dropped.\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.css?key=Unknown%20property\",\"line\":3,\"column\":23},\"groupId\":null,\"userProvidedStyles\":null}",
+ "stacktrace": null,
+ "frame": {
+ "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.css?key=Unknown%20property",
+ "line": 3,
+ "column": 23
+ },
+ "groupId": null,
+ "userProvidedStyles": null
+}));
+
+stubPreparedMessages.set("Error in parsing value for ‘padding-top’. Declaration dropped.", new ConsoleMessage({
+ "id": "1",
+ "allowRepeating": true,
+ "source": "css",
+ "type": "log",
+ "level": "warn",
+ "messageText": "Error in parsing value for ‘padding-top’. Declaration dropped.",
+ "parameters": null,
+ "repeat": 1,
+ "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"css\",\"type\":\"log\",\"level\":\"warn\",\"messageText\":\"Error in parsing value for ‘padding-top’. Declaration dropped.\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.css?key=Invalid%20property%20value\",\"line\":3,\"column\":15},\"groupId\":null,\"userProvidedStyles\":null}",
+ "stacktrace": null,
+ "frame": {
+ "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.css?key=Invalid%20property%20value",
+ "line": 3,
+ "column": 15
+ },
+ "groupId": null,
+ "userProvidedStyles": null
+}));
+
+
+stubPackets.set("Unknown property ‘such-unknown-property’. Declaration dropped.", {
+ "from": "server1.conn0.child1/consoleActor2",
+ "type": "pageError",
+ "pageError": {
+ "errorMessage": "Unknown property ‘such-unknown-property’. Declaration dropped.",
+ "errorMessageName": "",
+ "sourceName": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.css?key=Unknown%20property",
+ "lineText": " such-unknown-property: wow;",
+ "lineNumber": 3,
+ "columnNumber": 23,
+ "category": "CSS Parser",
+ "timeStamp": 1478964550247,
+ "warning": true,
+ "error": false,
+ "exception": false,
+ "strict": false,
+ "info": false,
+ "private": false,
+ "stacktrace": null
+ }
+});
+
+stubPackets.set("Error in parsing value for ‘padding-top’. Declaration dropped.", {
+ "from": "server1.conn0.child1/consoleActor2",
+ "type": "pageError",
+ "pageError": {
+ "errorMessage": "Error in parsing value for ‘padding-top’. Declaration dropped.",
+ "errorMessageName": "",
+ "sourceName": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.css?key=Invalid%20property%20value",
+ "lineText": " padding-top: invalid value;",
+ "lineNumber": 3,
+ "columnNumber": 15,
+ "category": "CSS Parser",
+ "timeStamp": 1478964550282,
+ "warning": true,
+ "error": false,
+ "exception": false,
+ "strict": false,
+ "info": false,
+ "private": false,
+ "stacktrace": null
+ }
+});
+
+
+module.exports = {
+ stubPreparedMessages,
+ stubPackets,
+}
\ No newline at end of file
--- a/devtools/client/webconsole/new-console-output/test/fixtures/stubs/index.js
+++ b/devtools/client/webconsole/new-console-output/test/fixtures/stubs/index.js
@@ -2,28 +2,31 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
let maps = [];
[
"consoleApi",
+ "cssMessage",
"evaluationResult",
"networkEvent",
"pageError",
].forEach((filename) => {
maps[filename] = require(`./${filename}`);
});
// Combine all the maps into a single map.
module.exports = {
- stubPreparedMessages: new Map([
- ...maps.consoleApi.stubPreparedMessages,
- ...maps.evaluationResult.stubPreparedMessages,
- ...maps.networkEvent.stubPreparedMessages,
- ...maps.pageError.stubPreparedMessages, ]),
- stubPackets: new Map([
- ...maps.consoleApi.stubPackets,
- ...maps.evaluationResult.stubPackets,
- ...maps.networkEvent.stubPackets,
- ...maps.pageError.stubPackets, ]),
+ stubPreparedMessages: new Map([
+ ...maps.consoleApi.stubPreparedMessages,
+ ...maps.cssMessage.stubPreparedMessages,
+ ...maps.evaluationResult.stubPreparedMessages,
+ ...maps.networkEvent.stubPreparedMessages,
+ ...maps.pageError.stubPreparedMessages, ]),
+ stubPackets: new Map([
+ ...maps.consoleApi.stubPackets,
+ ...maps.cssMessage.stubPackets,
+ ...maps.evaluationResult.stubPackets,
+ ...maps.networkEvent.stubPackets,
+ ...maps.pageError.stubPackets, ]),
};
--- a/devtools/client/webconsole/new-console-output/test/fixtures/stubs/moz.build
+++ b/devtools/client/webconsole/new-console-output/test/fixtures/stubs/moz.build
@@ -1,11 +1,12 @@
# 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/.
DevToolsModules(
'consoleApi.js',
+ 'cssMessage.js',
'evaluationResult.js',
'index.js',
'networkEvent.js',
'pageError.js',
)
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
@@ -12,10 +12,11 @@ support-files =
[browser_webconsole_batching.js]
[browser_webconsole_console_group.js]
[browser_webconsole_console_table.js]
[browser_webconsole_filters.js]
[browser_webconsole_init.js]
[browser_webconsole_input_focus.js]
[browser_webconsole_keyboard_accessibility.js]
+[browser_webconsole_nodes_highlight.js]
[browser_webconsole_observer_notifications.js]
[browser_webconsole_vview_close_on_esc_key.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_nodes_highlight.js
@@ -0,0 +1,51 @@
+/* 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/. */
+
+"use strict";
+
+// Check hovering logged nodes highlight them in the content page.
+
+const HTML = `
+ <!DOCTYPE html>
+ <html>
+ <body>
+ <h1>Node Highlight Test</h1>
+ </body>
+ <script>
+ function logNode(selector) {
+ console.log(document.querySelector(selector));
+ }
+ </script>
+ </html>
+`;
+const TEST_URI = "data:text/html;charset=utf-8," + encodeURI(HTML);
+
+add_task(function* () {
+ const hud = yield openNewTabAndConsole(TEST_URI);
+ const toolbox = gDevTools.getToolbox(hud.target);
+
+ yield ContentTask.spawn(gBrowser.selectedBrowser, null, () => {
+ content.wrappedJSObject.logNode("h1");
+ });
+
+ let msg = yield waitFor(() => findMessage(hud, "<h1>"));
+ let node = msg.querySelector(".objectBox-node");
+ ok(node !== null, "Node was logged as expected");
+ const view = node.ownerDocument.defaultView;
+
+ info("Highlight the node by moving the cursor on it");
+ let onNodeHighlight = toolbox.once("node-highlight");
+ EventUtils.synthesizeMouseAtCenter(node, {type: "mousemove"}, view);
+
+ let nodeFront = yield onNodeHighlight;
+ is(nodeFront.displayName, "h1", "The correct node was highlighted");
+
+ info("Unhighlight the node by moving away from the node");
+ let onNodeUnhighlight = toolbox.once("node-unhighlight");
+ let btn = toolbox.doc.querySelector(".toolbox-dock-button");
+ EventUtils.synthesizeMouseAtCenter(btn, {type: "mousemove"}, view);
+
+ yield onNodeUnhighlight;
+ ok(true, "node-unhighlight event was fired when moving away from the node");
+});
--- a/devtools/client/webconsole/new-console-output/test/store/filters.test.js
+++ b/devtools/client/webconsole/new-console-output/test/store/filters.test.js
@@ -55,16 +55,30 @@ describe("Filtering", () => {
it("filters error messages", () => {
store.dispatch(actions.filterToggle(MESSAGE_LEVEL.ERROR));
let messages = getAllMessages(store.getState());
expect(messages.size).toEqual(numMessages - 1);
});
+ it("filters css messages", () => {
+ let message = stubPreparedMessages.get(
+ "Unknown property ‘such-unknown-property’. Declaration dropped."
+ );
+ store.dispatch(messageAdd(message));
+
+ let messages = getAllMessages(store.getState());
+ expect(messages.size).toEqual(numMessages);
+
+ store.dispatch(actions.filterToggle("css"));
+ messages = getAllMessages(store.getState());
+ expect(messages.size).toEqual(numMessages + 1);
+ });
+
it("filters xhr messages", () => {
let message = stubPreparedMessages.get("XHR GET request");
store.dispatch(messageAdd(message));
let messages = getAllMessages(store.getState());
expect(messages.size).toEqual(numMessages);
store.dispatch(actions.filterToggle("netxhr"));
@@ -162,30 +176,32 @@ describe("Clear filters", () => {
// Setup test case
store.dispatch(actions.filterToggle(MESSAGE_LEVEL.ERROR));
store.dispatch(actions.filterToggle("netxhr"));
store.dispatch(actions.filterTextSet("foobar"));
let filters = getAllFilters(store.getState());
expect(filters.toJS()).toEqual({
+ "css": true,
"debug": true,
"error": false,
"info": true,
"log": true,
"net": false,
"netxhr": true,
"warn": true,
"text": "foobar"
});
store.dispatch(actions.filtersClear());
filters = getAllFilters(store.getState());
expect(filters.toJS()).toEqual({
+ "css": false,
"debug": true,
"error": true,
"info": true,
"log": true,
"net": false,
"netxhr": false,
"warn": true,
"text": ""
--- a/devtools/client/webconsole/new-console-output/utils/messages.js
+++ b/devtools/client/webconsole/new-console-output/utils/messages.js
@@ -152,18 +152,21 @@ function transformPacket(packet) {
}
const frame = pageError.sourceName ? {
source: pageError.sourceName,
line: pageError.lineNumber,
column: pageError.columnNumber
} : null;
+ let matchesCSS = /^(?:CSS|Layout)\b/.test(pageError.category);
+ let messageSource = matchesCSS ? MESSAGE_SOURCE.CSS
+ : MESSAGE_SOURCE.JAVASCRIPT;
return new ConsoleMessage({
- source: MESSAGE_SOURCE.JAVASCRIPT,
+ source: messageSource,
type: MESSAGE_TYPE.LOG,
level,
messageText: pageError.errorMessage,
stacktrace: pageError.stacktrace ? pageError.stacktrace : null,
frame,
exceptionDocURL: pageError.exceptionDocURL,
});
}
--- a/devtools/client/webconsole/webconsole.js
+++ b/devtools/client/webconsole/webconsole.js
@@ -3294,19 +3294,16 @@ WebConsoleConnectionProxy.prototype = {
console.error("Web Console getCachedMessages error: invalid state.");
}
let messages =
response.messages.concat(...this.webConsoleClient.getNetworkEvents());
messages.sort((a, b) => a.timeStamp - b.timeStamp);
if (this.webConsoleFrame.NEW_CONSOLE_OUTPUT_ENABLED) {
- // Filter out CSS page errors.
- messages = messages.filter(message => !(message._type == "PageError"
- && Utils.categoryForScriptError(message) === CATEGORY_CSS));
this.dispatchMessagesAdd(messages);
} else {
this.webConsoleFrame.displayCachedMessages(messages);
if (!this._hasNativeConsoleAPI) {
this.webConsoleFrame.logWarningAboutReplacedAPI();
}
}
@@ -3322,20 +3319,17 @@ WebConsoleConnectionProxy.prototype = {
* @param string type
* Message type.
* @param object packet
* The message received from the server.
*/
_onPageError: function (type, packet) {
if (this.webConsoleFrame && packet.from == this._consoleActor) {
if (this.webConsoleFrame.NEW_CONSOLE_OUTPUT_ENABLED) {
- let category = Utils.categoryForScriptError(packet.pageError);
- if (category !== CATEGORY_CSS) {
- this.dispatchMessageAdd(packet);
- }
+ this.dispatchMessageAdd(packet);
return;
}
this.webConsoleFrame.handlePageError(packet.pageError);
}
},
/**
* The "logMessage" message type handler. We redirect any message to the UI
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -8475,20 +8475,18 @@ nsContentUtils::SetFetchReferrerURIWithP
referrerURI = docCurURI;
}
}
if (!referrerURI) {
referrerURI = principalURI;
}
- net::ReferrerPolicy referrerPolicy = aReferrerPolicy;
- if (referrerPolicy == net::RP_Default) {
- referrerPolicy = aDoc->GetReferrerPolicy();
- }
+ net::ReferrerPolicy referrerPolicy = (aReferrerPolicy != net::RP_Unset) ?
+ aReferrerPolicy : net::RP_Default;
return aChannel->SetReferrerWithPolicy(referrerURI, referrerPolicy);
}
// static
net::ReferrerPolicy
nsContentUtils::GetReferrerPolicyFromHeader(const nsAString& aHeader)
{
// Multiple headers could be concatenated into one comma-separated
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -11838,17 +11838,30 @@ nsGlobalWindow::CloneStorageEvent(const
RefPtr<StorageEvent> event = StorageEvent::Constructor(this, aType, dict);
return event.forget();
}
void
nsGlobalWindow::Suspend()
{
MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(IsInnerWindow());
+ MOZ_DIAGNOSTIC_ASSERT(IsInnerWindow());
+
+ // We can only safely suspend windows that are the current inner window. If
+ // its not the current inner, then we are in one of two different cases.
+ // Either we are in the bfcache or we are doomed window that is going away.
+ // When a window becomes inactive we purposely avoid placing already suspended
+ // windows into the bfcache. It only expects windows suspended due to the
+ // Freeze() method which occurs while the window is still the current inner.
+ // So we must not call Suspend() on bfcache windows at this point or this
+ // invariant will be broken. If the window is doomed there is no point in
+ // suspending it since it will soon be gone.
+ if (!AsInner()->IsCurrentInnerWindow()) {
+ return;
+ }
// All children are also suspended. This ensure mSuspendDepth is
// set properly and the timers are properly canceled for each child.
CallOnChildren(&nsGlobalWindow::Suspend);
mSuspendDepth += 1;
if (mSuspendDepth != 1) {
return;
@@ -11886,17 +11899,27 @@ nsGlobalWindow::Suspend()
RefPtr<Promise> d = mAudioContexts[i]->Suspend(dummy);
}
}
void
nsGlobalWindow::Resume()
{
MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(IsInnerWindow());
+ MOZ_DIAGNOSTIC_ASSERT(IsInnerWindow());
+
+ // We can only safely resume a window if its the current inner window. If
+ // its not the current inner, then we are in one of two different cases.
+ // Either we are in the bfcache or we are doomed window that is going away.
+ // If a window is suspended when it becomes inactive we purposely do not
+ // put it in the bfcache, so Resume should never be needed in that case.
+ // If the window is doomed then there is no point in resuming it.
+ if (!AsInner()->IsCurrentInnerWindow()) {
+ return;
+ }
// Resume all children. This restores timers recursively canceled
// in Suspend() and ensures all children have the correct mSuspendDepth.
CallOnChildren(&nsGlobalWindow::Resume);
MOZ_ASSERT(mSuspendDepth != 0);
mSuspendDepth -= 1;
if (mSuspendDepth != 0) {
@@ -11983,26 +12006,27 @@ nsGlobalWindow::IsSuspended() const
}
return mSuspendDepth != 0;
}
void
nsGlobalWindow::Freeze()
{
MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(IsInnerWindow());
Suspend();
FreezeInternal();
}
void
nsGlobalWindow::FreezeInternal()
{
MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(IsSuspended());
+ MOZ_DIAGNOSTIC_ASSERT(IsInnerWindow());
+ MOZ_DIAGNOSTIC_ASSERT(AsInner()->IsCurrentInnerWindow());
+ MOZ_DIAGNOSTIC_ASSERT(IsSuspended());
CallOnChildren(&nsGlobalWindow::FreezeInternal);
mFreezeDepth += 1;
MOZ_ASSERT(mSuspendDepth >= mFreezeDepth);
if (mFreezeDepth != 1) {
return;
}
@@ -12028,26 +12052,27 @@ nsGlobalWindow::FreezeInternal()
NotifyDOMWindowFrozen(this);
}
void
nsGlobalWindow::Thaw()
{
MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(IsInnerWindow());
ThawInternal();
Resume();
}
void
nsGlobalWindow::ThawInternal()
{
MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(IsSuspended());
+ MOZ_DIAGNOSTIC_ASSERT(IsInnerWindow());
+ MOZ_DIAGNOSTIC_ASSERT(AsInner()->IsCurrentInnerWindow());
+ MOZ_DIAGNOSTIC_ASSERT(IsSuspended());
CallOnChildren(&nsGlobalWindow::ThawInternal);
MOZ_ASSERT(mFreezeDepth != 0);
mFreezeDepth -= 1;
MOZ_ASSERT(mSuspendDepth >= mFreezeDepth);
if (mFreezeDepth != 0) {
return;
@@ -12094,16 +12119,17 @@ nsGlobalWindow::IsFrozen() const
}
void
nsGlobalWindow::SyncStateFromParentWindow()
{
// This method should only be called on an inner window that has been
// assigned to an outer window already.
MOZ_ASSERT(IsInnerWindow());
+ MOZ_ASSERT(AsInner()->IsCurrentInnerWindow());
nsPIDOMWindowOuter* outer = GetOuterWindow();
MOZ_ASSERT(outer);
// Attempt to find our parent windows.
nsCOMPtr<Element> frame = outer->GetFrameElementInternal();
nsPIDOMWindowOuter* parentOuter = frame ? frame->OwnerDoc()->GetWindow()
: nullptr;
nsGlobalWindow* parentInner =
@@ -12137,16 +12163,18 @@ nsGlobalWindow::SyncStateFromParentWindo
}
}
template<typename Method>
void
nsGlobalWindow::CallOnChildren(Method aMethod)
{
MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(IsInnerWindow());
+ MOZ_ASSERT(AsInner()->IsCurrentInnerWindow());
nsCOMPtr<nsIDocShell> docShell = GetDocShell();
if (!docShell) {
return;
}
int32_t childCount = 0;
docShell->GetChildCount(&childCount);
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1087,23 +1087,23 @@ DOMInterfaces = {
'headerFile': 'WebGLBuffer.h'
},
'WEBGL_compressed_texture_atc': {
'nativeType': 'mozilla::WebGLExtensionCompressedTextureATC',
'headerFile': 'WebGLExtensions.h'
},
-'WEBGL_compressed_texture_etc1': {
- 'nativeType': 'mozilla::WebGLExtensionCompressedTextureETC1',
+'WEBGL_compressed_texture_etc': {
+ 'nativeType': 'mozilla::WebGLExtensionCompressedTextureES3',
'headerFile': 'WebGLExtensions.h'
},
-'WEBGL_compressed_texture_es3': {
- 'nativeType': 'mozilla::WebGLExtensionCompressedTextureES3',
+'WEBGL_compressed_texture_etc1': {
+ 'nativeType': 'mozilla::WebGLExtensionCompressedTextureETC1',
'headerFile': 'WebGLExtensions.h'
},
'WEBGL_compressed_texture_pvrtc': {
'nativeType': 'mozilla::WebGLExtensionCompressedTexturePVRTC',
'headerFile': 'WebGLExtensions.h'
},
@@ -1275,21 +1275,16 @@ DOMInterfaces = {
'headerFile': 'WebGLSync.h'
},
'WebGLTexture': {
'nativeType': 'mozilla::WebGLTexture',
'headerFile': 'WebGLTexture.h'
},
-'WebGLTimerQueryEXT': {
- 'nativeType': 'mozilla::WebGLTimerQuery',
- 'headerFile': 'WebGLTimerQuery.h'
-},
-
'WebGLTransformFeedback': {
'nativeType': 'mozilla::WebGLTransformFeedback',
'headerFile': 'WebGLTransformFeedback.h'
},
'WebGLUniformLocation': {
'nativeType': 'mozilla::WebGLUniformLocation',
'headerFile': 'WebGLUniformLocation.h'
--- a/dom/cache/DBSchema.cpp
+++ b/dom/cache/DBSchema.cpp
@@ -192,17 +192,20 @@ static_assert(int(HeadersGuardEnum::None
int(HeadersGuardEnum::EndGuard_) == 5,
"HeadersGuardEnum values are as expected");
static_assert(int(ReferrerPolicy::_empty) == 0 &&
int(ReferrerPolicy::No_referrer) == 1 &&
int(ReferrerPolicy::No_referrer_when_downgrade) == 2 &&
int(ReferrerPolicy::Origin) == 3 &&
int(ReferrerPolicy::Origin_when_cross_origin) == 4 &&
int(ReferrerPolicy::Unsafe_url) == 5 &&
- int(ReferrerPolicy::EndGuard_) == 6,
+ int(ReferrerPolicy::Same_origin) == 6 &&
+ int(ReferrerPolicy::Strict_origin) == 7 &&
+ int(ReferrerPolicy::Strict_origin_when_cross_origin) == 8 &&
+ int(ReferrerPolicy::EndGuard_) == 9,
"ReferrerPolicy values are as expected");
static_assert(int(RequestMode::Same_origin) == 0 &&
int(RequestMode::No_cors) == 1 &&
int(RequestMode::Cors) == 2 &&
int(RequestMode::Navigate) == 3 &&
int(RequestMode::EndGuard_) == 4,
"RequestMode values are as expected");
static_assert(int(RequestCredentials::Omit) == 0 &&
--- a/dom/canvas/WebGL1Context.cpp
+++ b/dom/canvas/WebGL1Context.cpp
@@ -33,22 +33,16 @@ WebGL1Context::CreateFormatUsage(gl::GLC
}
JSObject*
WebGL1Context::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
{
return dom::WebGLRenderingContextBinding::Wrap(cx, this, givenProto);
}
-bool
-WebGL1Context::ValidateQueryTarget(GLenum target, const char* info)
-{
- return false;
-}
-
} // namespace mozilla
nsresult
NS_NewCanvasRenderingContextWebGL(nsIDOMWebGLRenderingContext** out_result)
{
mozilla::Telemetry::Accumulate(mozilla::Telemetry::CANVAS_WEBGL_USED, 1);
nsIDOMWebGLRenderingContext* ctx = mozilla::WebGL1Context::Create();
--- a/dom/canvas/WebGL1Context.h
+++ b/dom/canvas/WebGL1Context.h
@@ -31,15 +31,14 @@ public:
// nsWrapperCache
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
private:
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type,
uint32_t* alignment,
const char* info) override;
- virtual bool ValidateQueryTarget(GLenum target, const char* info) override;
virtual bool ValidateUniformMatrixTranspose(bool transpose, const char* info) override;
};
} // namespace mozilla
#endif // WEBGL_1_CONTEXT_H_
--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -298,28 +298,16 @@ public:
GLuint srcElemOffset)
{
ClearBufferuiv(buffer, drawBuffer, Uint32Arr::From(list), srcElemOffset);
}
void ClearBufferfi(GLenum buffer, GLint drawBuffer, GLfloat depth, GLint stencil);
// -------------------------------------------------------------------------
- // Query Objects - WebGL2ContextQueries.cpp
-
- already_AddRefed<WebGLQuery> CreateQuery();
- void DeleteQuery(WebGLQuery* query);
- bool IsQuery(WebGLQuery* query);
- void BeginQuery(GLenum target, WebGLQuery* query);
- void EndQuery(GLenum target);
- already_AddRefed<WebGLQuery> GetQuery(GLenum target, GLenum pname);
- void GetQueryParameter(JSContext*, WebGLQuery* query, GLenum pname, JS::MutableHandleValue retval);
-
-
- // -------------------------------------------------------------------------
// Sampler Objects - WebGL2ContextSamplers.cpp
already_AddRefed<WebGLSampler> CreateSampler();
void DeleteSampler(WebGLSampler* sampler);
bool IsSampler(WebGLSampler* sampler);
void BindSampler(GLuint unit, WebGLSampler* sampler);
void SamplerParameteri(WebGLSampler* sampler, GLenum pname, GLint param);
void SamplerParameteriv(WebGLSampler* sampler, GLenum pname, const dom::Int32Array& param);
@@ -405,15 +393,14 @@ private:
void UpdateBoundQuery(GLenum target, WebGLQuery* query);
// CreateVertexArrayImpl is assumed to be infallible.
virtual WebGLVertexArray* CreateVertexArrayImpl() override;
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type,
uint32_t* alignment,
const char* info) override;
- virtual bool ValidateQueryTarget(GLenum target, const char* info) override;
virtual bool ValidateUniformMatrixTranspose(bool transpose, const char* info) override;
};
} // namespace mozilla
#endif
--- a/dom/canvas/WebGL2ContextQueries.cpp
+++ b/dom/canvas/WebGL2ContextQueries.cpp
@@ -17,393 +17,234 @@ namespace mozilla {
*
* OpenGL ES 3.0 spec 4.1.6:
* If the target of the query is ANY_SAMPLES_PASSED_CONSERVATIVE, an
* implementation may choose to use a less precise version of the test which
* can additionally set the samples-boolean state to TRUE in some other
* implementation-dependent cases.
*/
-static const char*
-GetQueryTargetEnumString(GLenum target)
+WebGLRefPtr<WebGLQuery>*
+WebGLContext::ValidateQuerySlotByTarget(const char* funcName, GLenum target)
{
- switch (target)
- {
- case LOCAL_GL_ANY_SAMPLES_PASSED:
- return "ANY_SAMPLES_PASSED";
- case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
- return "ANY_SAMPLES_PASSED_CONSERVATIVE";
- case LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
- return "TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN";
- default:
- break;
+ if (IsWebGL2()) {
+ switch (target) {
+ case LOCAL_GL_ANY_SAMPLES_PASSED:
+ case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
+ return &mQuerySlot_SamplesPassed;
+
+ case LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
+ return &mQuerySlot_TFPrimsWritten;
+
+ default:
+ break;
+ }
}
- MOZ_ASSERT(false, "Unknown query `target`.");
- return "UNKNOWN_QUERY_TARGET";
-}
+ if (IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query)) {
+ switch (target) {
+ case LOCAL_GL_TIME_ELAPSED_EXT:
+ return &mQuerySlot_TimeElapsed;
-static inline GLenum
-SimulateOcclusionQueryTarget(const gl::GLContext* gl, GLenum target)
-{
- MOZ_ASSERT(target == LOCAL_GL_ANY_SAMPLES_PASSED ||
- target == LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE,
- "unknown occlusion query target");
-
- if (gl->IsSupported(gl::GLFeature::occlusion_query_boolean)) {
- return target;
- } else if (gl->IsSupported(gl::GLFeature::occlusion_query2)) {
- return LOCAL_GL_ANY_SAMPLES_PASSED;
+ default:
+ break;
+ }
}
- return LOCAL_GL_SAMPLES_PASSED;
-}
-
-WebGLRefPtr<WebGLQuery>&
-WebGLContext::GetQuerySlotByTarget(GLenum target)
-{
- /* This function assumes that target has been validated for either
- * WebGL1 or WebGL2.
- */
- switch (target) {
- case LOCAL_GL_ANY_SAMPLES_PASSED:
- case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
- return mActiveOcclusionQuery;
-
- case LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
- return mActiveTransformFeedbackQuery;
-
- default:
- MOZ_CRASH("GFX: Should not get here.");
- }
+ ErrorInvalidEnum("%s: Bad `target`.", funcName);
+ return nullptr;
}
// -------------------------------------------------------------------------
// Query Objects
already_AddRefed<WebGLQuery>
-WebGL2Context::CreateQuery()
+WebGLContext::CreateQuery(const char* funcName)
{
+ if (!funcName) {
+ funcName = "createQuery";
+ }
+
if (IsContextLost())
return nullptr;
- if (mActiveOcclusionQuery && !gl->IsGLES()) {
- /* http://www.opengl.org/registry/specs/ARB/occlusion_query.txt
- *
- * Calling either GenQueriesARB or DeleteQueriesARB while any query of
- * any target is active causes an INVALID_OPERATION error to be
- * generated.
- */
- GenerateWarning("createQuery: The WebGL 2 prototype might generate"
- " INVALID_OPERATION when creating a query object while"
- " one other is active.");
- /*
- * We *need* to lock webgl2 to GL>=3.0 on desktop, but we don't have a
- * good mechanism to do this yet. See bug 898404.
- */
- }
-
RefPtr<WebGLQuery> globj = new WebGLQuery(this);
-
return globj.forget();
}
void
-WebGL2Context::DeleteQuery(WebGLQuery* query)
+WebGLContext::DeleteQuery(WebGLQuery* query, const char* funcName)
{
+ if (!funcName) {
+ funcName = "deleteQuery";
+ }
+
if (IsContextLost())
return;
if (!query)
return;
- if (query->IsDeleted())
+ if (!ValidateObjectAllowDeleted(funcName, query))
return;
- if (query->IsActive())
- EndQuery(query->mType);
-
- if (mActiveOcclusionQuery && !gl->IsGLES()) {
- /* http://www.opengl.org/registry/specs/ARB/occlusion_query.txt
- *
- * Calling either GenQueriesARB or DeleteQueriesARB while any query of
- * any target is active causes an INVALID_OPERATION error to be
- * generated.
- */
- GenerateWarning("deleteQuery: The WebGL 2 prototype might generate"
- " INVALID_OPERATION when deleting a query object while"
- " one other is active.");
- }
-
- query->RequestDelete();
+ query->DeleteQuery();
}
bool
-WebGL2Context::IsQuery(WebGLQuery* query)
+WebGLContext::IsQuery(const WebGLQuery* query, const char* funcName)
{
+ if (!funcName) {
+ funcName = "isQuery";
+ }
+
if (IsContextLost())
return false;
if (!query)
return false;
- return (ValidateObjectAllowDeleted("isQuery", query) &&
- !query->IsDeleted() &&
- query->HasEverBeenActive());
+ if (!ValidateObjectAllowDeleted("isQuery", query))
+ return false;
+
+ return query->IsQuery();
}
void
-WebGL2Context::BeginQuery(GLenum target, WebGLQuery* query)
+WebGLContext::BeginQuery(GLenum target, WebGLQuery* query, const char* funcName)
{
- if (IsContextLost())
- return;
-
- if (!ValidateQueryTarget(target, "beginQuery"))
- return;
-
- if (!query) {
- /* From GLES's EXT_occlusion_query_boolean:
- * BeginQueryEXT sets the active query object name for the query
- * type given by <target> to <id>. If BeginQueryEXT is called with
- * an <id> of zero, if the active query object name for <target> is
- * non-zero (for the targets ANY_SAMPLES_PASSED_EXT and
- * ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if the active query for
- * either target is non-zero), if <id> is the name of an existing
- * query object whose type does not match <target>, or if <id> is
- * the active query object name for any query type, the error
- * INVALID_OPERATION is generated.
- */
- ErrorInvalidOperation("beginQuery: Query should not be null.");
- return;
+ if (!funcName) {
+ funcName = "beginQuery";
}
- if (query->IsDeleted()) {
- /* From GLES's EXT_occlusion_query_boolean:
- * BeginQueryEXT fails and an INVALID_OPERATION error is generated
- * if <id> is not a name returned from a previous call to
- * GenQueriesEXT, or if such a name has since been deleted with
- * DeleteQueriesEXT.
- */
- ErrorInvalidOperation("beginQuery: Query has been deleted.");
- return;
- }
-
- if (query->HasEverBeenActive() &&
- query->mType != target)
- {
- ErrorInvalidOperation("beginQuery: Target doesn't match with the query"
- " type.");
- return;
- }
-
- WebGLRefPtr<WebGLQuery>& querySlot = GetQuerySlotByTarget(target);
- WebGLQuery* activeQuery = querySlot.get();
- if (activeQuery)
- return ErrorInvalidOperation("beginQuery: An other query already active.");
-
- if (!query->HasEverBeenActive())
- query->mType = target;
-
- MakeContextCurrent();
-
- if (target == LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) {
- gl->fBeginQuery(LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
- query->mGLName);
- } else {
- gl->fBeginQuery(SimulateOcclusionQueryTarget(gl, target),
- query->mGLName);
- }
-
- UpdateBoundQuery(target, query);
-}
-
-void
-WebGL2Context::EndQuery(GLenum target)
-{
if (IsContextLost())
return;
- if (!ValidateQueryTarget(target, "endQuery"))
+ if (!ValidateObjectAllowDeleted(funcName, query))
return;
- WebGLRefPtr<WebGLQuery>& querySlot = GetQuerySlotByTarget(target);
- WebGLQuery* activeQuery = querySlot.get();
+ if (query->IsDeleted())
+ return ErrorInvalidOperation("%s: Cannot begin a deleted query.", funcName);
- if (!activeQuery || target != activeQuery->mType)
- {
- /* From GLES's EXT_occlusion_query_boolean:
- * marks the end of the sequence of commands to be tracked for the
- * query type given by <target>. The active query object for
- * <target> is updated to indicate that query results are not
- * available, and the active query object name for <target> is reset
- * to zero. When the commands issued prior to EndQueryEXT have
- * completed and a final query result is available, the query object
- * active when EndQueryEXT is called is updated by the GL. The query
- * object is updated to indicate that the query results are
- * available and to contain the query result. If the active query
- * object name for <target> is zero when EndQueryEXT is called, the
- * error INVALID_OPERATION is generated.
- */
- ErrorInvalidOperation("endQuery: There is no active query of type %s.",
- GetQueryTargetEnumString(target));
+ const auto& slot = ValidateQuerySlotByTarget(funcName, target);
+ if (!slot)
return;
- }
-
- MakeContextCurrent();
-
- if (target == LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) {
- gl->fEndQuery(LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
- } else {
- gl->fEndQuery(SimulateOcclusionQueryTarget(gl, target));
- }
-
- UpdateBoundQuery(target, nullptr);
- NS_DispatchToCurrentThread(new WebGLQuery::AvailableRunnable(activeQuery));
-}
-already_AddRefed<WebGLQuery>
-WebGL2Context::GetQuery(GLenum target, GLenum pname)
-{
- if (IsContextLost())
- return nullptr;
-
- if (!ValidateQueryTarget(target, "getQuery"))
- return nullptr;
-
- if (pname != LOCAL_GL_CURRENT_QUERY) {
- /* OpenGL ES 3.0 spec 6.1.7:
- * pname must be CURRENT_QUERY.
- */
- ErrorInvalidEnum("getQuery: `pname` must be CURRENT_QUERY.");
- return nullptr;
- }
+ if (*slot)
+ return ErrorInvalidOperation("%s: Query target already active.", funcName);
- WebGLRefPtr<WebGLQuery>& targetSlot = GetQuerySlotByTarget(target);
- RefPtr<WebGLQuery> tmp = targetSlot.get();
- if (tmp && tmp->mType != target) {
- // Query in slot doesn't match target
- return nullptr;
- }
-
- return tmp.forget();
-}
+ ////
-static bool
-ValidateQueryEnum(WebGLContext* webgl, GLenum pname, const char* info)
-{
- switch (pname) {
- case LOCAL_GL_QUERY_RESULT_AVAILABLE:
- case LOCAL_GL_QUERY_RESULT:
- return true;
-
- default:
- webgl->ErrorInvalidEnum("%s: invalid pname: %s", info, webgl->EnumName(pname));
- return false;
- }
+ query->BeginQuery(target, *slot);
}
void
-WebGL2Context::GetQueryParameter(JSContext*, WebGLQuery* query, GLenum pname,
- JS::MutableHandleValue retval)
+WebGLContext::EndQuery(GLenum target, const char* funcName)
{
- retval.set(JS::NullValue());
+ if (!funcName) {
+ funcName = "endQuery";
+ }
if (IsContextLost())
return;
- if (!ValidateQueryEnum(this, pname, "getQueryParameter"))
+ const auto& slot = ValidateQuerySlotByTarget(funcName, target);
+ if (!slot)
return;
- if (!query) {
- /* OpenGL ES 3.0 spec 6.1.7 (spec getQueryObject 1):
- * If id is not the name of a query object, or if the query object
- * named by id is currently active, then an INVALID_OPERATION error
- * is generated. pname must be QUERY_RESULT or
- * QUERY_RESULT_AVAILABLE.
- */
- ErrorInvalidOperation("getQueryObject: `query` should not be null.");
- return;
- }
+ const auto& query = *slot;
+ if (!query)
+ return ErrorInvalidOperation("%s: Query target not active.", funcName);
+
+ query->EndQuery();
+}
- if (query->IsDeleted()) {
- // See (spec getQueryObject 1)
- ErrorInvalidOperation("getQueryObject: `query` has been deleted.");
- return;
- }
-
- if (query->IsActive()) {
- // See (spec getQueryObject 1)
- ErrorInvalidOperation("getQueryObject: `query` is active.");
- return;
+void
+WebGLContext::GetQuery(JSContext* cx, GLenum target, GLenum pname,
+ JS::MutableHandleValue retval, const char* funcName)
+{
+ if (!funcName) {
+ funcName = "getQuery";
}
- if (!query->HasEverBeenActive()) {
- /* See (spec getQueryObject 1)
- * If this instance of WebGLQuery has never been active before, that
- * mean that query->mGLName is not a query object yet.
- */
- ErrorInvalidOperation("getQueryObject: `query` has never been active.");
+ retval.setNull();
+ if (IsContextLost())
return;
- }
- // We must wait for an event loop before the query can be available
- if (!query->mCanBeAvailable && !gfxPrefs::WebGLImmediateQueries()) {
- if (pname == LOCAL_GL_QUERY_RESULT_AVAILABLE) {
- retval.set(JS::BooleanValue(false));
+ switch (pname) {
+ case LOCAL_GL_CURRENT_QUERY_EXT:
+ {
+ if (IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query) &&
+ target == LOCAL_GL_TIMESTAMP)
+ {
+ // Doesn't seem illegal to ask about, but is always null.
+ // TIMESTAMP has no slot, so ValidateQuerySlotByTarget would generate
+ // INVALID_ENUM.
+ return;
+ }
+
+ const auto& slot = ValidateQuerySlotByTarget(funcName, target);
+ if (!slot || !*slot)
+ return;
+
+ const auto& query = *slot;
+ if (target != query->Target())
+ return;
+
+ JS::Rooted<JS::Value> v(cx);
+ dom::GetOrCreateDOMReflector(cx, slot->get(), &v);
+ retval.set(v);
}
return;
- }
+
+ case LOCAL_GL_QUERY_COUNTER_BITS_EXT:
+ if (!IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query))
+ break;
- MakeContextCurrent();
- GLuint returned = 0;
- switch (pname) {
- case LOCAL_GL_QUERY_RESULT_AVAILABLE:
- gl->fGetQueryObjectuiv(query->mGLName, LOCAL_GL_QUERY_RESULT_AVAILABLE, &returned);
- retval.set(JS::BooleanValue(returned != 0));
- return;
-
- case LOCAL_GL_QUERY_RESULT:
- gl->fGetQueryObjectuiv(query->mGLName, LOCAL_GL_QUERY_RESULT, &returned);
-
- if (query->mType == LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) {
- retval.set(JS::NumberValue(returned));
+ if (target != LOCAL_GL_TIME_ELAPSED_EXT &&
+ target != LOCAL_GL_TIMESTAMP_EXT)
+ {
+ ErrorInvalidEnum("%s: Bad pname for target.", funcName);
return;
}
- /*
- * test (returned != 0) is important because ARB_occlusion_query on desktop drivers
- * return the number of samples drawed when the OpenGL ES extension
- * ARB_occlusion_query_boolean return only a boolean if a sample has been drawed.
- */
- retval.set(JS::BooleanValue(returned != 0));
+ {
+ GLint bits = 0;
+ gl->fGetQueryiv(target, pname, &bits);
+
+ if (!Has64BitTimestamps() && bits > 32) {
+ bits = 32;
+ }
+ retval.set(JS::Int32Value(bits));
+ }
return;
default:
break;
}
- ErrorInvalidEnum("getQueryObject: `pname` must be QUERY_RESULT{_AVAILABLE}.");
+ ErrorInvalidEnum("%s: Bad pname.", funcName);
+ return;
}
void
-WebGL2Context::UpdateBoundQuery(GLenum target, WebGLQuery* query)
-{
- WebGLRefPtr<WebGLQuery>& querySlot = GetQuerySlotByTarget(target);
- querySlot = query;
-}
-
-bool
-WebGL2Context::ValidateQueryTarget(GLenum target, const char* info)
+WebGLContext::GetQueryParameter(JSContext*, const WebGLQuery* query, GLenum pname,
+ JS::MutableHandleValue retval, const char* funcName)
{
- switch (target) {
- case LOCAL_GL_ANY_SAMPLES_PASSED:
- case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
- case LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
- return true;
+ if (!funcName) {
+ funcName = "getQueryParameter";
+ }
+
+ retval.setNull();
+ if (IsContextLost())
+ return;
- default:
- ErrorInvalidEnumInfo(info, target);
- return false;
- }
+ if (!ValidateObjectAllowDeleted(funcName, query))
+ return;
+
+ if (query->IsDeleted())
+ return ErrorInvalidOperation("%s: Query must not be deleted.", funcName);
+
+ query->GetQueryParameter(pname, retval);
}
} // namespace mozilla
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -66,17 +66,16 @@
#include "WebGLFramebuffer.h"
#include "WebGLMemoryTracker.h"
#include "WebGLObjectModel.h"
#include "WebGLProgram.h"
#include "WebGLQuery.h"
#include "WebGLSampler.h"
#include "WebGLShader.h"
#include "WebGLSync.h"
-#include "WebGLTimerQuery.h"
#include "WebGLTransformFeedback.h"
#include "WebGLVertexArray.h"
#include "WebGLVertexAttribData.h"
#ifdef MOZ_WIDGET_COCOA
#include "nsCocoaFeatures.h"
#endif
@@ -247,37 +246,39 @@ WebGLContext::DestroyResourcesAndContext
mBoundCopyWriteBuffer = nullptr;
mBoundPixelPackBuffer = nullptr;
mBoundPixelUnpackBuffer = nullptr;
mBoundUniformBuffer = nullptr;
mCurrentProgram = nullptr;
mActiveProgramLinkInfo = nullptr;
mBoundDrawFramebuffer = nullptr;
mBoundReadFramebuffer = nullptr;
- mActiveOcclusionQuery = nullptr;
mBoundRenderbuffer = nullptr;
mBoundVertexArray = nullptr;
mDefaultVertexArray = nullptr;
mBoundTransformFeedback = nullptr;
mDefaultTransformFeedback = nullptr;
+ mQuerySlot_SamplesPassed = nullptr;
+ mQuerySlot_TFPrimsWritten = nullptr;
+ mQuerySlot_TimeElapsed = nullptr;
+
mIndexedUniformBufferBindings.clear();
//////
ClearLinkedList(mBuffers);
ClearLinkedList(mFramebuffers);
ClearLinkedList(mPrograms);
ClearLinkedList(mQueries);
ClearLinkedList(mRenderbuffers);
ClearLinkedList(mSamplers);
ClearLinkedList(mShaders);
ClearLinkedList(mSyncs);
ClearLinkedList(mTextures);
- ClearLinkedList(mTimerQueries);
ClearLinkedList(mTransformFeedbacks);
ClearLinkedList(mVertexArrays);
//////
mFakeBlack_2D_0000 = nullptr;
mFakeBlack_2D_0001 = nullptr;
mFakeBlack_CubeMap_0000 = nullptr;
@@ -1642,17 +1643,17 @@ WebGLContext::DummyReadFramebufferOperat
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
ErrorInvalidFramebufferOperation("%s: Framebuffer must be complete.",
funcName);
}
}
bool
-WebGLContext::HasTimestampBits() const
+WebGLContext::Has64BitTimestamps() const
{
// 'sync' provides glGetInteger64v either by supporting ARB_sync, GL3+, or GLES3+.
return gl->IsSupported(GLFeature::sync);
}
static bool
CheckContextLost(GLContext* gl, bool* const out_isGuilty)
{
@@ -2508,28 +2509,37 @@ WebGLContext::StartVRPresentation()
TextureFlags::ORIGIN_BOTTOM_LEFT);
screen->Morph(Move(factory));
return true;
}
////////////////////////////////////////////////////////////////////////////////
+static inline size_t
+SizeOfViewElem(const dom::ArrayBufferView& view)
+{
+ const auto& elemType = view.Type();
+ if (elemType == js::Scalar::MaxTypedArrayViewType) // DataViews.
+ return 1;
+
+ return js::Scalar::byteSize(elemType);
+}
+
bool
WebGLContext::ValidateArrayBufferView(const char* funcName,
const dom::ArrayBufferView& view, GLuint elemOffset,
GLuint elemCountOverride, uint8_t** const out_bytes,
size_t* const out_byteLen)
{
view.ComputeLengthAndData();
uint8_t* const bytes = view.DataAllowShared();
const size_t byteLen = view.LengthAllowShared();
- const auto& elemType = view.Type();
- const auto& elemSize = js::Scalar::byteSize(elemType);
+ const auto& elemSize = SizeOfViewElem(view);
size_t elemCount = byteLen / elemSize;
if (elemOffset > elemCount) {
ErrorInvalidValue("%s: Invalid offset into ArrayBufferView.", funcName);
return false;
}
elemCount -= elemOffset;
@@ -2587,18 +2597,19 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(We
mBoundTransformFeedback,
mBoundUniformBuffer,
mCurrentProgram,
mBoundDrawFramebuffer,
mBoundReadFramebuffer,
mBoundRenderbuffer,
mBoundVertexArray,
mDefaultVertexArray,
- mActiveOcclusionQuery,
- mActiveTransformFeedbackQuery)
+ mQuerySlot_SamplesPassed,
+ mQuerySlot_TFPrimsWritten,
+ mQuerySlot_TimeElapsed)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLContext)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsIDOMWebGLRenderingContext)
NS_INTERFACE_MAP_ENTRY(nsICanvasRenderingContextInternal)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
// If the exact way we cast to nsISupports here ever changes, fix our
// ToSupports() method.
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -98,17 +98,16 @@ class WebGLFramebuffer;
class WebGLProgram;
class WebGLQuery;
class WebGLRenderbuffer;
class WebGLSampler;
class WebGLShader;
class WebGLShaderPrecisionFormat;
class WebGLSync;
class WebGLTexture;
-class WebGLTimerQuery;
class WebGLTransformFeedback;
class WebGLUniformLocation;
class WebGLVertexArray;
namespace dom {
class Element;
class ImageData;
class OwningHTMLCanvasElementOrOffscreenCanvas;
@@ -441,17 +440,17 @@ public:
// Prepare the context for capture before compositing
void BeginComposition();
// Clean up the context after captured for compositing
void EndComposition();
// a number that increments every time we have an event that causes
// all context resources to be lost.
- uint32_t Generation() { return mGeneration.value(); }
+ uint32_t Generation() const { return mGeneration.value(); }
// This is similar to GLContext::ClearSafely, but tries to minimize the
// amount of work it does.
// It only clears the buffers we specify, and can reset its state without
// first having to query anything, as WebGL knows its state at all times.
void ForceClearFramebufferWithDefaultValues(GLbitfield bufferBits, bool fakeNoAlpha);
// Calls ForceClearFramebufferWithDefaultValues() for the Context's 'screen'.
@@ -929,20 +928,34 @@ protected:
WebGLRefPtr<WebGLBuffer>& GetBufferSlotByTarget(GLenum target);
WebGLRefPtr<WebGLBuffer>& GetBufferSlotByTargetIndexed(GLenum target,
GLuint index);
// -----------------------------------------------------------------------------
// Queries (WebGL2ContextQueries.cpp)
protected:
- WebGLRefPtr<WebGLQuery>& GetQuerySlotByTarget(GLenum target);
+ WebGLRefPtr<WebGLQuery> mQuerySlot_SamplesPassed;
+ WebGLRefPtr<WebGLQuery> mQuerySlot_TFPrimsWritten;
+ WebGLRefPtr<WebGLQuery> mQuerySlot_TimeElapsed;
+
+ WebGLRefPtr<WebGLQuery>*
+ ValidateQuerySlotByTarget(const char* funcName, GLenum target);
- WebGLRefPtr<WebGLQuery> mActiveOcclusionQuery;
- WebGLRefPtr<WebGLQuery> mActiveTransformFeedbackQuery;
+public:
+ already_AddRefed<WebGLQuery> CreateQuery(const char* funcName = nullptr);
+ void DeleteQuery(WebGLQuery* query, const char* funcName = nullptr);
+ bool IsQuery(const WebGLQuery* query, const char* funcName = nullptr);
+ void BeginQuery(GLenum target, WebGLQuery* query, const char* funcName = nullptr);
+ void EndQuery(GLenum target, const char* funcName = nullptr);
+ void GetQuery(JSContext* cx, GLenum target, GLenum pname,
+ JS::MutableHandleValue retval, const char* funcName = nullptr);
+ void GetQueryParameter(JSContext* cx, const WebGLQuery* query, GLenum pname,
+ JS::MutableHandleValue retval, const char* funcName = nullptr);
+
// -----------------------------------------------------------------------------
// State and State Requests (WebGLContextState.cpp)
public:
void Disable(GLenum cap);
void Enable(GLenum cap);
bool GetStencilBits(GLint* const out_stencilBits);
bool GetChannelBits(const char* funcName, GLenum pname, GLint* const out_val);
@@ -1605,45 +1618,44 @@ protected:
WebGLTexelFormat srcFormat, bool srcPremultiplied,
WebGLTexelFormat dstFormat, bool dstPremultiplied,
size_t dstTexelSize);
//////
// Returns false if `object` is null or not valid.
template<class ObjectType>
- bool ValidateObject(const char* info, ObjectType* object);
+ bool ValidateObject(const char* info, const ObjectType* object);
// Returns false if `object` is not valid. Considers null to be valid.
template<class ObjectType>
- bool ValidateObjectAllowNull(const char* info, ObjectType* object);
+ bool ValidateObjectAllowNull(const char* info, const ObjectType* object);
// Returns false if `object` is not valid, but considers deleted objects and
// null objects valid.
template<class ObjectType>
- bool ValidateObjectAllowDeletedOrNull(const char* info, ObjectType* object);
+ bool ValidateObjectAllowDeletedOrNull(const char* info, const ObjectType* object);
// Returns false if `object` is null or not valid, but considers deleted
// objects valid.
template<class ObjectType>
- bool ValidateObjectAllowDeleted(const char* info, ObjectType* object);
+ bool ValidateObjectAllowDeleted(const char* info, const ObjectType* object);
private:
// Like ValidateObject, but only for cases when `object` is known to not be
// null already.
template<class ObjectType>
- bool ValidateObjectAssumeNonNull(const char* info, ObjectType* object);
+ bool ValidateObjectAssumeNonNull(const char* info, const ObjectType* object);
private:
// -------------------------------------------------------------------------
// Context customization points
virtual WebGLVertexArray* CreateVertexArrayImpl();
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, uint32_t* alignment, const char* info) = 0;
- virtual bool ValidateQueryTarget(GLenum usage, const char* info) = 0;
virtual bool ValidateUniformMatrixTranspose(bool transpose, const char* info) = 0;
public:
void ForceLoseContext(bool simulateLoss = false);
protected:
void ForceRestoreContext();
@@ -1670,17 +1682,16 @@ protected:
LinkedList<WebGLFramebuffer> mFramebuffers;
LinkedList<WebGLProgram> mPrograms;
LinkedList<WebGLQuery> mQueries;
LinkedList<WebGLRenderbuffer> mRenderbuffers;
LinkedList<WebGLSampler> mSamplers;
LinkedList<WebGLShader> mShaders;
LinkedList<WebGLSync> mSyncs;
LinkedList<WebGLTexture> mTextures;
- LinkedList<WebGLTimerQuery> mTimerQueries;
LinkedList<WebGLTransformFeedback> mTransformFeedbacks;
LinkedList<WebGLVertexArray> mVertexArrays;
WebGLRefPtr<WebGLTransformFeedback> mDefaultTransformFeedback;
WebGLRefPtr<WebGLVertexArray> mDefaultVertexArray;
// PixelStore parameters
uint32_t mPixelStore_UnpackImageHeight;
@@ -1785,17 +1796,17 @@ protected:
uint64_t mLastUseIndex;
bool mNeedsFakeNoAlpha;
bool mNeedsFakeNoDepth;
bool mNeedsFakeNoStencil;
bool mNeedsEmulatedLoneDepthStencil;
- bool HasTimestampBits() const;
+ bool Has64BitTimestamps() const;
struct ScopedMaskWorkaround {
WebGLContext& mWebGL;
const bool mFakeNoAlpha;
const bool mFakeNoDepth;
const bool mFakeNoStencil;
static bool ShouldFakeNoAlpha(WebGLContext& webgl) {
@@ -1893,17 +1904,16 @@ public:
friend class WebGLFramebuffer;
friend class WebGLRenderbuffer;
friend class WebGLProgram;
friend class WebGLQuery;
friend class WebGLBuffer;
friend class WebGLSampler;
friend class WebGLShader;
friend class WebGLSync;
- friend class WebGLTimerQuery;
friend class WebGLTransformFeedback;
friend class WebGLUniformLocation;
friend class WebGLVertexArray;
friend class WebGLVertexArrayFake;
friend class WebGLVertexArrayGL;
};
// used by DOM bindings in conjunction with GetParentObject
@@ -1915,70 +1925,70 @@ ToSupports(WebGLContext* webgl)
/**
** Template implementations
**/
template<class ObjectType>
inline bool
WebGLContext::ValidateObjectAllowDeletedOrNull(const char* info,
- ObjectType* object)
+ const ObjectType* object)
{
if (object && !object->IsCompatibleWithContext(this)) {
ErrorInvalidOperation("%s: object from different WebGL context "
"(or older generation of this one) "
"passed as argument", info);
return false;
}
return true;
}
template<class ObjectType>
inline bool
-WebGLContext::ValidateObjectAssumeNonNull(const char* info, ObjectType* object)
+WebGLContext::ValidateObjectAssumeNonNull(const char* info, const ObjectType* object)
{
MOZ_ASSERT(object);
if (!ValidateObjectAllowDeletedOrNull(info, object))
return false;
if (object->IsDeleted()) {
ErrorInvalidValue("%s: Deleted object passed as argument.", info);
return false;
}
return true;
}
template<class ObjectType>
inline bool
-WebGLContext::ValidateObjectAllowNull(const char* info, ObjectType* object)
+WebGLContext::ValidateObjectAllowNull(const char* info, const ObjectType* object)
{
if (!object)
return true;
return ValidateObjectAssumeNonNull(info, object);
}
template<class ObjectType>
inline bool
-WebGLContext::ValidateObjectAllowDeleted(const char* info, ObjectType* object)
+WebGLContext::ValidateObjectAllowDeleted(const char* info, const ObjectType* object)
{
if (!object) {
ErrorInvalidValue("%s: null object passed as argument", info);
return false;
}
return ValidateObjectAllowDeletedOrNull(info, object);
}
template<class ObjectType>
inline bool
-WebGLContext::ValidateObject(const char* info, ObjectType* object)
+WebGLContext::ValidateObject(const char* info, const ObjectType* object)
{
if (!object) {
ErrorInvalidValue("%s: null object passed as argument", info);
return false;
}
return ValidateObjectAssumeNonNull(info, object);
}
--- a/dom/canvas/WebGLContextExtensions.cpp
+++ b/dom/canvas/WebGLContextExtensions.cpp
@@ -43,17 +43,17 @@ WebGLContext::GetExtensionString(WebGLEx
WEBGL_EXTENSION_IDENTIFIER(OES_standard_derivatives)
WEBGL_EXTENSION_IDENTIFIER(OES_texture_float)
WEBGL_EXTENSION_IDENTIFIER(OES_texture_float_linear)
WEBGL_EXTENSION_IDENTIFIER(OES_texture_half_float)
WEBGL_EXTENSION_IDENTIFIER(OES_texture_half_float_linear)
WEBGL_EXTENSION_IDENTIFIER(OES_vertex_array_object)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_color_buffer_float)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_atc)
- WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_es3_0)
+ WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_etc)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_etc1)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_pvrtc)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_s3tc)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_debug_renderer_info)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_debug_shaders)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_depth_texture)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_draw_buffers)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_lose_context)
@@ -107,27 +107,29 @@ WebGLContext::IsExtensionSupported(WebGL
{
if (mDisableExtensions)
return false;
// Extensions for both WebGL 1 and 2.
switch (ext) {
// In alphabetical order
// EXT_
+ case WebGLExtensionID::EXT_disjoint_timer_query:
+ return WebGLExtensionDisjointTimerQuery::IsSupported(this);
case WebGLExtensionID::EXT_texture_filter_anisotropic:
return gl->IsExtensionSupported(gl::GLContext::EXT_texture_filter_anisotropic);
// OES_
case WebGLExtensionID::OES_texture_float_linear:
return gl->IsSupported(gl::GLFeature::texture_float_linear);
// WEBGL_
case WebGLExtensionID::WEBGL_compressed_texture_atc:
return gl->IsExtensionSupported(gl::GLContext::AMD_compressed_ATC_texture);
- case WebGLExtensionID::WEBGL_compressed_texture_es3_0:
+ case WebGLExtensionID::WEBGL_compressed_texture_etc:
return gl->IsSupported(gl::GLFeature::ES3_compatibility);
case WebGLExtensionID::WEBGL_compressed_texture_etc1:
return gl->IsExtensionSupported(gl::GLContext::OES_compressed_ETC1_RGB8_texture);
case WebGLExtensionID::WEBGL_compressed_texture_pvrtc:
return gl->IsExtensionSupported(gl::GLContext::IMG_texture_compression_pvrtc);
case WebGLExtensionID::WEBGL_compressed_texture_s3tc:
if (gl->IsExtensionSupported(gl::GLContext::EXT_texture_compression_s3tc))
return true;
@@ -206,24 +208,23 @@ WebGLContext::IsExtensionSupported(WebGL
case WebGLExtensionID::WEBGL_draw_buffers:
return WebGLExtensionDrawBuffers::IsSupported(this);
default:
// For warnings-as-errors.
break;
}
if (gfxPrefs::WebGLDraftExtensionsEnabled()) {
+ /*
switch (ext) {
- case WebGLExtensionID::EXT_disjoint_timer_query:
- return WebGLExtensionDisjointTimerQuery::IsSupported(this);
-
default:
// For warnings-as-errors.
break;
}
+ */
}
}
return false;
}
static bool
CompareWebGLExtensionName(const nsACString& name, const char* other)
@@ -390,17 +391,17 @@ WebGLContext::EnableExtension(WebGLExten
// WEBGL_
case WebGLExtensionID::WEBGL_color_buffer_float:
obj = new WebGLExtensionColorBufferFloat(this);
break;
case WebGLExtensionID::WEBGL_compressed_texture_atc:
obj = new WebGLExtensionCompressedTextureATC(this);
break;
- case WebGLExtensionID::WEBGL_compressed_texture_es3_0:
+ case WebGLExtensionID::WEBGL_compressed_texture_etc:
obj = new WebGLExtensionCompressedTextureES3(this);
break;
case WebGLExtensionID::WEBGL_compressed_texture_etc1:
obj = new WebGLExtensionCompressedTextureETC1(this);
break;
case WebGLExtensionID::WEBGL_compressed_texture_pvrtc:
obj = new WebGLExtensionCompressedTexturePVRTC(this);
break;
--- a/dom/canvas/WebGLContextState.cpp
+++ b/dom/canvas/WebGLContextState.cpp
@@ -259,34 +259,42 @@ WebGLContext::GetParameter(JSContext* cx
if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) {
if (pname == LOCAL_GL_VERTEX_ARRAY_BINDING) {
WebGLVertexArray* vao =
(mBoundVertexArray != mDefaultVertexArray) ? mBoundVertexArray.get() : nullptr;
return WebGLObjectAsJSValue(cx, vao, rv);
}
}
- if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query)) {
- if (pname == LOCAL_GL_TIMESTAMP_EXT) {
- GLuint64 iv = 0;
- if (HasTimestampBits()) {
- gl->fGetInteger64v(pname, (GLint64*)&iv);
- } else {
- GenerateWarning("QUERY_COUNTER_BITS_EXT for TIMESTAMP_EXT is 0.");
+ if (IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query)) {
+ switch (pname) {
+ case LOCAL_GL_TIMESTAMP_EXT:
+ {
+ uint64_t val = 0;
+ if (Has64BitTimestamps()) {
+ gl->fGetInteger64v(pname, (GLint64*)&val);
+ } else {
+ gl->fGetIntegerv(pname, (GLint*)&val);
+ }
+ // TODO: JS doesn't support 64-bit integers. Be lossy and
+ // cast to double (53 bits)
+ return JS::NumberValue(val);
}
- // TODO: JS doesn't support 64-bit integers. Be lossy and
- // cast to double (53 bits)
- return JS::NumberValue(static_cast<double>(iv));
- } else if (pname == LOCAL_GL_GPU_DISJOINT_EXT) {
- // When disjoint isn't supported, leave as false.
- realGLboolean disjoint = LOCAL_GL_FALSE;
- if (gl->IsExtensionSupported(gl::GLContext::EXT_disjoint_timer_query)) {
- gl->fGetBooleanv(pname, &disjoint);
+
+ case LOCAL_GL_GPU_DISJOINT_EXT:
+ {
+ realGLboolean val = false; // Not disjoint by default.
+ if (gl->IsExtensionSupported(gl::GLContext::EXT_disjoint_timer_query)) {
+ gl->fGetBooleanv(pname, &val);
+ }
+ return JS::BooleanValue(val);
}
- return JS::BooleanValue(bool(disjoint));
+
+ default:
+ break;
}
}
// Privileged string params exposed by WEBGL_debug_renderer_info.
// The privilege check is done in WebGLContext::IsExtensionSupported.
// So here we just have to check that the extension is enabled.
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_debug_renderer_info)) {
switch (pname) {
--- a/dom/canvas/WebGLExtensionCompressedTextureES3.cpp
+++ b/dom/canvas/WebGLExtensionCompressedTextureES3.cpp
@@ -58,11 +58,11 @@ WebGLExtensionCompressedTextureES3::WebG
#undef FOO
}
WebGLExtensionCompressedTextureES3::~WebGLExtensionCompressedTextureES3()
{
}
-IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionCompressedTextureES3, WEBGL_compressed_texture_es3)
+IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionCompressedTextureES3, WEBGL_compressed_texture_etc)
} // namespace mozilla
--- a/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp
+++ b/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp
@@ -7,252 +7,123 @@
#include "WebGLExtensions.h"
#include "gfxPrefs.h"
#include "GLContext.h"
#include "mozilla/dom/ToJSValue.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "mozilla/dom/BindingUtils.h"
#include "WebGLContext.h"
-#include "WebGLTimerQuery.h"
+#include "WebGLQuery.h"
namespace mozilla {
WebGLExtensionDisjointTimerQuery::WebGLExtensionDisjointTimerQuery(WebGLContext* webgl)
: WebGLExtensionBase(webgl)
- , mActiveQuery(nullptr)
{
- MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
+ MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
}
WebGLExtensionDisjointTimerQuery::~WebGLExtensionDisjointTimerQuery()
{
}
-already_AddRefed<WebGLTimerQuery>
-WebGLExtensionDisjointTimerQuery::CreateQueryEXT()
+already_AddRefed<WebGLQuery>
+WebGLExtensionDisjointTimerQuery::CreateQueryEXT() const
{
- if (mIsLost)
- return nullptr;
+ const char funcName[] = "createQueryEXT";
+ if (mIsLost)
+ return nullptr;
- RefPtr<WebGLTimerQuery> query = WebGLTimerQuery::Create(mContext);
- return query.forget();
+ return mContext->CreateQuery(funcName);
}
void
-WebGLExtensionDisjointTimerQuery::DeleteQueryEXT(WebGLTimerQuery* query)
+WebGLExtensionDisjointTimerQuery::DeleteQueryEXT(WebGLQuery* query) const
{
- if (mIsLost)
- return;
+ const char funcName[] = "deleteQueryEXT";
+ if (mIsLost)
+ return;
- if (!mContext->ValidateObject("deleteQueryEXT", query))
- return;
-
- query->RequestDelete();
+ mContext->DeleteQuery(query, funcName);
}
bool
-WebGLExtensionDisjointTimerQuery::IsQueryEXT(WebGLTimerQuery* query)
+WebGLExtensionDisjointTimerQuery::IsQueryEXT(const WebGLQuery* query) const
{
- if (!query)
- return false;
-
- if (!mContext->ValidateObjectAllowDeleted("isQueryEXT", query))
- return false;
-
- if (query->IsDeleted())
- return false;
-
- return true;
-}
-
-void
-WebGLExtensionDisjointTimerQuery::BeginQueryEXT(GLenum target,
- WebGLTimerQuery* query)
-{
- if (mIsLost)
- return;
-
- if (!mContext->ValidateObject("beginQueryEXT", query))
- return;
+ const char funcName[] = "isQueryEXT";
+ if (mIsLost)
+ return false;
- if (query->HasEverBeenBound() && query->Target() != target) {
- mContext->ErrorInvalidOperation("beginQueryEXT: Query is already bound"
- " to a different target.");
- return;
- }
-
- if (target != LOCAL_GL_TIME_ELAPSED_EXT) {
- mContext->ErrorInvalidEnumInfo("beginQueryEXT: Can only begin on target"
- " TIME_ELAPSED_EXT.", target);
- return;
- }
-
- if (mActiveQuery) {
- mContext->ErrorInvalidOperation("beginQueryEXT: A query is already"
- " active.");
- return;
- }
-
- mContext->MakeContextCurrent();
- gl::GLContext* gl = mContext->GL();
- gl->fBeginQuery(target, query->mGLName);
- query->mTarget = LOCAL_GL_TIME_ELAPSED_EXT;
- mActiveQuery = query;
+ return mContext->IsQuery(query, funcName);
}
void
-WebGLExtensionDisjointTimerQuery::EndQueryEXT(GLenum target)
+WebGLExtensionDisjointTimerQuery::BeginQueryEXT(GLenum target, WebGLQuery* query) const
{
- if (mIsLost)
- return;
+ const char funcName[] = "beginQueryEXT";
+ if (mIsLost)
+ return;
+
+ mContext->BeginQuery(target, query, funcName);
+}
- if (target != LOCAL_GL_TIME_ELAPSED_EXT) {
- mContext->ErrorInvalidEnumInfo("endQueryEXT: Can only end on"
- " TIME_ELAPSED_EXT.", target);
- return;
- }
+void
+WebGLExtensionDisjointTimerQuery::EndQueryEXT(GLenum target) const
+{
+ const char funcName[] = "endQueryEXT";
+ if (mIsLost)
+ return;
- if (!mActiveQuery) {
- mContext->ErrorInvalidOperation("endQueryEXT: A query is not active.");
- return;
- }
-
- mContext->MakeContextCurrent();
- mContext->GL()->fEndQuery(target);
- mActiveQuery->QueueAvailablity();
- mActiveQuery = nullptr;
+ mContext->EndQuery(target, funcName);
}
void
-WebGLExtensionDisjointTimerQuery::QueryCounterEXT(WebGLTimerQuery* query,
- GLenum target)
+WebGLExtensionDisjointTimerQuery::QueryCounterEXT(WebGLQuery* query, GLenum target) const
{
- if (mIsLost)
- return;
-
- if (!mContext->ValidateObject("queryCounterEXT", query))
- return;
+ const char funcName[] = "queryCounterEXT";
+ if (mIsLost)
+ return;
- if (target != LOCAL_GL_TIMESTAMP_EXT) {
- mContext->ErrorInvalidEnumInfo("queryCounterEXT: requires"
- " TIMESTAMP_EXT.", target);
- return;
- }
+ if (!mContext->ValidateObject(funcName, query))
+ return;
- mContext->MakeContextCurrent();
- mContext->GL()->fQueryCounter(query->mGLName, target);
- query->mTarget = LOCAL_GL_TIMESTAMP_EXT;
- query->QueueAvailablity();
+ query->QueryCounter(funcName, target);
}
void
-WebGLExtensionDisjointTimerQuery::GetQueryEXT(JSContext* cx, GLenum target,
- GLenum pname,
- JS::MutableHandle<JS::Value> retval)
+WebGLExtensionDisjointTimerQuery::GetQueryEXT(JSContext* cx, GLenum target, GLenum pname,
+ JS::MutableHandleValue retval) const
{
- if (mIsLost)
- return;
+ const char funcName[] = "getQueryEXT";
+ retval.setNull();
+ if (mIsLost)
+ return;
- mContext->MakeContextCurrent();
- switch (pname) {
- case LOCAL_GL_CURRENT_QUERY_EXT: {
- if (target != LOCAL_GL_TIME_ELAPSED_EXT) {
- mContext->ErrorInvalidEnumInfo("getQueryEXT: Invalid query target.",
- target);
- return;
- }
- if (mActiveQuery) {
- JS::Rooted<JS::Value> v(cx);
- dom::GetOrCreateDOMReflector(cx, mActiveQuery.get(), &v);
- retval.set(v);
- } else {
- retval.set(JS::NullValue());
- }
- break;
- }
- case LOCAL_GL_QUERY_COUNTER_BITS_EXT: {
- if (target != LOCAL_GL_TIME_ELAPSED_EXT &&
- target != LOCAL_GL_TIMESTAMP_EXT) {
- mContext->ErrorInvalidEnumInfo("getQueryEXT: Invalid query target.",
- target);
- return;
- }
- GLint bits = 0;
- if (mContext->HasTimestampBits()) {
- mContext->GL()->fGetQueryiv(target, pname, &bits);
- }
- retval.set(JS::Int32Value(int32_t(bits)));
- break;
- }
- default:
- mContext->ErrorInvalidEnumInfo("getQueryEXT: Invalid query property.",
- pname);
- break;
- }
+ mContext->GetQuery(cx, target, pname, retval, funcName);
}
void
WebGLExtensionDisjointTimerQuery::GetQueryObjectEXT(JSContext* cx,
- WebGLTimerQuery* query,
- GLenum pname,
- JS::MutableHandle<JS::Value> retval)
+ const WebGLQuery* query, GLenum pname,
+ JS::MutableHandleValue retval) const
{
- if (mIsLost)
- return;
-
- if (!mContext->ValidateObject("getQueryObjectEXT", query))
- return;
-
- if (query == mActiveQuery.get()) {
- mContext->ErrorInvalidOperation("getQueryObjectEXT: Query must not be"
- " active.");
- }
+ const char funcName[] = "getQueryObjectEXT";
+ retval.setNull();
+ if (mIsLost)
+ return;
- mContext->MakeContextCurrent();
- // XXX: Note that the query result *may change* within the same task!
- // This does not follow the specification, which states that all calls
- // checking query results must return the same value until the event loop
- // is empty.
- switch (pname) {
- case LOCAL_GL_QUERY_RESULT_EXT: {
- GLuint64 result = 0;
- mContext->GL()->fGetQueryObjectui64v(query->mGLName,
- LOCAL_GL_QUERY_RESULT_EXT,
- &result);
- retval.set(JS::NumberValue(result));
- break;
- }
- case LOCAL_GL_QUERY_RESULT_AVAILABLE_EXT: {
- GLuint avail = 0;
- mContext->GL()->fGetQueryObjectuiv(query->mGLName,
- LOCAL_GL_QUERY_RESULT_AVAILABLE_EXT,
- &avail);
- bool canBeAvailable = query->CanBeAvailable() || gfxPrefs::WebGLImmediateQueries();
- retval.set(JS::BooleanValue(bool(avail) && canBeAvailable));
- break;
- }
- default:
- mContext->ErrorInvalidEnumInfo("getQueryObjectEXT: Invalid query"
- " property.", pname);
- break;
- }
+ mContext->GetQueryParameter(cx, query, pname, retval, funcName);
}
bool
WebGLExtensionDisjointTimerQuery::IsSupported(const WebGLContext* webgl)
{
- webgl->MakeContextCurrent();
- gl::GLContext* gl = webgl->GL();
- return gl->IsSupported(gl::GLFeature::query_objects) &&
- gl->IsSupported(gl::GLFeature::get_query_object_i64v) &&
- gl->IsSupported(gl::GLFeature::query_counter); // provides GL_TIMESTAMP
-}
-
-void
-WebGLExtensionDisjointTimerQuery::OnMarkLost()
-{
- mActiveQuery = nullptr;
+ webgl->MakeContextCurrent();
+ gl::GLContext* gl = webgl->GL();
+ return gl->IsSupported(gl::GLFeature::query_objects) &&
+ gl->IsSupported(gl::GLFeature::get_query_object_i64v) &&
+ gl->IsSupported(gl::GLFeature::query_counter); // provides GL_TIMESTAMP
}
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionDisjointTimerQuery, EXT_disjoint_timer_query)
} // namespace mozilla
--- a/dom/canvas/WebGLExtensions.h
+++ b/dom/canvas/WebGLExtensions.h
@@ -20,17 +20,16 @@ class Sequence;
namespace webgl {
class FormatUsageAuthority;
} // namespace webgl
class WebGLContext;
class WebGLShader;
class WebGLQuery;
-class WebGLTimerQuery;
class WebGLVertexArray;
class WebGLExtensionBase
: public nsWrapperCache
, public WebGLContextBoundObject
{
public:
explicit WebGLExtensionBase(WebGLContext* webgl);
@@ -365,36 +364,27 @@ public:
class WebGLExtensionDisjointTimerQuery
: public WebGLExtensionBase
{
public:
explicit WebGLExtensionDisjointTimerQuery(WebGLContext* webgl);
virtual ~WebGLExtensionDisjointTimerQuery();
- already_AddRefed<WebGLTimerQuery> CreateQueryEXT();
- void DeleteQueryEXT(WebGLTimerQuery* query);
- bool IsQueryEXT(WebGLTimerQuery* query);
- void BeginQueryEXT(GLenum target, WebGLTimerQuery* query);
- void EndQueryEXT(GLenum target);
- void QueryCounterEXT(WebGLTimerQuery* query, GLenum target);
- void GetQueryEXT(JSContext *cx, GLenum target, GLenum pname,
- JS::MutableHandle<JS::Value> retval);
- void GetQueryObjectEXT(JSContext *cx, WebGLTimerQuery* query,
- GLenum pname,
- JS::MutableHandle<JS::Value> retval);
+ already_AddRefed<WebGLQuery> CreateQueryEXT() const;
+ void DeleteQueryEXT(WebGLQuery* query) const;
+ bool IsQueryEXT(const WebGLQuery* query) const;
+ void BeginQueryEXT(GLenum target, WebGLQuery* query) const;
+ void EndQueryEXT(GLenum target) const;
+ void QueryCounterEXT(WebGLQuery* query, GLenum target) const;
+ void GetQueryEXT(JSContext* cx, GLenum target, GLenum pname,
+ JS::MutableHandleValue retval) const;
+ void GetQueryObjectEXT(JSContext* cx, const WebGLQuery* query,
+ GLenum pname, JS::MutableHandleValue retval) const;
static bool IsSupported(const WebGLContext*);
DECL_WEBGL_EXTENSION_GOOP
-
-private:
- virtual void OnMarkLost() override;
-
- /**
- * An active TIME_ELAPSED query participating in a begin/end block.
- */
- WebGLRefPtr<WebGLTimerQuery> mActiveQuery;
};
} // namespace mozilla
#endif // WEBGL_EXTENSIONS_H_
--- a/dom/canvas/WebGLObjectModel.cpp
+++ b/dom/canvas/WebGLObjectModel.cpp
@@ -11,15 +11,15 @@ namespace mozilla {
WebGLContextBoundObject::WebGLContextBoundObject(WebGLContext* webgl)
: mContext(webgl)
, mContextGeneration(webgl->Generation())
{
}
bool
-WebGLContextBoundObject::IsCompatibleWithContext(WebGLContext* other)
+WebGLContextBoundObject::IsCompatibleWithContext(const WebGLContext* other) const
{
return (mContext == other &&
mContextGeneration == other->Generation());
}
} // namespace mozilla
--- a/dom/canvas/WebGLObjectModel.h
+++ b/dom/canvas/WebGLObjectModel.h
@@ -262,17 +262,17 @@ protected:
// This class is a mixin for objects that are tied to a specific
// context (which is to say, all of them). They provide initialization
// as well as comparison with the current context.
class WebGLContextBoundObject
{
public:
explicit WebGLContextBoundObject(WebGLContext* webgl);
- bool IsCompatibleWithContext(WebGLContext* other);
+ bool IsCompatibleWithContext(const WebGLContext* other) const;
WebGLContext* const mContext;
protected:
const uint32_t mContextGeneration;
};
// this class is a mixin for GL objects that have dimensions
// that we need to track.
--- a/dom/canvas/WebGLQuery.cpp
+++ b/dom/canvas/WebGLQuery.cpp
@@ -7,51 +7,267 @@
#include "GLContext.h"
#include "mozilla/dom/WebGL2RenderingContextBinding.h"
#include "nsContentUtils.h"
#include "WebGLContext.h"
namespace mozilla {
-JSObject*
-WebGLQuery::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
+class AvailableRunnable final : public Runnable
{
- return dom::WebGLQueryBinding::Wrap(cx, this, givenProto);
+ const RefPtr<WebGLQuery> mQuery;
+
+public:
+ explicit AvailableRunnable(WebGLQuery* query)
+ : mQuery(query)
+ { }
+
+ NS_IMETHOD Run() override {
+ mQuery->mCanBeAvailable = true;
+ return NS_OK;
+ }
+};
+
+////
+
+static GLuint
+GenQuery(gl::GLContext* gl)
+{
+ gl->MakeCurrent();
+
+ GLuint ret = 0;
+ gl->fGenQueries(1, &ret);
+ return ret;
}
WebGLQuery::WebGLQuery(WebGLContext* webgl)
: WebGLContextBoundObject(webgl)
+ , mGLName(GenQuery(mContext->gl))
+ , mTarget(0)
+ , mActiveSlot(nullptr)
, mCanBeAvailable(false)
- , mGLName(0)
- , mType(0)
{
mContext->mQueries.insertBack(this);
-
- mContext->MakeContextCurrent();
- mContext->gl->fGenQueries(1, &mGLName);
}
void
WebGLQuery::Delete()
{
mContext->MakeContextCurrent();
mContext->gl->fDeleteQueries(1, &mGLName);
LinkedListElement<WebGLQuery>::removeFrom(mContext->mQueries);
}
+////
+
+static GLenum
+TargetForDriver(const gl::GLContext* gl, GLenum target)
+{
+ switch (target) {
+ case LOCAL_GL_ANY_SAMPLES_PASSED:
+ case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
+ break;
+
+ default:
+ return target;
+ }
+
+ if (gl->IsSupported(gl::GLFeature::occlusion_query_boolean))
+ return target;
+
+ if (gl->IsSupported(gl::GLFeature::occlusion_query2))
+ return LOCAL_GL_ANY_SAMPLES_PASSED;
+
+ return LOCAL_GL_SAMPLES_PASSED;
+}
+
+void
+WebGLQuery::BeginQuery(GLenum target, WebGLRefPtr<WebGLQuery>& slot)
+{
+ const char funcName[] = "beginQuery";
+
+ if (mTarget && target != mTarget) {
+ mContext->ErrorInvalidOperation("%s: Queries cannot change targets.", funcName);
+ return;
+ }
+
+ ////
+
+ mTarget = target;
+ mActiveSlot = &slot;
+ *mActiveSlot = this;
+
+ ////
+
+ const auto& gl = mContext->gl;
+ gl->MakeCurrent();
+
+ const auto driverTarget = TargetForDriver(gl, mTarget);
+ gl->fBeginQuery(driverTarget, mGLName);
+}
+
+void
+WebGLQuery::EndQuery()
+{
+ *mActiveSlot = nullptr;
+ mActiveSlot = nullptr;
+ mCanBeAvailable = false;
+
+ ////
+
+ const auto& gl = mContext->gl;
+ gl->MakeCurrent();
+
+ const auto driverTarget = TargetForDriver(gl, mTarget);
+ gl->fEndQuery(driverTarget);
+
+ ////
+
+ NS_DispatchToCurrentThread(new AvailableRunnable(this));
+}
+
+void
+WebGLQuery::GetQueryParameter(GLenum pname, JS::MutableHandleValue retval) const
+{
+ const char funcName[] = "getQueryParameter";
+
+ switch (pname) {
+ case LOCAL_GL_QUERY_RESULT_AVAILABLE:
+ case LOCAL_GL_QUERY_RESULT:
+ break;
+
+ default:
+ mContext->ErrorInvalidEnum("%s: Invalid pname: %s", funcName,
+ mContext->EnumName(pname));
+ return;
+ }
+
+ if (!mTarget) {
+ mContext->ErrorInvalidOperation("%s: Query has never been active.", funcName);
+ return;
+ }
+
+ if (mActiveSlot)
+ return mContext->ErrorInvalidOperation("%s: Query is still active.", funcName);
+
+ // End of validation
+ ////
+
+ // We must usually wait for an event loop before the query can be available.
+ const bool canBeAvailable = (mCanBeAvailable || gfxPrefs::WebGLImmediateQueries());
+ if (!canBeAvailable) {
+ if (pname == LOCAL_GL_QUERY_RESULT_AVAILABLE) {
+ retval.set(JS::BooleanValue(false));
+ }
+ return;
+ }
+
+ const auto& gl = mContext->gl;
+ gl->MakeCurrent();
+
+ uint64_t val = 0;
+ switch (pname) {
+ case LOCAL_GL_QUERY_RESULT_AVAILABLE:
+ gl->fGetQueryObjectuiv(mGLName, pname, (GLuint*)&val);
+ retval.set(JS::BooleanValue(bool(val)));
+ return;
+
+ case LOCAL_GL_QUERY_RESULT:
+ switch (mTarget) {
+ case LOCAL_GL_TIME_ELAPSED_EXT:
+ case LOCAL_GL_TIMESTAMP_EXT:
+ if (mContext->Has64BitTimestamps()) {
+ gl->fGetQueryObjectui64v(mGLName, pname, &val);
+ break;
+ }
+ MOZ_FALLTHROUGH;
+
+ default:
+ gl->fGetQueryObjectuiv(mGLName, LOCAL_GL_QUERY_RESULT, (GLuint*)&val);
+ break;
+ }
+
+ switch (mTarget) {
+ case LOCAL_GL_ANY_SAMPLES_PASSED:
+ case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
+ retval.set(JS::BooleanValue(bool(val)));
+ break;
+
+ case LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
+ case LOCAL_GL_TIME_ELAPSED_EXT:
+ case LOCAL_GL_TIMESTAMP_EXT:
+ retval.set(JS::NumberValue(val));
+ break;
+
+ default:
+ MOZ_CRASH("Bad `mTarget`.");
+ }
+ return;
+
+ default:
+ MOZ_CRASH("Bad `pname`.");
+ }
+}
+
bool
-WebGLQuery::IsActive() const
+WebGLQuery::IsQuery() const
{
- if (!HasEverBeenActive())
+ if (IsDeleted())
return false;
- WebGLRefPtr<WebGLQuery>& targetSlot = mContext->GetQuerySlotByTarget(mType);
+ if (!mTarget)
+ return false;
+
+ return true;
+}
+
+void
+WebGLQuery::DeleteQuery()
+{
+ if (IsDeleted())
+ return;
+
+ if (mActiveSlot) {
+ EndQuery();
+ }
+
+ RequestDelete();
+}
- return targetSlot.get() == this;
+void
+WebGLQuery::QueryCounter(const char* funcName, GLenum target)
+{
+ if (target != LOCAL_GL_TIMESTAMP_EXT) {
+ mContext->ErrorInvalidEnum("%s: `target` must be TIMESTAMP_EXT.", funcName,
+ target);
+ return;
+ }
+
+ if (mTarget && target != mTarget) {
+ mContext->ErrorInvalidOperation("%s: Queries cannot change targets.", funcName);
+ return;
+ }
+
+ mTarget = target;
+ mCanBeAvailable = false;
+
+ const auto& gl = mContext->gl;
+ gl->MakeCurrent();
+ gl->fQueryCounter(mGLName, mTarget);
+
+ NS_DispatchToCurrentThread(new AvailableRunnable(this));
+}
+
+////
+
+JSObject*
+WebGLQuery::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
+{
+ return dom::WebGLQueryBinding::Wrap(cx, this, givenProto);
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLQuery)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLQuery, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLQuery, Release)
} // namespace mozilla
--- a/dom/canvas/WebGLQuery.h
+++ b/dom/canvas/WebGLQuery.h
@@ -15,61 +15,56 @@
namespace mozilla {
class WebGLQuery final
: public nsWrapperCache
, public WebGLRefCountedObject<WebGLQuery>
, public LinkedListElement<WebGLQuery>
, public WebGLContextBoundObject
{
-public:
- explicit WebGLQuery(WebGLContext* webgl);
-
- class AvailableRunnable final : public Runnable
- {
- public:
- explicit AvailableRunnable(WebGLQuery* query) : mQuery(query) { }
+ friend class AvailableRunnable;
+ friend class WebGLRefCountedObject<WebGLQuery>;
- NS_IMETHOD Run() override {
- mQuery->mCanBeAvailable = true;
- return NS_OK;
- }
- private:
- const RefPtr<WebGLQuery> mQuery;
- };
+public:
+ const GLuint mGLName;
+private:
+ GLenum mTarget;
+ WebGLRefPtr<WebGLQuery>* mActiveSlot;
- bool IsActive() const;
-
- bool HasEverBeenActive() const {
- return mType != 0;
- }
+ bool mCanBeAvailable; // Track whether the event loop has spun
- // WebGLRefCountedObject
- void Delete();
+ ////
+public:
+ GLenum Target() const { return mTarget; }
+ bool IsActive() const { return bool(mActiveSlot); }
- // nsWrapperCache
- WebGLContext* GetParentObject() const {
- return mContext;
- }
-
- // NS
- virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
+ ////
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLQuery)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLQuery)
- // Track whether the event loop has spun
- bool mCanBeAvailable;
+ explicit WebGLQuery(WebGLContext* webgl);
private:
~WebGLQuery() {
DeleteOnce();
};
- GLuint mGLName;
- GLenum mType;
+ // WebGLRefCountedObject
+ void Delete();
+
+public:
+ WebGLContext* GetParentObject() const { return mContext; }
+ virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
- friend class WebGL2Context;
+ ////
+
+ void BeginQuery(GLenum target, WebGLRefPtr<WebGLQuery>& slot);
+ void DeleteQuery();
+ void EndQuery();
+ void GetQueryParameter(GLenum pname, JS::MutableHandleValue retval) const;
+ bool IsQuery() const;
+ void QueryCounter(const char* funcName, GLenum target);
};
} // namespace mozilla
#endif // WEBGL_QUERY_H_
deleted file mode 100644
--- a/dom/canvas/WebGLTimerQuery.cpp
+++ /dev/null
@@ -1,75 +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/. */
-
-#include "WebGLTimerQuery.h"
-
-#include "GLContext.h"
-#include "mozilla/dom/WebGLRenderingContextBinding.h"
-#include "nsContentUtils.h"
-#include "WebGLContext.h"
-#include "nsThreadUtils.h"
-
-namespace mozilla {
-
-JSObject*
-WebGLTimerQuery::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
-{
- return dom::WebGLTimerQueryEXTBinding::Wrap(cx, this, givenProto);
-}
-
-WebGLTimerQuery::WebGLTimerQuery(WebGLContext* webgl, GLuint name)
- : WebGLContextBoundObject(webgl)
- , mGLName(name)
- , mTarget(LOCAL_GL_NONE)
- , mCanBeAvailable(false)
-{
- mContext->mTimerQueries.insertBack(this);
-}
-
-WebGLTimerQuery::~WebGLTimerQuery()
-{
- DeleteOnce();
-}
-
-WebGLTimerQuery*
-WebGLTimerQuery::Create(WebGLContext* webgl)
-{
- GLuint name = 0;
- webgl->MakeContextCurrent();
- webgl->gl->fGenQueries(1, &name);
- return new WebGLTimerQuery(webgl, name);
-}
-
-void
-WebGLTimerQuery::Delete()
-{
- gl::GLContext* gl = mContext->GL();
-
- gl->MakeCurrent();
- gl->fDeleteQueries(1, &mGLName);
-
- LinkedListElement<WebGLTimerQuery>::removeFrom(mContext->mTimerQueries);
-}
-
-WebGLContext*
-WebGLTimerQuery::GetParentObject() const
-{
- return mContext;
-}
-
-void
-WebGLTimerQuery::QueueAvailablity()
-{
- RefPtr<WebGLTimerQuery> self = this;
- NS_DispatchToCurrentThread(NS_NewRunnableFunction([self] { self->mCanBeAvailable = true; }));
-}
-
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTimerQuery)
-
-NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLTimerQuery, AddRef)
-NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLTimerQuery, Release)
-
-} // namespace mozilla
deleted file mode 100644
--- a/dom/canvas/WebGLTimerQuery.h
+++ /dev/null
@@ -1,54 +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/. */
-
-#ifndef WEBGL_TIMER_QUERY_H_
-#define WEBGL_TIMER_QUERY_H_
-
-#include "GLConsts.h"
-#include "nsWrapperCache.h"
-#include "WebGLObjectModel.h"
-
-namespace mozilla {
-
-class WebGLTimerQuery final
- : public nsWrapperCache
- , public WebGLRefCountedObject<WebGLTimerQuery>
- , public LinkedListElement<WebGLTimerQuery>
- , public WebGLContextBoundObject
-{
-public:
- static WebGLTimerQuery* Create(WebGLContext* webgl);
-
- void Delete();
-
- bool HasEverBeenBound() const { return mTarget != LOCAL_GL_NONE; }
- bool CanBeAvailable() const { return mCanBeAvailable; }
- void QueueAvailablity();
- GLenum Target() const { return mTarget; }
-
- WebGLContext* GetParentObject() const;
-
- // NS
- virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
-
- const GLenum mGLName;
-
- NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTimerQuery)
- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTimerQuery)
-
-private:
- WebGLTimerQuery(WebGLContext* webgl, GLuint name);
- ~WebGLTimerQuery();
-
- GLenum mTarget;
- bool mCanBeAvailable;
-
- friend class WebGLExtensionDisjointTimerQuery;
-};
-
-} // namespace mozilla
-
-#endif // WEBGL_TIMER_QUERY_H_
--- a/dom/canvas/WebGLTypes.h
+++ b/dom/canvas/WebGLTypes.h
@@ -153,17 +153,17 @@ enum class WebGLExtensionID : uint8_t {
OES_standard_derivatives,
OES_texture_float,
OES_texture_float_linear,
OES_texture_half_float,
OES_texture_half_float_linear,
OES_vertex_array_object,
WEBGL_color_buffer_float,
WEBGL_compressed_texture_atc,
- WEBGL_compressed_texture_es3_0,
+ WEBGL_compressed_texture_etc,
WEBGL_compressed_texture_etc1,
WEBGL_compressed_texture_pvrtc,
WEBGL_compressed_texture_s3tc,
WEBGL_debug_renderer_info,
WEBGL_debug_shaders,
WEBGL_depth_texture,
WEBGL_draw_buffers,
WEBGL_lose_context,
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -143,17 +143,16 @@ UNIFIED_SOURCES += [
'WebGLSampler.cpp',
'WebGLShader.cpp',
'WebGLShaderPrecisionFormat.cpp',
'WebGLShaderValidator.cpp',
'WebGLSync.cpp',
'WebGLTexelConversions.cpp',
'WebGLTexture.cpp',
'WebGLTextureUpload.cpp',
- 'WebGLTimerQuery.cpp',
'WebGLTransformFeedback.cpp',
'WebGLUniformLocation.cpp',
'WebGLValidateStrings.cpp',
'WebGLVertexArray.cpp',
'WebGLVertexArrayFake.cpp',
'WebGLVertexArrayGL.cpp',
'WebGLVertexArrayObject.cpp',
'WebGLVertexAttribData.cpp',
--- a/dom/canvas/test/webgl-mochitest/ensure-exts/test_EXT_disjoint_timer_query.html
+++ b/dom/canvas/test/webgl-mochitest/ensure-exts/test_EXT_disjoint_timer_query.html
@@ -5,15 +5,13 @@
<script src='/tests/SimpleTest/SimpleTest.js'></script>
<link rel='stylesheet' href='/tests/SimpleTest/test.css'>
<script src='ensure-ext.js'></script>
</head>
<body>
<script>
'use strict';
-Lastly_WithDraftExtsEnabled(function() {
- EnsureExtFor('webgl', 'EXT_disjoint_timer_query');
-});
+EnsureExt('EXT_disjoint_timer_query');
</script>
</body>
</html>
--- a/dom/canvas/test/webgl-mochitest/ensure-exts/test_common.html
+++ b/dom/canvas/test/webgl-mochitest/ensure-exts/test_common.html
@@ -14,16 +14,17 @@
var ENSURE = 'ENSURE'; // Works on all test machines.
var FORBID = 'FORBID'; // Should not work on any test machine.
var MACHINE_SPECIFIC = 'MACHINE_SPECIFIC';
var defaultExts = [
// Ratified
['ANGLE_instanced_arrays' , [MACHINE_SPECIFIC, FORBID ]],
['EXT_blend_minmax' , [MACHINE_SPECIFIC, FORBID ]],
+ ['EXT_disjoint_timer_query' , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
['EXT_frag_depth' , [MACHINE_SPECIFIC, FORBID ]],
['EXT_shader_texture_lod' , [MACHINE_SPECIFIC, FORBID ]],
['EXT_texture_filter_anisotropic', [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
['OES_element_index_uint' , [ENSURE , FORBID ]],
['OES_standard_derivatives' , [MACHINE_SPECIFIC, FORBID ]],
['OES_texture_float' , [ENSURE , FORBID ]],
['OES_texture_float_linear' , [ENSURE , ENSURE ]],
['OES_texture_half_float' , [ENSURE , FORBID ]],
@@ -42,17 +43,16 @@ var defaultExts = [
['EXT_sRGB' , [MACHINE_SPECIFIC, FORBID ]],
['WEBGL_color_buffer_float' , [MACHINE_SPECIFIC, FORBID ]],
['WEBGL_compressed_texture_atc' , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
['WEBGL_compressed_texture_etc1' , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
['WEBGL_compressed_texture_pvrtc', [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
];
var draftExts = [
- ['EXT_disjoint_timer_query' , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]], // TODO: Actually Community Approved now.
['WEBGL_compressed_texture_es3', [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
];
var nonImplementedExts = [
'OES_fbo_render_mipmap',
'WEBGL_compressed_texture_astc',
'WEBGL_security_sensitive_resources',
'WEBGL_shared_resources',
--- a/dom/canvas/test/webgl-mochitest/mochitest.ini
+++ b/dom/canvas/test/webgl-mochitest/mochitest.ini
@@ -77,17 +77,16 @@ skip-if = android_version == '18' #Andro
[test_uninit_data.html]
[test_webgl_available.html]
#[test_webgl_color_buffer_float.html]
# We haven't cleaned up the Try results yet, but let's get this on the books first.
[test_webgl_conformance.html]
skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
[test_webgl_compressed_texture_es3.html]
[test_webgl_disjoint_timer_query.html]
-fail-if = (os == 'win' && (os_version == '6.1' || os_version == '6.2' || os_version == '10.0'))
[test_webgl_force_enable.html]
[test_webgl_request_context.html]
skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
[test_webgl_request_mismatch.html]
skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
[test_webgl2_not_exposed.html]
skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
[test_webgl2_invalidate_framebuffer.html]
--- a/dom/canvas/test/webgl-mochitest/test_webgl_disjoint_timer_query.html
+++ b/dom/canvas/test/webgl-mochitest/test_webgl_disjoint_timer_query.html
@@ -26,20 +26,21 @@ function doTest() {
return;
}
ok(!ext.getQueryEXT(ext.TIME_ELAPSED_EXT, ext.CURRENT_QUERY_EXT),
"No query is active initially.");
var elapsedQuery = ext.createQueryEXT();
ok(elapsedQuery, "Query creation works.");
- ok(ext.isQueryEXT(elapsedQuery), "New query is valid after creation.");
+ ok(!ext.isQueryEXT(elapsedQuery), "isQuery fails after creation but before bind.");
ext.beginQueryEXT(ext.TIME_ELAPSED_EXT, elapsedQuery);
- is(ext.getQueryEXT(ext.TIME_ELAPSED_EXT, ext.CURRENT_QUERY_EXT), elapsedQuery,
+ ok(ext.isQueryEXT(elapsedQuery), "isQuery fails after bind.");
+ ok(ext.getQueryEXT(ext.TIME_ELAPSED_EXT, ext.CURRENT_QUERY_EXT) == elapsedQuery,
"Query is active after beginQueryEXT.");
ext.endQueryEXT(ext.TIME_ELAPSED_EXT);
gl.flush();
ok(!ext.getQueryEXT(ext.TIME_ELAPSED_EXT, ext.CURRENT_QUERY_EXT),
"Query is inactive after endQueryEXT.");
defer(function() {
@@ -60,23 +61,22 @@ function doTest() {
defer(function() {
ok(ext.getQueryObjectEXT(timestampQuery, ext.QUERY_RESULT_AVAILABLE_EXT),
"Timestamp query should be available immediately after flush and event loop tick.");
ok(ext.getQueryEXT(ext.TIMESTAMP_EXT, ext.QUERY_COUNTER_BITS_EXT) >= 30,
"Time elapsed must be at least 30 bits to hold at least 1 second of timing.");
SimpleTest.finish();
-
- });
+ });
} else {
SimpleTest.finish();
}
});
}
SimpleTest.waitForExplicitFinish();
-SpecialPowers.pushPrefEnv({"set": [['webgl.enable-draft-extensions', true]]}, doTest);
+doTest();
</script>
</body>
</html>
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -3999,17 +3999,17 @@ public:
mTargets.AppendObject(current);
}
// mouseenter/leave is fired only on elements.
current = current->GetParent();
}
}
}
- ~EnterLeaveDispatcher()
+ void Dispatch()
{
if (mEventMessage == eMouseEnter || mEventMessage == ePointerEnter) {
for (int32_t i = mTargets.Count() - 1; i >= 0; --i) {
mESM->DispatchMouseOrPointerEvent(mMouseEvent, mEventMessage,
mTargets[i], mRelatedTarget);
}
} else {
for (int32_t i = 0; i < mTargets.Count(); ++i) {
@@ -4084,16 +4084,17 @@ EventStateManager::NotifyMouseOut(Widget
EnterLeaveDispatcher leaveDispatcher(this, wrapper->mLastOverElement,
movingInto, aMouseEvent,
isPointer ? ePointerLeave : eMouseLeave);
// Fire mouseout
DispatchMouseOrPointerEvent(aMouseEvent, isPointer ? ePointerOut : eMouseOut,
wrapper->mLastOverElement, aMovingInto);
+ leaveDispatcher.Dispatch();
wrapper->mLastOverFrame = nullptr;
wrapper->mLastOverElement = nullptr;
// Turn recursion protection back off
wrapper->mFirstOutEventElement = nullptr;
}
@@ -4157,16 +4158,17 @@ EventStateManager::NotifyMouseOver(Widge
}
if (dispatch) {
// Fire mouseover
wrapper->mLastOverFrame =
DispatchMouseOrPointerEvent(aMouseEvent,
isPointer ? ePointerOver : eMouseOver,
aContent, lastOverElement);
+ enterDispatcher->Dispatch();
wrapper->mLastOverElement = aContent;
} else {
wrapper->mLastOverFrame = nullptr;
wrapper->mLastOverElement = nullptr;
}
// Turn recursion protection back off
wrapper->mFirstOverEventElement = nullptr;
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -30,16 +30,17 @@
#include "nsHttpChannel.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/workers/Workers.h"
#include "mozilla/ipc/PBackgroundSharedTypes.h"
#include "mozilla/Unused.h"
#include "Fetch.h"
+#include "FetchUtil.h"
#include "InternalRequest.h"
#include "InternalResponse.h"
namespace mozilla {
namespace dom {
NS_IMPL_ISUPPORTS(FetchDriver,
nsIStreamListener, nsIChannelEventSink, nsIInterfaceRequestor,
@@ -255,72 +256,40 @@ FetchDriver::HttpFetch()
nsAutoCString method;
mRequest->GetMethod(method);
rv = httpChan->SetRequestMethod(method);
NS_ENSURE_SUCCESS(rv, rv);
// Set the same headers.
SetRequestHeaders(httpChan);
- // Step 2. Set the referrer.
- nsAutoString referrer;
- mRequest->GetReferrer(referrer);
+ net::ReferrerPolicy net_referrerPolicy = mRequest->GetEnvironmentReferrerPolicy();
+ // Step 6 of
+ // https://fetch.spec.whatwg.org/#main-fetch
+ // If request's referrer policy is the empty string and request's client is
+ // non-null, then set request's referrer policy to request's client's
+ // associated referrer policy.
+ // Basically, "client" is not in our implementation, we use
+ // EnvironmentReferrerPolicy of the worker or document context
+ if (mRequest->ReferrerPolicy_() == ReferrerPolicy::_empty) {
+ mRequest->SetReferrerPolicy(net_referrerPolicy);
+ }
+ // Step 7 of
+ // https://fetch.spec.whatwg.org/#main-fetch
+ // If request’s referrer policy is the empty string,
+ // then set request’s referrer policy to "no-referrer-when-downgrade".
+ if (mRequest->ReferrerPolicy_() == ReferrerPolicy::_empty) {
+ mRequest->SetReferrerPolicy(net::RP_No_Referrer_When_Downgrade);
+ }
- // The Referrer Policy in Request can be used to override a referrer policy
- // associated with an environment settings object.
- // If there's no Referrer Policy in the request, it should be inherited
- // from environment.
- ReferrerPolicy referrerPolicy = mRequest->ReferrerPolicy_();
- net::ReferrerPolicy net_referrerPolicy = mRequest->GetEnvironmentReferrerPolicy();
- switch (referrerPolicy) {
- case ReferrerPolicy::_empty:
- break;
- case ReferrerPolicy::No_referrer:
- net_referrerPolicy = net::RP_No_Referrer;
- break;
- case ReferrerPolicy::No_referrer_when_downgrade:
- net_referrerPolicy = net::RP_No_Referrer_When_Downgrade;
- break;
- case ReferrerPolicy::Origin:
- net_referrerPolicy = net::RP_Origin;
- break;
- case ReferrerPolicy::Origin_when_cross_origin:
- net_referrerPolicy = net::RP_Origin_When_Crossorigin;
- break;
- case ReferrerPolicy::Unsafe_url:
- net_referrerPolicy = net::RP_Unsafe_URL;
- break;
- default:
- MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy enum value?");
- break;
- }
- if (referrer.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
- rv = nsContentUtils::SetFetchReferrerURIWithPolicy(mPrincipal,
- mDocument,
- httpChan,
- net_referrerPolicy);
- NS_ENSURE_SUCCESS(rv, rv);
- } else if (referrer.IsEmpty()) {
- rv = httpChan->SetReferrerWithPolicy(nullptr, net::RP_No_Referrer);
- NS_ENSURE_SUCCESS(rv, rv);
- } else {
- // From "Determine request's Referrer" step 3
- // "If request's referrer is a URL, let referrerSource be request's
- // referrer."
- nsCOMPtr<nsIURI> referrerURI;
- rv = NS_NewURI(getter_AddRefs(referrerURI), referrer, nullptr, nullptr);
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv =
- httpChan->SetReferrerWithPolicy(referrerURI,
- referrerPolicy == ReferrerPolicy::_empty ?
- mRequest->GetEnvironmentReferrerPolicy() :
- net_referrerPolicy);
- NS_ENSURE_SUCCESS(rv, rv);
- }
+ rv = FetchUtil::SetRequestReferrer(mPrincipal,
+ mDocument,
+ httpChan,
+ mRequest);
+ NS_ENSURE_SUCCESS(rv, rv);
// Bug 1120722 - Authorization will be handled later.
// Auth may require prompting, we don't support it yet.
// The next patch in this same bug prevents this from aborting the request.
// Credentials checks for CORS are handled by nsCORSListenerProxy,
nsCOMPtr<nsIHttpChannelInternal> internalChan = do_QueryInterface(httpChan);
@@ -818,39 +787,25 @@ FetchDriver::AsyncOnChannelRedirect(nsIC
mRequest->AddURL(spec, fragment);
NS_ConvertUTF8toUTF16 tRPHeaderValue(tRPHeaderCValue);
// updates request’s associated referrer policy according to the
// Referrer-Policy header (if any).
if (!tRPHeaderValue.IsEmpty()) {
net::ReferrerPolicy net_referrerPolicy =
nsContentUtils::GetReferrerPolicyFromHeader(tRPHeaderValue);
if (net_referrerPolicy != net::RP_Unset) {
- ReferrerPolicy referrerPolicy = mRequest->ReferrerPolicy_();
- switch (net_referrerPolicy) {
- case net::RP_No_Referrer:
- referrerPolicy = ReferrerPolicy::No_referrer;
- break;
- case net::RP_No_Referrer_When_Downgrade:
- referrerPolicy = ReferrerPolicy::No_referrer_when_downgrade;
- break;
- case net::RP_Origin:
- referrerPolicy = ReferrerPolicy::Origin;
- break;
- case net::RP_Origin_When_Crossorigin:
- referrerPolicy = ReferrerPolicy::Origin_when_cross_origin;
- break;
- case net::RP_Unsafe_URL:
- referrerPolicy = ReferrerPolicy::Unsafe_url;
- break;
- default:
- MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy value");
- break;
+ mRequest->SetReferrerPolicy(net_referrerPolicy);
+ // Should update channel's referrer policy
+ if (httpChannel) {
+ rv = FetchUtil::SetRequestReferrer(mPrincipal,
+ mDocument,
+ httpChannel,
+ mRequest);
+ NS_ENSURE_SUCCESS(rv, rv);
}
-
- mRequest->SetReferrerPolicy(referrerPolicy);
}
}
aCallback->OnRedirectVerifyCallback(NS_OK);
return NS_OK;
}
NS_IMETHODIMP
--- a/dom/fetch/FetchUtil.cpp
+++ b/dom/fetch/FetchUtil.cpp
@@ -1,15 +1,17 @@
#include "FetchUtil.h"
#include "nsError.h"
#include "nsIUnicodeDecoder.h"
#include "nsString.h"
+#include "nsIDocument.h"
#include "mozilla/dom/EncodingUtils.h"
+#include "mozilla/dom/InternalRequest.h"
namespace mozilla {
namespace dom {
// static
nsresult
FetchUtil::GetValidRequestMethod(const nsACString& aMethod, nsCString& outMethod)
{
@@ -105,10 +107,64 @@ FetchUtil::ExtractHeader(nsACString::con
if (!NS_IsReasonableHTTPHeaderValue(aHeaderValue)) {
return false;
}
aHeaderValue.CompressWhitespace();
return PushOverLine(aStart, aEnd);
}
+// static
+nsresult
+FetchUtil::SetRequestReferrer(nsIPrincipal* aPrincipal,
+ nsIDocument* aDoc,
+ nsIHttpChannel* aChannel,
+ InternalRequest* aRequest) {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ nsAutoString referrer;
+ aRequest->GetReferrer(referrer);
+ net::ReferrerPolicy policy = aRequest->GetReferrerPolicy();
+
+ nsresult rv = NS_OK;
+ if (referrer.IsEmpty()) {
+ // This is the case request’s referrer is "no-referrer"
+ rv = aChannel->SetReferrerWithPolicy(nullptr, net::RP_No_Referrer);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else if (referrer.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
+ rv = nsContentUtils::SetFetchReferrerURIWithPolicy(aPrincipal,
+ aDoc,
+ aChannel,
+ policy);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else {
+ // From "Determine request's Referrer" step 3
+ // "If request's referrer is a URL, let referrerSource be request's
+ // referrer."
+ nsCOMPtr<nsIURI> referrerURI;
+ rv = NS_NewURI(getter_AddRefs(referrerURI), referrer, nullptr, nullptr);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = aChannel->SetReferrerWithPolicy(referrerURI, policy);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ nsCOMPtr<nsIURI> referrerURI;
+ aChannel->GetReferrer(getter_AddRefs(referrerURI));
+
+ // Step 8 https://fetch.spec.whatwg.org/#main-fetch
+ // If request’s referrer is not "no-referrer", set request’s referrer to
+ // the result of invoking determine request’s referrer.
+ if (referrerURI) {
+ nsAutoCString spec;
+ rv = referrerURI->GetSpec(spec);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ aRequest->SetReferrer(NS_ConvertUTF8toUTF16(spec));
+ } else {
+ aRequest->SetReferrer(EmptyString());
+ }
+
+ return NS_OK;
+}
+
} // namespace dom
} // namespace mozilla
--- a/dom/fetch/FetchUtil.h
+++ b/dom/fetch/FetchUtil.h
@@ -3,19 +3,25 @@
#include "nsString.h"
#include "nsError.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/FormData.h"
+class nsIPrincipal;
+class nsIDocument;
+class nsIHttpChannel;
+
namespace mozilla {
namespace dom {
+class InternalRequest;
+
class FetchUtil final
{
private:
FetchUtil() = delete;
public:
/**
* Sets outMethod to a valid HTTP request method string based on an input method.
@@ -30,13 +36,20 @@ public:
* Extracts an HTTP header from a substring range.
*/
static bool
ExtractHeader(nsACString::const_iterator& aStart,
nsACString::const_iterator& aEnd,
nsCString& aHeaderName,
nsCString& aHeaderValue,
bool* aWasEmptyHeader);
+
+ static nsresult
+ SetRequestReferrer(nsIPrincipal* aPrincipal,
+ nsIDocument* aDoc,
+ nsIHttpChannel* aChannel,
+ InternalRequest* aRequest);
+
};
} // namespace dom
} // namespace mozilla
#endif
--- a/dom/fetch/InternalRequest.h
+++ b/dom/fetch/InternalRequest.h
@@ -228,16 +228,82 @@ public:
}
void
SetReferrerPolicy(ReferrerPolicy aReferrerPolicy)
{
mReferrerPolicy = aReferrerPolicy;
}
+ void
+ SetReferrerPolicy(net::ReferrerPolicy aReferrerPolicy)
+ {
+ switch (aReferrerPolicy) {
+ case net::RP_Unset:
+ mReferrerPolicy = ReferrerPolicy::_empty;
+ break;
+ case net::RP_No_Referrer:
+ mReferrerPolicy = ReferrerPolicy::No_referrer;
+ break;
+ case net::RP_No_Referrer_When_Downgrade:
+ mReferrerPolicy = ReferrerPolicy::No_referrer_when_downgrade;
+ break;
+ case net::RP_Origin:
+ mReferrerPolicy = ReferrerPolicy::Origin;
+ break;
+ case net::RP_Origin_When_Crossorigin:
+ mReferrerPolicy = ReferrerPolicy::Origin_when_cross_origin;
+ break;
+ case net::RP_Unsafe_URL:
+ mReferrerPolicy = ReferrerPolicy::Unsafe_url;
+ break;
+ case net::RP_Same_Origin:
+ mReferrerPolicy = ReferrerPolicy::Same_origin;
+ break;
+ case net::RP_Strict_Origin:
+ mReferrerPolicy = ReferrerPolicy::Strict_origin;
+ break;
+ case net::RP_Strict_Origin_When_Cross_Origin:
+ mReferrerPolicy = ReferrerPolicy::Strict_origin_when_cross_origin;
+ break;
+ default:
+ MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy value");
+ break;
+ }
+ }
+
+ net::ReferrerPolicy
+ GetReferrerPolicy()
+ {
+ switch (mReferrerPolicy) {
+ case ReferrerPolicy::_empty:
+ return net::RP_Unset;
+ case ReferrerPolicy::No_referrer:
+ return net::RP_No_Referrer;
+ case ReferrerPolicy::No_referrer_when_downgrade:
+ return net::RP_No_Referrer_When_Downgrade;
+ case ReferrerPolicy::Origin:
+ return net::RP_Origin;
+ case ReferrerPolicy::Origin_when_cross_origin:
+ return net::RP_Origin_When_Crossorigin;
+ case ReferrerPolicy::Unsafe_url:
+ return net::RP_Unsafe_URL;
+ case ReferrerPolicy::Strict_origin:
+ return net::RP_Strict_Origin;
+ case ReferrerPolicy::Same_origin:
+ return net::RP_Same_Origin;
+ case ReferrerPolicy::Strict_origin_when_cross_origin:
+ return net::RP_Strict_Origin_When_Cross_Origin;
+ default:
+ MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy enum value?");
+ break;
+ }
+ return net::RP_Unset;
+ }
+
net::ReferrerPolicy
GetEnvironmentReferrerPolicy() const
{
return mEnvironmentReferrerPolicy;
}
void
SetEnvironmentReferrerPolicy(net::ReferrerPolicy aReferrerPolicy)
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -619,28 +619,31 @@ HTMLCanvasElement::ParseAttribute(int32_
return aResult.ParseNonNegativeIntValue(aValue);
}
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
aResult);
}
-// HTMLCanvasElement::toDataURL
-NS_IMETHODIMP
-HTMLCanvasElement::ToDataURL(const nsAString& aType, JS::Handle<JS::Value> aParams,
- JSContext* aCx, nsAString& aDataURL)
+void
+HTMLCanvasElement::ToDataURL(JSContext* aCx, const nsAString& aType,
+ JS::Handle<JS::Value> aParams,
+ nsAString& aDataURL,
+ CallerType aCallerType,
+ ErrorResult& aRv)
{
// do a trust check if this is a write-only canvas
- if (mWriteOnly && !nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
+ if (mWriteOnly && aCallerType != CallerType::System) {
+ aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+ return;
}
- return ToDataURLImpl(aCx, aType, aParams, aDataURL);
+ aRv = ToDataURLImpl(aCx, aType, aParams, aDataURL);
}
void
HTMLCanvasElement::SetMozPrintCallback(PrintCallback* aCallback)
{
mPrintCallback = aCallback;
}
@@ -804,20 +807,21 @@ HTMLCanvasElement::ToDataURLImpl(JSConte
return Base64EncodeInputStream(stream, aDataURL, (uint32_t)count, aDataURL.Length());
}
void
HTMLCanvasElement::ToBlob(JSContext* aCx,
BlobCallback& aCallback,
const nsAString& aType,
JS::Handle<JS::Value> aParams,
+ CallerType aCallerType,
ErrorResult& aRv)
{
// do a trust check if this is a write-only canvas
- if (mWriteOnly && !nsContentUtils::IsCallerChrome()) {
+ if (mWriteOnly && aCallerType != CallerType::System) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
MOZ_ASSERT(global);
CanvasRenderingContextHelper::ToBlob(aCx, global, aCallback, aType,
@@ -858,50 +862,40 @@ HTMLCanvasElement::TransferControlToOffs
}
return mOffscreenCanvas;
}
already_AddRefed<File>
HTMLCanvasElement::MozGetAsFile(const nsAString& aName,
const nsAString& aType,
+ CallerType aCallerType,
ErrorResult& aRv)
{
- nsCOMPtr<nsISupports> file;
- aRv = MozGetAsFile(aName, aType, getter_AddRefs(file));
- if (NS_WARN_IF(aRv.Failed())) {
- return nullptr;
- }
-
- nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(file);
- RefPtr<Blob> domBlob = static_cast<Blob*>(blob.get());
- MOZ_ASSERT(domBlob->IsFile());
- return domBlob->ToFile();
-}
-
-NS_IMETHODIMP
-HTMLCanvasElement::MozGetAsFile(const nsAString& aName,
- const nsAString& aType,
- nsISupports** aResult)
-{
OwnerDoc()->WarnOnceAbout(nsIDocument::eMozGetAsFile);
// do a trust check if this is a write-only canvas
- if ((mWriteOnly) &&
- !nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
+ if (mWriteOnly && aCallerType != CallerType::System) {
+ aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+ return nullptr;
}
- return MozGetAsBlobImpl(aName, aType, aResult);
+
+ RefPtr<File> file;
+ aRv = MozGetAsFileImpl(aName, aType, getter_AddRefs(file));
+ if (NS_WARN_IF(aRv.Failed())) {
+ return nullptr;
+ }
+ return file.forget();
}
nsresult
-HTMLCanvasElement::MozGetAsBlobImpl(const nsAString& aName,
+HTMLCanvasElement::MozGetAsFileImpl(const nsAString& aName,
const nsAString& aType,
- nsISupports** aResult)
+ File** aResult)
{
nsCOMPtr<nsIInputStream> stream;
nsAutoString type(aType);
nsresult rv = ExtractData(type, EmptyString(), getter_AddRefs(stream));
NS_ENSURE_SUCCESS(rv, rv);
uint64_t imgSize;
rv = stream->Available(&imgSize);
@@ -915,17 +909,17 @@ HTMLCanvasElement::MozGetAsBlobImpl(cons
JSContext* cx = nsContentUtils::GetCurrentJSContext();
if (cx) {
JS_updateMallocCounter(cx, imgSize);
}
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(OwnerDoc()->GetScopeObject());
// The File takes ownership of the buffer
- nsCOMPtr<nsIDOMBlob> file =
+ RefPtr<File> file =
File::CreateMemoryFile(win, imgData, (uint32_t)imgSize, aName, type,
PR_Now());
file.forget(aResult);
return NS_OK;
}
nsresult
@@ -947,56 +941,60 @@ HTMLCanvasElement::GetContext(JSContext*
return nullptr;
}
return CanvasRenderingContextHelper::GetContext(aCx, aContextId,
aContextOptions.isObject() ? aContextOptions : JS::NullHandleValue,
aRv);
}
-NS_IMETHODIMP
+already_AddRefed<nsISupports>
HTMLCanvasElement::MozGetIPCContext(const nsAString& aContextId,
- nsISupports **aContext)
+ ErrorResult& aRv)
{
- if(!nsContentUtils::IsCallerChrome()) {
- // XXX ERRMSG we need to report an error to developers here! (bug 329026)
- return NS_ERROR_DOM_SECURITY_ERR;
- }
+ // Note that we're a [ChromeOnly] method, so from JS we can only be called by
+ // system code.
// We only support 2d shmem contexts for now.
- if (!aContextId.EqualsLiteral("2d"))
- return NS_ERROR_INVALID_ARG;
+ if (!aContextId.EqualsLiteral("2d")) {
+ aRv.Throw(NS_ERROR_INVALID_ARG);
+ return nullptr;
+ }
CanvasContextType contextType = CanvasContextType::Canvas2D;
if (!mCurrentContext) {
// This canvas doesn't have a context yet.
RefPtr<nsICanvasRenderingContextInternal> context;
context = CreateContext(contextType);
if (!context) {
- *aContext = nullptr;
- return NS_OK;
+ return nullptr;
}
mCurrentContext = context;
mCurrentContext->SetIsIPC(true);
mCurrentContextType = contextType;
ErrorResult dummy;
nsresult rv = UpdateContext(nullptr, JS::NullHandleValue, dummy);
- NS_ENSURE_SUCCESS(rv, rv);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ aRv.Throw(rv);
+ return nullptr;
+ }
} else {
// We already have a context of some type.
- if (contextType != mCurrentContextType)
- return NS_ERROR_INVALID_ARG;
+ if (contextType != mCurrentContextType) {
+ aRv.Throw(NS_ERROR_INVALID_ARG);
+ return nullptr;
+ }
}
- NS_ADDREF (*aContext = mCurrentContext);
- return NS_OK;
+ nsCOMPtr<nsISupports> context(mCurrentContext);
+ return context.forget();
}
nsIntSize
HTMLCanvasElement::GetSize()
{
return GetWidthHeight();
}
--- a/dom/html/HTMLCanvasElement.h
+++ b/dom/html/HTMLCanvasElement.h
@@ -11,16 +11,17 @@
#include "nsIDOMEventListener.h"
#include "nsIDOMHTMLCanvasElement.h"
#include "nsIObserver.h"
#include "nsGenericHTMLElement.h"
#include "nsGkAtoms.h"
#include "nsSize.h"
#include "nsError.h"
+#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/CanvasRenderingContextHelper.h"
#include "mozilla/gfx/Rect.h"
#include "mozilla/layers/LayersTypes.h"
class nsICanvasRenderingContextInternal;
class nsITimerCallback;
namespace mozilla {
@@ -171,25 +172,24 @@ public:
virtual already_AddRefed<nsISupports>
GetContext(JSContext* aCx, const nsAString& aContextId,
JS::Handle<JS::Value> aContextOptions,
ErrorResult& aRv) override;
void ToDataURL(JSContext* aCx, const nsAString& aType,
JS::Handle<JS::Value> aParams,
- nsAString& aDataURL, ErrorResult& aRv)
- {
- aRv = ToDataURL(aType, aParams, aCx, aDataURL);
- }
+ nsAString& aDataURL, CallerType aCallerType,
+ ErrorResult& aRv);
void ToBlob(JSContext* aCx,
BlobCallback& aCallback,
const nsAString& aType,
JS::Handle<JS::Value> aParams,
+ CallerType aCallerType,
ErrorResult& aRv);
OffscreenCanvas* TransferControlToOffscreen(ErrorResult& aRv);
bool MozOpaque() const
{
return GetBoolAttr(nsGkAtoms::moz_opaque);
}
@@ -199,24 +199,20 @@ public:
aRv.Throw(NS_ERROR_FAILURE);
return;
}
SetHTMLBoolAttr(nsGkAtoms::moz_opaque, aValue, aRv);
}
already_AddRefed<File> MozGetAsFile(const nsAString& aName,
const nsAString& aType,
+ CallerType aCallerType,
ErrorResult& aRv);
already_AddRefed<nsISupports> MozGetIPCContext(const nsAString& aContextId,
- ErrorResult& aRv)
- {
- nsCOMPtr<nsISupports> context;
- aRv = MozGetIPCContext(aContextId, getter_AddRefs(context));
- return context.forget();
- }
+ ErrorResult& aRv);
PrintCallback* GetMozPrintCallback() const;
void SetMozPrintCallback(PrintCallback* aCallback);
already_AddRefed<CanvasCaptureMediaStream>
CaptureStream(const Optional<double>& aFrameRate, ErrorResult& aRv);
/**
* Get the size in pixels of this canvas element
@@ -366,19 +362,19 @@ protected:
nsresult ExtractData(nsAString& aType,
const nsAString& aOptions,
nsIInputStream** aStream);
nsresult ToDataURLImpl(JSContext* aCx,
const nsAString& aMimeType,
const JS::Value& aEncoderOptions,
nsAString& aDataURL);
- nsresult MozGetAsBlobImpl(const nsAString& aName,
+ nsresult MozGetAsFileImpl(const nsAString& aName,
const nsAString& aType,
- nsISupports** aResult);
+ File** aResult);
void CallPrintCallback();
AsyncCanvasRenderer* GetAsyncCanvasRenderer();
bool mResetLayer;
RefPtr<HTMLCanvasElement> mOriginalCanvas;
RefPtr<PrintCallback> mPrintCallback;
RefPtr<HTMLCanvasPrintState> mPrintState;
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -3749,17 +3749,17 @@ HTMLInputElement::Select()
bool
HTMLInputElement::DispatchSelectEvent(nsPresContext* aPresContext)
{
nsEventStatus status = nsEventStatus_eIgnore;
// If already handling select event, don't dispatch a second.
if (!mHandlingSelectEvent) {
- WidgetEvent event(nsContentUtils::LegacyIsCallerChromeOrNativeCode(), eFormSelect);
+ WidgetEvent event(true, eFormSelect);
mHandlingSelectEvent = true;
EventDispatcher::Dispatch(static_cast<nsIContent*>(this),
aPresContext, &event, nullptr, &status);
mHandlingSelectEvent = false;
}
// If the DOM event was not canceled (e.g. by a JS event handler
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -7,16 +7,17 @@
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/dom/HTMLMediaElementBinding.h"
#include "mozilla/dom/HTMLSourceElement.h"
#include "mozilla/dom/ElementInlines.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/dom/MediaEncryptedEvent.h"
+#include "mozilla/EMEUtils.h"
#include "base/basictypes.h"
#include "nsIDOMHTMLMediaElement.h"
#include "nsIDOMHTMLSourceElement.h"
#include "TimeRanges.h"
#include "nsGenericHTMLElement.h"
#include "nsAttrValueInlines.h"
#include "nsPresContext.h"
@@ -5287,35 +5288,41 @@ void HTMLMediaElement::SuspendOrResumeEl
if (aPauseElement != mPausedForInactiveDocumentOrChannel) {
mPausedForInactiveDocumentOrChannel = aPauseElement;
UpdateSrcMediaStreamPlaying();
UpdateAudioChannelPlayingState();
if (aPauseElement) {
ReportTelemetry();
ReportEMETelemetry();
- // For EME content, force destruction of the CDM client (and CDM
+ // For EME content, we may force destruction of the CDM client (and CDM
// instance if this is the last client for that CDM instance) and
// the CDM's decoder. This ensures the CDM gets reliable and prompt
// shutdown notifications, as it may have book-keeping it needs
// to do on shutdown.
if (mMediaKeys) {
- mMediaKeys->Shutdown();
- mMediaKeys = nullptr;
- if (mDecoder) {
- ShutdownDecoder();
+ nsAutoString keySystem;
+ mMediaKeys->GetKeySystem(keySystem);
+ // If we're using Primetime we need to shutdown the key system and
+ // decoder to preserve secure stop like behavior, other CDMs don't
+ // implement this so we don't need to worry with them on a suspend.
+ if (IsPrimetimeKeySystem(keySystem)) {
+ mMediaKeys->Shutdown();
+ mMediaKeys = nullptr;
+ if (mDecoder) {
+ ShutdownDecoder();
+ }
}
}
if (mDecoder) {
mDecoder->Pause();
mDecoder->Suspend();
}
mEventDeliveryPaused = aSuspendEvents;
} else {
- MOZ_ASSERT(!mMediaKeys);
if (mDecoder) {
mDecoder->Resume();
if (!mPaused && !mDecoder->IsEnded()) {
mDecoder->Play();
}
}
if (mEventDeliveryPaused) {
mEventDeliveryPaused = false;
@@ -5349,16 +5356,25 @@ void HTMLMediaElement::NotifyOwnerDocume
if (mDecoder && !IsBeingDestroyed()) {
mDecoder->NotifyOwnerActivityChanged(visible);
}
bool pauseElement = ShouldElementBePaused();
SuspendOrResumeElement(pauseElement, !IsActive());
+ // If the owning document has become inactive we should shutdown the CDM.
+ if (!OwnerDoc()->IsCurrentActiveDocument() && mMediaKeys) {
+ mMediaKeys->Shutdown();
+ mMediaKeys = nullptr;
+ if (mDecoder) {
+ ShutdownDecoder();
+ }
+ }
+
AddRemoveSelfReference();
}
void HTMLMediaElement::AddRemoveSelfReference()
{
// XXX we could release earlier here in many situations if we examined
// which event listeners are attached. Right now we assume there is a
// potential listener for every event. We would also have to keep the
--- a/dom/html/HTMLMenuElement.cpp
+++ b/dom/html/HTMLMenuElement.cpp
@@ -53,87 +53,69 @@ HTMLMenuElement::HTMLMenuElement(already
{
}
HTMLMenuElement::~HTMLMenuElement()
{
}
NS_IMPL_ISUPPORTS_INHERITED(HTMLMenuElement, nsGenericHTMLElement,
- nsIDOMHTMLMenuElement, nsIHTMLMenu)
+ nsIDOMHTMLMenuElement)
NS_IMPL_ELEMENT_CLONE(HTMLMenuElement)
NS_IMPL_BOOL_ATTR(HTMLMenuElement, Compact, compact)
NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLMenuElement, Type, type,
kMenuDefaultType->tag)
NS_IMPL_STRING_ATTR(HTMLMenuElement, Label, label)
-NS_IMETHODIMP
+void
HTMLMenuElement::SendShowEvent()
{
- NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_DOM_SECURITY_ERR);
-
nsCOMPtr<nsIDocument> document = GetComposedDoc();
if (!document) {
- return NS_ERROR_FAILURE;
+ return;
}
WidgetEvent event(true, eShow);
event.mFlags.mBubbles = false;
event.mFlags.mCancelable = false;
nsCOMPtr<nsIPresShell> shell = document->GetShell();
if (!shell) {
- return NS_ERROR_FAILURE;
+ return;
}
RefPtr<nsPresContext> presContext = shell->GetPresContext();
nsEventStatus status = nsEventStatus_eIgnore;
EventDispatcher::Dispatch(static_cast<nsIContent*>(this), presContext,
&event, nullptr, &status);
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-HTMLMenuElement::CreateBuilder(nsIMenuBuilder** _retval)
-{
- NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_DOM_SECURITY_ERR);
-
- nsCOMPtr<nsIMenuBuilder> builder = CreateBuilder();
- builder.swap(*_retval);
- return NS_OK;
}
already_AddRefed<nsIMenuBuilder>
HTMLMenuElement::CreateBuilder()
{
if (mType != MENU_TYPE_CONTEXT) {
return nullptr;
}
nsCOMPtr<nsIMenuBuilder> builder = do_CreateInstance(HTMLMENUBUILDER_CONTRACTID);
NS_WARNING_ASSERTION(builder, "No builder available");
return builder.forget();
}
-NS_IMETHODIMP
+void
HTMLMenuElement::Build(nsIMenuBuilder* aBuilder)
{
- NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_DOM_SECURITY_ERR);
-
if (!aBuilder) {
- return NS_OK;
+ return;
}
BuildSubmenu(EmptyString(), this, aBuilder);
-
- return NS_OK;
}
bool
HTMLMenuElement::ParseAttribute(int32_t aNamespaceID,
nsIAtom* aAttribute,
const nsAString& aValue,
nsAttrValue& aResult)
--- a/dom/html/HTMLMenuElement.h
+++ b/dom/html/HTMLMenuElement.h
@@ -4,40 +4,37 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_HTMLMenuElement_h
#define mozilla_dom_HTMLMenuElement_h
#include "mozilla/Attributes.h"
#include "nsIDOMHTMLMenuElement.h"
-#include "nsIHTMLMenu.h"
#include "nsGenericHTMLElement.h"
+class nsIMenuBuilder;
+
namespace mozilla {
namespace dom {
class HTMLMenuElement final : public nsGenericHTMLElement,
- public nsIDOMHTMLMenuElement,
- public nsIHTMLMenu
+ public nsIDOMHTMLMenuElement
{
public:
explicit HTMLMenuElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLMenuElement, menu)
// nsISupports
NS_DECL_ISUPPORTS_INHERITED
// nsIDOMHTMLMenuElement
NS_DECL_NSIDOMHTMLMENUELEMENT
- // nsIHTMLMenu
- NS_DECL_NSIHTMLMENU
-
virtual bool ParseAttribute(int32_t aNamespaceID,
nsIAtom* aAttribute,
const nsAString& aValue,
nsAttrValue& aResult) override;
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
uint8_t GetType() const { return mType; }
@@ -60,21 +57,21 @@ public:
{
return GetBoolAttr(nsGkAtoms::compact);
}
void SetCompact(bool aCompact, ErrorResult& aError)
{
SetHTMLBoolAttr(nsGkAtoms::compact, aCompact, aError);
}
- // The XPCOM SendShowEvent is OK for us
+ void SendShowEvent();
already_AddRefed<nsIMenuBuilder> CreateBuilder();
- // The XPCOM Build is OK for us
+ void Build(nsIMenuBuilder* aBuilder);
protected:
virtual ~HTMLMenuElement();
virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
protected:
--- a/dom/html/HTMLTextAreaElement.cpp
+++ b/dom/html/HTMLTextAreaElement.cpp
@@ -358,19 +358,16 @@ HTMLTextAreaElement::SetValue(const nsAS
}
return NS_OK;
}
NS_IMETHODIMP
HTMLTextAreaElement::SetUserInput(const nsAString& aValue)
{
- if (!nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
return SetValueInternal(aValue, nsTextEditorState::eSetValue_BySetUserInput);
}
NS_IMETHODIMP
HTMLTextAreaElement::SetValueChanged(bool aValueChanged)
{
bool previousValue = mValueChanged;
--- a/dom/html/moz.build
+++ b/dom/html/moz.build
@@ -15,17 +15,16 @@ MOCHITEST_CHROME_MANIFESTS += [
'test/forms/chrome.ini',
]
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
XPIDL_SOURCES += [
'nsIDateTimeInputArea.idl',
'nsIFormSubmitObserver.idl',
- 'nsIHTMLMenu.idl',
'nsIImageDocument.idl',
'nsIMenuBuilder.idl',
'nsIPhonetic.idl',
]
XPIDL_MODULE = 'content_html'
EXPORTS += [
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -2408,17 +2408,17 @@ nsGenericHTMLFormElement::IsLabelable()
type == NS_FORM_OUTPUT ||
type == NS_FORM_SELECT ||
type == NS_FORM_TEXTAREA;
}
//----------------------------------------------------------------------
void
-nsGenericHTMLElement::Click()
+nsGenericHTMLElement::Click(CallerType aCallerType)
{
if (HandlingClick())
return;
// Strong in case the event kills it
nsCOMPtr<nsIDocument> doc = GetComposedDoc();
nsCOMPtr<nsIPresShell> shell;
@@ -2427,20 +2427,18 @@ nsGenericHTMLElement::Click()
shell = doc->GetShell();
if (shell) {
context = shell->GetPresContext();
}
}
SetHandlingClick();
- // Click() is never called from native code, but it may be
- // called from chrome JS. Mark this event trusted if Click()
- // is called from chrome code.
- WidgetMouseEvent event(nsContentUtils::IsCallerChrome(),
+ // Mark this event trusted if Click() is called from system code.
+ WidgetMouseEvent event(aCallerType == CallerType::System,
eMouseClick, nullptr, WidgetMouseEvent::eReal);
event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
EventDispatcher::Dispatch(static_cast<nsIContent*>(this), context, &event);
ClearHandlingClick();
}
@@ -2562,23 +2560,16 @@ nsGenericHTMLElement::DispatchSimulatedC
WidgetMouseEvent::eReal);
event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
return EventDispatcher::Dispatch(ToSupports(aElement), aPresContext, &event);
}
nsresult
nsGenericHTMLElement::GetEditor(nsIEditor** aEditor)
{
- *aEditor = nullptr;
-
- // See also HTMLTextFieldAccessible::GetEditor.
- if (!nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
-
NS_IF_ADDREF(*aEditor = GetEditorInternal());
return NS_OK;
}
already_AddRefed<nsIEditor>
nsGenericHTMLElement::GetAssociatedEditor()
{
// If contenteditable is ever implemented, it might need to do something different here?
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -11,16 +11,17 @@
#include "nsMappedAttributeElement.h"
#include "nsIDOMHTMLElement.h"
#include "nsNameSpaceManager.h" // for kNameSpaceID_None
#include "nsIFormControl.h"
#include "nsGkAtoms.h"
#include "nsContentCreatorFunctions.h"
#include "mozilla/ErrorResult.h"
#include "nsIDOMHTMLMenuElement.h"
+#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/DOMRect.h"
#include "mozilla/dom/ValidityState.h"
#include "mozilla/dom/ElementInlines.h"
class nsDOMTokenList;
class nsIDOMHTMLMenuElement;
class nsIEditor;
class nsIFormControlFrame;
@@ -98,17 +99,17 @@ public:
bool Hidden() const
{
return GetBoolAttr(nsGkAtoms::hidden);
}
void SetHidden(bool aHidden, mozilla::ErrorResult& aError)
{
SetHTMLBoolAttr(nsGkAtoms::hidden, aHidden, aError);
}
- virtual void Click();
+ void Click(mozilla::dom::CallerType aCallerType);
void GetAccessKey(nsString& aAccessKey)
{
GetHTMLAttr(nsGkAtoms::accesskey, aAccessKey);
}
void SetAccessKey(const nsAString& aAccessKey, mozilla::ErrorResult& aError)
{
SetHTMLAttr(nsGkAtoms::accesskey, aAccessKey, aError);
}
@@ -423,20 +424,16 @@ public:
NS_IMETHOD GetOffsetWidth(int32_t* aOffsetWidth) final override {
*aOffsetWidth = OffsetWidth();
return NS_OK;
}
NS_IMETHOD GetOffsetHeight(int32_t* aOffsetHeight) final override {
*aOffsetHeight = OffsetHeight();
return NS_OK;
}
- NS_IMETHOD DOMClick() final override {
- Click();
- return NS_OK;
- }
NS_IMETHOD GetTabIndex(int32_t* aTabIndex) final override {
*aTabIndex = TabIndex();
return NS_OK;
}
NS_IMETHOD SetTabIndex(int32_t aTabIndex) final override {
mozilla::ErrorResult rv;
SetTabIndex(aTabIndex, rv);
return rv.StealNSResult();
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -111,16 +111,17 @@
#include "nsIStringBundle.h"
#include "nsDOMClassInfo.h"
#include "nsFocusManager.h"
#include "nsIFrame.h"
#include "nsIContent.h"
#include "nsLayoutStylesheetCache.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
+#include "mozilla/Unused.h"
using namespace mozilla;
using namespace mozilla::dom;
#define NS_MAX_DOCUMENT_WRITE_DEPTH 20
#include "prtime.h"
@@ -2790,27 +2791,31 @@ nsHTMLDocument::EditingStateChanged()
return NS_OK;
}
}
if (makeWindowEditable) {
// Set the editor to not insert br's on return when in p
// elements by default.
// XXX Do we only want to do this for designMode?
- bool unused;
- rv = ExecCommand(NS_LITERAL_STRING("insertBrOnReturn"), false,
- NS_LITERAL_STRING("false"), &unused);
-
- if (NS_FAILED(rv)) {
+ // Note that it doesn't matter what CallerType we pass, because the callee
+ // doesn't use it for this command. Play it safe and pass the more
+ // restricted one.
+ ErrorResult errorResult;
+ Unused << ExecCommand(NS_LITERAL_STRING("insertBrOnReturn"), false,
+ NS_LITERAL_STRING("false"), CallerType::NonSystem,
+ errorResult);
+
+ if (errorResult.Failed()) {
// Editor setup failed. Editing is not on after all.
// XXX Should we reset the editable flag on nodes?
editSession->TearDownEditorOnWindow(window);
mEditingState = eOff;
- return rv;
+ return errorResult.StealNSResult();
}
}
if (updateState) {
nsAutoScriptBlocker scriptBlocker;
NotifyEditableStateChange(this, this);
}
@@ -3116,32 +3121,21 @@ ConvertToMidasInternalCommand(const nsAS
nsAutoCString dummyCString;
nsAutoString dummyString;
bool dummyBool;
return ConvertToMidasInternalCommandInner(inCommandID, dummyString,
outCommandID, dummyCString,
dummyBool, dummyBool, true);
}
-/* TODO: don't let this call do anything if the page is not done loading */
-NS_IMETHODIMP
-nsHTMLDocument::ExecCommand(const nsAString& commandID,
- bool doShowUI,
- const nsAString& value,
- bool* _retval)
-{
- ErrorResult rv;
- *_retval = ExecCommand(commandID, doShowUI, value, rv);
- return rv.StealNSResult();
-}
-
bool
nsHTMLDocument::ExecCommand(const nsAString& commandID,
bool doShowUI,
const nsAString& value,
+ CallerType aCallerType,
ErrorResult& rv)
{
// for optional parameters see dom/src/base/nsHistory.cpp: HistoryImpl::Go()
// this might add some ugly JS dependencies?
nsAutoCString cmdToDispatch, paramStr;
bool isBool, boolVal;
if (!ConvertToMidasInternalCommand(commandID, value,
@@ -3191,17 +3185,17 @@ nsHTMLDocument::ExecCommand(const nsAStr
}
if (commandID.LowerCaseEqualsLiteral("gethtml")) {
rv.Throw(NS_ERROR_FAILURE);
return false;
}
bool restricted = commandID.LowerCaseEqualsLiteral("paste");
- if (restricted && !nsContentUtils::IsCallerChrome()) {
+ if (restricted && aCallerType != CallerType::System) {
return false;
}
// get command manager and dispatch command to our window if it's acceptable
nsCOMPtr<nsICommandManager> cmdMgr;
GetMidasCommandManager(getter_AddRefs(cmdMgr));
if (!cmdMgr) {
rv.Throw(NS_ERROR_FAILURE);
@@ -3255,43 +3249,36 @@ nsHTMLDocument::ExecCommand(const nsAStr
return false;
}
rv = cmdMgr->DoCommand(cmdToDispatch.get(), cmdParams, window);
}
return !rv.Failed();
}
-NS_IMETHODIMP
+bool
nsHTMLDocument::QueryCommandEnabled(const nsAString& commandID,
- bool* _retval)
-{
- ErrorResult rv;
- *_retval = QueryCommandEnabled(commandID, rv);
- return rv.StealNSResult();
-}
-
-bool
-nsHTMLDocument::QueryCommandEnabled(const nsAString& commandID, ErrorResult& rv)
+ CallerType aCallerType,
+ ErrorResult& rv)
{
nsAutoCString cmdToDispatch;
if (!ConvertToMidasInternalCommand(commandID, cmdToDispatch)) {
return false;
}
// cut & copy are always allowed
bool isCutCopy = commandID.LowerCaseEqualsLiteral("cut") ||
commandID.LowerCaseEqualsLiteral("copy");
if (isCutCopy) {
return nsContentUtils::IsCutCopyAllowed();
}
// Report false for restricted commands
bool restricted = commandID.LowerCaseEqualsLiteral("paste");
- if (restricted && !nsContentUtils::IsCallerChrome()) {
+ if (restricted && aCallerType != CallerType::System) {
return false;
}
// if editing is not on, bail
if (!IsEditingOnAfterFlush()) {
return false;
}
@@ -3449,34 +3436,27 @@ nsHTMLDocument::QueryCommandState(const
// If command does not have a state_all value, this call fails and sets
// retval to false. This is fine -- we want to return false in that case
// anyway (bug 738385), so we just succeed and return false regardless.
bool retval = false;
cmdParams->GetBooleanValue("state_all", &retval);
return retval;
}
-NS_IMETHODIMP
-nsHTMLDocument::QueryCommandSupported(const nsAString & commandID,
- bool *_retval)
-{
- *_retval = QueryCommandSupported(commandID);
- return NS_OK;
-}
-
bool
-nsHTMLDocument::QueryCommandSupported(const nsAString& commandID)
+nsHTMLDocument::QueryCommandSupported(const nsAString& commandID,
+ CallerType aCallerType)
{
// Gecko technically supports all the clipboard commands including
// cut/copy/paste, but non-privileged content will be unable to call
// paste, and depending on the pref "dom.allow_cut_copy", cut and copy
// may also be disallowed to be called from non-privileged content.
// For that reason, we report the support status of corresponding
// command accordingly.
- if (!nsContentUtils::IsCallerChrome()) {
+ if (aCallerType != CallerType::System) {
if (commandID.LowerCaseEqualsLiteral("paste")) {
return false;
}
if (nsContentUtils::IsCutCopyRestricted()) {
if (commandID.LowerCaseEqualsLiteral("cut") ||
commandID.LowerCaseEqualsLiteral("copy")) {
return false;
}
--- a/dom/html/nsHTMLDocument.h
+++ b/dom/html/nsHTMLDocument.h
@@ -15,16 +15,17 @@
#include "nsTArray.h"
#include "PLDHashTable.h"
#include "nsIHttpChannel.h"
#include "nsHTMLStyleSheet.h"
#include "nsICommandManager.h"
#include "mozilla/dom/HTMLSharedElement.h"
+#include "mozilla/dom/BindingDeclarations.h"
class nsIEditor;
class nsIURI;
class nsIDocShell;
class nsICachingChannel;
class nsIWyciwygChannel;
class nsILoadGroup;
@@ -217,23 +218,27 @@ public:
}
void SetDesignMode(const nsAString& aDesignMode,
nsIPrincipal& aSubjectPrincipal,
mozilla::ErrorResult& rv);
void SetDesignMode(const nsAString& aDesignMode,
const mozilla::Maybe<nsIPrincipal*>& aSubjectPrincipal,
mozilla::ErrorResult& rv);
bool ExecCommand(const nsAString& aCommandID, bool aDoShowUI,
- const nsAString& aValue, mozilla::ErrorResult& rv);
+ const nsAString& aValue,
+ mozilla::dom::CallerType aCallerType,
+ mozilla::ErrorResult& rv);
bool QueryCommandEnabled(const nsAString& aCommandID,
+ mozilla::dom::CallerType aCallerType,
mozilla::ErrorResult& rv);
bool QueryCommandIndeterm(const nsAString& aCommandID,
mozilla::ErrorResult& rv);
bool QueryCommandState(const nsAString& aCommandID, mozilla::ErrorResult& rv);
- bool QueryCommandSupported(const nsAString& aCommandID);
+ bool QueryCommandSupported(const nsAString& aCommandID,
+ mozilla::dom::CallerType aCallerType);
void QueryCommandValue(const nsAString& aCommandID, nsAString& aValue,
mozilla::ErrorResult& rv);
// The XPCOM Get/SetFgColor work OK for us, since they never throw.
// The XPCOM Get/SetLinkColor work OK for us, since they never throw.
// The XPCOM Get/SetVLinkColor work OK for us, since they never throw.
// The XPCOM Get/SetALinkColor work OK for us, since they never throw.
// The XPCOM Get/SetBgColor work OK for us, since they never throw.
nsIHTMLCollection* Anchors();
deleted file mode 100644
--- a/dom/html/nsIHTMLMenu.idl
+++ /dev/null
@@ -1,42 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsISupports.idl"
-
-interface nsIMenuBuilder;
-
-/**
- * A private interface.
- * All methods throw NS_ERROR_DOM_SECURITY_ERR if the caller is not chrome.
- */
-
-[scriptable, uuid(d3d068d8-e223-4228-ba39-4d6df21ba616)]
-interface nsIHTMLMenu : nsISupports
-{
- /**
- * Creates and dispatches a trusted event named "show".
- * The event is not cancelable and does not bubble.
- * See http://www.whatwg.org/specs/web-apps/current-work/multipage/interactive-elements.html#context-menus
- */
- void sendShowEvent();
-
- /**
- * Creates a native menu builder. The builder type is dependent on menu type.
- * Currently, it returns nsXULContextMenuBuilder for context menus.
- * Toolbar menus are not yet supported (the method returns null).
- */
- nsIMenuBuilder createBuilder();
-
- /*
- * Builds a menu by iterating over menu children.
- * See http://www.whatwg.org/specs/web-apps/current-work/multipage/interactive-elements.html#building-menus-and-toolbars
- * The caller can use a native builder by calling createBuilder() or provide
- * a custom builder that implements the nsIMenuBuilder interface.
- * A custom builder can be used for example to build native context menus
- * that are not defined using <menupopup>.
- */
- void build(in nsIMenuBuilder aBuilder);
-
-};
--- a/dom/interfaces/html/nsIDOMHTMLCanvasElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLCanvasElement.idl
@@ -20,28 +20,10 @@ interface nsIVariant;
interface nsIInputStreamCallback;
[uuid(4e8f1316-b601-471d-8f44-3c650d91ee9b)]
interface nsIDOMHTMLCanvasElement : nsISupports
{
attribute unsigned long width;
attribute unsigned long height;
attribute boolean mozOpaque;
-
- // Valid calls are:
- // toDataURL(); -- defaults to image/png
- // toDataURL(type); -- uses given type
- // toDataURL(type, params); -- uses given type, and any valid parameters
- [implicit_jscontext]
- DOMString toDataURL([optional] in DOMString type,
- [optional] in jsval params);
-
- // Valid calls are
- // mozGetAsFile(name); -- defaults to image/png
- // mozGetAsFile(name, type); -- uses given type
- // The return value is a File object.
- nsISupports mozGetAsFile(in DOMString name, [optional] in DOMString type);
-
- // A Mozilla-only extension to get a canvas context backed by double-buffered
- // shared memory. Only privileged callers can call this.
- nsISupports MozGetIPCContext(in DOMString contextId);
};
--- a/dom/interfaces/html/nsIDOMHTMLDocument.idl
+++ b/dom/interfaces/html/nsIDOMHTMLDocument.idl
@@ -47,32 +47,22 @@ interface nsIDOMHTMLDocument : nsIDOMDoc
[implicit_jscontext]
void writeln([optional, Null(Stringify)] in DOMString text);
/**
* Midas additions
*/
attribute DOMString designMode;
- boolean execCommand(in DOMString commandID,
- [optional] in boolean doShowUI,
- [optional] in DOMString value);
-
- // returns true if the command is enabled (false otherwise)
- boolean queryCommandEnabled(in DOMString commandID);
-
// returns true if the command is in a indeterminate state (false otherwise)
boolean queryCommandIndeterm(in DOMString commandID);
// returns true if the command has been executed (false otherwise)
boolean queryCommandState(in DOMString commandID);
- // returns true if the command is supported on the current range
- boolean queryCommandSupported(in DOMString commandID);
-
// returns the current value of the document or current selection for command
DOMString queryCommandValue(in DOMString commandID);
// Obsolete APIs
attribute DOMString fgColor;
attribute DOMString bgColor;
attribute DOMString linkColor;
--- a/dom/interfaces/html/nsIDOMHTMLElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLElement.idl
@@ -30,18 +30,16 @@ interface nsIDOMHTMLElement : nsIDOMElem
// user interaction
/**
* Indicates that the element is not yet, or is no longer, relevant.
*
* See <http://www.whatwg.org/html5/#the-hidden-attribute>.
*/
attribute boolean hidden;
- [binaryname(DOMClick)]
- void click();
attribute long tabIndex;
void focus();
[binaryname(DOMBlur)]
void blur();
attribute DOMString accessKey;
readonly attribute DOMString accessKeyLabel;
attribute boolean draggable;
attribute DOMString contentEditable;
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1451,18 +1451,21 @@ ContentChild::RecvSetProcessSandbox(cons
bool
ContentChild::RecvNotifyLayerAllocated(const dom::TabId& aTabId, const uint64_t& aLayersId)
{
if (!CompositorBridgeChild::Get()->IPCOpen()) {
return true;
}
+ // Note: sending the constructor could fail, but we do not propagate the
+ // error back since the GPU process is fallible.
APZChild* apz = ContentProcessController::Create(aTabId);
- return CompositorBridgeChild::Get()->SendPAPZConstructor(apz, aLayersId);
+ CompositorBridgeChild::Get()->SendPAPZConstructor(apz, aLayersId);
+ return true;
}
bool
ContentChild::RecvSpeakerManagerNotify()
{
#ifdef MOZ_WIDGET_GONK
// Only notify the process which has the SpeakerManager instance.
RefPtr<SpeakerManagerService> service =
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1341,23 +1341,17 @@ TabChild::RecvShow(const ScreenIntSize&
}
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation());
if (!baseWindow) {
NS_ERROR("WebNavigation() doesn't QI to nsIBaseWindow");
return false;
}
- if (!InitRenderingState(aTextureFactoryIdentifier, aLayersId, aRenderFrame)) {
- // We can fail to initialize our widget if the <browser
- // remote> has already been destroyed, and we couldn't hook
- // into the parent-process's layer system. That's not a fatal
- // error.
- return true;
- }
+ InitRenderingState(aTextureFactoryIdentifier, aLayersId, aRenderFrame);
baseWindow->SetVisibility(true);
bool res = InitTabChildGlobal();
ApplyShowInfo(aInfo);
RecvParentActivated(aParentIsActive);
return res;
@@ -2560,39 +2554,37 @@ TabChild::InitTabChildGlobal(FrameScript
if (IsMozBrowserOrApp()) {
RecvLoadRemoteScript(BROWSER_ELEMENT_CHILD_SCRIPT, true);
}
}
return true;
}
-bool
+void
TabChild::InitRenderingState(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
const uint64_t& aLayersId,
PRenderFrameChild* aRenderFrame)
{
mPuppetWidget->InitIMEState();
- RenderFrameChild* remoteFrame = static_cast<RenderFrameChild*>(aRenderFrame);
- if (!remoteFrame) {
- NS_WARNING("failed to construct RenderFrame");
- return false;
+ if (!aRenderFrame) {
+ NS_WARNING("failed to construct RenderFrame");
+ return;
}
MOZ_ASSERT(aLayersId != 0);
mTextureFactoryIdentifier = aTextureFactoryIdentifier;
// Pushing layers transactions directly to a separate
// compositor context.
PCompositorBridgeChild* compositorChild = CompositorBridgeChild::Get();
if (!compositorChild) {
NS_WARNING("failed to get CompositorBridgeChild instance");
- PRenderFrameChild::Send__delete__(remoteFrame);
- return false;
+ return;
}
ShadowLayerForwarder* lf =
mPuppetWidget->GetLayerManager(
nullptr, mTextureFactoryIdentifier.mParentBackend)
->AsShadowForwarder();
// As long as we are creating a ClientLayerManager for the puppet widget,
// lf must be non-null here.
@@ -2600,36 +2592,25 @@ TabChild::InitRenderingState(const Textu
if (lf) {
nsTArray<LayersBackend> backends;
backends.AppendElement(mTextureFactoryIdentifier.mParentBackend);
bool success;
PLayerTransactionChild* shadowManager =
compositorChild->SendPLayerTransactionConstructor(backends,
aLayersId, &mTextureFactoryIdentifier, &success);
- if (!success) {
- NS_WARNING("failed to properly allocate layer transaction");
- PRenderFrameChild::Send__delete__(remoteFrame);
- return false;
+ if (shadowManager && success) {
+ lf->SetShadowManager(shadowManager);
+ lf->IdentifyTextureHost(mTextureFactoryIdentifier);
+ ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier);
+ gfx::VRManagerChild::IdentifyTextureHost(mTextureFactoryIdentifier);
}
-
- if (!shadowManager) {
- NS_WARNING("failed to construct LayersChild");
- // This results in |remoteFrame| being deleted.
- PRenderFrameChild::Send__delete__(remoteFrame);
- return false;
- }
-
- lf->SetShadowManager(shadowManager);
- lf->IdentifyTextureHost(mTextureFactoryIdentifier);
- ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier);
- gfx::VRManagerChild::IdentifyTextureHost(mTextureFactoryIdentifier);
}
- mRemoteFrame = remoteFrame;
+ mRemoteFrame = static_cast<RenderFrameChild*>(aRenderFrame);
if (aLayersId != 0) {
if (!sTabChildren) {
sTabChildren = new TabChildMap;
}
MOZ_ASSERT(!sTabChildren->Get(aLayersId));
sTabChildren->Put(aLayersId, this);
mLayersId = aLayersId;
}
@@ -2639,17 +2620,16 @@ TabChild::InitRenderingState(const Textu
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (observerService) {
observerService->AddObserver(this,
BEFORE_FIRST_PAINT,
false);
}
- return true;
}
void
TabChild::GetDPI(float* aDPI)
{
*aDPI = -1.0;
if (!mRemoteFrame) {
return;
@@ -2998,18 +2978,16 @@ TabChild::ReinitRendering()
nsCOMPtr<nsIDocument> doc(GetDocument());
doc->NotifyLayerManagerRecreated();
}
void
TabChild::CompositorUpdated(const TextureFactoryIdentifier& aNewIdentifier)
{
- gfxPlatform::GetPlatform()->CompositorUpdated();
-
RefPtr<LayerManager> lm = mPuppetWidget->GetLayerManager();
ClientLayerManager* clm = lm->AsClientLayerManager();
MOZ_ASSERT(clm);
mTextureFactoryIdentifier = aNewIdentifier;
clm->UpdateTextureFactoryIdentifier(aNewIdentifier);
FrameLayerBuilder::InvalidateAllLayers(clm);
}
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -723,17 +723,17 @@ private:
void UpdateFrameType();
void ActorDestroy(ActorDestroyReason why) override;
enum FrameScriptLoading { DONT_LOAD_SCRIPTS, DEFAULT_LOAD_SCRIPTS };
bool InitTabChildGlobal(FrameScriptLoading aScriptLoading = DEFAULT_LOAD_SCRIPTS);
- bool InitRenderingState(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
+ void InitRenderingState(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
const uint64_t& aLayersId,
PRenderFrameChild* aRenderFrame);
void DestroyWindow();
void SetProcessNameToAppName();
void ApplyShowInfo(const ShowInfo& aInfo);
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -632,17 +632,16 @@ TabParent::Show(const ScreenIntSize& siz
if (IsInitedByParent()) {
// If TabParent is initialized by parent side then the RenderFrame must also
// be created here. If TabParent is initialized by child side,
// child side will create RenderFrame.
MOZ_ASSERT(!GetRenderFrame());
RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
if (frameLoader) {
renderFrame = new RenderFrameParent(frameLoader, &success);
- MOZ_ASSERT(success);
layersId = renderFrame->GetLayersId();
renderFrame->GetTextureFactoryIdentifier(&textureFactoryIdentifier);
AddTabParentToTable(layersId, this);
Unused << SendPRenderFrameConstructor(renderFrame);
}
} else {
// Otherwise, the child should have constructed the RenderFrame,
// and we should already know about it.
--- a/dom/media/eme/CDMProxy.h
+++ b/dom/media/eme/CDMProxy.h
@@ -93,16 +93,18 @@ public:
// Loads the CDM corresponding to mKeySystem.
// Calls MediaKeys::OnCDMCreated() when the CDM is created.
virtual void Init(PromiseId aPromiseId,
const nsAString& aOrigin,
const nsAString& aTopLevelOrigin,
const nsAString& aName,
bool aInPrivateBrowsing) = 0;
+ virtual void OnSetDecryptorId(uint32_t aId) {}
+
// Main thread only.
// Uses the CDM to create a key session.
// Calls MediaKeys::OnSessionActivated() when session is created.
// Assumes ownership of (Move()s) aInitData's contents.
virtual void CreateSession(uint32_t aCreateSessionToken,
MediaKeySessionType aSessionType,
PromiseId aPromiseId,
const nsAString& aInitDataType,
@@ -214,16 +216,18 @@ public:
virtual void GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId,
nsTArray<nsCString>& aSessionIds) = 0;
#ifdef DEBUG
virtual bool IsOnOwnerThread() = 0;
#endif
+ virtual uint32_t GetDecryptorId() { return 0; }
+
protected:
virtual ~CDMProxy() {}
// Helper to enforce that a raw pointer is only accessed on the main thread.
template<class Type>
class MainThreadOnlyRawPtr {
public:
explicit MainThreadOnlyRawPtr(Type* aPtr)
--- a/dom/media/eme/DecryptorProxyCallback.h
+++ b/dom/media/eme/DecryptorProxyCallback.h
@@ -10,16 +10,18 @@
#include "mozilla/dom/MediaKeyMessageEventBinding.h" // For MediaKeyMessageType
#include "mozilla/CDMProxy.h"
class DecryptorProxyCallback {
public:
virtual ~DecryptorProxyCallback() {}
+ virtual void SetDecryptorId(uint32_t aId) = 0;
+
virtual void SetSessionId(uint32_t aCreateSessionId,
const nsCString& aSessionId) = 0;
virtual void ResolveLoadSessionPromise(uint32_t aPromiseId,
bool aSuccess) = 0;
virtual void ResolvePromise(uint32_t aPromiseId) = 0;
--- a/dom/media/eme/mediadrm/MediaDrmCDMCallbackProxy.h
+++ b/dom/media/eme/mediadrm/MediaDrmCDMCallbackProxy.h
@@ -12,16 +12,19 @@
namespace mozilla {
class CDMProxy;
// Proxies call backs from the MediaDrmProxy -> MediaDrmProxySupport back to the MediaKeys
// object on the main thread.
// We used annotation calledFrom = "gecko" to ensure running on main thread.
class MediaDrmCDMCallbackProxy : public DecryptorProxyCallback {
public:
+
+ void SetDecryptorId(uint32_t aId) override {}
+
void SetSessionId(uint32_t aCreateSessionToken,
const nsCString& aSessionId) override;
void ResolveLoadSessionPromise(uint32_t aPromiseId,
bool aSuccess) override;
void ResolvePromise(uint32_t aPromiseId) override;
--- a/dom/media/gmp/GMPCDMCallbackProxy.cpp
+++ b/dom/media/gmp/GMPCDMCallbackProxy.cpp
@@ -17,16 +17,29 @@
namespace mozilla {
GMPCDMCallbackProxy::GMPCDMCallbackProxy(CDMProxy* aProxy)
: mProxy(aProxy)
{}
void
+GMPCDMCallbackProxy::SetDecryptorId(uint32_t aId)
+{
+ MOZ_ASSERT(mProxy->IsOnOwnerThread());
+
+ RefPtr<CDMProxy> proxy = mProxy;
+ NS_DispatchToMainThread(
+ NS_NewRunnableFunction([proxy, aId] ()
+ {
+ proxy->OnSetDecryptorId(aId);
+ })
+ );}
+
+void
GMPCDMCallbackProxy::SetSessionId(uint32_t aToken,
const nsCString& aSessionId)
{
MOZ_ASSERT(mProxy->IsOnOwnerThread());
RefPtr<CDMProxy> proxy = mProxy;
auto sid = NS_ConvertUTF8toUTF16(aSessionId);
NS_DispatchToMainThread(
--- a/dom/media/gmp/GMPCDMCallbackProxy.h
+++ b/dom/media/gmp/GMPCDMCallbackProxy.h
@@ -12,16 +12,19 @@
#include "GMPDecryptorProxy.h"
namespace mozilla {
// Proxies call backs from the CDM on the GMP thread back to the MediaKeys
// object on the main thread.
class GMPCDMCallbackProxy : public GMPDecryptorProxyCallback {
public:
+
+ void SetDecryptorId(uint32_t aId) override;
+
void SetSessionId(uint32_t aCreateSessionToken,
const nsCString& aSessionId) override;
void ResolveLoadSessionPromise(uint32_t aPromiseId,
bool aSuccess) override;
void ResolvePromise(uint32_t aPromiseId) override;
--- a/dom/media/gmp/GMPCDMProxy.cpp
+++ b/dom/media/gmp/GMPCDMProxy.cpp
@@ -33,16 +33,18 @@ GMPCDMProxy::GMPCDMProxy(dom::MediaKeys*
: CDMProxy(aKeys,
aKeySystem,
aDistinctiveIdentifierRequired,
aPersistentStateRequired)
, mCrashHelper(aCrashHelper)
, mCDM(nullptr)
, mDecryptionJobCount(0)
, mShutdownCalled(false)
+ , mDecryptorId(0)
+ , mCreatePromiseId(0)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_COUNT_CTOR(GMPCDMProxy);
}
GMPCDMProxy::~GMPCDMProxy()
{
MOZ_COUNT_DTOR(GMPCDMProxy);
@@ -126,20 +128,29 @@ GMPCDMProxy::gmp_InitDone(GMPDecryptorPr
return;
}
mCDM = aCDM;
mCallback = new GMPCDMCallbackProxy(this);
mCDM->Init(mCallback,
mDistinctiveIdentifierRequired,
mPersistentStateRequired);
+
+ // Await the OnSetDecryptorId callback.
+ mCreatePromiseId = aData->mPromiseId;
+}
+
+void GMPCDMProxy::OnSetDecryptorId(uint32_t aId)
+{
+ MOZ_ASSERT(mCreatePromiseId);
+ mDecryptorId = aId;
nsCOMPtr<nsIRunnable> task(
NewRunnableMethod<uint32_t>(this,
&GMPCDMProxy::OnCDMCreated,
- aData->mPromiseId));
+ mCreatePromiseId));
NS_DispatchToMainThread(task);
}
class gmp_InitDoneCallback : public GetGMPDecryptorCallback
{
public:
gmp_InitDoneCallback(GMPCDMProxy* aGMPCDMProxy,
nsAutoPtr<GMPCDMProxy::InitData>&& aData)
@@ -763,14 +774,26 @@ GMPCDMProxy::GetSessionIdsForKeyId(const
caps.GetSessionIdsForKeyId(aKeyId, aSessionIds);
}
void
GMPCDMProxy::Terminated()
{
MOZ_ASSERT(NS_IsMainThread());
NS_WARNING("CDM terminated");
+ if (mCreatePromiseId) {
+ RejectPromise(mCreatePromiseId,
+ NS_ERROR_DOM_MEDIA_FATAL_ERR,
+ NS_LITERAL_CSTRING("Crashed waiting for CDM to initialize"));
+ mCreatePromiseId = 0;
+ }
if (!mKeys.IsNull()) {
mKeys->Terminated();
}
}
+uint32_t
+GMPCDMProxy::GetDecryptorId()
+{
+ return mDecryptorId;
+}
+
} // namespace mozilla
--- a/dom/media/gmp/GMPCDMProxy.h
+++ b/dom/media/gmp/GMPCDMProxy.h
@@ -29,16 +29,18 @@ public:
bool aPersistentStateRequired);
void Init(PromiseId aPromiseId,
const nsAString& aOrigin,
const nsAString& aTopLevelOrigin,
const nsAString& aGMPName,
bool aInPrivateBrowsing) override;
+ void OnSetDecryptorId(uint32_t aId) override;
+
void CreateSession(uint32_t aCreateSessionToken,
dom::MediaKeySessionType aSessionType,
PromiseId aPromiseId,
const nsAString& aInitDataType,
nsTArray<uint8_t>& aInitData) override;
void LoadSession(PromiseId aPromiseId,
const nsAString& aSessionId) override;
@@ -104,16 +106,18 @@ public:
void GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId,
nsTArray<nsCString>& aSessionIds) override;
#ifdef DEBUG
bool IsOnOwnerThread() override;
#endif
+ uint32_t GetDecryptorId() override;
+
private:
friend class gmp_InitDoneCallback;
friend class gmp_InitGetGMPDecryptorCallback;
struct InitData {
uint32_t mPromiseId;
nsString mOrigin;
nsString mTopLevelOrigin;
@@ -245,14 +249,18 @@ private:
// mDecryptionJobs as that shrinks as jobs are completed and removed
// from it.
// GMP thread only.
uint32_t mDecryptionJobCount;
// True if GMPCDMProxy::gmp_Shutdown was called.
// GMP thread only.
bool mShutdownCalled;
+
+ uint32_t mDecryptorId;
+
+ PromiseId mCreatePromiseId;
};
} // namespace mozilla
#endif // GMPCDMProxy_h_
--- a/dom/media/gmp/GMPChild.cpp
+++ b/dom/media/gmp/GMPChild.cpp
@@ -272,22 +272,25 @@ GMPChild::RecvSetNodeId(const nsCString&
// Store the per origin salt for the node id. Note: we do this in a
// separate message than RecvStartPlugin() so that the string is not
// sitting in a string on the IPC code's call stack.
mNodeId = aNodeId;
return true;
}
GMPErr
-GMPChild::GetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI)
+GMPChild::GetAPI(const char* aAPIName,
+ void* aHostAPI,
+ void** aPluginAPI,
+ uint32_t aDecryptorId)
{
if (!mGMPLoader) {
return GMPGenericErr;
}
- return mGMPLoader->GetAPI(aAPIName, aHostAPI, aPluginAPI);
+ return mGMPLoader->GetAPI(aAPIName, aHostAPI, aPluginAPI, aDecryptorId);
}
bool
GMPChild::RecvPreloadLibs(const nsCString& aLibs)
{
#ifdef XP_WIN
// Pre-load DLLs that need to be used by the EME plugin but that can't be
// loaded after the sandbox has started
--- a/dom/media/gmp/GMPChild.h
+++ b/dom/media/gmp/GMPChild.h
@@ -71,17 +71,17 @@ private:
bool RecvCrashPluginNow() override;
bool RecvBeginAsyncShutdown() override;
bool RecvCloseActive() override;
void ActorDestroy(ActorDestroyReason aWhy) override;
void ProcessingError(Result aCode, const char* aReason) override;
- GMPErr GetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI);
+ GMPErr GetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI, uint32_t aDecryptorId = 0);
nsTArray<UniquePtr<GMPContentChild>> mGMPContentChildren;
GMPAsyncShutdown* mAsyncShutdown;
RefPtr<GMPTimerChild> mTimerChild;
RefPtr<GMPStorageChild> mStorage;
MessageLoop* mGMPMessageLoop;
--- a/dom/media/gmp/GMPContentChild.cpp
+++ b/dom/media/gmp/GMPContentChild.cpp
@@ -75,17 +75,17 @@ GMPContentChild::AllocPGMPDecryptorChild
bool
GMPContentChild::DeallocPGMPDecryptorChild(PGMPDecryptorChild* aActor)
{
static_cast<GMPDecryptorChild*>(aActor)->Release();
return true;
}
PGMPVideoDecoderChild*
-GMPContentChild::AllocPGMPVideoDecoderChild()
+GMPContentChild::AllocPGMPVideoDecoderChild(const uint32_t& aDecryptorId)
{
GMPVideoDecoderChild* actor = new GMPVideoDecoderChild(this);
actor->AddRef();
return actor;
}
bool
GMPContentChild::DeallocPGMPVideoDecoderChild(PGMPVideoDecoderChild* aActor)
@@ -201,17 +201,17 @@ private:
bool
GMPContentChild::RecvPGMPDecryptorConstructor(PGMPDecryptorChild* aActor)
{
GMPDecryptorChild* child = static_cast<GMPDecryptorChild*>(aActor);
GMPDecryptorHost* host = static_cast<GMPDecryptorHost*>(child);
void* ptr = nullptr;
- GMPErr err = mGMPChild->GetAPI(GMP_API_DECRYPTOR, host, &ptr);
+ GMPErr err = mGMPChild->GetAPI(GMP_API_DECRYPTOR, host, &ptr, aActor->Id());
GMPDecryptor* decryptor = nullptr;
if (GMP_SUCCEEDED(err) && ptr) {
decryptor = static_cast<GMPDecryptor*>(ptr);
} else if (err != GMPNoErr) {
// We Adapt the previous GMPDecryptor version to the current, so that
// Gecko thinks it's only talking to the current version. v7 differs
// from v9 in its Init() function arguments, and v9 has extra enumeration
// members at the end of the key status enumerations.
@@ -239,22 +239,23 @@ GMPContentChild::RecvPGMPAudioDecoderCon
}
vdc->Init(static_cast<GMPAudioDecoder*>(vd));
return true;
}
bool
-GMPContentChild::RecvPGMPVideoDecoderConstructor(PGMPVideoDecoderChild* aActor)
+GMPContentChild::RecvPGMPVideoDecoderConstructor(PGMPVideoDecoderChild* aActor,
+ const uint32_t& aDecryptorId)
{
auto vdc = static_cast<GMPVideoDecoderChild*>(aActor);
void* vd = nullptr;
- GMPErr err = mGMPChild->GetAPI(GMP_API_VIDEO_DECODER, &vdc->Host(), &vd);
+ GMPErr err = mGMPChild->GetAPI(GMP_API_VIDEO_DECODER, &vdc->Host(), &vd, aDecryptorId);
if (err != GMPNoErr || !vd) {
NS_WARNING("GMPGetAPI call failed trying to construct decoder.");
return false;
}
vdc->Init(static_cast<GMPVideoDecoder*>(vd));
return true;
--- a/dom/media/gmp/GMPContentChild.h
+++ b/dom/media/gmp/GMPContentChild.h
@@ -20,26 +20,26 @@ class GMPContentChild : public PGMPConte
public:
explicit GMPContentChild(GMPChild* aChild);
virtual ~GMPContentChild();
MessageLoop* GMPMessageLoop();
bool RecvPGMPAudioDecoderConstructor(PGMPAudioDecoderChild* aActor) override;
bool RecvPGMPDecryptorConstructor(PGMPDecryptorChild* aActor) override;
- bool RecvPGMPVideoDecoderConstructor(PGMPVideoDecoderChild* aActor) override;
+ bool RecvPGMPVideoDecoderConstructor(PGMPVideoDecoderChild* aActor, const uint32_t& aDecryptorId) override;
bool RecvPGMPVideoEncoderConstructor(PGMPVideoEncoderChild* aActor) override;
PGMPAudioDecoderChild* AllocPGMPAudioDecoderChild() override;
bool DeallocPGMPAudioDecoderChild(PGMPAudioDecoderChild* aActor) override;
PGMPDecryptorChild* AllocPGMPDecryptorChild() override;
bool DeallocPGMPDecryptorChild(PGMPDecryptorChild* aActor) override;
- PGMPVideoDecoderChild* AllocPGMPVideoDecoderChild() override;
+ PGMPVideoDecoderChild* AllocPGMPVideoDecoderChild(const uint32_t& aDecryptorId) override;
bool DeallocPGMPVideoDecoderChild(PGMPVideoDecoderChild* aActor) override;
PGMPVideoEncoderChild* AllocPGMPVideoEncoderChild() override;
bool DeallocPGMPVideoEncoderChild(PGMPVideoEncoderChild* aActor) override;
void ActorDestroy(ActorDestroyReason aWhy) override;
void ProcessingError(Result aCode, const char* aReason) override;
--- a/dom/media/gmp/GMPContentParent.cpp
+++ b/dom/media/gmp/GMPContentParent.cpp
@@ -189,20 +189,21 @@ GMPContentParent::GetGMPAudioDecoder(GMP
NS_ADDREF(vap);
*aGMPAD = vap;
mAudioDecoders.AppendElement(vap);
return NS_OK;
}
nsresult
-GMPContentParent::GetGMPVideoDecoder(GMPVideoDecoderParent** aGMPVD)
+GMPContentParent::GetGMPVideoDecoder(GMPVideoDecoderParent** aGMPVD,
+ uint32_t aDecryptorId)
{
// returned with one anonymous AddRef that locks it until Destroy
- PGMPVideoDecoderParent* pvdp = SendPGMPVideoDecoderConstructor();
+ PGMPVideoDecoderParent* pvdp = SendPGMPVideoDecoderConstructor(aDecryptorId);
if (!pvdp) {
return NS_ERROR_FAILURE;
}
GMPVideoDecoderParent *vdp = static_cast<GMPVideoDecoderParent*>(pvdp);
// This addref corresponds to the Proxy pointer the consumer is returned.
// It's dropped by calling Close() on the interface.
NS_ADDREF(vdp);
*aGMPVD = vdp;
@@ -225,17 +226,17 @@ GMPContentParent::GetGMPVideoEncoder(GMP
NS_ADDREF(vep);
*aGMPVE = vep;
mVideoEncoders.AppendElement(vep);
return NS_OK;
}
PGMPVideoDecoderParent*
-GMPContentParent::AllocPGMPVideoDecoderParent()
+GMPContentParent::AllocPGMPVideoDecoderParent(const uint32_t& aDecryptorId)
{
GMPVideoDecoderParent* vdp = new GMPVideoDecoderParent(this);
NS_ADDREF(vdp);
return vdp;
}
bool
GMPContentParent::DeallocPGMPVideoDecoderParent(PGMPVideoDecoderParent* aActor)
--- a/dom/media/gmp/GMPContentParent.h
+++ b/dom/media/gmp/GMPContentParent.h
@@ -22,17 +22,18 @@ class GMPVideoEncoderParent;
class GMPContentParent final : public PGMPContentParent,
public GMPSharedMem
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPContentParent)
explicit GMPContentParent(GMPParent* aParent = nullptr);
- nsresult GetGMPVideoDecoder(GMPVideoDecoderParent** aGMPVD);
+ nsresult GetGMPVideoDecoder(GMPVideoDecoderParent** aGMPVD,
+ uint32_t aDecryptorId);
void VideoDecoderDestroyed(GMPVideoDecoderParent* aDecoder);
nsresult GetGMPVideoEncoder(GMPVideoEncoderParent** aGMPVE);
void VideoEncoderDestroyed(GMPVideoEncoderParent* aEncoder);
nsresult GetGMPDecryptor(GMPDecryptorParent** aGMPKS);
void DecryptorDestroyed(GMPDecryptorParent* aSession);
@@ -61,17 +62,17 @@ public:
return mPluginId;
}
private:
~GMPContentParent();
void ActorDestroy(ActorDestroyReason aWhy) override;
- PGMPVideoDecoderParent* AllocPGMPVideoDecoderParent() override;
+ PGMPVideoDecoderParent* AllocPGMPVideoDecoderParent(const uint32_t& aDecryptorId) override;
bool DeallocPGMPVideoDecoderParent(PGMPVideoDecoderParent* aActor) override;
PGMPVideoEncoderParent* AllocPGMPVideoEncoderParent() override;
bool DeallocPGMPVideoEncoderParent(PGMPVideoEncoderParent* aActor) override;
PGMPDecryptorParent* AllocPGMPDecryptorParent() override;
bool DeallocPGMPDecryptorParent(PGMPDecryptorParent* aActor) override;
--- a/dom/media/gmp/GMPCrashHelperHolder.h
+++ b/dom/media/gmp/GMPCrashHelperHolder.h
@@ -48,22 +48,22 @@ namespace mozilla {
// In the crashing case, the GMPCrashHelpers are deallocated when the crash
// report is processed in GeckoMediaPluginService::RunPluginCrashCallbacks().
//
// It's a bit yuck that we have to have two paths for disconnecting the crash
// helpers, but there aren't really any better options.
class GMPCrashHelperHolder
{
public:
-
+
void SetCrashHelper(GMPCrashHelper* aHelper)
{
mCrashHelper = aHelper;
}
-
+
GMPCrashHelper* GetCrashHelper()
{
return mCrashHelper;
}
void MaybeDisconnect(bool aAbnormalShutdown)
{
if (!aAbnormalShutdown) {
--- a/dom/media/gmp/GMPDecryptorChild.cpp
+++ b/dom/media/gmp/GMPDecryptorChild.cpp
@@ -68,16 +68,21 @@ GMPDecryptorChild::CallOnGMPThread(Metho
}
}
void
GMPDecryptorChild::Init(GMPDecryptor* aSession)
{
MOZ_ASSERT(aSession);
mSession = aSession;
+ // The ID of this decryptor is the IPDL actor ID. Note it's unique inside
+ // the child process, but not necessarily across all gecko processes. However,
+ // since GMPDecryptors are segregated by node ID/origin, we shouldn't end up
+ // with clashes in the content process.
+ SendSetDecryptorId(Id());
}
void
GMPDecryptorChild::SetSessionId(uint32_t aCreateSessionToken,
const char* aSessionId,
uint32_t aSessionIdLength)
{
CALL_ON_GMP_THREAD(SendSetSessionId,
--- a/dom/media/gmp/GMPDecryptorParent.cpp
+++ b/dom/media/gmp/GMPDecryptorParent.cpp
@@ -35,16 +35,27 @@ GMPDecryptorParent::GMPDecryptorParent(G
{
MOZ_ASSERT(mPlugin && mGMPThread);
}
GMPDecryptorParent::~GMPDecryptorParent()
{
}
+bool
+GMPDecryptorParent::RecvSetDecryptorId(const uint32_t& aId)
+{
+ if (!mIsOpen) {
+ NS_WARNING("Trying to use a dead GMP decrypter!");
+ return false;
+ }
+ mCallback->SetDecryptorId(aId);
+ return true;
+}
+
nsresult
GMPDecryptorParent::Init(GMPDecryptorProxyCallback* aCallback,
bool aDistinctiveIdentifierRequired,
bool aPersistentStateRequired)
{
LOGD(("GMPDecryptorParent[%p]::Init()", this));
if (mIsOpen) {
--- a/dom/media/gmp/GMPDecryptorParent.h
+++ b/dom/media/gmp/GMPDecryptorParent.h
@@ -67,16 +67,18 @@ public:
void Shutdown();
private:
~GMPDecryptorParent();
// PGMPDecryptorParent
+ bool RecvSetDecryptorId(const uint32_t& aId) override;
+
bool RecvSetSessionId(const uint32_t& aCreateSessionToken,
const nsCString& aSessionId) override;
bool RecvResolveLoadSessionPromise(const uint32_t& aPromiseId,
const bool& aSuccess) override;
bool RecvResolvePromise(const uint32_t& aPromiseId) override;
--- a/dom/media/gmp/GMPLoader.cpp
+++ b/dom/media/gmp/GMPLoader.cpp
@@ -34,17 +34,18 @@ public:
uint32_t aUTF8LibPathLen,
char* aOriginSalt,
uint32_t aOriginSaltLen,
const GMPPlatformAPI* aPlatformAPI,
GMPAdapter* aAdapter) override;
GMPErr GetAPI(const char* aAPIName,
void* aHostAPI,
- void** aPluginAPI) override;
+ void** aPluginAPI,
+ uint32_t aDecryptorId) override;
void Shutdown() override;
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
void SetSandboxInfo(MacSandboxInfo* aSandboxInfo) override;
#endif
private:
@@ -75,17 +76,20 @@ public:
}
GMPInitFunc initFunc = reinterpret_cast<GMPInitFunc>(PR_FindFunctionSymbol(mLib, "GMPInit"));
if (!initFunc) {
return GMPNotImplementedErr;
}
return initFunc(aPlatformAPI);
}
- GMPErr GMPGetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI) override
+ GMPErr GMPGetAPI(const char* aAPIName,
+ void* aHostAPI,
+ void** aPluginAPI,
+ uint32_t aDecryptorId) override
{
if (!mLib) {
return GMPGenericErr;
}
GMPGetAPIFunc getapiFunc = reinterpret_cast<GMPGetAPIFunc>(PR_FindFunctionSymbol(mLib, "GMPGetAPI"));
if (!getapiFunc) {
return GMPNotImplementedErr;
}
@@ -185,19 +189,20 @@ GMPLoaderImpl::Load(const char* aUTF8Lib
mAdapter->GMPSetNodeId(nodeId.c_str(), nodeId.size());
return true;
}
GMPErr
GMPLoaderImpl::GetAPI(const char* aAPIName,
void* aHostAPI,
- void** aPluginAPI)
+ void** aPluginAPI,
+ uint32_t aDecryptorId)
{
- return mAdapter->GMPGetAPI(aAPIName, aHostAPI, aPluginAPI);
+ return mAdapter->GMPGetAPI(aAPIName, aHostAPI, aPluginAPI, aDecryptorId);
}
void
GMPLoaderImpl::Shutdown()
{
if (mAdapter) {
mAdapter->GMPShutdown();
}
--- a/dom/media/gmp/GMPLoader.h
+++ b/dom/media/gmp/GMPLoader.h
@@ -37,17 +37,20 @@ public:
virtual ~GMPAdapter() {}
// Sets the adapted to plugin library module.
// Note: the GMPAdapter is responsible for calling PR_UnloadLibrary on aLib
// when it's finished with it.
virtual void SetAdaptee(PRLibrary* aLib) = 0;
// These are called in place of the corresponding GMP API functions.
virtual GMPErr GMPInit(const GMPPlatformAPI* aPlatformAPI) = 0;
- virtual GMPErr GMPGetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI) = 0;
+ virtual GMPErr GMPGetAPI(const char* aAPIName,
+ void* aHostAPI,
+ void** aPluginAPI,
+ uint32_t aDecryptorId) = 0;
virtual void GMPShutdown() = 0;
virtual void GMPSetNodeId(const char* aNodeId, uint32_t aLength) = 0;
};
// Encapsulates generating the device-bound node id, activating the sandbox,
// loading the GMP, and passing the node id to the GMP (in that order).
//
// In Desktop Gecko, the implementation of this lives in plugin-container,
@@ -78,17 +81,20 @@ public:
virtual bool Load(const char* aUTF8LibPath,
uint32_t aLibPathLen,
char* aOriginSalt,
uint32_t aOriginSaltLen,
const GMPPlatformAPI* aPlatformAPI,
GMPAdapter* aAdapter = nullptr) = 0;
// Retrieves an interface pointer from the GMP.
- virtual GMPErr GetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI) = 0;
+ virtual GMPErr GetAPI(const char* aAPIName,
+ void* aHostAPI,
+ void** aPluginAPI,
+ uint32_t aDecryptorId) = 0;
// Calls the GMPShutdown function exported by the GMP lib, and unloads the
// plugin library.
virtual void Shutdown() = 0;
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
// On OS X we need to set Mac-specific sandbox info just before we start the
// sandbox, which we don't yet know when the GMPLoader and SandboxStarter
--- a/dom/media/gmp/GMPService.cpp
+++ b/dom/media/gmp/GMPService.cpp
@@ -344,54 +344,58 @@ GeckoMediaPluginService::GetGMPAudioDeco
return NS_OK;
}
class GetGMPContentParentForVideoDecoderDone : public GetGMPContentParentCallback
{
public:
explicit GetGMPContentParentForVideoDecoderDone(UniquePtr<GetGMPVideoDecoderCallback>&& aCallback,
- GMPCrashHelper* aHelper)
+ GMPCrashHelper* aHelper,
+ uint32_t aDecryptorId)
: mCallback(Move(aCallback))
, mHelper(aHelper)
+ , mDecryptorId(aDecryptorId)
{
}
void Done(GMPContentParent* aGMPParent) override
{
GMPVideoDecoderParent* gmpVDP = nullptr;
GMPVideoHostImpl* videoHost = nullptr;
- if (aGMPParent && NS_SUCCEEDED(aGMPParent->GetGMPVideoDecoder(&gmpVDP))) {
+ if (aGMPParent && NS_SUCCEEDED(aGMPParent->GetGMPVideoDecoder(&gmpVDP, mDecryptorId))) {
videoHost = &gmpVDP->Host();
gmpVDP->SetCrashHelper(mHelper);
}
mCallback->Done(gmpVDP, videoHost);
}
private:
UniquePtr<GetGMPVideoDecoderCallback> mCallback;
RefPtr<GMPCrashHelper> mHelper;
+ const uint32_t mDecryptorId;
};
NS_IMETHODIMP
-GeckoMediaPluginService::GetGMPVideoDecoder(GMPCrashHelper* aHelper,
- nsTArray<nsCString>* aTags,
- const nsACString& aNodeId,
- UniquePtr<GetGMPVideoDecoderCallback>&& aCallback)
+GeckoMediaPluginService::GetDecryptingGMPVideoDecoder(GMPCrashHelper* aHelper,
+ nsTArray<nsCString>* aTags,
+ const nsACString& aNodeId,
+ UniquePtr<GetGMPVideoDecoderCallback>&& aCallback,
+ uint32_t aDecryptorId)
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
NS_ENSURE_ARG(aCallback);
if (mShuttingDownOnGMPThread) {
return NS_ERROR_FAILURE;
}
UniquePtr<GetGMPContentParentCallback> callback(
- new GetGMPContentParentForVideoDecoderDone(Move(aCallback), aHelper));
+ new GetGMPContentParentForVideoDecoderDone(Move(aCallback), aHelper, aDecryptorId));
if (!GetContentParentFrom(aHelper,
aNodeId,
NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER),
*aTags,
Move(callback))) {
return NS_ERROR_FAILURE;
}
--- a/dom/media/gmp/GMPService.h
+++ b/dom/media/gmp/GMPService.h
@@ -64,20 +64,21 @@ public:
static already_AddRefed<GeckoMediaPluginService> GetGeckoMediaPluginService();
virtual nsresult Init();
NS_DECL_THREADSAFE_ISUPPORTS
// mozIGeckoMediaPluginService
NS_IMETHOD GetThread(nsIThread** aThread) override;
- NS_IMETHOD GetGMPVideoDecoder(GMPCrashHelper* aHelper,
- nsTArray<nsCString>* aTags,
- const nsACString& aNodeId,
- UniquePtr<GetGMPVideoDecoderCallback>&& aCallback)
+ NS_IMETHOD GetDecryptingGMPVideoDecoder(GMPCrashHelper* aHelper,
+ nsTArray<nsCString>* aTags,
+ const nsACString& aNodeId,
+ UniquePtr<GetGMPVideoDecoderCallback>&& aCallback,
+ uint32_t aDecryptorId)
override;
NS_IMETHOD GetGMPVideoEncoder(GMPCrashHelper* aHelper,
nsTArray<nsCString>* aTags,
const nsACString& aNodeId,
UniquePtr<GetGMPVideoEncoderCallback>&& aCallback)
override;
NS_IMETHOD GetGMPAudioDecoder(GMPCrashHelper* aHelper,
nsTArray<nsCString>* aTags,
@@ -85,16 +86,26 @@ public:
UniquePtr<GetGMPAudioDecoderCallback>&& aCallback)
override;
NS_IMETHOD GetGMPDecryptor(GMPCrashHelper* aHelper,
nsTArray<nsCString>* aTags,
const nsACString& aNodeId,
UniquePtr<GetGMPDecryptorCallback>&& aCallback)
override;
+ // Helper for backwards compatibility with WebRTC/tests.
+ NS_IMETHOD
+ GetGMPVideoDecoder(GMPCrashHelper* aHelper,
+ nsTArray<nsCString>* aTags,
+ const nsACString& aNodeId,
+ UniquePtr<GetGMPVideoDecoderCallback>&& aCallback) override
+ {
+ return GetDecryptingGMPVideoDecoder(aHelper, aTags, aNodeId, Move(aCallback), 0);
+ }
+
int32_t AsyncShutdownTimeoutMs();
NS_IMETHOD RunPluginCrashCallbacks(uint32_t aPluginId,
const nsACString& aPluginName) override;
RefPtr<AbstractThread> GetAbstractGMPThread();
void ConnectCrashHelper(uint32_t aPluginId, GMPCrashHelper* aHelper);
--- a/dom/media/gmp/GMPServiceParent.cpp
+++ b/dom/media/gmp/GMPServiceParent.cpp
@@ -1383,25 +1383,22 @@ GeckoMediaPluginServiceParent::GetNodeId
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
LOGD(("%s::%s: (%s, %s), %s", __CLASS__, __FUNCTION__,
NS_ConvertUTF16toUTF8(aOrigin).get(),
NS_ConvertUTF16toUTF8(aTopLevelOrigin).get(),
(aInPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing")));
nsresult rv;
- if (aGMPName.EqualsLiteral("gmp-widevinecdm") ||
- aOrigin.EqualsLiteral("null") ||
+ if (aOrigin.EqualsLiteral("null") ||
aOrigin.IsEmpty() ||
aTopLevelOrigin.EqualsLiteral("null") ||
aTopLevelOrigin.IsEmpty()) {
- // This is for the Google Widevine CDM, which doesn't have persistent
- // storage and which can't handle being used by more than one origin at
- // once in the same plugin instance, or at least one of the
- // (origin, topLevelOrigin) is null or empty; probably a local file.
+ // (origin, topLevelOrigin) is null or empty; this is for an anonymous
+ // origin, probably a local file, for which we don't provide persistent storage.
// Generate a random node id, and don't store it so that the GMP's storage
// is temporary and the process for this GMP is not shared with GMP
// instances that have the same nodeId.
nsAutoCString salt;
rv = GenerateRandomPathName(salt, NodeIdSaltLength);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
--- a/dom/media/gmp/PGMPContent.ipdl
+++ b/dom/media/gmp/PGMPContent.ipdl
@@ -20,14 +20,14 @@ intr protocol PGMPContent
manages PGMPAudioDecoder;
manages PGMPDecryptor;
manages PGMPVideoDecoder;
manages PGMPVideoEncoder;
child:
async PGMPAudioDecoder();
async PGMPDecryptor();
- async PGMPVideoDecoder();
+ async PGMPVideoDecoder(uint32_t aDecryptorId);
async PGMPVideoEncoder();
};
} // namespace gmp
} // namespace mozilla
--- a/dom/media/gmp/PGMPDecryptor.ipdl
+++ b/dom/media/gmp/PGMPDecryptor.ipdl
@@ -48,16 +48,18 @@ child:
uint8_t[] aBuffer,
GMPDecryptionData aMetadata);
async DecryptingComplete();
parent:
async __delete__();
+ async SetDecryptorId(uint32_t aId);
+
async SetSessionId(uint32_t aCreateSessionToken,
nsCString aSessionId);
async ResolveLoadSessionPromise(uint32_t aPromiseId,
bool aSuccess);
async ResolvePromise(uint32_t aPromiseId);
--- a/dom/media/gmp/mozIGeckoMediaPluginService.idl
+++ b/dom/media/gmp/mozIGeckoMediaPluginService.idl
@@ -89,16 +89,29 @@ interface mozIGeckoMediaPluginService :
*/
[noscript]
void getGMPVideoDecoder(in GMPCrashHelperPtr helper,
in TagArray tags,
[optional] in ACString nodeId,
in GetGMPVideoDecoderCallback callback);
/**
+ * Gets a video decoder as per getGMPVideoDecoder, except it is linked to
+ * with a corresponding GMPDecryptor via the decryptor's ID.
+ * This is a temporary measure, until we can implement a Chromium CDM
+ * GMP protocol which does both decryption and decoding.
+ */
+ [noscript]
+ void getDecryptingGMPVideoDecoder(in GMPCrashHelperPtr helper,
+ in TagArray tags,
+ in ACString nodeId,
+ in GetGMPVideoDecoderCallback callback,
+ in uint32_t decryptorId);
+
+ /**
* Get a video encoder that supports the specified tags.
* The array of tags should at least contain a codec tag, and optionally
* other tags.
* Callable only on GMP thread.
* This is an asynchronous operation, the Done method of the callback object
* will be called on the GMP thread with the result (which might be null in
* the case of failure). This method always takes ownership of the callback
* object, but if this method returns an error then the Done method of the
--- a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
+++ b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
@@ -8,24 +8,21 @@
#include "VideoUtils.h"
#include "WidevineDecryptor.h"
#include "WidevineUtils.h"
#include "WidevineVideoDecoder.h"
#include "gmp-api/gmp-entrypoints.h"
#include "gmp-api/gmp-decryption.h"
#include "gmp-api/gmp-video-codec.h"
#include "gmp-api/gmp-platform.h"
-#include "mozilla/StaticPtr.h"
static const GMPPlatformAPI* sPlatform = nullptr;
namespace mozilla {
-StaticRefPtr<CDMWrapper> sCDMWrapper;
-
GMPErr GMPGetCurrentTime(GMPTimestamp* aOutTime) {
return sPlatform->getcurrenttime(aOutTime);
}
// Call on main thread only.
GMPErr GMPSetTimerOnMainThread(GMPTask* aTask, int64_t aTimeoutMS) {
return sPlatform->settimer(aTask, aTimeoutMS);
}
@@ -83,61 +80,62 @@ WidevineAdapter::GMPInit(const GMPPlatfo
init();
return GMPNoErr;
}
GMPErr
WidevineAdapter::GMPGetAPI(const char* aAPIName,
void* aHostAPI,
- void** aPluginAPI)
+ void** aPluginAPI,
+ uint32_t aDecryptorId)
{
- Log("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p) this=0x%p",
- aAPIName, aHostAPI, aPluginAPI, this);
+ Log("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p",
+ aAPIName, aHostAPI, aPluginAPI, this, aDecryptorId);
if (!strcmp(aAPIName, GMP_API_DECRYPTOR)) {
- if (sCDMWrapper) {
- // We only support one CDM instance per GMP process. Fail!
- Log("WidevineAdapter::GMPGetAPI() Tried to create more than once CDM per process! FAIL!");
+ if (WidevineDecryptor::GetInstance(aDecryptorId)) {
+ // We only support one CDM instance per PGMPDecryptor. Fail!
+ Log("WidevineAdapter::GMPGetAPI() Tried to create more than once CDM per IPDL actor! FAIL!");
return GMPQuotaExceededErr;
}
auto create = reinterpret_cast<decltype(::CreateCdmInstance)*>(
PR_FindFunctionSymbol(mLib, "CreateCdmInstance"));
if (!create) {
- Log("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p) this=0x%p FAILED to find CreateCdmInstance",
- aAPIName, aHostAPI, aPluginAPI, this);
+ Log("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p FAILED to find CreateCdmInstance",
+ aAPIName, aHostAPI, aPluginAPI, this, aDecryptorId);
return GMPGenericErr;
}
WidevineDecryptor* decryptor = new WidevineDecryptor();
auto cdm = reinterpret_cast<cdm::ContentDecryptionModule*>(
create(cdm::ContentDecryptionModule::kVersion,
kEMEKeySystemWidevine.get(),
kEMEKeySystemWidevine.Length(),
&GetCdmHost,
decryptor));
if (!cdm) {
- Log("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p) this=0x%p FAILED to create cdm",
- aAPIName, aHostAPI, aPluginAPI, this);
+ Log("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p FAILED to create cdm",
+ aAPIName, aHostAPI, aPluginAPI, this, aDecryptorId);
return GMPGenericErr;
}
Log("cdm: 0x%x", cdm);
- sCDMWrapper = new CDMWrapper(cdm);
- decryptor->SetCDM(RefPtr<CDMWrapper>(sCDMWrapper));
+ RefPtr<CDMWrapper> wrapper(new CDMWrapper(cdm));
+ decryptor->SetCDM(wrapper, aDecryptorId);
*aPluginAPI = decryptor;
} else if (!strcmp(aAPIName, GMP_API_VIDEO_DECODER)) {
- if (!sCDMWrapper) {
- Log("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p) this=0x%p No cdm for video decoder",
- aAPIName, aHostAPI, aPluginAPI, this);
+ RefPtr<CDMWrapper> wrapper = WidevineDecryptor::GetInstance(aDecryptorId);
+ if (!wrapper) {
+ Log("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p No cdm for video decoder",
+ aAPIName, aHostAPI, aPluginAPI, thiss, aDecryptorId);
return GMPGenericErr;
}
*aPluginAPI = new WidevineVideoDecoder(static_cast<GMPVideoHost*>(aHostAPI),
- RefPtr<CDMWrapper>(sCDMWrapper));
-
+ wrapper);
}
return *aPluginAPI ? GMPNoErr : GMPNotImplementedErr;
}
void
WidevineAdapter::GMPShutdown()
{
Log("WidevineAdapter::GMPShutdown()");
--- a/dom/media/gmp/widevine-adapter/WidevineAdapter.h
+++ b/dom/media/gmp/widevine-adapter/WidevineAdapter.h
@@ -16,17 +16,20 @@ namespace mozilla {
class WidevineAdapter : public gmp::GMPAdapter {
public:
void SetAdaptee(PRLibrary* aLib) override;
// These are called in place of the corresponding GMP API functions.
GMPErr GMPInit(const GMPPlatformAPI* aPlatformAPI) override;
- GMPErr GMPGetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI) override;
+ GMPErr GMPGetAPI(const char* aAPIName,
+ void* aHostAPI,
+ void** aPluginAPI,
+ uint32_t aDecryptorId) override;
void GMPShutdown() override;
void GMPSetNodeId(const char* aNodeId, uint32_t aLength) override;
static bool Supports(int32_t aModuleVersion,
int32_t aInterfaceVersion,
int32_t aHostVersion);
private:
--- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
+++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
@@ -11,33 +11,48 @@
#include <mozilla/SizePrintfMacros.h>
#include <stdarg.h>
using namespace cdm;
using namespace std;
namespace mozilla {
+static map<uint32_t, RefPtr<CDMWrapper>> sDecryptors;
+
+/* static */
+RefPtr<CDMWrapper>
+WidevineDecryptor::GetInstance(uint32_t aInstanceId)
+{
+ auto itr = sDecryptors.find(aInstanceId);
+ if (itr != sDecryptors.end()) {
+ return itr->second;
+ }
+ return nullptr;
+}
+
WidevineDecryptor::WidevineDecryptor()
: mCallback(nullptr)
{
Log("WidevineDecryptor created this=%p", this);
AddRef(); // Released in DecryptingComplete().
}
WidevineDecryptor::~WidevineDecryptor()
{
Log("WidevineDecryptor destroyed this=%p", this);
}
void
-WidevineDecryptor::SetCDM(RefPtr<CDMWrapper> aCDM)
+WidevineDecryptor::SetCDM(RefPtr<CDMWrapper> aCDM, uint32_t aInstanceId)
{
mCDM = aCDM;
+ mInstanceId = aInstanceId;
+ sDecryptors[mInstanceId] = aCDM;
}
void
WidevineDecryptor::Init(GMPDecryptorCallback* aCallback,
bool aDistinctiveIdentifierRequired,
bool aPersistentStateRequired)
{
Log("WidevineDecryptor::Init() this=%p distinctiveId=%d persistentState=%d",
@@ -205,17 +220,22 @@ WidevineDecryptor::Decrypt(GMPBuffer* aB
}
mCallback->Decrypted(aBuffer, ToGMPErr(rv));
}
void
WidevineDecryptor::DecryptingComplete()
{
Log("WidevineDecryptor::DecryptingComplete() this=%p", this);
+ // Drop our references to the CDMWrapper. When any other references
+ // held elsewhere are dropped (for example references held by a
+ // WidevineVideoDecoder, or a runnable), the CDMWrapper destroys
+ // the CDM.
mCDM = nullptr;
+ sDecryptors.erase(mInstanceId);
mCallback = nullptr;
Release();
}
class WidevineBuffer : public cdm::Buffer {
public:
explicit WidevineBuffer(size_t aSize) {
Log("WidevineBuffer(size=" PRIuSIZE ") created", aSize);
--- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.h
+++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.h
@@ -19,17 +19,19 @@ class WidevineDecryptor : public GMPDecr
, public cdm::Host_8
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WidevineDecryptor)
WidevineDecryptor();
- void SetCDM(RefPtr<CDMWrapper> aCDM);
+ void SetCDM(RefPtr<CDMWrapper> aCDM, uint32_t aDecryptorId);
+
+ static RefPtr<CDMWrapper> GetInstance(uint32_t aDecryptorId);
// GMPDecryptor
void Init(GMPDecryptorCallback* aCallback,
bool aDistinctiveIdentifierRequired,
bool aPersistentStateRequired) override;
void CreateSession(uint32_t aCreateSessionToken,
uint32_t aPromiseId,
@@ -119,13 +121,14 @@ private:
~WidevineDecryptor();
RefPtr<CDMWrapper> mCDM;
cdm::ContentDecryptionModule_8* CDM() { return mCDM->GetCDM(); }
GMPDecryptorCallback* mCallback;
std::map<uint32_t, uint32_t> mPromiseIdToNewSessionTokens;
bool mDistinctiveIdentifierRequired = false;
bool mPersistentStateRequired = false;
+ uint32_t mInstanceId = 0;
};
} // namespace mozilla
#endif // WidevineDecryptor_h_
--- a/dom/media/gtest/TestAudioSegment.cpp
+++ b/dom/media/gtest/TestAudioSegment.cpp
@@ -197,17 +197,17 @@ void TestUpmixStereo()
AudioChannelsUpMix(&channelsptr, 2, SilentChannel<T>());
for (size_t channel = 0; channel < 2; channel++) {
for (size_t i = 0; i < arraySize; i++) {
ASSERT_TRUE(channelsptr[channel][i] == GetHighValue<T>());
}
}
- delete channels[0];
+ delete [] channels[0];
}
template<typename T>
void TestDownmixStereo()
{
const size_t arraySize = 1024;
nsTArray<const T*> inputptr;
nsTArray<T*> input;
@@ -229,18 +229,18 @@ void TestDownmixStereo()
AudioChannelsDownMix(inputptr, output, 1, arraySize);
for (size_t i = 0; i < arraySize; i++) {
ASSERT_TRUE(output[0][i] == GetSilentValue<T>());
ASSERT_TRUE(output[0][i] == GetSilentValue<T>());
}
- delete output[0];
- delete output;
+ delete [] output[0];
+ delete [] output;
}
TEST(AudioSegment, Test)
{
TestInterleaveAndConvert<float, float>();
TestInterleaveAndConvert<float, int16_t>();
TestInterleaveAndConvert<int16_t, float>();
TestInterleaveAndConvert<int16_t, int16_t>();
--- a/dom/media/gtest/TestGMPCrossOrigin.cpp
+++ b/dom/media/gtest/TestGMPCrossOrigin.cpp
@@ -591,37 +591,33 @@ class GMPStorageTest : public GMPDecrypt
EXPECT_TRUE(!aNodeId1.Equals(nodeId3));
SetFinished();
}
class CreateDecryptorDone : public GetGMPDecryptorCallback
{
public:
- CreateDecryptorDone(GMPStorageTest* aRunner, nsIRunnable* aContinuation)
- : mRunner(aRunner),
- mContinuation(aContinuation)
+ explicit CreateDecryptorDone(GMPStorageTest* aRunner)
+ : mRunner(aRunner)
{
}
void Done(GMPDecryptorProxy* aDecryptor) override
{
mRunner->mDecryptor = aDecryptor;
EXPECT_TRUE(!!mRunner->mDecryptor);
if (mRunner->mDecryptor) {
mRunner->mDecryptor->Init(mRunner, false, true);
}
- nsCOMPtr<nsIThread> thread(GetGMPThread());
- thread->Dispatch(mContinuation, NS_DISPATCH_NORMAL);
}
private:
RefPtr<GMPStorageTest> mRunner;
- nsCOMPtr<nsIRunnable> mContinuation;
};
void CreateDecryptor(const nsCString& aNodeId,
const nsCString& aUpdate)
{
nsTArray<nsCString> updates;
updates.AppendElement(aUpdate);
nsCOMPtr<nsIRunnable> continuation(new Updates(this, Move(updates)));
@@ -674,17 +670,23 @@ class GMPStorageTest : public GMPDecrypt
mNodeId = aNodeId;
EXPECT_TRUE(!mNodeId.IsEmpty());
nsTArray<nsCString> tags;
tags.AppendElement(NS_LITERAL_CSTRING("fake"));
UniquePtr<GetGMPDecryptorCallback> callback(
- new CreateDecryptorDone(this, aContinuation));
+ new CreateDecryptorDone(this));
+
+ // Continue after the OnSetDecryptorId message, so that we don't
+ // get warnings in the async shutdown tests due to receiving the
+ // SetDecryptorId message after we've started shutdown.
+ mSetDecryptorIdContinuation = aContinuation;
+
nsresult rv =
service->GetGMPDecryptor(nullptr, &tags, mNodeId, Move(callback));
EXPECT_TRUE(NS_SUCCEEDED(rv));
}
void TestBasicStorage() {
AssertIsOnGMPThread();
EXPECT_TRUE(IsGMPStorageIsEmpty());
@@ -1368,16 +1370,26 @@ class GMPStorageTest : public GMPDecrypt
nsCOMPtr<nsIRunnable> continuation = mExpected[0].mContinuation;
mExpected.RemoveElementAt(0);
if (continuation) {
NS_DispatchToCurrentThread(continuation);
}
}
}
+ void SetDecryptorId(uint32_t aId) override
+ {
+ if (!mSetDecryptorIdContinuation) {
+ return;
+ }
+ nsCOMPtr<nsIThread> thread(GetGMPThread());
+ thread->Dispatch(mSetDecryptorIdContinuation, NS_DISPATCH_NORMAL);
+ mSetDecryptorIdContinuation = nullptr;
+ }
+
void SetSessionId(uint32_t aCreateSessionToken,
const nsCString& aSessionId) override { }
void ResolveLoadSessionPromise(uint32_t aPromiseId,
bool aSuccess) override {}
void ResolvePromise(uint32_t aPromiseId) override {}
void RejectPromise(uint32_t aPromiseId,
nsresult aException,
const nsCString& aSessionId) override { }
@@ -1411,16 +1423,18 @@ private:
, mContinuation(aContinuation)
{}
nsCString mMessage;
nsCOMPtr<nsIRunnable> mContinuation;
};
nsTArray<ExpectedMessage> mExpected;
+ RefPtr<nsIRunnable> mSetDecryptorIdContinuation;
+
GMPDecryptorProxy* mDecryptor;
Monitor mMonitor;
Atomic<bool> mFinished;
nsCString mNodeId;
};
void
GMPTestRunner::DoTest(void (GMPTestRunner::*aTestMethod)(GMPTestMonitor&))
--- a/dom/media/platforms/agnostic/eme/EMEVideoDecoder.cpp
+++ b/dom/media/platforms/agnostic/eme/EMEVideoDecoder.cpp
@@ -27,16 +27,17 @@ EMEVideoCallbackAdapter::Error(GMPErr aE
EMEVideoDecoder::EMEVideoDecoder(CDMProxy* aProxy,
const GMPVideoDecoderParams& aParams)
: GMPVideoDecoder(GMPVideoDecoderParams(aParams).WithAdapter(
new EMEVideoCallbackAdapter(aParams.mCallback,
VideoInfo(aParams.mConfig.mDisplay),
aParams.mImageContainer)))
, mProxy(aProxy)
+ , mDecryptorId(aProxy->GetDecryptorId())
{}
void
EMEVideoDecoder::InitTags(nsTArray<nsCString>& aTags)
{
VideoInfo config = GetConfig();
if (MP4Decoder::IsH264(config.mMimeType)) {
aTags.AppendElement(NS_LITERAL_CSTRING("h264"));
--- a/dom/media/platforms/agnostic/eme/EMEVideoDecoder.h
+++ b/dom/media/platforms/agnostic/eme/EMEVideoDecoder.h
@@ -28,16 +28,18 @@ public:
class EMEVideoDecoder : public GMPVideoDecoder {
public:
EMEVideoDecoder(CDMProxy* aProxy, const GMPVideoDecoderParams& aParams);
private:
void InitTags(nsTArray<nsCString>& aTags) override;
nsCString GetNodeId() override;
+ uint32_t DecryptorId() const override { return mDecryptorId; }
GMPUniquePtr<GMPVideoEncodedFrame> CreateFrame(MediaRawData* aSample) override;
RefPtr<CDMProxy> mProxy;
+ uint32_t mDecryptorId;
};
} // namespace mozilla
#endif // EMEVideoDecoder_h_
--- a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp
+++ b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp
@@ -306,17 +306,21 @@ GMPVideoDecoder::Init()
mMPS = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
MOZ_ASSERT(mMPS);
RefPtr<InitPromise> promise(mInitPromise.Ensure(__func__));
nsTArray<nsCString> tags;
InitTags(tags);
UniquePtr<GetGMPVideoDecoderCallback> callback(new GMPInitDoneCallback(this));
- if (NS_FAILED(mMPS->GetGMPVideoDecoder(mCrashHelper, &tags, GetNodeId(), Move(callback)))) {
+ if (NS_FAILED(mMPS->GetDecryptingGMPVideoDecoder(mCrashHelper,
+ &tags,
+ GetNodeId(),
+ Move(callback),
+ DecryptorId()))) {
mInitPromise.Reject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
}
return promise;
}
void
GMPVideoDecoder::Input(MediaRawData* aSample)
--- a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h
+++ b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h
@@ -77,16 +77,17 @@ public:
const char* GetDescriptionName() const override
{
return "GMP video decoder";
}
protected:
virtual void InitTags(nsTArray<nsCString>& aTags);
virtual nsCString GetNodeId();
+ virtual uint32_t DecryptorId() const { return 0; }
virtual GMPUniquePtr<GMPVideoEncodedFrame> CreateFrame(MediaRawData* aSample);
virtual const VideoInfo& GetConfig() const;
private:
class GMPInitDoneCallback : public GetGMPVideoDecoderCallback
{
public:
--- a/dom/presentation/provider/AndroidCastDeviceProvider.js
+++ b/dom/presentation/provider/AndroidCastDeviceProvider.js
@@ -403,17 +403,17 @@ AndroidCastDeviceProvider.prototype = {
if (!this._listener) {
// remove observer
Services.obs.removeObserver(this, TOPIC_ANDROID_CAST_DEVICE_ADDED);
Services.obs.removeObserver(this, TOPIC_ANDROID_CAST_DEVICE_REMOVED);
return;
}
// Sync all device already found by Android.
- Services.obs.notifyObservers(null, TOPIC_ANDROID_CAST_DEVICE_SYNCDEVICE, "");
+ Messaging.sendRequest({ type: TOPIC_ANDROID_CAST_DEVICE_SYNCDEVICE });
// Observer registration
Services.obs.addObserver(this, TOPIC_ANDROID_CAST_DEVICE_ADDED, false);
Services.obs.addObserver(this, TOPIC_ANDROID_CAST_DEVICE_REMOVED, false);
},
get listener() {
return this._listener;
},
--- a/dom/security/test/csp/test_referrerdirective.html
+++ b/dom/security/test/csp/test_referrerdirective.html
@@ -110,17 +110,20 @@ var referrerDirectiveTests = {
SimpleTest.finish();
}
};
SimpleTest.waitForExplicitFinish();
// have to disable mixed content blocking to test https->http referrers.
SpecialPowers.pushPrefEnv({
'set': [['security.mixed_content.block_active_content', false],
- ['security.mixed_content.block_display_content', false]]
+ ['security.mixed_content.block_display_content', false],
+ ['security.mixed_content.send_hsts_priming', false],
+ ['security.mixed_content.use_hsts', false],
+ ]
},
function() {
// each of the iframes we create will call us back when its contents are loaded.
window.addEventListener("message", referrerDirectiveTests.onIframeComplete.bind(window), false);
// one iframe created for each test case
for (var id in testData) {
var elt = document.createElement("iframe");
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -1247,16 +1247,18 @@ var interfaceNamesInGlobalScope =
"WebGLTexture",
// IMPORTANT: Do not change this list without review from a DOM peer!
"WebGLTransformFeedback",
// IMPORTANT: Do not change this list without review from a DOM peer!
"WebGLUniformLocation",
// IMPORTANT: Do not change this list without review from a DOM peer!
"WebGLVertexArrayObject",
// IMPORTANT: Do not change this list without review from a DOM peer!
+ "WebGLVertexArrayObjectOES",
+// IMPORTANT: Do not change this list without review from a DOM peer!
"WebKitCSSMatrix",
// IMPORTANT: Do not change this list without review from a DOM peer!
"WebSocket",
// IMPORTANT: Do not change this list without review from a DOM peer!
"WheelEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!
"Window",
// IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/url/URL.cpp
+++ b/dom/url/URL.cpp
@@ -12,16 +12,17 @@
#include "mozilla/dom/URLBinding.h"
#include "mozilla/dom/ipc/BlobChild.h"
#include "mozilla/dom/ipc/nsIRemoteBlob.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "nsContentUtils.h"
#include "nsEscape.h"
#include "nsHostObjectProtocolHandler.h"
#include "nsIIOService.h"
+#include "nsIURIWithQuery.h"
#include "nsIURL.h"
#include "nsNetCID.h"
#include "nsNetUtil.h"
#include "nsServiceManagerUtils.h"
#include "WorkerPrivate.h"
#include "WorkerRunnable.h"
#include "WorkerScope.h"
@@ -516,65 +517,67 @@ URLMainThread::SetPort(const nsAString&
mURI->SetPort(port);
}
void
URLMainThread::GetPathname(nsAString& aPathname, ErrorResult& aRv) const
{
aPathname.Truncate();
- nsCOMPtr<nsIURL> url(do_QueryInterface(mURI));
- if (!url) {
- nsAutoCString path;
- nsresult rv = mURI->GetPath(path);
- if (NS_FAILED(rv)){
- // Do not throw! Not having a valid URI or URL should result in an empty
- // string.
- return;
+ // Do not throw! Not having a valid URI or URL should result in an empty
+ // string.
+
+ nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(mURI));
+ if (url) {
+ nsAutoCString file;
+ nsresult rv = url->GetFilePath(file);
+ if (NS_SUCCEEDED(rv)) {
+ CopyUTF8toUTF16(file, aPathname);
}
- CopyUTF8toUTF16(path, aPathname);
return;
}
- nsAutoCString file;
- nsresult rv = url->GetFilePath(file);
+ nsAutoCString path;
+ nsresult rv = mURI->GetPath(path);
if (NS_SUCCEEDED(rv)) {
- CopyUTF8toUTF16(file, aPathname);
+ CopyUTF8toUTF16(path, aPathname);
}
}
void
URLMainThread::SetPathname(const nsAString& aPathname, ErrorResult& aRv)
{
- nsCOMPtr<nsIURL> url(do_QueryInterface(mURI));
- if (!url) {
- // Ignore failures to be compatible with NS4.
+ // Do not throw!
+
+ nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(mURI));
+ if (url) {
+ url->SetFilePath(NS_ConvertUTF16toUTF8(aPathname));
return;
}
-
- url->SetFilePath(NS_ConvertUTF16toUTF8(aPathname));
}
void
URLMainThread::GetSearch(nsAString& aSearch, ErrorResult& aRv) const
{
aSearch.Truncate();
- nsCOMPtr<nsIURL> url(do_QueryInterface(mURI));
- if (!url) {
- // Do not throw! Not having a valid URI or URL should result in an empty
- // string.
- return;
- }
+ // Do not throw! Not having a valid URI or URL should result in an empty
+ // string.
nsAutoCString search;
- nsresult rv = url->GetQuery(search);
- if (NS_SUCCEEDED(rv) && !search.IsEmpty()) {
- CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, aSearch);
+ nsresult rv;
+
+ nsCOMPtr<nsIURIWithQuery> url(do_QueryInterface(mURI));
+ if (url) {
+ rv = url->GetQuery(search);
+ if (NS_SUCCEEDED(rv) && !search.IsEmpty()) {
+ CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, aSearch);
+ }
+ return;
}
}
void
URLMainThread::GetHash(nsAString& aHash, ErrorResult& aRv) const
{
aHash.Truncate();
@@ -593,23 +596,23 @@ void
URLMainThread::SetHash(const nsAString& aHash, ErrorResult& aRv)
{
mURI->SetRef(NS_ConvertUTF16toUTF8(aHash));
}
void
URLMainThread::SetSearchInternal(const nsAString& aSearch, ErrorResult& aRv)
{
- nsCOMPtr<nsIURL> url(do_QueryInterface(mURI));
- if (!url) {
- // Ignore failures to be compatible with NS4.
+ // Ignore failures to be compatible with NS4.
+
+ nsCOMPtr<nsIURIWithQuery> uriWithQuery(do_QueryInterface(mURI));
+ if (uriWithQuery) {
+ uriWithQuery->SetQuery(NS_ConvertUTF16toUTF8(aSearch));
return;
}
-
- url->SetQuery(NS_ConvertUTF16toUTF8(aSearch));
}
} // anonymous namespace
///////////////////////////////////////////////////////////////////////////////
// URL for Workers
///////////////////////////////////////////////////////////////////////////////
--- a/dom/url/tests/test_url.html
+++ b/dom/url/tests/test_url.html
@@ -212,16 +212,26 @@
{ url: 'about:blank',
base: undefined,
error: false,
protocol: 'about:',
pathname: 'blank',
skip_setters: false,
},
+
+ { url: 'foo:bar?what#yeah',
+ base: undefined,
+ error: false,
+ protocol: 'foo:',
+ pathname: 'bar',
+ search: '?what',
+ hash: '#yeah',
+ skip_setters: false,
+ },
];
while(tests.length) {
var test = tests.shift();
var error = false;
var url;
try {
@@ -382,10 +392,45 @@
is(url.href, "ftp://tmp/test");
url = new URL("ftp:\\\\tmp\\test", base);
is(url.href, "ftp://tmp/test");
url = new URL("scheme://tmp\\test", base);
is(url.href, "scheme://tmp\\test");
</script>
+
+ <script>
+ var url = new URL("scheme:path/to/file?query#hash");
+ is(url.href, "scheme:path/to/file?query#hash");
+ is(url.pathname, "path/to/file");
+ is(url.search, "?query");
+ is(url.hash, "#hash");
+
+ // pathname cannot be overwritten.
+ url.pathname = "new/path?newquery#newhash";
+ is(url.href, "scheme:path/to/file?query#hash");
+
+ url.search = "?newquery#newhash";
+ is(url.href, "scheme:path/to/file?newquery%23newhash#hash");
+
+ // nulls get encoded, whitespace gets stripped
+ url = new URL("scheme:pa\0\nth/to/fi\0\nle?qu\0\nery#ha\0\nsh");
+ is(url.href, "scheme:pa%00th/to/fi%00le?qu%00ery#ha%00sh");
+
+ url.search = "new\0\nquery";
+ is(url.href, "scheme:pa%00th/to/fi%00le?new%00%0Aquery#ha%00sh");
+ url.hash = "new\0\nhash";
+ is(url.href, "scheme:pa%00th/to/fi%00le?new%00%0Aquery#new%00%0Ahash");
+
+ url = new URL("scheme:path#hash");
+ is(url.href, "scheme:path#hash");
+ url.search = "query";
+ is(url.href, "scheme:path?query#hash");
+ url.hash = "";
+ is(url.href, "scheme:path?query");
+ url.hash = "newhash";
+ is(url.href, "scheme:path?query#newhash");
+ url.search = "";
+ is(url.href, "scheme:path#newhash");
+ </script>
</body>
</html>
--- a/dom/webidl/HTMLCanvasElement.webidl
+++ b/dom/webidl/HTMLCanvasElement.webidl
@@ -17,33 +17,36 @@ interface HTMLCanvasElement : HTMLElemen
[Pure, SetterThrows]
attribute unsigned long width;
[Pure, SetterThrows]
attribute unsigned long height;
[Throws]
nsISupports? getContext(DOMString contextId, optional any contextOptions = null);
- [Throws]
+ [Throws, NeedsCallerType]
DOMString toDataURL(optional DOMString type = "",
optional any encoderOptions);
- [Throws]
+ [Throws, NeedsCallerType]
void toBlob(BlobCallback _callback,
optional DOMString type = "",
optional any encoderOptions);
};
// Mozilla specific bits
partial interface HTMLCanvasElement {
[Pure, SetterThrows]
attribute boolean mozOpaque;
- [Throws]
+ [Throws, NeedsCallerType]
File mozGetAsFile(DOMString name, optional DOMString? type = null);
+ // A Mozilla-only extension to get a canvas context backed by double-buffered
+ // shared memory. Only privileged callers can call this.
[ChromeOnly, Throws]
nsISupports? MozGetIPCContext(DOMString contextId);
+
attribute PrintCallback? mozPrintCallback;
[Throws, UnsafeInPrerendering, Pref="canvas.capturestream.enabled"]
CanvasCaptureMediaStream captureStream(optional double frameRate);
};
// For OffscreenCanvas
// Reference: https://wiki.whatwg.org/wiki/OffscreenCanvas
--- a/dom/webidl/HTMLDocument.webidl
+++ b/dom/webidl/HTMLDocument.webidl
@@ -40,25 +40,26 @@ interface HTMLDocument : Document {
void close();
[Throws]
void write(DOMString... text);
[Throws]
void writeln(DOMString... text);
[SetterThrows, NeedsSubjectPrincipal]
attribute DOMString designMode;
- [Throws]
+ [Throws, NeedsCallerType]
boolean execCommand(DOMString commandId, optional boolean showUI = false,
optional DOMString value = "");
- [Throws]
+ [Throws, NeedsCallerType]
boolean queryCommandEnabled(DOMString commandId);
[Throws]
boolean queryCommandIndeterm(DOMString commandId);
[Throws]
boolean queryCommandState(DOMString commandId);
+ [NeedsCallerType]
boolean queryCommandSupported(DOMString commandId);
[Throws]
DOMString queryCommandValue(DOMString commandId);
[TreatNullAs=EmptyString] attribute DOMString fgColor;
[TreatNullAs=EmptyString] attribute DOMString linkColor;
[TreatNullAs=EmptyString] attribute DOMString vlinkColor;
[TreatNullAs=EmptyString] attribute DOMString alinkColor;
--- a/dom/webidl/HTMLElement.webidl
+++ b/dom/webidl/HTMLElement.webidl
@@ -23,16 +23,17 @@ interface HTMLElement : Element {
readonly attribute DOMStringMap dataset;
[GetterThrows, Pure, TreatNullAs=EmptyString]
attribute DOMString innerText;
// user interaction
[SetterThrows, Pure]
attribute boolean hidden;
+ [NeedsCallerType]
void click();
[SetterThrows, Pure]
attribute long tabIndex;
[Throws]
void focus();
[Throws]
void blur();
[SetterThrows, Pure]
--- a/dom/webidl/MimeTypeArray.webidl
+++ b/dom/webidl/MimeTypeArray.webidl
@@ -1,15 +1,13 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*/
-// [LegacyUnenumerableNamedProperties]
-// Named properties enumerable for now; see
-// https://bugzilla.mozilla.org/show_bug.cgi?id=1270364
+[LegacyUnenumerableNamedProperties]
interface MimeTypeArray {
readonly attribute unsigned long length;
getter MimeType? item(unsigned long index);
getter MimeType? namedItem(DOMString name);
};
--- a/dom/webidl/Plugin.webidl
+++ b/dom/webidl/Plugin.webidl
@@ -1,17 +1,15 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*/
-// [LegacyUnenumerableNamedProperties]
-// Named properties enumerable for now; see
-// https://bugzilla.mozilla.org/show_bug.cgi?id=1270366
+[LegacyUnenumerableNamedProperties]
interface Plugin {
readonly attribute DOMString description;
readonly attribute DOMString filename;
readonly attribute DOMString version;
readonly attribute DOMString name;
readonly attribute unsigned long length;
getter MimeType? item(unsigned long index);
--- a/dom/webidl/PluginArray.webidl
+++ b/dom/webidl/PluginArray.webidl
@@ -1,17 +1,15 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*/
-// [LegacyUnenumerableNamedProperties]
-// Named properties enumerable for now; see
-// https://bugzilla.mozilla.org/show_bug.cgi?id=1270366
+[LegacyUnenumerableNamedProperties]
interface PluginArray {
readonly attribute unsigned long length;
getter Plugin? item(unsigned long index);
getter Plugin? namedItem(DOMString name);
void refresh(optional boolean reloadDocuments = false);
};
--- a/dom/webidl/Request.webidl
+++ b/dom/webidl/Request.webidl
@@ -58,9 +58,13 @@ enum RequestContext {
"sharedworker", "subresource", "style", "track", "video", "worker", "xmlhttprequest",
"xslt"
};
enum RequestMode { "same-origin", "no-cors", "cors", "navigate" };
enum RequestCredentials { "omit", "same-origin", "include" };
enum RequestCache { "default", "no-store", "reload", "no-cache", "force-cache", "only-if-cached" };
enum RequestRedirect { "follow", "error", "manual" };
-enum ReferrerPolicy { "", "no-referrer", "no-referrer-when-downgrade", "origin", "origin-when-cross-origin", "unsafe-url" };
+enum ReferrerPolicy {
+ "", "no-referrer", "no-referrer-when-downgrade", "origin",
+ "origin-when-cross-origin", "unsafe-url", "same-origin", "strict-origin",
+ "strict-origin-when-cross-origin"
+};
--- a/dom/webidl/WebGL2RenderingContext.webidl
+++ b/dom/webidl/WebGL2RenderingContext.webidl
@@ -6,20 +6,16 @@
* The source for this IDL is found at https://www.khronos.org/registry/webgl/specs/latest/2.0
* This IDL depends on WebGLRenderingContext.webidl
*/
typedef long long GLint64;
typedef unsigned long long GLuint64;
[Pref="webgl.enable-webgl2"]
-interface WebGLQuery {
-};
-
-[Pref="webgl.enable-webgl2"]
interface WebGLSampler {
};
[Pref="webgl.enable-webgl2"]
interface WebGLSync {
};
[Pref="webgl.enable-webgl2"]
@@ -620,17 +616,17 @@ interface WebGL2RenderingContext : WebGL
void clearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
/* Query Objects */
WebGLQuery? createQuery();
void deleteQuery(WebGLQuery? query);
[WebGLHandlesContextLoss] GLboolean isQuery(WebGLQuery? query);
void beginQuery(GLenum target, WebGLQuery? query);
void endQuery(GLenum target);
- WebGLQuery? getQuery(GLenum target, GLenum pname);
+ any getQuery(GLenum target, GLenum pname);
any getQueryParameter(WebGLQuery? query, GLenum pname);
/* Sampler Objects */
WebGLSampler? createSampler();
void deleteSampler(WebGLSampler? sampler);
[WebGLHandlesContextLoss] GLboolean isSampler(WebGLSampler? sampler);
void bindSampler(GLuint unit, WebGLSampler? sampler);
void samplerParameteri(WebGLSampler? sampler, GLenum pname, GLint param);
--- a/dom/webidl/WebGLRenderingContext.webidl
+++ b/dom/webidl/WebGLRenderingContext.webidl
@@ -75,17 +75,16 @@ interface WebGLShader {
interface WebGLTexture {
};
[Exposed=(Window,Worker),
Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"]
interface WebGLUniformLocation {
};
-[NoInterfaceObject]
interface WebGLVertexArrayObjectOES {
};
[Exposed=(Window,Worker),
Func="mozilla::dom::OffscreenCanvas::PrefEnabledOnWorkerThread"]
interface WebGLActiveInfo {
readonly attribute GLint size;
readonly attribute GLenum type;
@@ -802,17 +801,17 @@ interface WEBGL_compressed_texture_s3tc
interface WEBGL_compressed_texture_atc
{
const GLenum COMPRESSED_RGB_ATC_WEBGL = 0x8C92;
const GLenum COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL = 0x8C93;
const GLenum COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL = 0x87EE;
};
[NoInterfaceObject]
-interface WEBGL_compressed_texture_es3
+interface WEBGL_compressed_texture_etc
{
const GLenum COMPRESSED_R11_EAC = 0x9270;
const GLenum COMPRESSED_SIGNED_R11_EAC = 0x9271;
const GLenum COMPRESSED_RG11_EAC = 0x9272;
const GLenum COMPRESSED_SIGNED_RG11_EAC = 0x9273;
const GLenum COMPRESSED_RGB8_ETC2 = 0x9274;
const GLenum COMPRESSED_SRGB8_ETC2 = 0x9275;
const GLenum COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9276;
@@ -998,31 +997,30 @@ interface ANGLE_instanced_arrays {
};
[NoInterfaceObject]
interface EXT_blend_minmax {
const GLenum MIN_EXT = 0x8007;
const GLenum MAX_EXT = 0x8008;
};
-[NoInterfaceObject]
-interface WebGLTimerQueryEXT {
+interface WebGLQuery {
};
[NoInterfaceObject]
interface EXT_disjoint_timer_query {
const GLenum QUERY_COUNTER_BITS_EXT = 0x8864;
const GLenum CURRENT_QUERY_EXT = 0x8865;
const GLenum QUERY_RESULT_EXT = 0x8866;
const GLenum QUERY_RESULT_AVAILABLE_EXT = 0x8867;
const GLenum TIME_ELAPSED_EXT = 0x88BF;
const GLenum TIMESTAMP_EXT = 0x8E28;
const GLenum GPU_DISJOINT_EXT = 0x8FBB;
- WebGLTimerQueryEXT? createQueryEXT();
- void deleteQueryEXT(WebGLTimerQueryEXT? query);
- [WebGLHandlesContextLoss] boolean isQueryEXT(WebGLTimerQueryEXT? query);
- void beginQueryEXT(GLenum target, WebGLTimerQueryEXT? query);
+ WebGLQuery? createQueryEXT();
+ void deleteQueryEXT(WebGLQuery? query);
+ [WebGLHandlesContextLoss] boolean isQueryEXT(WebGLQuery? query);
+ void beginQueryEXT(GLenum target, WebGLQuery? query);
void endQueryEXT(GLenum target);
- void queryCounterEXT(WebGLTimerQueryEXT? query, GLenum target);
+ void queryCounterEXT(WebGLQuery? query, GLenum target);
any getQueryEXT(GLenum target, GLenum pname);
- any getQueryObjectEXT(WebGLTimerQueryEXT? query, GLenum pname);
+ any getQueryObjectEXT(WebGLQuery? query, GLenum pname);
};
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -200,18 +200,20 @@ ChannelFromScriptURL(nsIPrincipal* princ
nullptr, // aCallbacks
aLoadFlags,
ios);
}
NS_ENSURE_SUCCESS(rv, rv);
if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel)) {
+ mozilla::net::ReferrerPolicy referrerPolicy = parentDoc ?
+ parentDoc->GetReferrerPolicy() : mozilla::net::RP_Default;
rv = nsContentUtils::SetFetchReferrerURIWithPolicy(principal, parentDoc,
- httpChannel, mozilla::net::RP_Default);
+ httpChannel, referrerPolicy);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
channel.forget(aChannel);
return rv;
}
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -1336,37 +1336,53 @@ public:
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
MOZ_ASSERT(httpChannel, "How come we don't have an HTTP channel?");
nsAutoCString referrer;
// Ignore the return value since the Referer header may not exist.
httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("Referer"), referrer);
if (!referrer.IsEmpty()) {
mReferrer = referrer;
+ } else {
+ // If there's no referrer Header, means the header was omitted for
+ // security/privacy reason.
+ mReferrer = EmptyCString();
}
uint32_t referrerPolicy = 0;
rv = httpChannel->GetReferrerPolicy(&referrerPolicy);
NS_ENSURE_SUCCESS(rv, rv);
switch (referrerPolicy) {
+ case nsIHttpChannel::REFERRER_POLICY_UNSET:
+ mReferrerPolicy = ReferrerPolicy::_empty;
+ break;
case nsIHttpChannel::REFERRER_POLICY_NO_REFERRER:
mReferrerPolicy = ReferrerPolicy::No_referrer;
break;
case nsIHttpChannel::REFERRER_POLICY_ORIGIN:
mReferrerPolicy = ReferrerPolicy::Origin;
break;
case nsIHttpChannel::REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE:
mReferrerPolicy = ReferrerPolicy::No_referrer_when_downgrade;
break;
case nsIHttpChannel::REFERRER_POLICY_ORIGIN_WHEN_XORIGIN:
mReferrerPolicy = ReferrerPolicy::Origin_when_cross_origin;
break;
case nsIHttpChannel::REFERRER_POLICY_UNSAFE_URL:
mReferrerPolicy = ReferrerPolicy::Unsafe_url;
break;
+ case nsIHttpChannel::REFERRER_POLICY_SAME_ORIGIN:
+ mReferrerPolicy = ReferrerPolicy::Same_origin;
+ break;
+ case nsIHttpChannel::REFERRER_POLICY_STRICT_ORIGIN_WHEN_XORIGIN:
+ mReferrerPolicy = ReferrerPolicy::Strict_origin_when_cross_origin;
+ break;
+ case nsIHttpChannel::REFERRER_POLICY_STRICT_ORIGIN:
+ mReferrerPolicy = ReferrerPolicy::Strict_origin;
+ break;
default:
MOZ_ASSERT_UNREACHABLE("Invalid Referrer Policy enum value?");
break;
}
rv = httpChannel->GetRequestMethod(mMethod);
NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -2536,19 +2536,20 @@ XMLHttpRequestMainThread::InitiateFetch(
mAuthorRequestHeaders.Set("accept", NS_LITERAL_CSTRING("*/*"));
}
mAuthorRequestHeaders.ApplyToChannel(httpChannel);
if (!IsSystemXHR()) {
nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner();
nsCOMPtr<nsIDocument> doc = owner ? owner->GetExtantDoc() : nullptr;
+ mozilla::net::ReferrerPolicy referrerPolicy = doc ?
+ doc->GetReferrerPolicy() : mozilla::net::RP_Default;
nsContentUtils::SetFetchReferrerURIWithPolicy(mPrincipal, doc,
- httpChannel,
- mozilla::net::RP_Default);
+ httpChannel, referrerPolicy);
}
// Some extensions override the http protocol handler and provide their own
// implementation. The channels returned from that implementation don't
// always seem to implement the nsIUploadChannel2 interface, presumably
// because it's a new interface. Eventually we should remove this and simply
// require that http channels implement the new interface (see bug 529041).
nsCOMPtr<nsIUploadChannel2> uploadChannel2 = do_QueryInterface(httpChannel);
new file mode 100644
--- /dev/null
+++ b/dom/xhr/tests/file_sync_xhr_document_write_with_iframe.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<body>
+<script>
+function syncXHR() {
+ let xhr = new XMLHttpRequest();
+ xhr.open("GET", window.location, false);
+ xhr.send(null);
+}
+
+addEventListener('load', evt => {
+ syncXHR();
+ document.open();
+ document.write(
+ '<body>' +
+ '<iframe src="about:blank"></iframe>' +
+ '<script>window.opener.postMessage("DONE", "*");</' + 'script>' +
+ '</body>');
+ document.close();
+}, { once: true });
+</script>
+</body>
--- a/dom/xhr/tests/mochitest.ini
+++ b/dom/xhr/tests/mochitest.ini
@@ -58,16 +58,17 @@ support-files =
subdir/relativeLoad_sub_worker2.js
subdir/relativeLoad_sub_import.js
common_temporaryFileBlob.js
worker_temporaryFileBlob.js
worker_bug1300552.js
sync_xhr_unload.sjs
iframe_sync_xhr_unload.html
empty.html
+ file_sync_xhr_document_write_with_iframe.html
[test_bug1300552.html]
[test_html_in_xhr.html]
[test_relativeLoad.html]
skip-if = buildapp == 'b2g' # b2g(Failed to load script: relativeLoad_import.js) b2g-debug(Failed to load script: relativeLoad_import.js) b2g-desktop(Failed to load script: relativeLoad_import.js)
[test_sync_xhr_timer.xhtml]
skip-if = toolkit == 'android'
[test_sync_xhr_unload.html]
@@ -106,8 +107,9 @@ skip-if = toolkit == 'android'
skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(12 total, 2 failing - .mozSystem == true - got false, expected true + ) b2g-desktop(12 total, 2 failing - .mozSystem == true - got false, expected true + )
[test_XHR_timeout.html]
skip-if = buildapp == 'b2g' || (android_version == '18' && debug) # b2g(flaky on B2G, bug 960743) b2g-debug(flaky on B2G, bug 960743) b2g-desktop(flaky on B2G, bug 960743)
support-files = test_XHR_timeout.js
[test_xhr_withCredentials.html]
[test_XHRDocURI.html]
[test_XHRResponseURL.html]
[test_XHRSendData.html]
+[test_sync_xhr_document_write_with_iframe.html]
new file mode 100644
--- /dev/null
+++ b/dom/xhr/tests/test_sync_xhr_document_write_with_iframe.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug </title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>