Compare commits
224
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
610e44320c | ||
|
|
10476e27da | ||
|
|
a4777b1c21 | ||
|
|
9f6e448f78 | ||
|
|
19a21bac1b | ||
|
|
c7867ce130 | ||
|
|
34c068e611 | ||
|
|
a48e621048 | ||
|
|
de5d3b1034 | ||
|
|
f8737bbf4f | ||
|
|
d9c70eaba2 | ||
|
|
9308c63ce6 | ||
|
|
6314e01691 | ||
|
|
b7b2f1de84 | ||
|
|
b838d6634c | ||
|
|
dc4ea7f680 | ||
|
|
2132ea4a22 | ||
|
|
33bff10b1c | ||
|
|
9493e8c3de | ||
|
|
7631297112 | ||
|
|
5e381b021c | ||
|
|
5c9a1efa7c | ||
|
|
93ddeb613e | ||
|
|
2fae5d3e6b | ||
|
|
5fd365cb76 | ||
|
|
d7f8e56f04 | ||
|
|
6ee56b0a60 | ||
|
|
165ef56547 | ||
|
|
9d333be11b | ||
|
|
aff6fbf36c | ||
|
|
ef8447ad4b | ||
|
|
21face45d3 | ||
|
|
ff4d550c80 | ||
|
|
45b9cfbe93 | ||
|
|
4321dbddcc | ||
|
|
3a67a9510b | ||
|
|
ea464a764f | ||
|
|
72a2a5f2bd | ||
|
|
0b70c77657 | ||
|
|
ca04aefa67 | ||
|
|
89dec27643 | ||
|
|
53a8a408f2 | ||
|
|
a653f74576 | ||
|
|
5fa394b169 | ||
|
|
3d92b82125 | ||
|
|
ccb41c645c | ||
|
|
98c3aa5743 | ||
|
|
2c2ddd98d2 | ||
|
|
b15a36452d | ||
|
|
a71597905c | ||
|
|
028aa731ed | ||
|
|
688ed9a114 | ||
|
|
c30be25773 | ||
|
|
72f30730e7 | ||
|
|
782202963e | ||
|
|
dd2fbc763a | ||
|
|
f4d408dffe | ||
|
|
f7c0599e1e | ||
|
|
855109b028 | ||
|
|
c48055d6ea | ||
|
|
8b746b6c12 | ||
|
|
1889edcea8 | ||
|
|
6df4c18747 | ||
|
|
d5231ca7e7 | ||
|
|
93823836d7 | ||
|
|
1e3301e987 | ||
|
|
ccbeea30aa | ||
|
|
398486a64b | ||
|
|
4554cb9929 | ||
|
|
8f62ed27eb | ||
|
|
3e71cd6b93 | ||
|
|
6c6c16b7f0 | ||
|
|
6ad6cc9c2d | ||
|
|
5b5672fd56 | ||
|
|
0e427867e3 | ||
|
|
8137a4e122 | ||
|
|
f2ec6ef34d | ||
|
|
42c8b9470c | ||
|
|
d0d6e8edf5 | ||
|
|
30d3325148 | ||
|
|
0451648c60 | ||
|
|
7a10dcaadf | ||
|
|
a63cf31989 | ||
|
|
ea3785a6d7 | ||
|
|
d0d9e63809 | ||
|
|
e80bbcfe91 | ||
|
|
08406731e5 | ||
|
|
6076431d7c | ||
|
|
60b4d804bd | ||
|
|
2b1281f2c9 | ||
|
|
087febcc4b | ||
|
|
6430adfb2d | ||
|
|
d5020b69bd | ||
|
|
46138995f6 | ||
|
|
aeb9de40a5 | ||
|
|
3d693801f9 | ||
|
|
3b39358c84 | ||
|
|
4df8e7664a | ||
|
|
14fa712b8c | ||
|
|
7d93034fd0 | ||
|
|
1769e74839 | ||
|
|
cdfd243b5a | ||
|
|
b326873871 | ||
|
|
0ea78ba5fa | ||
|
|
95a8edc5fc | ||
|
|
38dfadad45 | ||
|
|
9bee3a8b72 | ||
|
|
c8218f73b7 | ||
|
|
81cf4413e2 | ||
|
|
09e6d13d6b | ||
|
|
69cfed48da | ||
|
|
1b2c1d8eac | ||
|
|
e0746ccf31 | ||
|
|
8f6d5c5ba0 | ||
|
|
78120a7693 | ||
|
|
ecc90c09ef | ||
|
|
8698518416 | ||
|
|
cf178171a4 | ||
|
|
92ad63b579 | ||
|
|
8c63b950f5 | ||
|
|
9aed582fc1 | ||
|
|
1b5b970a53 | ||
|
|
bf6ed5545d | ||
|
|
302411b4df | ||
|
|
2cb4813adb | ||
|
|
c5ba4dd2a4 | ||
|
|
322bbcad1b | ||
|
|
a2f69c22f8 | ||
|
|
9d69fa3c37 | ||
|
|
5d76f35990 | ||
|
|
054f135a54 | ||
|
|
5c8336d123 | ||
|
|
0f0adfa1b4 | ||
|
|
ec38250eea | ||
|
|
682e5a4727 | ||
|
|
16e405f818 | ||
|
|
bfae2ed943 | ||
|
|
1337373ee1 | ||
|
|
efc3e99b90 | ||
|
|
eaf9a3cc57 | ||
|
|
b7a5d73ba9 | ||
|
|
aa1caf5ade | ||
|
|
bc4d5cec6a | ||
|
|
7d55641d43 | ||
|
|
3f799def4d | ||
|
|
796863b719 | ||
|
|
aced9bbc94 | ||
|
|
b1d111ab6b | ||
|
|
99c25d8e98 | ||
|
|
8a45238908 | ||
|
|
1b588e0d73 | ||
|
|
c9020fed9c | ||
|
|
4c6e382f47 | ||
|
|
26cb9b0802 | ||
|
|
1fd5023fdc | ||
|
|
8a0c7bde63 | ||
|
|
cc43ec658c | ||
|
|
07df24f00f | ||
|
|
ed7b08e608 | ||
|
|
1a429629d2 | ||
|
|
03ec9c095b | ||
|
|
24edfc1652 | ||
|
|
efd2b96387 | ||
|
|
4a179ff885 | ||
|
|
8c5a0f0de9 | ||
|
|
cc8f43bf79 | ||
|
|
552d964ae7 | ||
|
|
0099fc1627 | ||
|
|
8ce17f02ee | ||
|
|
269a703200 | ||
|
|
582fd0dd81 | ||
|
|
395caa8780 | ||
|
|
f31471e689 | ||
|
|
be4b71b580 | ||
|
|
de91800956 | ||
|
|
7a48dfc066 | ||
|
|
4769b2a9fa | ||
|
|
b12c222c61 | ||
|
|
2ac006763b | ||
|
|
3edbfa6b6e | ||
|
|
fcb74a0fb6 | ||
|
|
bfda40bce9 | ||
|
|
8b4aae99b4 | ||
|
|
4e1d7760d5 | ||
|
|
1b2961f93f | ||
|
|
8775eedca5 | ||
|
|
8ffb592b72 | ||
|
|
522d8c66a5 | ||
|
|
7df5060161 | ||
|
|
73a150b1c1 | ||
|
|
89f280a78e | ||
|
|
6aeae2ba74 | ||
|
|
5fd783135d | ||
|
|
1b2be9536f | ||
|
|
2ad1f8f08d | ||
|
|
85734b9adf | ||
|
|
2b46202164 | ||
|
|
18ec63e459 | ||
|
|
004a3d003b | ||
|
|
9c72ce666b | ||
|
|
47f213c878 | ||
|
|
d2eb2ce9f4 | ||
|
|
dba1e36601 | ||
|
|
bb39e1e38f | ||
|
|
7003ea7dc4 | ||
|
|
dca8417ba7 | ||
|
|
99184b1764 | ||
|
|
8f26f1a873 | ||
|
|
53ce814858 | ||
|
|
33d4be58a5 | ||
|
|
8635073418 | ||
|
|
f122b231e5 | ||
|
|
1a7f79ef9a | ||
|
|
281497201e | ||
|
|
dce6745dec | ||
|
|
a9bb437550 | ||
|
|
01ee4539cb | ||
|
|
47fbe9552a | ||
|
|
c94c303447 | ||
|
|
a15cbf9256 | ||
|
|
ebf4f559e0 | ||
|
|
d9eb5d3e2b | ||
|
|
9e85eb2816 | ||
|
|
32ef10e763 |
No files matched your search
@@ -22,4 +22,4 @@
|
||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Touching ICU's build system requires a CLOBBER. (Issue #2165)
|
||||
Switching to C++17 requires CLOBBER to pick up compiler conf. (Issue #2281)
|
||||
@@ -176,7 +176,7 @@ private:
|
||||
uint32_t AddSubtree(ProxyAccessible* aParent,
|
||||
const nsTArray<AccessibleData>& aNewTree, uint32_t aIdx,
|
||||
uint32_t aIdxInParent);
|
||||
MOZ_MUST_USE bool CheckDocTree() const;
|
||||
[[nodiscard]] bool CheckDocTree() const;
|
||||
xpcAccessibleGeneric* GetXPCAccessible(ProxyAccessible* aProxy);
|
||||
|
||||
nsTArray<DocAccessibleParent*> mChildDocs;
|
||||
|
||||
@@ -173,7 +173,7 @@ public: // construction, destruction
|
||||
/**
|
||||
* Find an accessible by the given child ID in cached documents.
|
||||
*/
|
||||
MOZ_MUST_USE already_AddRefed<IAccessible>
|
||||
[[nodiscard]] already_AddRefed<IAccessible>
|
||||
GetIAccessibleFor(const VARIANT& aVarChild, bool* aIsDefunct);
|
||||
|
||||
virtual void GetNativeInterface(void **aOutAccessible) override;
|
||||
@@ -198,7 +198,7 @@ protected:
|
||||
/**
|
||||
* Find a remote accessible by the given child ID.
|
||||
*/
|
||||
MOZ_MUST_USE already_AddRefed<IAccessible>
|
||||
[[nodiscard]] already_AddRefed<IAccessible>
|
||||
GetRemoteIAccessibleFor(const VARIANT& aVarChild);
|
||||
|
||||
/**
|
||||
|
||||
@@ -179,7 +179,6 @@ def old_configure_options(*options):
|
||||
'--enable-directshow',
|
||||
'--enable-dtrace',
|
||||
'--enable-dump-painting',
|
||||
'--enable-eme',
|
||||
'--enable-elf-hack',
|
||||
'--enable-extensions',
|
||||
'--enable-faststripe',
|
||||
|
||||
@@ -340,17 +340,16 @@ def check_compiler(compiler, language, target):
|
||||
if info.type in ('clang-cl', 'clang', 'gcc'):
|
||||
append_flag('-std=gnu99')
|
||||
|
||||
# Note: this is a strict version check because we used to always add
|
||||
# -std=gnu++14.
|
||||
cxx14_version = 201402
|
||||
cxx17_version = 201703
|
||||
if info.language == 'C++':
|
||||
if info.type in ('clang', 'gcc') and info.language_version != cxx14_version:
|
||||
append_flag('-std=gnu++14')
|
||||
# MSVC 2015 headers include C++14 features, but don't guard them
|
||||
# with appropriate checks.
|
||||
if info.type == 'clang-cl' and info.language_version != cxx14_version:
|
||||
append_flag('-std=c++14')
|
||||
# MSVC from 2015 on defaults to C++14.
|
||||
if info.language_version != cxx17_version:
|
||||
# Compiler doesn't default to C++17, so add the appropriate flag.
|
||||
if info.type in ('clang', 'gcc'):
|
||||
# We're on Clang or GCC, enable C++17 and add GNU extensions.
|
||||
append_flag('-std=gnu++17')
|
||||
else:
|
||||
# We're on MSVC; enable C++17 language mode.
|
||||
append_flag('-std:c++17')
|
||||
|
||||
# We force clang-cl to emulate Visual C++ 2015 Update 3 with fallback to
|
||||
# cl.exe.
|
||||
|
||||
@@ -52,7 +52,7 @@ check_and_add_gcc_warning('-Wclass-varargs')
|
||||
check_and_add_gcc_warning('-Wloop-analysis')
|
||||
|
||||
# catches C++ version forward-compat issues
|
||||
check_and_add_gcc_warning('-Wc++1z-compat', cxx_compiler)
|
||||
# check_and_add_gcc_warning('-Wc++2a-compat', cxx_compiler)
|
||||
|
||||
# catches unintentional switch case fallthroughs
|
||||
check_and_add_gcc_warning('-Wimplicit-fallthrough', cxx_compiler)
|
||||
|
||||
@@ -51,12 +51,12 @@ public:
|
||||
// Don't use this method for anything else than debugging!
|
||||
void CreateAnonymizedSuffix(nsACString& aStr) const;
|
||||
|
||||
MOZ_MUST_USE bool PopulateFromSuffix(const nsACString& aStr);
|
||||
[[nodiscard]] bool PopulateFromSuffix(const nsACString& aStr);
|
||||
|
||||
// Populates the attributes from a string like
|
||||
// |uri!key1=value1&key2=value2| and returns the uri without the suffix.
|
||||
MOZ_MUST_USE bool PopulateFromOrigin(const nsACString& aOrigin,
|
||||
nsACString& aOriginNoSuffix);
|
||||
[[nodiscard]] bool PopulateFromOrigin(const nsACString& aOrigin,
|
||||
nsACString& aOriginNoSuffix);
|
||||
|
||||
// Helper function to match mIsPrivateBrowsing to existing private browsing
|
||||
// flags. Once all other flags are removed, this can be removed too.
|
||||
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
LIBRARY lgpllibs.dll
|
||||
|
||||
EXPORTS
|
||||
av_rdft_init
|
||||
av_rdft_calc
|
||||
av_rdft_end
|
||||
Vendored
+2
-6
@@ -4,14 +4,10 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# The lgpllibs library stores symbols from third-party LGPL licensed libraries,
|
||||
# such as libav and libsoundtouch. It fulfills the requirement of dynamically
|
||||
# linking these symbols into gecko.
|
||||
# such as libsoundtouch. It fulfills the requirement of dynamically linking
|
||||
# these symbols into Goanna.
|
||||
#
|
||||
# Any library added here should also be reflected in the about:license page.
|
||||
|
||||
GeckoSharedLibrary('lgpllibs', linkage=None)
|
||||
SHARED_LIBRARY_NAME = 'lgpllibs'
|
||||
|
||||
if CONFIG['MOZ_LIBAV_FFT']:
|
||||
DIRS += ['/media/libav']
|
||||
DEFFILE = SRCDIR + '/lgpllibs.def'
|
||||
@@ -8,4 +8,4 @@
|
||||
# Referenced by milestone.py.
|
||||
#--------------------------------------------------------
|
||||
|
||||
6.3.0
|
||||
6.5.0
|
||||
@@ -1068,7 +1068,7 @@ var Debugger =
|
||||
// be either 3, or 5, or 6. This influences support for strict
|
||||
// mode, the set of reserved words, support for getters and
|
||||
// setters and other features.
|
||||
ecmaVersion: 5,
|
||||
ecmaVersion: 6,
|
||||
// Turn on `strictSemicolons` to prevent the parser from doing
|
||||
// automatic semicolon insertion.
|
||||
strictSemicolons: false,
|
||||
|
||||
@@ -1299,7 +1299,7 @@ var defaultOptions = {
|
||||
// be either 3, or 5, or 6. This influences support for strict
|
||||
// mode, the set of reserved words, support for getters and
|
||||
// setters and other features.
|
||||
ecmaVersion: 5,
|
||||
ecmaVersion: 6,
|
||||
// Source type ("script" or "module") for different semantics
|
||||
sourceType: "script",
|
||||
// `onInsertedSemicolon` can be a callback that will be called
|
||||
|
||||
@@ -115,6 +115,27 @@ Crypto::GetRandomValues(JSContext* aCx, const ArrayBufferView& aArray,
|
||||
aRetval.set(view);
|
||||
}
|
||||
|
||||
void Crypto::RandomUUID(nsAString& aRetVal)
|
||||
{
|
||||
// NSID_LENGTH == 39 == 36 UUID chars + 2 curly braces + 1 NUL byte
|
||||
static_assert(NSID_LENGTH == 39, "Crypto:RandomUUID: NSID_LENGTH must be 39");
|
||||
|
||||
nsCOMPtr<nsIUUIDGenerator> uuidgen =
|
||||
do_GetService("@mozilla.org/uuid-generator;1");
|
||||
|
||||
nsID uuid;
|
||||
|
||||
nsresult rv = uuidgen->GenerateUUIDInPlace(&uuid);
|
||||
|
||||
char uuidBuffer[NSID_LENGTH];
|
||||
uuid.ToProvidedString(uuidBuffer);
|
||||
|
||||
nsCString asciiString(uuidBuffer);
|
||||
|
||||
// Convert UUID chars to UTF-16 retval, omitting the curly braces and NUL
|
||||
CopyASCIItoUTF16(Substring(asciiString, 1, NSID_LENGTH - 3), aRetVal);
|
||||
}
|
||||
|
||||
SubtleCrypto*
|
||||
Crypto::Subtle()
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "mozilla/dom/SubtleCrypto.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
#define NS_DOMCRYPTO_CID \
|
||||
@@ -39,6 +40,8 @@ public:
|
||||
JS::MutableHandle<JSObject*> aRetval,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void RandomUUID(nsAString& aRetVal);
|
||||
|
||||
SubtleCrypto*
|
||||
Subtle();
|
||||
|
||||
|
||||
@@ -398,7 +398,7 @@ FormData::Constructor(const GlobalObject& aGlobal,
|
||||
|
||||
NS_IMETHODIMP
|
||||
FormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
|
||||
nsACString& aContentType, nsACString& aCharset)
|
||||
nsACString& aContentTypeWithCharset, nsACString& aCharset)
|
||||
{
|
||||
FSMultipartFormData fs(NS_LITERAL_CSTRING("UTF-8"), nullptr);
|
||||
|
||||
@@ -419,7 +419,7 @@ FormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
|
||||
}
|
||||
}
|
||||
|
||||
fs.GetContentType(aContentType);
|
||||
fs.GetContentType(aContentTypeWithCharset);
|
||||
aCharset.Truncate();
|
||||
*aContentLength = 0;
|
||||
NS_ADDREF(*aBody = fs.GetSubmissionBody(aContentLength));
|
||||
|
||||
@@ -147,8 +147,7 @@ public:
|
||||
virtual bool TextIsOnlyWhitespace() override;
|
||||
virtual bool HasTextForTranslation() override;
|
||||
virtual void AppendTextTo(nsAString& aResult) override;
|
||||
MOZ_MUST_USE
|
||||
virtual bool AppendTextTo(nsAString& aResult, const mozilla::fallible_t&) override;
|
||||
[[nodiscard]] virtual bool AppendTextTo(nsAString& aResult, const mozilla::fallible_t&) override;
|
||||
virtual nsIContent *GetBindingParent() const override;
|
||||
virtual nsXBLBinding *GetXBLBinding() const override;
|
||||
virtual void SetXBLBinding(nsXBLBinding* aBinding,
|
||||
|
||||
+66
-206
@@ -11,7 +11,9 @@
|
||||
#include "nsPluginArray.h"
|
||||
#include "nsMimeTypeArray.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/dom/BodyExtractor.h"
|
||||
#include "mozilla/dom/DesktopNotification.h"
|
||||
#include "mozilla/dom/FetchBinding.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "nsGeolocation.h"
|
||||
#include "nsIClassOfService.h"
|
||||
@@ -38,6 +40,7 @@
|
||||
#include "mozilla/dom/ServiceWorkerContainer.h"
|
||||
#include "mozilla/dom/StorageManager.h"
|
||||
#include "mozilla/dom/TCPSocket.h"
|
||||
#include "mozilla/dom/URLSearchParams.h"
|
||||
#include "mozilla/dom/workers/RuntimeService.h"
|
||||
#include "mozilla/Hal.h"
|
||||
#include "nsISiteSpecificUserAgent.h"
|
||||
@@ -88,11 +91,6 @@
|
||||
#endif
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
|
||||
#ifdef MOZ_EME
|
||||
#include "mozilla/EMEUtils.h"
|
||||
#include "mozilla/DetailedPromise.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
@@ -195,9 +193,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
|
||||
#ifdef MOZ_EME
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaKeySystemAccessManager)
|
||||
#endif
|
||||
#ifdef MOZ_GAMEPAD
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepadServiceTest)
|
||||
#endif
|
||||
@@ -258,13 +253,6 @@ Navigator::Invalidate()
|
||||
|
||||
mServiceWorkerContainer = nullptr;
|
||||
|
||||
#ifdef MOZ_EME
|
||||
if (mMediaKeySystemAccessManager) {
|
||||
mMediaKeySystemAccessManager->Shutdown();
|
||||
mMediaKeySystemAccessManager = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_GAMEPAD
|
||||
if (mGamepadServiceTest) {
|
||||
mGamepadServiceTest->Shutdown();
|
||||
@@ -845,8 +833,52 @@ BeaconStreamListener::OnDataAvailable(nsIRequest *aRequest,
|
||||
|
||||
bool
|
||||
Navigator::SendBeacon(const nsAString& aUrl,
|
||||
const Nullable<ArrayBufferViewOrBlobOrStringOrFormData>& aData,
|
||||
const Nullable<fetch::BodyInit>& aData,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (aData.IsNull()) {
|
||||
return SendBeaconInternal(aUrl, nullptr, eBeaconTypeOther, aRv);
|
||||
}
|
||||
|
||||
if (aData.Value().IsArrayBuffer()) {
|
||||
BodyExtractor<const ArrayBuffer> body(&aData.Value().GetAsArrayBuffer());
|
||||
return SendBeaconInternal(aUrl, &body, eBeaconTypeOther, aRv);
|
||||
}
|
||||
|
||||
if (aData.Value().IsArrayBufferView()) {
|
||||
BodyExtractor<const ArrayBufferView> body(&aData.Value().GetAsArrayBufferView());
|
||||
return SendBeaconInternal(aUrl, &body, eBeaconTypeOther, aRv);
|
||||
}
|
||||
|
||||
if (aData.Value().IsBlob()) {
|
||||
BodyExtractor<nsIXHRSendable> body(&aData.Value().GetAsBlob());
|
||||
return SendBeaconInternal(aUrl, &body, eBeaconTypeOther, aRv);
|
||||
}
|
||||
|
||||
if (aData.Value().IsFormData()) {
|
||||
BodyExtractor<nsIXHRSendable> body(&aData.Value().GetAsFormData());
|
||||
return SendBeaconInternal(aUrl, &body, eBeaconTypeOther, aRv);
|
||||
}
|
||||
|
||||
if (aData.Value().IsUSVString()) {
|
||||
BodyExtractor<const nsAString> body(&aData.Value().GetAsUSVString());
|
||||
return SendBeaconInternal(aUrl, &body, eBeaconTypeOther, aRv);
|
||||
}
|
||||
|
||||
if (aData.Value().IsURLSearchParams()) {
|
||||
BodyExtractor<nsIXHRSendable> body(&aData.Value().GetAsURLSearchParams());
|
||||
return SendBeaconInternal(aUrl, &body, eBeaconTypeOther, aRv);
|
||||
}
|
||||
|
||||
MOZ_CRASH("Invalid data type.");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Navigator::SendBeaconInternal(const nsAString& aUrl,
|
||||
BodyExtractorBase* aBody,
|
||||
BeaconType aType,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (!mWindow) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
@@ -887,9 +919,9 @@ Navigator::SendBeacon(const nsAString& aUrl,
|
||||
nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
|
||||
|
||||
// No need to use CORS for sendBeacon unless it's a BLOB
|
||||
nsSecurityFlags securityFlags = (!aData.IsNull() && aData.Value().IsBlob())
|
||||
? nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS
|
||||
: nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS;
|
||||
nsSecurityFlags securityFlags = aType == eBeaconTypeBlob
|
||||
? nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS
|
||||
: nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS;
|
||||
securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
|
||||
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
@@ -915,76 +947,30 @@ Navigator::SendBeacon(const nsAString& aUrl,
|
||||
}
|
||||
httpChannel->SetReferrer(documentURI);
|
||||
|
||||
nsCString mimeType;
|
||||
if (!aData.IsNull()) {
|
||||
nsCOMPtr<nsIInputStream> in;
|
||||
nsCOMPtr<nsIInputStream> in;
|
||||
nsAutoCString contentTypeWithCharset;
|
||||
nsAutoCString charset;
|
||||
uint64_t length = 0;
|
||||
|
||||
if (aData.Value().IsString()) {
|
||||
nsCString stringData = NS_ConvertUTF16toUTF8(aData.Value().GetAsString());
|
||||
nsCOMPtr<nsIStringInputStream> strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return false;
|
||||
}
|
||||
rv = strStream->SetData(stringData.BeginReading(), stringData.Length());
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return false;
|
||||
}
|
||||
mimeType.AssignLiteral("text/plain;charset=UTF-8");
|
||||
in = strStream;
|
||||
|
||||
} else if (aData.Value().IsArrayBufferView()) {
|
||||
|
||||
nsCOMPtr<nsIStringInputStream> strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return false;
|
||||
}
|
||||
|
||||
const ArrayBufferView& view = aData.Value().GetAsArrayBufferView();
|
||||
view.ComputeLengthAndData();
|
||||
rv = strStream->SetData(reinterpret_cast<char*>(view.Data()),
|
||||
view.Length());
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return false;
|
||||
}
|
||||
mimeType.AssignLiteral("application/octet-stream");
|
||||
in = strStream;
|
||||
|
||||
} else if (aData.Value().IsBlob()) {
|
||||
Blob& blob = aData.Value().GetAsBlob();
|
||||
blob.GetInternalStream(getter_AddRefs(in), aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoString type;
|
||||
blob.GetType(type);
|
||||
mimeType = NS_ConvertUTF16toUTF8(type);
|
||||
|
||||
} else if (aData.Value().IsFormData()) {
|
||||
FormData& form = aData.Value().GetAsFormData();
|
||||
uint64_t len;
|
||||
nsAutoCString charset;
|
||||
form.GetSendInfo(getter_AddRefs(in),
|
||||
&len,
|
||||
mimeType,
|
||||
charset);
|
||||
} else {
|
||||
MOZ_ASSERT(false, "switch statements not in sync");
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
if (aBody) {
|
||||
aRv = aBody->GetAsStream(getter_AddRefs(in), &length,
|
||||
contentTypeWithCharset, charset);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aType == eBeaconTypeArrayBuffer) {
|
||||
MOZ_ASSERT(contentTypeWithCharset.IsEmpty());
|
||||
MOZ_ASSERT(charset.IsEmpty());
|
||||
contentTypeWithCharset.Assign("application/octet-stream");
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(channel);
|
||||
if (!uploadChannel) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return false;
|
||||
}
|
||||
uploadChannel->ExplicitSetUploadStream(in, mimeType, -1,
|
||||
uploadChannel->ExplicitSetUploadStream(in, contentTypeWithCharset, length,
|
||||
NS_LITERAL_CSTRING("POST"),
|
||||
false);
|
||||
} else {
|
||||
@@ -1503,131 +1489,5 @@ Navigator::GetUserAgent(nsPIDOMWindowInner* aWindow, nsIURI* aURI,
|
||||
return siteSpecificUA->GetUserAgentForURIAndWindow(aURI, aWindow, aUserAgent);
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
static nsCString
|
||||
ToCString(const nsString& aString)
|
||||
{
|
||||
nsCString str("'");
|
||||
str.Append(NS_ConvertUTF16toUTF8(aString));
|
||||
str.AppendLiteral("'");
|
||||
return str;
|
||||
}
|
||||
|
||||
static nsCString
|
||||
ToCString(const MediaKeysRequirement aValue)
|
||||
{
|
||||
nsCString str("'");
|
||||
str.Append(nsDependentCString(MediaKeysRequirementValues::strings[static_cast<uint32_t>(aValue)].value));
|
||||
str.AppendLiteral("'");
|
||||
return str;
|
||||
}
|
||||
|
||||
static nsCString
|
||||
ToCString(const MediaKeySystemMediaCapability& aValue)
|
||||
{
|
||||
nsCString str;
|
||||
str.AppendLiteral("{contentType=");
|
||||
str.Append(ToCString(aValue.mContentType));
|
||||
str.AppendLiteral(", robustness=");
|
||||
str.Append(ToCString(aValue.mRobustness));
|
||||
str.AppendLiteral("}");
|
||||
return str;
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
static nsCString
|
||||
ToCString(const Sequence<Type>& aSequence)
|
||||
{
|
||||
nsCString str;
|
||||
str.AppendLiteral("[");
|
||||
for (size_t i = 0; i < aSequence.Length(); i++) {
|
||||
if (i != 0) {
|
||||
str.AppendLiteral(",");
|
||||
}
|
||||
str.Append(ToCString(aSequence[i]));
|
||||
}
|
||||
str.AppendLiteral("]");
|
||||
return str;
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
static nsCString
|
||||
ToCString(const Optional<Sequence<Type>>& aOptional)
|
||||
{
|
||||
nsCString str;
|
||||
if (aOptional.WasPassed()) {
|
||||
str.Append(ToCString(aOptional.Value()));
|
||||
} else {
|
||||
str.AppendLiteral("[]");
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static nsCString
|
||||
ToCString(const MediaKeySystemConfiguration& aConfig)
|
||||
{
|
||||
nsCString str;
|
||||
str.AppendLiteral("{label=");
|
||||
str.Append(ToCString(aConfig.mLabel));
|
||||
|
||||
str.AppendLiteral(", initDataTypes=");
|
||||
str.Append(ToCString(aConfig.mInitDataTypes));
|
||||
|
||||
str.AppendLiteral(", audioCapabilities=");
|
||||
str.Append(ToCString(aConfig.mAudioCapabilities));
|
||||
|
||||
str.AppendLiteral(", videoCapabilities=");
|
||||
str.Append(ToCString(aConfig.mVideoCapabilities));
|
||||
|
||||
str.AppendLiteral(", distinctiveIdentifier=");
|
||||
str.Append(ToCString(aConfig.mDistinctiveIdentifier));
|
||||
|
||||
str.AppendLiteral(", persistentState=");
|
||||
str.Append(ToCString(aConfig.mPersistentState));
|
||||
|
||||
str.AppendLiteral(", sessionTypes=");
|
||||
str.Append(ToCString(aConfig.mSessionTypes));
|
||||
|
||||
str.AppendLiteral("}");
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static nsCString
|
||||
RequestKeySystemAccessLogString(const nsAString& aKeySystem,
|
||||
const Sequence<MediaKeySystemConfiguration>& aConfigs)
|
||||
{
|
||||
nsCString str;
|
||||
str.AppendPrintf("Navigator::RequestMediaKeySystemAccess(keySystem='%s' options=",
|
||||
NS_ConvertUTF16toUTF8(aKeySystem).get());
|
||||
str.Append(ToCString(aConfigs));
|
||||
str.AppendLiteral(")");
|
||||
return str;
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Navigator::RequestMediaKeySystemAccess(const nsAString& aKeySystem,
|
||||
const Sequence<MediaKeySystemConfiguration>& aConfigs,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
EME_LOG("%s", RequestKeySystemAccessLogString(aKeySystem, aConfigs).get());
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
|
||||
RefPtr<DetailedPromise> promise =
|
||||
DetailedPromise::Create(go, aRv,
|
||||
NS_LITERAL_CSTRING("navigator.requestMediaKeySystemAccess"));
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mMediaKeySystemAccessManager) {
|
||||
mMediaKeySystemAccessManager = new MediaKeySystemAccessManager(mWindow);
|
||||
}
|
||||
|
||||
mMediaKeySystemAccessManager->Request(promise, aKeySystem, aConfigs);
|
||||
return promise.forget();
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
+17
-14
@@ -7,6 +7,7 @@
|
||||
#define mozilla_dom_Navigator_h
|
||||
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/dom/Fetch.h"
|
||||
#include "mozilla/dom/Nullable.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "nsIDOMNavigator.h"
|
||||
@@ -17,9 +18,6 @@
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsWeakPtr.h"
|
||||
#ifdef MOZ_EME
|
||||
#include "mozilla/dom/MediaKeySystemAccessManager.h"
|
||||
#endif
|
||||
|
||||
class nsPluginArray;
|
||||
class nsMimeTypeArray;
|
||||
@@ -30,12 +28,13 @@ class nsIURI;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class BodyExtractorBase;
|
||||
class Geolocation;
|
||||
class systemMessageCallback;
|
||||
class MediaDevices;
|
||||
struct MediaStreamConstraints;
|
||||
class WakeLock;
|
||||
class ArrayBufferViewOrBlobOrStringOrFormData;
|
||||
class ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams;
|
||||
class ServiceWorkerContainer;
|
||||
class DOMRequest;
|
||||
} // namespace dom
|
||||
@@ -196,7 +195,7 @@ public:
|
||||
#endif // MOZ_AUDIO_CHANNEL_MANAGER
|
||||
|
||||
bool SendBeacon(const nsAString& aUrl,
|
||||
const Nullable<ArrayBufferViewOrBlobOrStringOrFormData>& aData,
|
||||
const Nullable<fetch::BodyInit>& aData,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void MozGetUserMedia(const MediaStreamConstraints& aConstraints,
|
||||
@@ -238,21 +237,25 @@ public:
|
||||
// any, else null.
|
||||
static already_AddRefed<nsPIDOMWindowInner> GetWindowFromGlobal(JSObject* aGlobal);
|
||||
|
||||
#ifdef MOZ_EME
|
||||
already_AddRefed<Promise>
|
||||
RequestMediaKeySystemAccess(const nsAString& aKeySystem,
|
||||
const Sequence<MediaKeySystemConfiguration>& aConfig,
|
||||
ErrorResult& aRv);
|
||||
private:
|
||||
RefPtr<MediaKeySystemAccessManager> mMediaKeySystemAccessManager;
|
||||
#endif
|
||||
|
||||
private:
|
||||
virtual ~Navigator();
|
||||
|
||||
bool CheckPermission(const char* type);
|
||||
static bool CheckPermission(nsPIDOMWindowInner* aWindow, const char* aType);
|
||||
|
||||
// This enum helps SendBeaconInternal to apply different behaviors to body
|
||||
// types.
|
||||
enum BeaconType {
|
||||
eBeaconTypeBlob,
|
||||
eBeaconTypeArrayBuffer,
|
||||
eBeaconTypeOther
|
||||
};
|
||||
|
||||
bool SendBeaconInternal(const nsAString& aUrl,
|
||||
BodyExtractorBase* aBody,
|
||||
BeaconType aType,
|
||||
ErrorResult& aRv);
|
||||
|
||||
RefPtr<nsMimeTypeArray> mMimeTypes;
|
||||
RefPtr<nsPluginArray> mPlugins;
|
||||
RefPtr<Permissions> mPermissions;
|
||||
|
||||
@@ -303,6 +303,30 @@ ResizeObserverEntry::Constructor(const GlobalObject& aGlobal,
|
||||
return observerEntry.forget();
|
||||
}
|
||||
|
||||
void ResizeObserverEntry::GetBorderBoxSize(
|
||||
nsTArray<RefPtr<ResizeObserverSize>>& aRetVal) const {
|
||||
// In the resize-observer-1 spec, there will only be a single
|
||||
// ResizeObserverSize returned in the FrozenArray.
|
||||
//
|
||||
// Note: the usage of FrozenArray is to support elements that have multiple
|
||||
// fragments, which occur in multi-column scenarios. See:
|
||||
// https://drafts.csswg.org/resize-observer/#resize-observer-entry-interface
|
||||
aRetVal.Clear();
|
||||
aRetVal.AppendElement(mBorderBoxSize);
|
||||
}
|
||||
|
||||
void ResizeObserverEntry::GetContentBoxSize(
|
||||
nsTArray<RefPtr<ResizeObserverSize>>& aRetVal) const {
|
||||
// In the resize-observer-1 spec, there will only be a single
|
||||
// ResizeObserverSize returned in the FrozenArray.
|
||||
//
|
||||
// Note: the usage of FrozenArray is to support elements that have multiple
|
||||
// fragments, which occur in multi-column scenarios.
|
||||
// https://drafts.csswg.org/resize-observer/#resize-observer-entry-interface
|
||||
aRetVal.Clear();
|
||||
aRetVal.AppendElement(mContentBoxSize);
|
||||
}
|
||||
|
||||
void
|
||||
ResizeObserverEntry::SetBorderBoxSize(const nsSize& aSize) {
|
||||
nsIFrame* frame = mTarget->GetPrimaryFrame();
|
||||
|
||||
@@ -163,14 +163,10 @@ public:
|
||||
|
||||
/**
|
||||
* Returns target's logical border-box size and content-box size as
|
||||
* ResizeObserverSize.
|
||||
* a ResizeObserverSize array.
|
||||
*/
|
||||
ResizeObserverSize* BorderBoxSize() const {
|
||||
return mBorderBoxSize;
|
||||
}
|
||||
ResizeObserverSize* ContentBoxSize() const {
|
||||
return mContentBoxSize;
|
||||
}
|
||||
void GetBorderBoxSize(nsTArray<RefPtr<ResizeObserverSize>>& aRetVal) const;
|
||||
void GetContentBoxSize(nsTArray<RefPtr<ResizeObserverSize>>& aRetVal) const;
|
||||
|
||||
// Set borderBoxSize.
|
||||
void SetBorderBoxSize(const nsSize& aSize);
|
||||
|
||||
@@ -84,7 +84,7 @@ private:
|
||||
nsIContent **outImageOrLinkNode,
|
||||
bool* outDragSelectedText);
|
||||
static already_AddRefed<nsIContent> FindParentLinkNode(nsIContent* inNode);
|
||||
static MOZ_MUST_USE nsresult
|
||||
static [[nodiscard]] nsresult
|
||||
GetAnchorURL(nsIContent* inNode, nsAString& outURL);
|
||||
static void GetNodeString(nsIContent* inNode, nsAString & outNodeString);
|
||||
static void CreateLinkText(const nsAString& inURL, const nsAString & inText,
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/CustomElementRegistry.h"
|
||||
#include "mozilla/dom/DocumentFragment.h"
|
||||
#include "mozilla/dom/DOMException.h"
|
||||
#include "mozilla/dom/DOMExceptionBinding.h"
|
||||
#include "mozilla/dom/DOMTypes.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/FileSystemSecurity.h"
|
||||
@@ -8733,6 +8735,25 @@ nsContentUtils::PushEnabled(JSContext* aCx, JSObject* aObj)
|
||||
return workerPrivate->PushEnabled();
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
nsContentUtils::StreamsEnabled(JSContext* aCx, JSObject* aObj)
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
return Preferences::GetBool("dom.streams.enabled", false);
|
||||
}
|
||||
|
||||
using namespace workers;
|
||||
|
||||
// Otherwise, check the pref via the WorkerPrivate
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
|
||||
if (!workerPrivate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return workerPrivate->StreamsEnabled();
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
nsContentUtils::IsNonSubresourceRequest(nsIChannel* aChannel)
|
||||
@@ -10060,3 +10081,72 @@ void nsContentUtils::StructuredClone(JSContext* aCx,
|
||||
nsTArray<RefPtr<MessagePort>> ports = holder.TakeTransferredPorts();
|
||||
Unused << ports;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsContentUtils::ExtractErrorValues(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue,
|
||||
nsACString& aSourceSpecOut,
|
||||
uint32_t* aLineOut,
|
||||
uint32_t* aColumnOut,
|
||||
nsString& aMessageOut)
|
||||
{
|
||||
MOZ_ASSERT(aLineOut);
|
||||
MOZ_ASSERT(aColumnOut);
|
||||
|
||||
if (aValue.isObject()) {
|
||||
JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
|
||||
RefPtr<dom::DOMException> domException;
|
||||
|
||||
// Try to process as an Error object. Use the file/line/column values
|
||||
// from the Error as they will be more specific to the root cause of
|
||||
// the problem.
|
||||
JSErrorReport* err = obj ? JS_ErrorFromException(aCx, obj) : nullptr;
|
||||
if (err) {
|
||||
// Use xpc to extract the error message only. We don't actually send
|
||||
// this report anywhere.
|
||||
RefPtr<xpc::ErrorReport> report = new xpc::ErrorReport();
|
||||
report->Init(err,
|
||||
"<unknown>", // toString result
|
||||
false, // chrome
|
||||
0); // window ID
|
||||
|
||||
if (!report->mFileName.IsEmpty()) {
|
||||
CopyUTF16toUTF8(report->mFileName, aSourceSpecOut);
|
||||
*aLineOut = report->mLineNumber;
|
||||
*aColumnOut = report->mColumn;
|
||||
}
|
||||
aMessageOut.Assign(report->mErrorMsg);
|
||||
}
|
||||
|
||||
// Next, try to unwrap the rejection value as a DOMException.
|
||||
else if(NS_SUCCEEDED(UNWRAP_OBJECT(DOMException, obj, domException))) {
|
||||
|
||||
nsAutoString filename;
|
||||
domException->GetFilename(aCx, filename);
|
||||
if (!filename.IsEmpty()) {
|
||||
CopyUTF16toUTF8(filename, aSourceSpecOut);
|
||||
*aLineOut = domException->LineNumber(aCx);
|
||||
*aColumnOut = domException->ColumnNumber();
|
||||
}
|
||||
|
||||
domException->GetName(aMessageOut);
|
||||
aMessageOut.AppendLiteral(": ");
|
||||
|
||||
nsAutoString message;
|
||||
domException->GetMessageMoz(message);
|
||||
aMessageOut.Append(message);
|
||||
}
|
||||
}
|
||||
|
||||
// If we could not unwrap a specific error type, then perform default safe
|
||||
// string conversions on primitives. Objects will result in "[Object]"
|
||||
// unfortunately.
|
||||
if (aMessageOut.IsEmpty()) {
|
||||
nsAutoJSString jsString;
|
||||
if (jsString.init(aCx, aValue)) {
|
||||
aMessageOut = jsString;
|
||||
} else {
|
||||
JS_ClearPendingException(aCx);
|
||||
}
|
||||
}
|
||||
}
|
||||
+26
-19
@@ -1010,6 +1010,10 @@ public:
|
||||
|
||||
static bool PrefetchEnabled(nsIDocShell* aDocShell);
|
||||
|
||||
static void ExtractErrorValues(JSContext* aCx, JS::Handle<JS::Value> aValue,
|
||||
nsACString& aSourceSpecOut, uint32_t *aLineOut,
|
||||
uint32_t *aColumnOut, nsString& aMessageOut);
|
||||
|
||||
static nsresult CalculateBufferSizeForImage(const uint32_t& aStride,
|
||||
const mozilla::gfx::IntSize& aImageSize,
|
||||
const mozilla::gfx::SurfaceFormat& aFormat,
|
||||
@@ -1504,9 +1508,10 @@ public:
|
||||
* @param aResult the result. Out param.
|
||||
* @return false on out of memory errors, true otherwise.
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
static bool GetNodeTextContent(nsINode* aNode, bool aDeep,
|
||||
nsAString& aResult, const mozilla::fallible_t&);
|
||||
[[nodiscard]] static bool GetNodeTextContent(nsINode* aNode,
|
||||
bool aDeep,
|
||||
nsAString& aResult,
|
||||
const mozilla::fallible_t&);
|
||||
|
||||
static void GetNodeTextContent(nsINode* aNode, bool aDeep,
|
||||
nsAString& aResult);
|
||||
@@ -1865,28 +1870,29 @@ public:
|
||||
*/
|
||||
static bool CanAccessNativeAnon();
|
||||
|
||||
MOZ_MUST_USE
|
||||
static nsresult WrapNative(JSContext *cx, nsISupports *native,
|
||||
const nsIID* aIID, JS::MutableHandle<JS::Value> vp,
|
||||
bool aAllowWrapping = true)
|
||||
[[nodiscard]] static nsresult WrapNative(JSContext* cx,
|
||||
nsISupports* native,
|
||||
const nsIID* aIID,
|
||||
JS::MutableHandle<JS::Value> vp,
|
||||
bool aAllowWrapping = true)
|
||||
{
|
||||
return WrapNative(cx, native, nullptr, aIID, vp, aAllowWrapping);
|
||||
}
|
||||
|
||||
// Same as the WrapNative above, but use this one if aIID is nsISupports' IID.
|
||||
MOZ_MUST_USE
|
||||
static nsresult WrapNative(JSContext *cx, nsISupports *native,
|
||||
JS::MutableHandle<JS::Value> vp,
|
||||
bool aAllowWrapping = true)
|
||||
[[nodiscard]] static nsresult WrapNative(JSContext* cx,
|
||||
nsISupports* native,
|
||||
JS::MutableHandle<JS::Value> vp,
|
||||
bool aAllowWrapping = true)
|
||||
{
|
||||
return WrapNative(cx, native, nullptr, nullptr, vp, aAllowWrapping);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE
|
||||
static nsresult WrapNative(JSContext *cx, nsISupports *native,
|
||||
nsWrapperCache *cache,
|
||||
JS::MutableHandle<JS::Value> vp,
|
||||
bool aAllowWrapping = true)
|
||||
[[nodiscard]] static nsresult WrapNative(JSContext* cx,
|
||||
nsISupports* native,
|
||||
nsWrapperCache* cache,
|
||||
JS::MutableHandle<JS::Value> vp,
|
||||
bool aAllowWrapping = true)
|
||||
{
|
||||
return WrapNative(cx, native, cache, nullptr, vp, aAllowWrapping);
|
||||
}
|
||||
@@ -1910,9 +1916,8 @@ public:
|
||||
* @param aString the string to convert the newlines inside [in/out]
|
||||
*/
|
||||
static void PlatformToDOMLineBreaks(nsString &aString);
|
||||
MOZ_MUST_USE
|
||||
static bool PlatformToDOMLineBreaks(nsString &aString,
|
||||
const mozilla::fallible_t&);
|
||||
[[nodiscard]] static bool PlatformToDOMLineBreaks(nsString &aString,
|
||||
const mozilla::fallible_t&);
|
||||
|
||||
/**
|
||||
* Populates aResultString with the contents of the string-buffer aBuf, up
|
||||
@@ -2679,6 +2684,8 @@ public:
|
||||
static mozilla::net::ReferrerPolicy GetReferrerPolicyFromHeader(const nsAString& aHeader);
|
||||
|
||||
static bool PushEnabled(JSContext* aCx, JSObject* aObj);
|
||||
|
||||
static bool StreamsEnabled(JSContext* aCx, JSObject* aObj);
|
||||
|
||||
static bool IsNonSubresourceRequest(nsIChannel* aChannel);
|
||||
|
||||
|
||||
@@ -4206,32 +4206,6 @@ nsDocument::SetScopeObject(nsIGlobalObject* aGlobal)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
static void
|
||||
CheckIfContainsEMEContent(nsISupports* aSupports, void* aContainsEME)
|
||||
{
|
||||
nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aSupports));
|
||||
if (domMediaElem) {
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(domMediaElem));
|
||||
MOZ_ASSERT(content, "aSupports is not a content");
|
||||
HTMLMediaElement* mediaElem = static_cast<HTMLMediaElement*>(content.get());
|
||||
bool* contains = static_cast<bool*>(aContainsEME);
|
||||
if (mediaElem->GetMediaKeys()) {
|
||||
*contains = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocument::ContainsEMEContent()
|
||||
{
|
||||
bool containsEME = false;
|
||||
EnumerateActivityObservers(CheckIfContainsEMEContent,
|
||||
static_cast<void*>(&containsEME));
|
||||
return containsEME;
|
||||
}
|
||||
#endif // MOZ_EME
|
||||
|
||||
static void
|
||||
CheckIfContainsMSEContent(nsISupports* aSupports, void* aContainsMSE)
|
||||
{
|
||||
@@ -8036,14 +8010,6 @@ nsDocument::CanSavePresentation(nsIRequest *aNewRequest)
|
||||
}
|
||||
#endif // MOZ_WEBRTC
|
||||
|
||||
#ifdef MOZ_EME
|
||||
// Don't save presentations for documents containing EME content, so that
|
||||
// CDMs reliably shutdown upon user navigation.
|
||||
if (ContainsEMEContent()) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Don't save presentations for documents containing MSE content, to
|
||||
// reduce memory usage.
|
||||
if (ContainsMSEContent()) {
|
||||
|
||||
@@ -1104,10 +1104,6 @@ public:
|
||||
|
||||
js::ExpandoAndGeneration mExpandoAndGeneration;
|
||||
|
||||
#ifdef MOZ_EME
|
||||
bool ContainsEMEContent();
|
||||
#endif
|
||||
|
||||
bool ContainsMSEContent();
|
||||
|
||||
protected:
|
||||
|
||||
@@ -144,9 +144,8 @@ public:
|
||||
virtual bool TextIsOnlyWhitespace() override;
|
||||
virtual bool HasTextForTranslation() override;
|
||||
virtual void AppendTextTo(nsAString& aResult) override;
|
||||
MOZ_MUST_USE
|
||||
virtual bool AppendTextTo(nsAString& aResult,
|
||||
const mozilla::fallible_t&) override;
|
||||
[[nodiscard]] virtual bool AppendTextTo(nsAString& aResult,
|
||||
const mozilla::fallible_t&) override;
|
||||
virtual void SaveSubtreeState() override;
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
+13
-23
@@ -4222,6 +4222,15 @@ nsGlobalWindow::GetPerformance()
|
||||
return AsInner()->GetPerformance();
|
||||
}
|
||||
|
||||
void
|
||||
nsPIDOMWindowInner::QueuePerformanceNavigationTiming()
|
||||
{
|
||||
CreatePerformanceObjectIfNeeded();
|
||||
if (mPerformance) {
|
||||
mPerformance->QueueNavigationTimingEntry();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsPIDOMWindowInner::CreatePerformanceObjectIfNeeded()
|
||||
{
|
||||
@@ -12685,41 +12694,22 @@ nsGlobalWindow::SetTimeout(JSContext* aCx, const nsAString& aHandler,
|
||||
return SetTimeoutOrInterval(aCx, aHandler, aTimeout, false, aError);
|
||||
}
|
||||
|
||||
static bool
|
||||
IsInterval(const Optional<int32_t>& aTimeout, int32_t& aResultTimeout)
|
||||
{
|
||||
if (aTimeout.WasPassed()) {
|
||||
aResultTimeout = aTimeout.Value();
|
||||
return true;
|
||||
}
|
||||
|
||||
// If no interval was specified, treat this like a timeout, to avoid setting
|
||||
// an interval of 0 milliseconds.
|
||||
aResultTimeout = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t
|
||||
nsGlobalWindow::SetInterval(JSContext* aCx, Function& aFunction,
|
||||
const Optional<int32_t>& aTimeout,
|
||||
const int32_t aTimeout,
|
||||
const Sequence<JS::Value>& aArguments,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
int32_t timeout;
|
||||
bool isInterval = IsInterval(aTimeout, timeout);
|
||||
return SetTimeoutOrInterval(aCx, aFunction, timeout, aArguments, isInterval,
|
||||
aError);
|
||||
return SetTimeoutOrInterval(aCx, aFunction, aTimeout, aArguments, true, aError);
|
||||
}
|
||||
|
||||
int32_t
|
||||
nsGlobalWindow::SetInterval(JSContext* aCx, const nsAString& aHandler,
|
||||
const Optional<int32_t>& aTimeout,
|
||||
const int32_t aTimeout,
|
||||
const Sequence<JS::Value>& /* unused */,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
int32_t timeout;
|
||||
bool isInterval = IsInterval(aTimeout, timeout);
|
||||
return SetTimeoutOrInterval(aCx, aHandler, timeout, isInterval, aError);
|
||||
return SetTimeoutOrInterval(aCx, aHandler, aTimeout, true, aError);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
||||
@@ -953,11 +953,11 @@ public:
|
||||
mozilla::ErrorResult& aError);
|
||||
void ClearTimeout(int32_t aHandle);
|
||||
int32_t SetInterval(JSContext* aCx, mozilla::dom::Function& aFunction,
|
||||
const mozilla::dom::Optional<int32_t>& aTimeout,
|
||||
const int32_t aTimeout,
|
||||
const mozilla::dom::Sequence<JS::Value>& aArguments,
|
||||
mozilla::ErrorResult& aError);
|
||||
int32_t SetInterval(JSContext* aCx, const nsAString& aHandler,
|
||||
const mozilla::dom::Optional<int32_t>& aTimeout,
|
||||
const int32_t aTimeout,
|
||||
const mozilla::dom::Sequence<JS::Value>& /* unused */,
|
||||
mozilla::ErrorResult& aError);
|
||||
void ClearInterval(int32_t aHandle);
|
||||
|
||||
@@ -37,18 +37,16 @@ class nsHTMLContentSerializer final : public nsXHTMLContentSerializer {
|
||||
nsAString& aStr) override;
|
||||
protected:
|
||||
|
||||
MOZ_MUST_USE
|
||||
virtual bool SerializeHTMLAttributes(nsIContent* aContent,
|
||||
nsIContent *aOriginalElement,
|
||||
nsAString& aTagPrefix,
|
||||
const nsAString& aTagNamespaceURI,
|
||||
nsIAtom* aTagName,
|
||||
int32_t aNamespace,
|
||||
nsAString& aStr);
|
||||
[[nodiscard]] virtual bool SerializeHTMLAttributes(nsIContent* aContent,
|
||||
nsIContent* aOriginalElement,
|
||||
nsAString& aTagPrefix,
|
||||
const nsAString& aTagNamespaceURI,
|
||||
nsIAtom* aTagName,
|
||||
int32_t aNamespace,
|
||||
nsAString& aStr);
|
||||
|
||||
MOZ_MUST_USE
|
||||
virtual bool AppendAndTranslateEntities(const nsAString& aStr,
|
||||
nsAString& aOutputStr) override;
|
||||
[[nodiscard]] virtual bool AppendAndTranslateEntities(const nsAString& aStr,
|
||||
nsAString& aOutputStr) override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -576,8 +576,7 @@ public:
|
||||
* Append the text content to aResult.
|
||||
* NOTE: This asserts and returns for elements
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
virtual bool AppendTextTo(nsAString& aResult, const mozilla::fallible_t&) = 0;
|
||||
[[nodiscard]] virtual bool AppendTextTo(nsAString& aResult, const mozilla::fallible_t&) = 0;
|
||||
|
||||
/**
|
||||
* Check if this content is focusable and in the current tab order.
|
||||
|
||||
@@ -2513,8 +2513,8 @@ public:
|
||||
mozilla::ErrorResult& rv);
|
||||
virtual mozilla::dom::DOMImplementation*
|
||||
GetImplementation(mozilla::ErrorResult& rv) = 0;
|
||||
MOZ_MUST_USE nsresult GetURL(nsString& retval) const;
|
||||
MOZ_MUST_USE nsresult GetDocumentURI(nsString& retval) const;
|
||||
[[nodiscard]] nsresult GetURL(nsString& retval) const;
|
||||
[[nodiscard]] nsresult GetDocumentURI(nsString& retval) const;
|
||||
// Return the URI for the document.
|
||||
// The returned value may differ if the document is loaded via XHR, and
|
||||
// when accessed from chrome privileged script and
|
||||
|
||||
+1
-1
@@ -1873,7 +1873,7 @@ public:
|
||||
aNodeName.SetStringBuffer(nsStringBuffer::FromString(nodeName),
|
||||
nodeName.Length());
|
||||
}
|
||||
MOZ_MUST_USE nsresult GetBaseURI(nsAString& aBaseURI) const;
|
||||
[[nodiscard]] nsresult GetBaseURI(nsAString& aBaseURI) const;
|
||||
// Return the base URI for the document.
|
||||
// The returned value may differ if the document is loaded via XHR, and
|
||||
// when accessed from chrome privileged script and
|
||||
|
||||
@@ -143,7 +143,7 @@ public:
|
||||
// After getting a notification that an off-thread compilation terminated,
|
||||
// this function will take the result of the parser and move it to the main
|
||||
// thread.
|
||||
MOZ_MUST_USE nsresult JoinCompile(void** aOffThreadToken);
|
||||
[[nodiscard]] nsresult JoinCompile(void** aOffThreadToken);
|
||||
|
||||
// Compile a script contained in a SourceText.
|
||||
nsresult Compile(JS::CompileOptions& aCompileOptions,
|
||||
@@ -167,7 +167,7 @@ public:
|
||||
JSScript* GetScript();
|
||||
|
||||
// Execute the compiled script and ignore the return value.
|
||||
MOZ_MUST_USE nsresult ExecScript();
|
||||
[[nodiscard]] nsresult ExecScript();
|
||||
|
||||
// Execute the compiled script a get the return value.
|
||||
//
|
||||
@@ -180,10 +180,10 @@ public:
|
||||
// compartment given as argument to the ExecutionContext constructor. If the
|
||||
// caller is in a different compartment, then the out-param value should be
|
||||
// wrapped by calling |JS_WrapValue|.
|
||||
MOZ_MUST_USE nsresult
|
||||
[[nodiscard]] nsresult
|
||||
ExtractReturnValue(JS::MutableHandle<JS::Value> aRetValue);
|
||||
|
||||
MOZ_MUST_USE nsresult ExecScript(JS::MutableHandle<JS::Value> aRetValue);
|
||||
[[nodiscard]] nsresult ExecScript(JS::MutableHandle<JS::Value> aRetValue);
|
||||
};
|
||||
|
||||
static nsresult CompileModule(JSContext* aCx,
|
||||
|
||||
@@ -382,7 +382,7 @@ class nsObjectLoadingContent : public nsImageLoadingContent
|
||||
void GetNestedParams(nsTArray<mozilla::dom::MozPluginParameter>& aParameters,
|
||||
bool aIgnoreCodebase);
|
||||
|
||||
MOZ_MUST_USE nsresult BuildParametersArray();
|
||||
[[nodiscard]] nsresult BuildParametersArray();
|
||||
|
||||
/**
|
||||
* Loads fallback content with the specified FallbackType
|
||||
|
||||
@@ -727,6 +727,8 @@ public:
|
||||
|
||||
mozilla::dom::Performance* GetPerformance();
|
||||
|
||||
void QueuePerformanceNavigationTiming();
|
||||
|
||||
bool HasMutationListeners(uint32_t aMutationEventType) const
|
||||
{
|
||||
if (!mOuterWindow) {
|
||||
|
||||
@@ -136,7 +136,7 @@ public:
|
||||
* Append the contents of this string fragment to aString
|
||||
* @return false if an out of memory condition is detected, true otherwise
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
bool AppendTo(nsAString& aString,
|
||||
const mozilla::fallible_t& aFallible) const {
|
||||
if (mState.mIs2b) {
|
||||
@@ -170,7 +170,7 @@ public:
|
||||
* @param aLength the length of the substring
|
||||
* @return false if an out of memory condition is detected, true otherwise
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
bool AppendTo(nsAString& aString, int32_t aOffset, int32_t aLength,
|
||||
const mozilla::fallible_t& aFallible) const
|
||||
{
|
||||
|
||||
@@ -46,7 +46,7 @@ class nsXHTMLContentSerializer : public nsXMLContentSerializer {
|
||||
nsAString& aStr,
|
||||
nsresult& aResult) override;
|
||||
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
virtual bool AfterElementStart(nsIContent* aContent,
|
||||
nsIContent* aOriginalElement,
|
||||
nsAString& aStr) override;
|
||||
@@ -70,7 +70,7 @@ class nsXHTMLContentSerializer : public nsXMLContentSerializer {
|
||||
virtual void MaybeEnterInPreContent(nsIContent* aNode) override;
|
||||
virtual void MaybeLeaveFromPreContent(nsIContent* aNode) override;
|
||||
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
virtual bool SerializeAttributes(nsIContent* aContent,
|
||||
nsIContent *aOriginalElement,
|
||||
nsAString& aTagPrefix,
|
||||
@@ -82,13 +82,13 @@ class nsXHTMLContentSerializer : public nsXMLContentSerializer {
|
||||
|
||||
bool IsFirstChildOfOL(nsIContent* aElement);
|
||||
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
bool SerializeLIValueAttribute(nsIContent* aElement,
|
||||
nsAString& aStr);
|
||||
bool IsShorthandAttr(const nsIAtom* aAttrName,
|
||||
const nsIAtom* aElementName);
|
||||
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
virtual bool AppendAndTranslateEntities(const nsAString& aStr,
|
||||
nsAString& aOutputStr) override;
|
||||
|
||||
|
||||
@@ -72,23 +72,21 @@ class nsXMLContentSerializer : public nsIContentSerializer {
|
||||
/**
|
||||
* Appends a char16_t character and increments the column position
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
bool AppendToString(const char16_t aChar,
|
||||
nsAString& aOutputStr);
|
||||
[[nodiscard]] bool AppendToString(const char16_t aChar,
|
||||
nsAString& aOutputStr);
|
||||
|
||||
/**
|
||||
* Appends a nsAString string and increments the column position
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
bool AppendToString(const nsAString& aStr,
|
||||
nsAString& aOutputStr);
|
||||
[[nodiscard]] bool AppendToString(const nsAString& aStr,
|
||||
nsAString& aOutputStr);
|
||||
|
||||
/**
|
||||
* Appends a string by replacing all line-endings
|
||||
* by mLineBreak, except in the case of raw output.
|
||||
* It increments the column position.
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
bool AppendToStringConvertLF(const nsAString& aStr,
|
||||
nsAString& aOutputStr);
|
||||
|
||||
@@ -96,7 +94,7 @@ class nsXMLContentSerializer : public nsIContentSerializer {
|
||||
* Appends a string by wrapping it when necessary.
|
||||
* It updates the column position.
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
bool AppendToStringWrapped(const nsASingleFragmentString& aStr,
|
||||
nsAString& aOutputStr);
|
||||
|
||||
@@ -104,12 +102,12 @@ class nsXMLContentSerializer : public nsIContentSerializer {
|
||||
* Appends a string by formating and wrapping it when necessary
|
||||
* It updates the column position.
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
bool AppendToStringFormatedWrapped(const nsASingleFragmentString& aStr,
|
||||
nsAString& aOutputStr);
|
||||
|
||||
// used by AppendToStringWrapped
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
bool AppendWrapped_WhitespaceSequence(
|
||||
nsASingleFragmentString::const_char_iterator &aPos,
|
||||
const nsASingleFragmentString::const_char_iterator aEnd,
|
||||
@@ -117,7 +115,7 @@ class nsXMLContentSerializer : public nsIContentSerializer {
|
||||
nsAString &aOutputStr);
|
||||
|
||||
// used by AppendToStringFormatedWrapped
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
bool AppendFormatedWrapped_WhitespaceSequence(
|
||||
nsASingleFragmentString::const_char_iterator &aPos,
|
||||
const nsASingleFragmentString::const_char_iterator aEnd,
|
||||
@@ -126,7 +124,7 @@ class nsXMLContentSerializer : public nsIContentSerializer {
|
||||
nsAString &aOutputStr);
|
||||
|
||||
// used by AppendToStringWrapped and AppendToStringFormatedWrapped
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
bool AppendWrapped_NonWhitespaceSequence(
|
||||
nsASingleFragmentString::const_char_iterator &aPos,
|
||||
const nsASingleFragmentString::const_char_iterator aEnd,
|
||||
@@ -139,7 +137,7 @@ class nsXMLContentSerializer : public nsIContentSerializer {
|
||||
* add mLineBreak to the string
|
||||
* It updates the column position and other flags.
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
bool AppendNewLineToString(nsAString& aOutputStr);
|
||||
|
||||
|
||||
@@ -147,7 +145,7 @@ class nsXMLContentSerializer : public nsIContentSerializer {
|
||||
* Appends a string by translating entities
|
||||
* It doesn't increment the column position
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
virtual bool AppendAndTranslateEntities(const nsAString& aStr,
|
||||
nsAString& aOutputStr);
|
||||
|
||||
@@ -197,7 +195,7 @@ class nsXMLContentSerializer : public nsIContentSerializer {
|
||||
nsIContent *aOriginalElement,
|
||||
const nsAString& aTagNamespaceURI);
|
||||
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
virtual bool SerializeAttributes(nsIContent* aContent,
|
||||
nsIContent *aOriginalElement,
|
||||
nsAString& aTagPrefix,
|
||||
@@ -207,7 +205,7 @@ class nsXMLContentSerializer : public nsIContentSerializer {
|
||||
uint32_t aSkipAttr,
|
||||
bool aAddNSAttr);
|
||||
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
bool SerializeAttr(const nsAString& aPrefix,
|
||||
const nsAString& aName,
|
||||
const nsAString& aValue,
|
||||
@@ -239,7 +237,7 @@ class nsXMLContentSerializer : public nsIContentSerializer {
|
||||
* aElement and aOriginalElement are the same as the corresponding arguments
|
||||
* to AppendElementStart.
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
bool AppendEndOfElementStart(mozilla::dom::Element* aEleemnt,
|
||||
mozilla::dom::Element* aOriginalElement,
|
||||
nsAString& aStr);
|
||||
@@ -249,7 +247,7 @@ class nsXMLContentSerializer : public nsIContentSerializer {
|
||||
* after the serialization ot the start tag.
|
||||
* (called at the end of AppendElementStart)
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
virtual bool AfterElementStart(nsIContent* aContent,
|
||||
nsIContent* aOriginalElement,
|
||||
nsAString& aStr) { return true; };
|
||||
@@ -299,17 +297,14 @@ class nsXMLContentSerializer : public nsIContentSerializer {
|
||||
* add intendation. Call only in the case of formating and if the current
|
||||
* position is at 0. It updates the column position.
|
||||
*/
|
||||
MOZ_MUST_USE
|
||||
bool AppendIndentation(nsAString& aStr);
|
||||
[[nodiscard]] bool AppendIndentation(nsAString& aStr);
|
||||
|
||||
MOZ_MUST_USE
|
||||
bool IncrIndentation(nsIAtom* aName);
|
||||
[[nodiscard]] bool IncrIndentation(nsIAtom* aName);
|
||||
void DecrIndentation(nsIAtom* aName);
|
||||
|
||||
// Functions to check for newlines that needs to be added between nodes in
|
||||
// the root of a document. See mAddNewlineForRootNode
|
||||
MOZ_MUST_USE
|
||||
bool MaybeAddNewlineForRootNode(nsAString& aStr);
|
||||
[[nodiscard]] bool MaybeAddNewlineForRootNode(nsAString& aStr);
|
||||
void MaybeFlagNewlineForRootNode(nsINode* aNode);
|
||||
|
||||
// Functions to check if we enter in or leave from a preformated content
|
||||
|
||||
@@ -103,11 +103,13 @@ DOMInterfaces = {
|
||||
},
|
||||
|
||||
'Cache': {
|
||||
'implicitJSContext': [ 'add', 'addAll' ],
|
||||
'implicitJSContext': [ 'add', 'addAll', 'match', 'matchAll', 'put',
|
||||
'delete', 'keys' ],
|
||||
'nativeType': 'mozilla::dom::cache::Cache',
|
||||
},
|
||||
|
||||
'CacheStorage': {
|
||||
'implicitJSContext': [ 'match' ],
|
||||
'nativeType': 'mozilla::dom::cache::CacheStorage',
|
||||
},
|
||||
|
||||
@@ -705,6 +707,7 @@ DOMInterfaces = {
|
||||
'headers': 'headers_',
|
||||
'referrerPolicy': 'referrerPolicy_'
|
||||
},
|
||||
'implicitJSContext': [ 'arrayBuffer', 'blob', 'formData', 'json', 'text' ],
|
||||
},
|
||||
|
||||
'ResizeObservation': {
|
||||
@@ -729,6 +732,8 @@ DOMInterfaces = {
|
||||
|
||||
'Response': {
|
||||
'binaryNames': { 'headers': 'headers_' },
|
||||
'implicitJSContext': [ 'arrayBuffer', 'blob', 'formData', 'json', 'text',
|
||||
'clone', 'cloneUnfiltered' ],
|
||||
},
|
||||
|
||||
'RGBColor': {
|
||||
|
||||
+90
-74
@@ -1156,7 +1156,10 @@ class CGHeaders(CGWrapper):
|
||||
# just include their header if we need to have functions
|
||||
# taking references to them declared in that header.
|
||||
headerSet = declareIncludes
|
||||
headerSet.add("mozilla/dom/TypedArray.h")
|
||||
if unrolled.isReadableStream():
|
||||
headerSet.add("mozilla/dom/ReadableStream.h")
|
||||
else:
|
||||
headerSet.add("mozilla/dom/TypedArray.h")
|
||||
else:
|
||||
try:
|
||||
typeDesc = config.getDescriptor(unrolled.inner.identifier.name)
|
||||
@@ -1371,7 +1374,10 @@ def UnionTypes(unionTypes, config):
|
||||
elif f.isInterface():
|
||||
if f.isSpiderMonkeyInterface():
|
||||
headers.add("jsfriendapi.h")
|
||||
headers.add("mozilla/dom/TypedArray.h")
|
||||
if f.isReadableStream():
|
||||
headers.add("mozilla/dom/ReadableStream.h")
|
||||
else:
|
||||
headers.add("mozilla/dom/TypedArray.h")
|
||||
else:
|
||||
try:
|
||||
typeDesc = config.getDescriptor(f.inner.identifier.name)
|
||||
@@ -1457,7 +1463,10 @@ def UnionConversions(unionTypes, config):
|
||||
elif f.isInterface():
|
||||
if f.isSpiderMonkeyInterface():
|
||||
headers.add("jsfriendapi.h")
|
||||
headers.add("mozilla/dom/TypedArray.h")
|
||||
if f.isReadableStream():
|
||||
headers.add("mozilla/dom/ReadableStream.h")
|
||||
else:
|
||||
headers.add("mozilla/dom/TypedArray.h")
|
||||
elif f.inner.isExternal():
|
||||
try:
|
||||
typeDesc = config.getDescriptor(f.inner.identifier.name)
|
||||
@@ -5582,8 +5591,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
if type.isSpiderMonkeyInterface():
|
||||
assert not isEnforceRange and not isClamp
|
||||
name = type.unroll().name # unroll() because it may be nullable
|
||||
arrayType = CGGeneric(name)
|
||||
declType = arrayType
|
||||
interfaceType = CGGeneric(name)
|
||||
declType = interfaceType
|
||||
if type.nullable():
|
||||
declType = CGTemplatedType("Nullable", declType)
|
||||
objRef = "${declName}.SetValue()"
|
||||
@@ -5607,22 +5616,23 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
# This is a bit annoying. In a union we don't want to have a
|
||||
# holder, since unions don't support that. But if we're optional we
|
||||
# want to have a holder, so that the callee doesn't see
|
||||
# Optional<RootedTypedArray<ArrayType> >. So do a holder if we're
|
||||
# optional and use a RootedTypedArray otherwise.
|
||||
# Optional<RootedSpiderMonkeyInterface<InterfaceType>>. So do a
|
||||
# holder if we're optional and use a RootedSpiderMonkeyInterface
|
||||
# otherwise.
|
||||
if isOptional:
|
||||
holderType = CGTemplatedType("TypedArrayRooter", arrayType)
|
||||
# If our typed array is nullable, this will set the Nullable to
|
||||
# be not-null, but that's ok because we make an explicit
|
||||
# SetNull() call on it as needed if our JS value is actually
|
||||
# null. XXXbz Because "Maybe" takes const refs for constructor
|
||||
# arguments, we can't pass a reference here; have to pass a
|
||||
# pointer.
|
||||
holderType = CGTemplatedType("SpiderMonkeyInterfaceRooter", interfaceType)
|
||||
# If our SpiderMonkey interface is nullable, this will set the
|
||||
# Nullable to be not-null, but that's ok because we make an
|
||||
# explicit SetNull() call on it as needed if our JS value is
|
||||
# actually null. XXXbz Because "Maybe" takes const refs for
|
||||
# constructor arguments, we can't pass a reference here; have
|
||||
# to pass a pointer.
|
||||
holderArgs = "cx, &%s" % objRef
|
||||
declArgs = None
|
||||
else:
|
||||
holderType = None
|
||||
holderArgs = None
|
||||
declType = CGTemplatedType("RootedTypedArray", declType)
|
||||
declType = CGTemplatedType("RootedSpiderMonkeyInterface", declType)
|
||||
declArgs = "cx"
|
||||
else:
|
||||
holderType = None
|
||||
@@ -6371,7 +6381,7 @@ def getMaybeWrapValueFuncForType(type):
|
||||
if type.nullable():
|
||||
return "MaybeWrapObjectOrNullValue"
|
||||
return "MaybeWrapObjectValue"
|
||||
# Spidermonkey interfaces are never DOM objects. Neither are sequences or
|
||||
# SpiderMonkey interfaces are never DOM objects. Neither are sequences or
|
||||
# dictionaries, since those are always plain JS objects.
|
||||
if type.isSpiderMonkeyInterface() or type.isDictionary() or type.isSequence():
|
||||
if type.nullable():
|
||||
@@ -6391,7 +6401,8 @@ recordWrapLevel = 0
|
||||
|
||||
|
||||
def getWrapTemplateForType(type, descriptorProvider, result, successCode,
|
||||
returnsNewObject, exceptionCode, typedArraysAreStructs,
|
||||
returnsNewObject, exceptionCode,
|
||||
spiderMonkeyInterfacesAreStructs,
|
||||
isConstructorRetval=False):
|
||||
"""
|
||||
Reflect a C++ value stored in "result", of IDL type "type" into JS. The
|
||||
@@ -6401,8 +6412,9 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
|
||||
doing a 'break' if the entire conversion template is inside a block that
|
||||
the 'break' will exit).
|
||||
|
||||
If typedArraysAreStructs is true, then if the type is a typed array,
|
||||
"result" is one of the dom::TypedArray subclasses, not a JSObject*.
|
||||
If spiderMonkeyInterfacesAreStructs is true, then if the type is a
|
||||
SpiderMonkey interface, "result" is one of the
|
||||
dom::SpiderMonkeyInterfaceObjectStorage subclasses, not a JSObject*.
|
||||
|
||||
The resulting string should be used with string.Template. It
|
||||
needs the following keys when substituting:
|
||||
@@ -6497,7 +6509,7 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
|
||||
recTemplate, recInfall = getWrapTemplateForType(type.inner, descriptorProvider,
|
||||
"%s.Value()" % result, successCode,
|
||||
returnsNewObject, exceptionCode,
|
||||
typedArraysAreStructs)
|
||||
spiderMonkeyInterfacesAreStructs)
|
||||
code = fill(
|
||||
"""
|
||||
|
||||
@@ -6529,7 +6541,7 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
|
||||
'returnsNewObject': returnsNewObject,
|
||||
'exceptionCode': exceptionCode,
|
||||
'obj': "returnArray",
|
||||
'typedArraysAreStructs': typedArraysAreStructs
|
||||
'spiderMonkeyInterfacesAreStructs': spiderMonkeyInterfacesAreStructs
|
||||
})
|
||||
sequenceWrapLevel -= 1
|
||||
code = fill(
|
||||
@@ -6583,7 +6595,7 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
|
||||
'returnsNewObject': returnsNewObject,
|
||||
'exceptionCode': exceptionCode,
|
||||
'obj': "returnObj",
|
||||
'typedArraysAreStructs': typedArraysAreStructs
|
||||
'spiderMonkeyInterfacesAreStructs': spiderMonkeyInterfacesAreStructs
|
||||
})
|
||||
recordWrapLevel -= 1
|
||||
if type.keyType.isByteString():
|
||||
@@ -6749,7 +6761,7 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
|
||||
return (head + _setValue(result, wrapAsType=type), False)
|
||||
|
||||
if (type.isObject() or (type.isSpiderMonkeyInterface() and
|
||||
not typedArraysAreStructs)):
|
||||
not spiderMonkeyInterfacesAreStructs)):
|
||||
# See comments in GetOrCreateDOMReflector explaining why we need
|
||||
# to wrap here.
|
||||
if type.nullable():
|
||||
@@ -6768,21 +6780,21 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
|
||||
|
||||
if not (type.isUnion() or type.isPrimitive() or type.isDictionary() or
|
||||
type.isDate() or
|
||||
(type.isSpiderMonkeyInterface() and typedArraysAreStructs)):
|
||||
(type.isSpiderMonkeyInterface() and spiderMonkeyInterfacesAreStructs)):
|
||||
raise TypeError("Need to learn to wrap %s" % type)
|
||||
|
||||
if type.nullable():
|
||||
recTemplate, recInfal = getWrapTemplateForType(type.inner, descriptorProvider,
|
||||
"%s.Value()" % result, successCode,
|
||||
returnsNewObject, exceptionCode,
|
||||
typedArraysAreStructs)
|
||||
spiderMonkeyInterfacesAreStructs)
|
||||
return ("if (%s.IsNull()) {\n" % result +
|
||||
indent(setNull()) +
|
||||
"}\n" +
|
||||
recTemplate, recInfal)
|
||||
|
||||
if type.isSpiderMonkeyInterface():
|
||||
assert typedArraysAreStructs
|
||||
assert spiderMonkeyInterfacesAreStructs
|
||||
# See comments in GetOrCreateDOMReflector explaining why we need
|
||||
# to wrap here.
|
||||
# NB: setObject(..., some-object-type) calls JS_WrapValue(), so is fallible
|
||||
@@ -6864,7 +6876,7 @@ def wrapForType(type, descriptorProvider, templateValues):
|
||||
templateValues.get('successCode', None),
|
||||
templateValues.get('returnsNewObject', False),
|
||||
templateValues.get('exceptionCode', "return false;\n"),
|
||||
templateValues.get('typedArraysAreStructs', False),
|
||||
templateValues.get('spiderMonkeyInterfacesAreStructs', False),
|
||||
isConstructorRetval=templateValues.get('isConstructorRetval', False))[0]
|
||||
|
||||
defaultValues = {'obj': 'obj'}
|
||||
@@ -8193,10 +8205,10 @@ class CGMethodCall(CGThing):
|
||||
# "object" arg.
|
||||
|
||||
# First grab all the overloads that have a non-callback interface
|
||||
# (which includes typed arrays and arraybuffers) at the
|
||||
# distinguishing index. We can also include the ones that have an
|
||||
# "object" here, since if those are present no other object-typed
|
||||
# argument will be.
|
||||
# (which includes SpiderMonkey interfaces) at the distinguishing
|
||||
# index. We can also include the ones that have an "object" here,
|
||||
# since if those are present no other object-typed argument will
|
||||
# be.
|
||||
objectSigs = [
|
||||
s for s in possibleSignatures
|
||||
if (distinguishingType(s).isObject() or
|
||||
@@ -8227,16 +8239,17 @@ class CGMethodCall(CGThing):
|
||||
# There might be more than one thing in objectSigs; we need to check
|
||||
# which ones we unwrap to.
|
||||
if len(objectSigs) > 0:
|
||||
# Here it's enough to guard on our argument being an object. The
|
||||
# code for unwrapping non-callback interfaces, typed arrays,
|
||||
# sequences, and Dates will just bail out and move on to
|
||||
# the next overload if the object fails to unwrap correctly,
|
||||
# while "object" accepts any object anyway. We could even not
|
||||
# do the isObject() check up front here, but in cases where we
|
||||
# have multiple object overloads it makes sense to do it only
|
||||
# once instead of for each overload. That will also allow the
|
||||
# unwrapping test to skip having to do codegen for the
|
||||
# null-or-undefined case, which we already handled above.
|
||||
# Here it's enough to guard on our argument being an object.
|
||||
# The code for unwrapping non-callback interfaces, spiderMonkey
|
||||
# interfaces, sequences, and Dates will just bail out and move
|
||||
# on to the next overload if the object fails to unwrap
|
||||
# correctly, while "object" accepts any object anyway. We
|
||||
# could even not do the isObject() check up front here, but in
|
||||
# cases where we have multiple object overloads it makes sense
|
||||
# to do it only once instead of for each overload. That will
|
||||
# also allow the unwrapping test to skip having to do codegen
|
||||
# for the null-or-undefined case, which we already handled
|
||||
# above.
|
||||
caseBody.append(CGGeneric("if (%s.isObject()) {\n" %
|
||||
distinguishingArg))
|
||||
for sig in objectSigs:
|
||||
@@ -10239,7 +10252,7 @@ class CGUnionStruct(CGThing):
|
||||
"jsvalHandle": "rval",
|
||||
"obj": "scopeObj",
|
||||
"result": val,
|
||||
"typedArraysAreStructs": True
|
||||
"spiderMonkeyInterfacesAreStructs": True
|
||||
})
|
||||
return CGGeneric(wrapCode)
|
||||
|
||||
@@ -13219,7 +13232,7 @@ class CGDictionary(CGThing):
|
||||
# 'obj' can just be allowed to be the string "obj", since that
|
||||
# will be our dictionary object, which is presumably itself in
|
||||
# the right scope.
|
||||
'typedArraysAreStructs': True
|
||||
'spiderMonkeyInterfacesAreStructs': True
|
||||
})
|
||||
conversion = CGGeneric(innerTemplate)
|
||||
conversion = CGWrapper(conversion,
|
||||
@@ -13679,7 +13692,7 @@ class ForwardDeclarationBuilder:
|
||||
except NoSuchDescriptorError:
|
||||
pass
|
||||
|
||||
# Note: Spidermonkey interfaces are typedefs, so can't be
|
||||
# Note: SpiderMonkey interfaces are typedefs, so can't be
|
||||
# forward-declared
|
||||
elif t.isPromise():
|
||||
self.addInMozillaDom("Promise")
|
||||
@@ -13988,7 +14001,7 @@ class CGBindingRoot(CGThing):
|
||||
return {desc.getDescriptor(desc.interface.parent.identifier.name)}
|
||||
for x in dependencySortObjects(jsImplemented, getParentDescriptor,
|
||||
lambda d: d.interface.identifier.name):
|
||||
cgthings.append(CGCallbackInterface(x, typedArraysAreStructs=True))
|
||||
cgthings.append(CGCallbackInterface(x, spiderMonkeyInterfacesAreStructs=True))
|
||||
cgthings.append(CGJSImplClass(x))
|
||||
|
||||
# And make sure we have the right number of newlines at the end
|
||||
@@ -14050,14 +14063,13 @@ class CGBindingRoot(CGThing):
|
||||
class CGNativeMember(ClassMethod):
|
||||
def __init__(self, descriptorProvider, member, name, signature, extendedAttrs,
|
||||
breakAfter=True, passJSBitsAsNeeded=True, visibility="public",
|
||||
typedArraysAreStructs=True, variadicIsSequence=False,
|
||||
resultNotAddRefed=False,
|
||||
virtual=False,
|
||||
override=False):
|
||||
spiderMonkeyInterfacesAreStructs=True,
|
||||
variadicIsSequence=False, resultNotAddRefed=False,
|
||||
virtual=False, override=False):
|
||||
"""
|
||||
If typedArraysAreStructs is false, typed arrays will be passed as
|
||||
JS::Handle<JSObject*>. If it's true they will be passed as one of the
|
||||
dom::TypedArray subclasses.
|
||||
If spiderMonkeyInterfacesAreStructs is false, SpiderMonkey interfaces
|
||||
will be passed as JS::Handle<JSObject*>. If it's true they will be
|
||||
passed as one of the dom::SpiderMonkeyInterfaceObjectStorage subclasses.
|
||||
|
||||
If passJSBitsAsNeeded is false, we don't automatically pass in a
|
||||
JSContext* or a JSObject* based on the return and argument types. We
|
||||
@@ -14068,7 +14080,7 @@ class CGNativeMember(ClassMethod):
|
||||
self.extendedAttrs = extendedAttrs
|
||||
self.resultAlreadyAddRefed = not resultNotAddRefed
|
||||
self.passJSBitsAsNeeded = passJSBitsAsNeeded
|
||||
self.typedArraysAreStructs = typedArraysAreStructs
|
||||
self.spiderMonkeyInterfacesAreStructs = spiderMonkeyInterfacesAreStructs
|
||||
self.variadicIsSequence = variadicIsSequence
|
||||
breakAfterSelf = "\n" if breakAfter else ""
|
||||
ClassMethod.__init__(self, name,
|
||||
@@ -14375,7 +14387,7 @@ class CGNativeMember(ClassMethod):
|
||||
False, False)
|
||||
|
||||
if type.isSpiderMonkeyInterface():
|
||||
if not self.typedArraysAreStructs:
|
||||
if not self.spiderMonkeyInterfacesAreStructs:
|
||||
return "JS::Handle<JSObject*>", False, False
|
||||
|
||||
# Unroll for the name, in case we're nullable.
|
||||
@@ -15547,16 +15559,16 @@ class CGFastCallback(CGClass):
|
||||
|
||||
|
||||
class CGCallbackInterface(CGCallback):
|
||||
def __init__(self, descriptor, typedArraysAreStructs=False):
|
||||
def __init__(self, descriptor, spiderMonkeyInterfacesAreStructs=False):
|
||||
iface = descriptor.interface
|
||||
attrs = [m for m in iface.members if m.isAttr() and not m.isStatic()]
|
||||
getters = [CallbackGetter(a, descriptor, typedArraysAreStructs)
|
||||
getters = [CallbackGetter(a, descriptor, spiderMonkeyInterfacesAreStructs)
|
||||
for a in attrs]
|
||||
setters = [CallbackSetter(a, descriptor, typedArraysAreStructs)
|
||||
setters = [CallbackSetter(a, descriptor, spiderMonkeyInterfacesAreStructs)
|
||||
for a in attrs if not a.readonly]
|
||||
methods = [m for m in iface.members
|
||||
if m.isMethod() and not m.isStatic() and not m.isIdentifierLess()]
|
||||
methods = [CallbackOperation(m, sig, descriptor, typedArraysAreStructs)
|
||||
methods = [CallbackOperation(m, sig, descriptor, spiderMonkeyInterfacesAreStructs)
|
||||
for m in methods for sig in m.signatures()]
|
||||
if iface.isJSImplemented() and iface.ctor():
|
||||
sigs = descriptor.interface.ctor().signatures()
|
||||
@@ -15601,7 +15613,8 @@ class CallbackMember(CGNativeMember):
|
||||
# CallSetup already handled the unmark-gray bits for us. we don't have
|
||||
# anything better to use for 'obj', really...
|
||||
def __init__(self, sig, name, descriptorProvider, needThisHandling,
|
||||
rethrowContentException=False, typedArraysAreStructs=False,
|
||||
rethrowContentException=False,
|
||||
spiderMonkeyInterfacesAreStructs=False,
|
||||
wrapScope='CallbackKnownNotGray()'):
|
||||
"""
|
||||
needThisHandling is True if we need to be able to accept a specified
|
||||
@@ -15636,7 +15649,7 @@ class CallbackMember(CGNativeMember):
|
||||
extendedAttrs={},
|
||||
passJSBitsAsNeeded=False,
|
||||
visibility=visibility,
|
||||
typedArraysAreStructs=typedArraysAreStructs)
|
||||
spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs)
|
||||
# We have to do all the generation of our body now, because
|
||||
# the caller relies on us throwing if we can't manage it.
|
||||
self.exceptionCode = ("aRv.Throw(NS_ERROR_UNEXPECTED);\n"
|
||||
@@ -15753,7 +15766,7 @@ class CallbackMember(CGNativeMember):
|
||||
'obj': self.wrapScope,
|
||||
'returnsNewObject': False,
|
||||
'exceptionCode': self.exceptionCode,
|
||||
'typedArraysAreStructs': self.typedArraysAreStructs
|
||||
'spiderMonkeyInterfacesAreStructs': self.spiderMonkeyInterfacesAreStructs
|
||||
})
|
||||
except MethodNotNewObjectError as err:
|
||||
raise TypeError("%s being passed as an argument to %s but is not "
|
||||
@@ -15857,10 +15870,11 @@ class CallbackMember(CGNativeMember):
|
||||
|
||||
class CallbackMethod(CallbackMember):
|
||||
def __init__(self, sig, name, descriptorProvider, needThisHandling,
|
||||
rethrowContentException=False, typedArraysAreStructs=False):
|
||||
rethrowContentException=False,
|
||||
spiderMonkeyInterfacesAreStructs=False):
|
||||
CallbackMember.__init__(self, sig, name, descriptorProvider,
|
||||
needThisHandling, rethrowContentException,
|
||||
typedArraysAreStructs=typedArraysAreStructs)
|
||||
spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs)
|
||||
|
||||
def getRvalDecl(self):
|
||||
return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
|
||||
@@ -15919,12 +15933,12 @@ class CallbackOperationBase(CallbackMethod):
|
||||
"""
|
||||
def __init__(self, signature, jsName, nativeName, descriptor,
|
||||
singleOperation, rethrowContentException=False,
|
||||
typedArraysAreStructs=False):
|
||||
spiderMonkeyInterfacesAreStructs=False):
|
||||
self.singleOperation = singleOperation
|
||||
self.methodName = descriptor.binaryNameFor(jsName)
|
||||
CallbackMethod.__init__(self, signature, nativeName, descriptor,
|
||||
singleOperation, rethrowContentException,
|
||||
typedArraysAreStructs=typedArraysAreStructs)
|
||||
spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs)
|
||||
|
||||
def getThisDecl(self):
|
||||
if not self.singleOperation:
|
||||
@@ -15975,7 +15989,8 @@ class CallbackOperation(CallbackOperationBase):
|
||||
"""
|
||||
Codegen actual WebIDL operations on callback interfaces.
|
||||
"""
|
||||
def __init__(self, method, signature, descriptor, typedArraysAreStructs):
|
||||
def __init__(self, method, signature, descriptor,
|
||||
spiderMonkeyInterfacesAreStructs):
|
||||
self.ensureASCIIName(method)
|
||||
self.method = method
|
||||
jsName = method.identifier.name
|
||||
@@ -15984,7 +15999,7 @@ class CallbackOperation(CallbackOperationBase):
|
||||
MakeNativeName(descriptor.binaryNameFor(jsName)),
|
||||
descriptor, descriptor.interface.isSingleOperationInterface(),
|
||||
rethrowContentException=descriptor.interface.isJSImplemented(),
|
||||
typedArraysAreStructs=typedArraysAreStructs)
|
||||
spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs)
|
||||
|
||||
def getPrettyName(self):
|
||||
return "%s.%s" % (self.descriptorProvider.interface.identifier.name,
|
||||
@@ -15995,13 +16010,14 @@ class CallbackAccessor(CallbackMember):
|
||||
"""
|
||||
Shared superclass for CallbackGetter and CallbackSetter.
|
||||
"""
|
||||
def __init__(self, attr, sig, name, descriptor, typedArraysAreStructs):
|
||||
def __init__(self, attr, sig, name, descriptor,
|
||||
spiderMonkeyInterfacesAreStructs):
|
||||
self.ensureASCIIName(attr)
|
||||
self.attrName = attr.identifier.name
|
||||
CallbackMember.__init__(self, sig, name, descriptor,
|
||||
needThisHandling=False,
|
||||
rethrowContentException=descriptor.interface.isJSImplemented(),
|
||||
typedArraysAreStructs=typedArraysAreStructs)
|
||||
spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs)
|
||||
|
||||
def getPrettyName(self):
|
||||
return "%s.%s" % (self.descriptorProvider.interface.identifier.name,
|
||||
@@ -16009,12 +16025,12 @@ class CallbackAccessor(CallbackMember):
|
||||
|
||||
|
||||
class CallbackGetter(CallbackAccessor):
|
||||
def __init__(self, attr, descriptor, typedArraysAreStructs):
|
||||
def __init__(self, attr, descriptor, spiderMonkeyInterfacesAreStructs):
|
||||
CallbackAccessor.__init__(self, attr,
|
||||
(attr.type, []),
|
||||
callbackGetterName(attr, descriptor),
|
||||
descriptor,
|
||||
typedArraysAreStructs)
|
||||
spiderMonkeyInterfacesAreStructs)
|
||||
|
||||
def getRvalDecl(self):
|
||||
return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
|
||||
@@ -16036,12 +16052,12 @@ class CallbackGetter(CallbackAccessor):
|
||||
|
||||
|
||||
class CallbackSetter(CallbackAccessor):
|
||||
def __init__(self, attr, descriptor, typedArraysAreStructs):
|
||||
def __init__(self, attr, descriptor, spiderMonkeyInterfacesAreStructs):
|
||||
CallbackAccessor.__init__(self, attr,
|
||||
(BuiltinTypes[IDLBuiltinType.Types.void],
|
||||
[FakeArgument(attr.type, attr)]),
|
||||
callbackSetterName(attr, descriptor),
|
||||
descriptor, typedArraysAreStructs)
|
||||
descriptor, spiderMonkeyInterfacesAreStructs)
|
||||
|
||||
def getRvalDecl(self):
|
||||
# We don't need an rval
|
||||
@@ -16076,7 +16092,7 @@ class CGJSImplInitOperation(CallbackOperationBase):
|
||||
"__init", "__Init", descriptor,
|
||||
singleOperation=False,
|
||||
rethrowContentException=True,
|
||||
typedArraysAreStructs=True)
|
||||
spiderMonkeyInterfacesAreStructs=True)
|
||||
|
||||
def getPrettyName(self):
|
||||
return "__init"
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/* -*- 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 mozilla_dom_ReadableStream_h
|
||||
#define mozilla_dom_ReadableStream_h
|
||||
|
||||
#include "mozilla/dom/SpiderMonkeyInterface.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct ReadableStream : public SpiderMonkeyInterfaceObjectStorage
|
||||
{
|
||||
inline bool Init(JSObject* obj)
|
||||
{
|
||||
MOZ_ASSERT(!inited());
|
||||
mImplObj = mWrappedObj = js::UnwrapReadableStream(obj);
|
||||
return inited();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_dom_ReadableStream_h */
|
||||
@@ -0,0 +1,144 @@
|
||||
/* -*- 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 mozilla_dom_SpiderMonkeyInterface_h
|
||||
#define mozilla_dom_SpiderMonkeyInterface_h
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/TracingAPI.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/*
|
||||
* Class that just handles the JSObject storage and tracing for spidermonkey
|
||||
* interfaces
|
||||
*/
|
||||
struct SpiderMonkeyInterfaceObjectStorage
|
||||
{
|
||||
protected:
|
||||
JSObject* mImplObj;
|
||||
JSObject* mWrappedObj;
|
||||
|
||||
SpiderMonkeyInterfaceObjectStorage()
|
||||
: mImplObj(nullptr),
|
||||
mWrappedObj(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
SpiderMonkeyInterfaceObjectStorage(SpiderMonkeyInterfaceObjectStorage&& aOther)
|
||||
: mImplObj(aOther.mImplObj),
|
||||
mWrappedObj(aOther.mWrappedObj)
|
||||
{
|
||||
aOther.mImplObj = nullptr;
|
||||
aOther.mWrappedObj = nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
inline void TraceSelf(JSTracer* trc)
|
||||
{
|
||||
JS::UnsafeTraceRoot(trc, &mImplObj, "SpiderMonkeyInterfaceObjectStorage.mImplObj");
|
||||
JS::UnsafeTraceRoot(trc, &mWrappedObj, "SpiderMonkeyInterfaceObjectStorage.mWrappedObj");
|
||||
}
|
||||
|
||||
inline bool inited() const
|
||||
{
|
||||
return !!mImplObj;
|
||||
}
|
||||
|
||||
inline bool WrapIntoNewCompartment(JSContext* cx)
|
||||
{
|
||||
return JS_WrapObject(cx,
|
||||
JS::MutableHandle<JSObject*>::fromMarkedLocation(&mWrappedObj));
|
||||
}
|
||||
|
||||
inline JSObject *Obj() const
|
||||
{
|
||||
MOZ_ASSERT(inited());
|
||||
return mWrappedObj;
|
||||
}
|
||||
|
||||
private:
|
||||
SpiderMonkeyInterfaceObjectStorage(const SpiderMonkeyInterfaceObjectStorage&) = delete;
|
||||
};
|
||||
|
||||
// A class for rooting an existing SpiderMonkey Interface struct
|
||||
template<typename InterfaceType>
|
||||
class MOZ_RAII SpiderMonkeyInterfaceRooter : private JS::CustomAutoRooter
|
||||
{
|
||||
public:
|
||||
template <typename CX>
|
||||
SpiderMonkeyInterfaceRooter(const CX& cx,
|
||||
InterfaceType* aInterface MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
|
||||
mInterface(aInterface)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void trace(JSTracer* trc) override
|
||||
{
|
||||
mInterface->TraceSelf(trc);
|
||||
}
|
||||
|
||||
private:
|
||||
SpiderMonkeyInterfaceObjectStorage* const mInterface;
|
||||
};
|
||||
|
||||
// And a specialization for dealing with nullable SpiderMonkey interfaces
|
||||
template<typename Inner> struct Nullable;
|
||||
template<typename InterfaceType>
|
||||
class MOZ_RAII SpiderMonkeyInterfaceRooter<Nullable<InterfaceType>> :
|
||||
private JS::CustomAutoRooter
|
||||
{
|
||||
public:
|
||||
template <typename CX>
|
||||
SpiderMonkeyInterfaceRooter(const CX& cx,
|
||||
Nullable<InterfaceType>* aInterface MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
|
||||
mInterface(aInterface)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void trace(JSTracer* trc) override
|
||||
{
|
||||
if (!mInterface->IsNull()) {
|
||||
mInterface->Value().TraceSelf(trc);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Nullable<InterfaceType>* const mInterface;
|
||||
};
|
||||
|
||||
// Class for easily setting up a rooted SpiderMonkey interface object on the
|
||||
// stack
|
||||
template<typename InterfaceType>
|
||||
class MOZ_RAII RootedSpiderMonkeyInterface final : public InterfaceType,
|
||||
private SpiderMonkeyInterfaceRooter<InterfaceType>
|
||||
{
|
||||
public:
|
||||
template <typename CX>
|
||||
explicit RootedSpiderMonkeyInterface(const CX& cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: InterfaceType(),
|
||||
SpiderMonkeyInterfaceRooter<InterfaceType>(cx, this
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename CX>
|
||||
RootedSpiderMonkeyInterface(const CX& cx, JSObject* obj MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: InterfaceType(obj),
|
||||
SpiderMonkeyInterfaceRooter<InterfaceType>(cx, this
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_dom_SpiderMonkeyInterface_h */
|
||||
+23
-23
@@ -24,7 +24,7 @@ class Promise;
|
||||
// JSContext.
|
||||
|
||||
// Accept strings.
|
||||
MOZ_MUST_USE bool
|
||||
[[nodiscard]] bool
|
||||
ToJSValue(JSContext* aCx,
|
||||
const nsAString& aArgument,
|
||||
JS::MutableHandle<JS::Value> aValue);
|
||||
@@ -35,7 +35,7 @@ ToJSValue(JSContext* aCx,
|
||||
// desirable. So make this a template that only gets used if the argument type
|
||||
// is actually boolean
|
||||
template<typename T>
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
typename EnableIf<IsSame<T, bool>::value, bool>::Type
|
||||
ToJSValue(JSContext* aCx,
|
||||
T aArgument,
|
||||
@@ -123,7 +123,7 @@ ToJSValue(JSContext* aCx,
|
||||
}
|
||||
|
||||
// Accept CallbackObjects
|
||||
MOZ_MUST_USE inline bool
|
||||
[[nodiscard]] inline bool
|
||||
ToJSValue(JSContext* aCx,
|
||||
CallbackObject& aArgument,
|
||||
JS::MutableHandle<JS::Value> aValue)
|
||||
@@ -139,7 +139,7 @@ ToJSValue(JSContext* aCx,
|
||||
// Accept objects that inherit from nsWrapperCache (e.g. most
|
||||
// DOM objects).
|
||||
template <class T>
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
typename EnableIf<IsBaseOf<nsWrapperCache, T>::value, bool>::Type
|
||||
ToJSValue(JSContext* aCx,
|
||||
T& aArgument,
|
||||
@@ -155,7 +155,7 @@ ToJSValue(JSContext* aCx,
|
||||
|
||||
// Accept typed arrays built from appropriate nsTArray values
|
||||
template<typename T>
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
typename EnableIf<IsBaseOf<AllTypedArraysBase, T>::value, bool>::Type
|
||||
ToJSValue(JSContext* aCx,
|
||||
const TypedArrayCreator<T>& aArgument,
|
||||
@@ -175,7 +175,7 @@ ToJSValue(JSContext* aCx,
|
||||
// Accept objects that inherit from nsISupports but not nsWrapperCache (e.g.
|
||||
// DOM File).
|
||||
template <class T>
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
typename EnableIf<!IsBaseOf<nsWrapperCache, T>::value &&
|
||||
!IsBaseOf<CallbackObject, T>::value &&
|
||||
IsBaseOf<nsISupports, T>::value, bool>::Type
|
||||
@@ -193,7 +193,7 @@ ToJSValue(JSContext* aCx,
|
||||
|
||||
// Accept nsRefPtr/nsCOMPtr
|
||||
template <typename T>
|
||||
MOZ_MUST_USE bool
|
||||
[[nodiscard]] bool
|
||||
ToJSValue(JSContext* aCx,
|
||||
const nsCOMPtr<T>& aArgument,
|
||||
JS::MutableHandle<JS::Value> aValue)
|
||||
@@ -202,7 +202,7 @@ ToJSValue(JSContext* aCx,
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MOZ_MUST_USE bool
|
||||
[[nodiscard]] bool
|
||||
ToJSValue(JSContext* aCx,
|
||||
const RefPtr<T>& aArgument,
|
||||
JS::MutableHandle<JS::Value> aValue)
|
||||
@@ -211,7 +211,7 @@ ToJSValue(JSContext* aCx,
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MOZ_MUST_USE bool
|
||||
[[nodiscard]] bool
|
||||
ToJSValue(JSContext* aCx,
|
||||
const NonNull<T>& aArgument,
|
||||
JS::MutableHandle<JS::Value> aValue)
|
||||
@@ -221,7 +221,7 @@ ToJSValue(JSContext* aCx,
|
||||
|
||||
// Accept WebIDL dictionaries
|
||||
template <class T>
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
typename EnableIf<IsBaseOf<DictionaryBase, T>::value, bool>::Type
|
||||
ToJSValue(JSContext* aCx,
|
||||
const T& aArgument,
|
||||
@@ -231,7 +231,7 @@ ToJSValue(JSContext* aCx,
|
||||
}
|
||||
|
||||
// Accept existing JS values (which may not be same-compartment with us
|
||||
MOZ_MUST_USE inline bool
|
||||
[[nodiscard]] inline bool
|
||||
ToJSValue(JSContext* aCx, JS::Handle<JS::Value> aArgument,
|
||||
JS::MutableHandle<JS::Value> aValue)
|
||||
{
|
||||
@@ -240,7 +240,7 @@ ToJSValue(JSContext* aCx, JS::Handle<JS::Value> aArgument,
|
||||
}
|
||||
|
||||
// Accept existing JS values on the Heap (which may not be same-compartment with us
|
||||
MOZ_MUST_USE inline bool
|
||||
[[nodiscard]] inline bool
|
||||
ToJSValue(JSContext* aCx, const JS::Heap<JS::Value>& aArgument,
|
||||
JS::MutableHandle<JS::Value> aValue)
|
||||
{
|
||||
@@ -249,7 +249,7 @@ ToJSValue(JSContext* aCx, const JS::Heap<JS::Value>& aArgument,
|
||||
}
|
||||
|
||||
// Accept existing rooted JS values (which may not be same-compartment with us
|
||||
MOZ_MUST_USE inline bool
|
||||
[[nodiscard]] inline bool
|
||||
ToJSValue(JSContext* aCx, const JS::Rooted<JS::Value>& aArgument,
|
||||
JS::MutableHandle<JS::Value> aValue)
|
||||
{
|
||||
@@ -259,7 +259,7 @@ ToJSValue(JSContext* aCx, const JS::Rooted<JS::Value>& aArgument,
|
||||
|
||||
// Accept existing rooted JS objects (which may not be same-compartment with
|
||||
// us).
|
||||
MOZ_MUST_USE inline bool
|
||||
[[nodiscard]] inline bool
|
||||
ToJSValue(JSContext* aCx, const JS::Rooted<JSObject*>& aArgument,
|
||||
JS::MutableHandle<JS::Value> aValue)
|
||||
{
|
||||
@@ -269,7 +269,7 @@ ToJSValue(JSContext* aCx, const JS::Rooted<JSObject*>& aArgument,
|
||||
|
||||
// Accept nsresult, for use in rejections, and create an XPCOM
|
||||
// exception object representing that nsresult.
|
||||
MOZ_MUST_USE bool
|
||||
[[nodiscard]] bool
|
||||
ToJSValue(JSContext* aCx,
|
||||
nsresult aArgument,
|
||||
JS::MutableHandle<JS::Value> aValue);
|
||||
@@ -277,14 +277,14 @@ ToJSValue(JSContext* aCx,
|
||||
// Accept ErrorResult, for use in rejections, and create an exception
|
||||
// representing the failure. Note, the ErrorResult must indicate a failure
|
||||
// with aArgument.Failure() returning true.
|
||||
MOZ_MUST_USE bool
|
||||
[[nodiscard]] bool
|
||||
ToJSValue(JSContext* aCx,
|
||||
ErrorResult& aArgument,
|
||||
JS::MutableHandle<JS::Value> aValue);
|
||||
|
||||
// Accept owning WebIDL unions.
|
||||
template <typename T>
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
typename EnableIf<IsBaseOf<AllOwningUnionBase, T>::value, bool>::Type
|
||||
ToJSValue(JSContext* aCx,
|
||||
const T& aArgument,
|
||||
@@ -296,7 +296,7 @@ ToJSValue(JSContext* aCx,
|
||||
|
||||
// Accept pointers to other things we accept
|
||||
template <typename T>
|
||||
MOZ_MUST_USE
|
||||
[[nodiscard]]
|
||||
typename EnableIf<IsPointer<T>::value, bool>::Type
|
||||
ToJSValue(JSContext* aCx,
|
||||
T aArgument,
|
||||
@@ -306,14 +306,14 @@ ToJSValue(JSContext* aCx,
|
||||
}
|
||||
|
||||
// Accept Promise objects, which need special handling.
|
||||
MOZ_MUST_USE bool
|
||||
[[nodiscard]] bool
|
||||
ToJSValue(JSContext* aCx,
|
||||
Promise& aArgument,
|
||||
JS::MutableHandle<JS::Value> aValue);
|
||||
|
||||
// Accept arrays of other things we accept
|
||||
template <typename T>
|
||||
MOZ_MUST_USE bool
|
||||
[[nodiscard]] bool
|
||||
ToJSValue(JSContext* aCx,
|
||||
T* aArguments,
|
||||
size_t aLength,
|
||||
@@ -340,7 +340,7 @@ ToJSValue(JSContext* aCx,
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MOZ_MUST_USE bool
|
||||
[[nodiscard]] bool
|
||||
ToJSValue(JSContext* aCx,
|
||||
const nsTArray<T>& aArgument,
|
||||
JS::MutableHandle<JS::Value> aValue)
|
||||
@@ -350,7 +350,7 @@ ToJSValue(JSContext* aCx,
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MOZ_MUST_USE bool
|
||||
[[nodiscard]] bool
|
||||
ToJSValue(JSContext* aCx,
|
||||
const FallibleTArray<T>& aArgument,
|
||||
JS::MutableHandle<JS::Value> aValue)
|
||||
@@ -360,7 +360,7 @@ ToJSValue(JSContext* aCx,
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
MOZ_MUST_USE bool
|
||||
[[nodiscard]] bool
|
||||
ToJSValue(JSContext* aCx,
|
||||
const T(&aArgument)[N],
|
||||
JS::MutableHandle<JS::Value> aValue)
|
||||
|
||||
+7
-127
@@ -6,51 +6,15 @@
|
||||
#ifndef mozilla_dom_TypedArray_h
|
||||
#define mozilla_dom_TypedArray_h
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/TracingAPI.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/SpiderMonkeyInterface.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/*
|
||||
* Class that just handles the JSObject storage and tracing for typed arrays
|
||||
*/
|
||||
struct TypedArrayObjectStorage : AllTypedArraysBase {
|
||||
protected:
|
||||
JSObject* mTypedObj;
|
||||
JSObject* mWrappedObj;
|
||||
|
||||
TypedArrayObjectStorage()
|
||||
: mTypedObj(nullptr),
|
||||
mWrappedObj(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
TypedArrayObjectStorage(TypedArrayObjectStorage&& aOther)
|
||||
: mTypedObj(aOther.mTypedObj),
|
||||
mWrappedObj(aOther.mWrappedObj)
|
||||
{
|
||||
aOther.mTypedObj = nullptr;
|
||||
aOther.mWrappedObj = nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
inline void TraceSelf(JSTracer* trc)
|
||||
{
|
||||
JS::UnsafeTraceRoot(trc, &mTypedObj, "TypedArray.mTypedObj");
|
||||
JS::UnsafeTraceRoot(trc, &mWrappedObj, "TypedArray.mWrappedObj");
|
||||
}
|
||||
|
||||
private:
|
||||
TypedArrayObjectStorage(const TypedArrayObjectStorage&) = delete;
|
||||
};
|
||||
|
||||
/*
|
||||
* Various typed array classes for argument conversion. We have a base class
|
||||
* that has a way of initializing a TypedArray from an existing typed array, and
|
||||
@@ -60,7 +24,9 @@ private:
|
||||
template<typename T,
|
||||
JSObject* UnwrapArray(JSObject*),
|
||||
void GetLengthAndDataAndSharedness(JSObject*, uint32_t*, bool*, T**)>
|
||||
struct TypedArray_base : public TypedArrayObjectStorage {
|
||||
struct TypedArray_base : public SpiderMonkeyInterfaceObjectStorage,
|
||||
AllTypedArraysBase
|
||||
{
|
||||
typedef T element_type;
|
||||
|
||||
TypedArray_base()
|
||||
@@ -72,7 +38,7 @@ struct TypedArray_base : public TypedArrayObjectStorage {
|
||||
}
|
||||
|
||||
TypedArray_base(TypedArray_base&& aOther)
|
||||
: TypedArrayObjectStorage(Move(aOther)),
|
||||
: SpiderMonkeyInterfaceObjectStorage(Move(aOther)),
|
||||
mData(aOther.mData),
|
||||
mLength(aOther.mLength),
|
||||
mShared(aOther.mShared),
|
||||
@@ -94,14 +60,10 @@ public:
|
||||
inline bool Init(JSObject* obj)
|
||||
{
|
||||
MOZ_ASSERT(!inited());
|
||||
mTypedObj = mWrappedObj = UnwrapArray(obj);
|
||||
mImplObj = mWrappedObj = UnwrapArray(obj);
|
||||
return inited();
|
||||
}
|
||||
|
||||
inline bool inited() const {
|
||||
return !!mTypedObj;
|
||||
}
|
||||
|
||||
// About shared memory:
|
||||
//
|
||||
// Any DOM TypedArray as well as any DOM ArrayBufferView that does
|
||||
@@ -173,22 +135,11 @@ public:
|
||||
return mLength;
|
||||
}
|
||||
|
||||
inline JSObject *Obj() const {
|
||||
MOZ_ASSERT(inited());
|
||||
return mWrappedObj;
|
||||
}
|
||||
|
||||
inline bool WrapIntoNewCompartment(JSContext* cx)
|
||||
{
|
||||
return JS_WrapObject(cx,
|
||||
JS::MutableHandle<JSObject*>::fromMarkedLocation(&mWrappedObj));
|
||||
}
|
||||
|
||||
inline void ComputeLengthAndData() const
|
||||
{
|
||||
MOZ_ASSERT(inited());
|
||||
MOZ_ASSERT(!mComputed);
|
||||
GetLengthAndDataAndSharedness(mTypedObj, &mLength, &mShared, &mData);
|
||||
GetLengthAndDataAndSharedness(mImplObj, &mLength, &mShared, &mData);
|
||||
mComputed = true;
|
||||
}
|
||||
|
||||
@@ -363,77 +314,6 @@ class TypedArrayCreator
|
||||
const ArrayType& mArray;
|
||||
};
|
||||
|
||||
// A class for rooting an existing TypedArray struct
|
||||
template<typename ArrayType>
|
||||
class MOZ_RAII TypedArrayRooter : private JS::CustomAutoRooter
|
||||
{
|
||||
public:
|
||||
template <typename CX>
|
||||
TypedArrayRooter(const CX& cx,
|
||||
ArrayType* aArray MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
|
||||
JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
|
||||
mArray(aArray)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void trace(JSTracer* trc) override
|
||||
{
|
||||
mArray->TraceSelf(trc);
|
||||
}
|
||||
|
||||
private:
|
||||
TypedArrayObjectStorage* const mArray;
|
||||
};
|
||||
|
||||
// And a specialization for dealing with nullable typed arrays
|
||||
template<typename Inner> struct Nullable;
|
||||
template<typename ArrayType>
|
||||
class MOZ_RAII TypedArrayRooter<Nullable<ArrayType> > :
|
||||
private JS::CustomAutoRooter
|
||||
{
|
||||
public:
|
||||
template <typename CX>
|
||||
TypedArrayRooter(const CX& cx,
|
||||
Nullable<ArrayType>* aArray MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
|
||||
JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
|
||||
mArray(aArray)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void trace(JSTracer* trc) override
|
||||
{
|
||||
if (!mArray->IsNull()) {
|
||||
mArray->Value().TraceSelf(trc);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Nullable<ArrayType>* const mArray;
|
||||
};
|
||||
|
||||
// Class for easily setting up a rooted typed array object on the stack
|
||||
template<typename ArrayType>
|
||||
class MOZ_RAII RootedTypedArray final : public ArrayType,
|
||||
private TypedArrayRooter<ArrayType>
|
||||
{
|
||||
public:
|
||||
template <typename CX>
|
||||
explicit RootedTypedArray(const CX& cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
|
||||
ArrayType(),
|
||||
TypedArrayRooter<ArrayType>(cx, this
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename CX>
|
||||
RootedTypedArray(const CX& cx, JSObject* obj MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
|
||||
ArrayType(obj),
|
||||
TypedArrayRooter<ArrayType>(cx, this
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
@@ -38,9 +38,11 @@ EXPORTS.mozilla.dom += [
|
||||
'NonRefcountedDOMObject.h',
|
||||
'Nullable.h',
|
||||
'PrimitiveConversions.h',
|
||||
'ReadableStream.h',
|
||||
'Record.h',
|
||||
'RootedDictionary.h',
|
||||
'SimpleGlobalObject.h',
|
||||
'SpiderMonkeyInterface.h',
|
||||
'StructuredClone.h',
|
||||
'ToJSValue.h',
|
||||
'TypedArray.h',
|
||||
|
||||
@@ -2054,6 +2054,9 @@ class IDLType(IDLObject):
|
||||
def isRecord(self):
|
||||
return False
|
||||
|
||||
def isReadableStream(self):
|
||||
return False
|
||||
|
||||
def isArrayBuffer(self):
|
||||
return False
|
||||
|
||||
@@ -2081,12 +2084,12 @@ class IDLType(IDLObject):
|
||||
|
||||
def isSpiderMonkeyInterface(self):
|
||||
""" Returns a boolean indicating whether this type is an 'interface'
|
||||
type that is implemented in Spidermonkey. At the moment, this
|
||||
only returns true for the types from the TypedArray spec. """
|
||||
type that is implemented in SpiderMonkey. """
|
||||
return self.isInterface() and (self.isArrayBuffer() or
|
||||
self.isArrayBufferView() or
|
||||
self.isSharedArrayBuffer() or
|
||||
self.isTypedArray())
|
||||
self.isTypedArray() or
|
||||
self.isReadableStream())
|
||||
|
||||
def isDictionary(self):
|
||||
return False
|
||||
@@ -2275,6 +2278,9 @@ class IDLNullableType(IDLParameterizedType):
|
||||
def isRecord(self):
|
||||
return self.inner.isRecord()
|
||||
|
||||
def isReadableStream(self):
|
||||
return self.inner.isReadableStream()
|
||||
|
||||
def isArrayBuffer(self):
|
||||
return self.inner.isArrayBuffer()
|
||||
|
||||
@@ -2634,6 +2640,9 @@ class IDLTypedefType(IDLType):
|
||||
def isRecord(self):
|
||||
return self.inner.isRecord()
|
||||
|
||||
def isReadableStream(self):
|
||||
return self.inner.isReadableStream()
|
||||
|
||||
def isDictionary(self):
|
||||
return self.inner.isDictionary()
|
||||
|
||||
@@ -2945,7 +2954,8 @@ class IDLBuiltinType(IDLType):
|
||||
'Int32Array',
|
||||
'Uint32Array',
|
||||
'Float32Array',
|
||||
'Float64Array'
|
||||
'Float64Array',
|
||||
'ReadableStream',
|
||||
)
|
||||
|
||||
TagLookup = {
|
||||
@@ -2980,7 +2990,8 @@ class IDLBuiltinType(IDLType):
|
||||
Types.Int32Array: IDLType.Tags.interface,
|
||||
Types.Uint32Array: IDLType.Tags.interface,
|
||||
Types.Float32Array: IDLType.Tags.interface,
|
||||
Types.Float64Array: IDLType.Tags.interface
|
||||
Types.Float64Array: IDLType.Tags.interface,
|
||||
Types.ReadableStream: IDLType.Tags.interface,
|
||||
}
|
||||
|
||||
def __init__(self, location, name, type):
|
||||
@@ -3027,6 +3038,9 @@ class IDLBuiltinType(IDLType):
|
||||
return (self._typeTag >= IDLBuiltinType.Types.Int8Array and
|
||||
self._typeTag <= IDLBuiltinType.Types.Float64Array)
|
||||
|
||||
def isReadableStream(self):
|
||||
return self._typeTag == IDLBuiltinType.Types.ReadableStream
|
||||
|
||||
def isInterface(self):
|
||||
# TypedArray things are interface types per the TypedArray spec,
|
||||
# but we handle them as builtins because SpiderMonkey implements
|
||||
@@ -3034,7 +3048,8 @@ class IDLBuiltinType(IDLType):
|
||||
return (self.isArrayBuffer() or
|
||||
self.isArrayBufferView() or
|
||||
self.isSharedArrayBuffer() or
|
||||
self.isTypedArray())
|
||||
self.isTypedArray() or
|
||||
self.isReadableStream())
|
||||
|
||||
def isNonCallbackInterface(self):
|
||||
# All the interfaces we can be are non-callback
|
||||
@@ -3104,6 +3119,7 @@ class IDLBuiltinType(IDLType):
|
||||
# that's not an ArrayBuffer or a callback interface
|
||||
(self.isArrayBuffer() and not other.isArrayBuffer()) or
|
||||
(self.isSharedArrayBuffer() and not other.isSharedArrayBuffer()) or
|
||||
(self.isReadableStream() and not other.isReadableStream()) or
|
||||
# ArrayBufferView is distinguishable from everything
|
||||
# that's not an ArrayBufferView or typed array.
|
||||
(self.isArrayBufferView() and not other.isArrayBufferView() and
|
||||
@@ -3213,7 +3229,10 @@ BuiltinTypes = {
|
||||
IDLBuiltinType.Types.Float32Array),
|
||||
IDLBuiltinType.Types.Float64Array:
|
||||
IDLBuiltinType(BuiltinLocation("<builtin type>"), "Float64Array",
|
||||
IDLBuiltinType.Types.Float64Array)
|
||||
IDLBuiltinType.Types.Float64Array),
|
||||
IDLBuiltinType.Types.ReadableStream:
|
||||
IDLBuiltinType(BuiltinLocation("<builtin type>"), "ReadableStream",
|
||||
IDLBuiltinType.Types.ReadableStream),
|
||||
}
|
||||
|
||||
|
||||
@@ -5232,7 +5251,8 @@ class Tokenizer(object):
|
||||
"maplike": "MAPLIKE",
|
||||
"setlike": "SETLIKE",
|
||||
"iterable": "ITERABLE",
|
||||
"namespace": "NAMESPACE"
|
||||
"namespace": "NAMESPACE",
|
||||
"ReadableStream": "READABLESTREAM",
|
||||
}
|
||||
|
||||
tokens.extend(keywords.values())
|
||||
@@ -6420,6 +6440,7 @@ class Parser(Tokenizer):
|
||||
NonAnyType : PrimitiveType Null
|
||||
| ARRAYBUFFER Null
|
||||
| SHAREDARRAYBUFFER Null
|
||||
| READABLESTREAM Null
|
||||
| OBJECT Null
|
||||
"""
|
||||
if p[1] == "object":
|
||||
@@ -6428,6 +6449,8 @@ class Parser(Tokenizer):
|
||||
type = BuiltinTypes[IDLBuiltinType.Types.ArrayBuffer]
|
||||
elif p[1] == "SharedArrayBuffer":
|
||||
type = BuiltinTypes[IDLBuiltinType.Types.SharedArrayBuffer]
|
||||
elif p[1] == "ReadableStream":
|
||||
type = BuiltinTypes[IDLBuiltinType.Types.ReadableStream]
|
||||
else:
|
||||
type = BuiltinTypes[p[1]]
|
||||
|
||||
|
||||
Vendored
+4
-4
@@ -289,9 +289,9 @@ MatchInPutList(InternalRequest* aRequest,
|
||||
} // namespace
|
||||
|
||||
void
|
||||
AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
SchemeAction aSchemeAction, Response& aResponse,
|
||||
ErrorResult& aRv)
|
||||
AutoChildOpArgs::Add(JSContext* aCx, InternalRequest* aRequest,
|
||||
BodyAction aBodyAction, SchemeAction aSchemeAction,
|
||||
Response& aResponse, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mSent);
|
||||
|
||||
@@ -329,7 +329,7 @@ AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
mTypeUtils->ToCacheRequest(pair.request(), aRequest, aBodyAction,
|
||||
aSchemeAction, mStreamCleanupList, aRv);
|
||||
if (!aRv.Failed()) {
|
||||
mTypeUtils->ToCacheResponse(pair.response(), aResponse,
|
||||
mTypeUtils->ToCacheResponse(aCx, pair.response(), aResponse,
|
||||
mStreamCleanupList, aRv);
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -55,7 +55,7 @@ public:
|
||||
|
||||
void Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
SchemeAction aSchemeAction, ErrorResult& aRv);
|
||||
void Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
void Add(JSContext* aCx, InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
SchemeAction aSchemeAction, Response& aResponse, ErrorResult& aRv);
|
||||
|
||||
const CacheOpArgs& SendAsOpArgs();
|
||||
|
||||
Vendored
+23
-17
@@ -184,7 +184,10 @@ public:
|
||||
|
||||
// Now store the unwrapped Response list in the Cache.
|
||||
ErrorResult result;
|
||||
RefPtr<Promise> put = mCache->PutAll(mRequestList, responseList, result);
|
||||
// TODO: Here we use the JSContext as received by the ResolvedCallback, and
|
||||
// its state could be the wrong one. The spec doesn't say anything
|
||||
// about it, yet (bug 1384006)
|
||||
RefPtr<Promise> put = mCache->PutAll(aCx, mRequestList, responseList, result);
|
||||
if (NS_WARN_IF(result.Failed())) {
|
||||
// TODO: abort the fetch requests we have running (bug 1157434)
|
||||
mPromise->MaybeReject(result);
|
||||
@@ -245,7 +248,7 @@ Cache::Cache(nsIGlobalObject* aGlobal, CacheChild* aActor)
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Cache::Match(const RequestOrUSVString& aRequest,
|
||||
Cache::Match(JSContext* aCx, const RequestOrUSVString& aRequest,
|
||||
const CacheQueryOptions& aOptions, ErrorResult& aRv)
|
||||
{
|
||||
if (NS_WARN_IF(!mActor)) {
|
||||
@@ -255,7 +258,8 @@ Cache::Match(const RequestOrUSVString& aRequest,
|
||||
|
||||
CacheChild::AutoLock actorLock(mActor);
|
||||
|
||||
RefPtr<InternalRequest> ir = ToInternalRequest(aRequest, IgnoreBody, aRv);
|
||||
RefPtr<InternalRequest> ir =
|
||||
ToInternalRequest(aCx, aRequest, IgnoreBody, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -274,7 +278,7 @@ Cache::Match(const RequestOrUSVString& aRequest,
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Cache::MatchAll(const Optional<RequestOrUSVString>& aRequest,
|
||||
Cache::MatchAll(JSContext* aCx, const Optional<RequestOrUSVString>& aRequest,
|
||||
const CacheQueryOptions& aOptions, ErrorResult& aRv)
|
||||
{
|
||||
if (NS_WARN_IF(!mActor)) {
|
||||
@@ -290,8 +294,8 @@ Cache::MatchAll(const Optional<RequestOrUSVString>& aRequest,
|
||||
AutoChildOpArgs args(this, CacheMatchAllArgs(void_t(), params), 1);
|
||||
|
||||
if (aRequest.WasPassed()) {
|
||||
RefPtr<InternalRequest> ir = ToInternalRequest(aRequest.Value(),
|
||||
IgnoreBody, aRv);
|
||||
RefPtr<InternalRequest> ir = ToInternalRequest(aCx, aRequest.Value(),
|
||||
IgnoreBody, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -390,8 +394,8 @@ Cache::AddAll(JSContext* aContext,
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Cache::Put(const RequestOrUSVString& aRequest, Response& aResponse,
|
||||
ErrorResult& aRv)
|
||||
Cache::Put(JSContext* aCx, const RequestOrUSVString& aRequest,
|
||||
Response& aResponse, ErrorResult& aRv)
|
||||
{
|
||||
if (NS_WARN_IF(!mActor)) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
@@ -404,14 +408,14 @@ Cache::Put(const RequestOrUSVString& aRequest, Response& aResponse,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<InternalRequest> ir = ToInternalRequest(aRequest, ReadBody, aRv);
|
||||
RefPtr<InternalRequest> ir = ToInternalRequest(aCx, aRequest, ReadBody, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AutoChildOpArgs args(this, CachePutAllArgs(), 1);
|
||||
|
||||
args.Add(ir, ReadBody, TypeErrorOnInvalidScheme,
|
||||
args.Add(aCx, ir, ReadBody, TypeErrorOnInvalidScheme,
|
||||
aResponse, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
@@ -421,7 +425,7 @@ Cache::Put(const RequestOrUSVString& aRequest, Response& aResponse,
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Cache::Delete(const RequestOrUSVString& aRequest,
|
||||
Cache::Delete(JSContext* aCx, const RequestOrUSVString& aRequest,
|
||||
const CacheQueryOptions& aOptions, ErrorResult& aRv)
|
||||
{
|
||||
if (NS_WARN_IF(!mActor)) {
|
||||
@@ -431,7 +435,8 @@ Cache::Delete(const RequestOrUSVString& aRequest,
|
||||
|
||||
CacheChild::AutoLock actorLock(mActor);
|
||||
|
||||
RefPtr<InternalRequest> ir = ToInternalRequest(aRequest, IgnoreBody, aRv);
|
||||
RefPtr<InternalRequest> ir =
|
||||
ToInternalRequest(aCx, aRequest, IgnoreBody, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -450,7 +455,7 @@ Cache::Delete(const RequestOrUSVString& aRequest,
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Cache::Keys(const Optional<RequestOrUSVString>& aRequest,
|
||||
Cache::Keys(JSContext* aCx, const Optional<RequestOrUSVString>& aRequest,
|
||||
const CacheQueryOptions& aOptions, ErrorResult& aRv)
|
||||
{
|
||||
if (NS_WARN_IF(!mActor)) {
|
||||
@@ -466,8 +471,8 @@ Cache::Keys(const Optional<RequestOrUSVString>& aRequest,
|
||||
AutoChildOpArgs args(this, CacheKeysArgs(void_t(), params), 1);
|
||||
|
||||
if (aRequest.WasPassed()) {
|
||||
RefPtr<InternalRequest> ir = ToInternalRequest(aRequest.Value(),
|
||||
IgnoreBody, aRv);
|
||||
RefPtr<InternalRequest> ir =
|
||||
ToInternalRequest(aCx, aRequest.Value(), IgnoreBody, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -627,7 +632,7 @@ Cache::AddAll(const GlobalObject& aGlobal,
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Cache::PutAll(const nsTArray<RefPtr<Request>>& aRequestList,
|
||||
Cache::PutAll(JSContext* aCx, const nsTArray<RefPtr<Request>>& aRequestList,
|
||||
const nsTArray<RefPtr<Response>>& aResponseList,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
@@ -644,7 +649,8 @@ Cache::PutAll(const nsTArray<RefPtr<Request>>& aRequestList,
|
||||
|
||||
for (uint32_t i = 0; i < aRequestList.Length(); ++i) {
|
||||
RefPtr<InternalRequest> ir = aRequestList[i]->GetInternalRequest();
|
||||
args.Add(ir, ReadBody, TypeErrorOnInvalidScheme, *aResponseList[i], aRv);
|
||||
args.Add(aCx, ir, ReadBody, TypeErrorOnInvalidScheme, *aResponseList[i],
|
||||
aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Vendored
+8
-8
@@ -43,10 +43,10 @@ public:
|
||||
|
||||
// webidl interface methods
|
||||
already_AddRefed<Promise>
|
||||
Match(const RequestOrUSVString& aRequest, const CacheQueryOptions& aOptions,
|
||||
ErrorResult& aRv);
|
||||
Match(JSContext* aCx, const RequestOrUSVString& aRequest,
|
||||
const CacheQueryOptions& aOptions, ErrorResult& aRv);
|
||||
already_AddRefed<Promise>
|
||||
MatchAll(const Optional<RequestOrUSVString>& aRequest,
|
||||
MatchAll(JSContext* aCx, const Optional<RequestOrUSVString>& aRequest,
|
||||
const CacheQueryOptions& aOptions, ErrorResult& aRv);
|
||||
already_AddRefed<Promise>
|
||||
Add(JSContext* aContext, const RequestOrUSVString& aRequest,
|
||||
@@ -55,13 +55,13 @@ public:
|
||||
AddAll(JSContext* aContext,
|
||||
const Sequence<OwningRequestOrUSVString>& aRequests, ErrorResult& aRv);
|
||||
already_AddRefed<Promise>
|
||||
Put(const RequestOrUSVString& aRequest, Response& aResponse,
|
||||
Put(JSContext* aCx, const RequestOrUSVString& aRequest, Response& aResponse,
|
||||
ErrorResult& aRv);
|
||||
already_AddRefed<Promise>
|
||||
Delete(const RequestOrUSVString& aRequest, const CacheQueryOptions& aOptions,
|
||||
ErrorResult& aRv);
|
||||
Delete(JSContext* aCx, const RequestOrUSVString& aRequest,
|
||||
const CacheQueryOptions& aOptions, ErrorResult& aRv);
|
||||
already_AddRefed<Promise>
|
||||
Keys(const Optional<RequestOrUSVString>& aRequest,
|
||||
Keys(JSContext* aCx, const Optional<RequestOrUSVString>& aRequest,
|
||||
const CacheQueryOptions& aParams, ErrorResult& aRv);
|
||||
|
||||
// binding methods
|
||||
@@ -100,7 +100,7 @@ private:
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
PutAll(const nsTArray<RefPtr<Request>>& aRequestList,
|
||||
PutAll(JSContext* aCx, const nsTArray<RefPtr<Request>>& aRequestList,
|
||||
const nsTArray<RefPtr<Response>>& aResponseList,
|
||||
ErrorResult& aRv);
|
||||
|
||||
|
||||
Vendored
+10
-2
@@ -74,7 +74,11 @@ CacheOpChild::CacheOpChild(CacheWorkerHolder* aWorkerHolder,
|
||||
MOZ_DIAGNOSTIC_ASSERT(mPromise);
|
||||
|
||||
MOZ_ASSERT_IF(!NS_IsMainThread(), aWorkerHolder);
|
||||
SetWorkerHolder(aWorkerHolder);
|
||||
RefPtr<CacheWorkerHolder> workerHolder =
|
||||
CacheWorkerHolder::PreferBehavior(aWorkerHolder,
|
||||
CacheWorkerHolder::PreventIdleShutdownStart);
|
||||
|
||||
SetWorkerHolder(workerHolder);
|
||||
}
|
||||
|
||||
CacheOpChild::~CacheOpChild()
|
||||
@@ -165,7 +169,11 @@ CacheOpChild::Recv__delete__(const ErrorResult& aRv,
|
||||
break;
|
||||
}
|
||||
|
||||
actor->SetWorkerHolder(GetWorkerHolder());
|
||||
RefPtr<CacheWorkerHolder> workerHolder =
|
||||
CacheWorkerHolder::PreferBehavior(GetWorkerHolder(),
|
||||
CacheWorkerHolder::AllowIdleShutdownStart);
|
||||
|
||||
actor->SetWorkerHolder(workerHolder);
|
||||
RefPtr<Cache> cache = new Cache(mGlobal, actor);
|
||||
mPromise->MaybeResolve(cache);
|
||||
break;
|
||||
|
||||
Vendored
+5
-4
@@ -204,7 +204,8 @@ CacheStorage::CreateOnWorker(Namespace aNamespace, nsIGlobalObject* aGlobal,
|
||||
}
|
||||
|
||||
RefPtr<CacheWorkerHolder> workerHolder =
|
||||
CacheWorkerHolder::Create(aWorkerPrivate);
|
||||
CacheWorkerHolder::Create(aWorkerPrivate,
|
||||
CacheWorkerHolder::AllowIdleShutdownStart);
|
||||
if (!workerHolder) {
|
||||
NS_WARNING("Worker thread is shutting down.");
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
@@ -315,7 +316,7 @@ CacheStorage::CacheStorage(nsresult aFailureResult)
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
CacheStorage::Match(const RequestOrUSVString& aRequest,
|
||||
CacheStorage::Match(JSContext* aCx, const RequestOrUSVString& aRequest,
|
||||
const CacheQueryOptions& aOptions, ErrorResult& aRv)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||
@@ -325,8 +326,8 @@ CacheStorage::Match(const RequestOrUSVString& aRequest,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<InternalRequest> request = ToInternalRequest(aRequest, IgnoreBody,
|
||||
aRv);
|
||||
RefPtr<InternalRequest> request =
|
||||
ToInternalRequest(aCx, aRequest, IgnoreBody, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Vendored
+3
-3
@@ -59,9 +59,9 @@ public:
|
||||
DefineCaches(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
|
||||
|
||||
// webidl interface methods
|
||||
already_AddRefed<Promise> Match(const RequestOrUSVString& aRequest,
|
||||
const CacheQueryOptions& aOptions,
|
||||
ErrorResult& aRv);
|
||||
already_AddRefed<Promise>
|
||||
Match(JSContext* aCx, const RequestOrUSVString& aRequest,
|
||||
const CacheQueryOptions& aOptions, ErrorResult& aRv);
|
||||
already_AddRefed<Promise> Has(const nsAString& aKey, ErrorResult& aRv);
|
||||
already_AddRefed<Promise> Open(const nsAString& aKey, ErrorResult& aRv);
|
||||
already_AddRefed<Promise> Delete(const nsAString& aKey, ErrorResult& aRv);
|
||||
|
||||
Vendored
+27
-4
@@ -18,11 +18,11 @@ using mozilla::dom::workers::WorkerPrivate;
|
||||
|
||||
// static
|
||||
already_AddRefed<CacheWorkerHolder>
|
||||
CacheWorkerHolder::Create(WorkerPrivate* aWorkerPrivate)
|
||||
CacheWorkerHolder::Create(WorkerPrivate* aWorkerPrivate, Behavior aBehavior)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate);
|
||||
|
||||
RefPtr<CacheWorkerHolder> workerHolder = new CacheWorkerHolder();
|
||||
RefPtr<CacheWorkerHolder> workerHolder = new CacheWorkerHolder(aBehavior);
|
||||
if (NS_WARN_IF(!workerHolder->HoldWorker(aWorkerPrivate, Terminating))) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -30,6 +30,28 @@ CacheWorkerHolder::Create(WorkerPrivate* aWorkerPrivate)
|
||||
return workerHolder.forget();
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<CacheWorkerHolder>
|
||||
CacheWorkerHolder::PreferBehavior(CacheWorkerHolder* aCurrentHolder,
|
||||
Behavior aBehavior)
|
||||
{
|
||||
if (!aCurrentHolder) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<CacheWorkerHolder> orig = aCurrentHolder;
|
||||
if (orig->GetBehavior() == aBehavior) {
|
||||
return orig.forget();
|
||||
}
|
||||
|
||||
RefPtr<CacheWorkerHolder> replace = Create(orig->mWorkerPrivate, aBehavior);
|
||||
if (!replace) {
|
||||
return orig.forget();
|
||||
}
|
||||
|
||||
return replace.forget();
|
||||
}
|
||||
|
||||
void
|
||||
CacheWorkerHolder::AddActor(ActorChild* aActor)
|
||||
{
|
||||
@@ -88,8 +110,9 @@ CacheWorkerHolder::Notify(Status aStatus)
|
||||
return true;
|
||||
}
|
||||
|
||||
CacheWorkerHolder::CacheWorkerHolder()
|
||||
: mNotified(false)
|
||||
CacheWorkerHolder::CacheWorkerHolder(Behavior aBehavior)
|
||||
: WorkerHolder(aBehavior)
|
||||
, mNotified(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Vendored
+6
-2
@@ -25,7 +25,11 @@ class CacheWorkerHolder final : public workers::WorkerHolder
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<CacheWorkerHolder>
|
||||
Create(workers::WorkerPrivate* aWorkerPrivate);
|
||||
Create(workers::WorkerPrivate* aWorkerPrivate,
|
||||
Behavior aBehavior);
|
||||
|
||||
static already_AddRefed<CacheWorkerHolder>
|
||||
PreferBehavior(CacheWorkerHolder* aCurrentHolder, Behavior aBehavior);
|
||||
|
||||
void AddActor(ActorChild* aActor);
|
||||
void RemoveActor(ActorChild* aActor);
|
||||
@@ -36,7 +40,7 @@ public:
|
||||
virtual bool Notify(workers::Status aStatus) override;
|
||||
|
||||
private:
|
||||
CacheWorkerHolder();
|
||||
explicit CacheWorkerHolder(Behavior aBehavior);
|
||||
~CacheWorkerHolder();
|
||||
|
||||
nsTArray<ActorChild*> mActorList;
|
||||
|
||||
Vendored
+17
-10
@@ -79,7 +79,7 @@ ToHeadersEntryList(nsTArray<HeadersEntry>& aOut, InternalHeaders* aHeaders)
|
||||
} // namespace
|
||||
|
||||
already_AddRefed<InternalRequest>
|
||||
TypeUtils::ToInternalRequest(const RequestOrUSVString& aIn,
|
||||
TypeUtils::ToInternalRequest(JSContext* aCx, const RequestOrUSVString& aIn,
|
||||
BodyAction aBodyAction, ErrorResult& aRv)
|
||||
{
|
||||
if (aIn.IsRequest()) {
|
||||
@@ -87,7 +87,7 @@ TypeUtils::ToInternalRequest(const RequestOrUSVString& aIn,
|
||||
|
||||
// Check and set bodyUsed flag immediately because its on Request
|
||||
// instead of InternalRequest.
|
||||
CheckAndSetBodyUsed(&request, aBodyAction, aRv);
|
||||
CheckAndSetBodyUsed(aCx, &request, aBodyAction, aRv);
|
||||
if (aRv.Failed()) { return nullptr; }
|
||||
|
||||
return request.GetInternalRequest();
|
||||
@@ -97,7 +97,8 @@ TypeUtils::ToInternalRequest(const RequestOrUSVString& aIn,
|
||||
}
|
||||
|
||||
already_AddRefed<InternalRequest>
|
||||
TypeUtils::ToInternalRequest(const OwningRequestOrUSVString& aIn,
|
||||
TypeUtils::ToInternalRequest(JSContext* aCx,
|
||||
const OwningRequestOrUSVString& aIn,
|
||||
BodyAction aBodyAction, ErrorResult& aRv)
|
||||
{
|
||||
|
||||
@@ -106,7 +107,7 @@ TypeUtils::ToInternalRequest(const OwningRequestOrUSVString& aIn,
|
||||
|
||||
// Check and set bodyUsed flag immediately because its on Request
|
||||
// instead of InternalRequest.
|
||||
CheckAndSetBodyUsed(request, aBodyAction, aRv);
|
||||
CheckAndSetBodyUsed(aCx, request, aBodyAction, aRv);
|
||||
if (aRv.Failed()) { return nullptr; }
|
||||
|
||||
return request->GetInternalRequest();
|
||||
@@ -189,7 +190,7 @@ TypeUtils::ToCacheResponseWithoutBody(CacheResponse& aOut,
|
||||
aOut.statusText() = aIn.GetUnfilteredStatusText();
|
||||
RefPtr<InternalHeaders> headers = aIn.UnfilteredHeaders();
|
||||
MOZ_DIAGNOSTIC_ASSERT(headers);
|
||||
if (HasVaryStar(headers)) {
|
||||
if (aIn.Type() != ResponseType::Opaque && HasVaryStar(headers)) {
|
||||
aRv.ThrowTypeError<MSG_RESPONSE_HAS_VARY_STAR>();
|
||||
return;
|
||||
}
|
||||
@@ -204,7 +205,7 @@ TypeUtils::ToCacheResponseWithoutBody(CacheResponse& aOut,
|
||||
}
|
||||
|
||||
void
|
||||
TypeUtils::ToCacheResponse(CacheResponse& aOut, Response& aIn,
|
||||
TypeUtils::ToCacheResponse(JSContext* aCx, CacheResponse& aOut, Response& aIn,
|
||||
nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
@@ -222,7 +223,10 @@ TypeUtils::ToCacheResponse(CacheResponse& aOut, Response& aIn,
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
ir->GetUnfilteredBody(getter_AddRefs(stream));
|
||||
if (stream) {
|
||||
aIn.SetBodyUsed();
|
||||
aIn.SetBodyUsed(aCx, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SerializeCacheStream(stream, &aOut.body(), aStreamCleanupList, aRv);
|
||||
@@ -426,8 +430,8 @@ TypeUtils::ProcessURL(nsACString& aUrl, bool* aSchemeValidOut,
|
||||
}
|
||||
|
||||
void
|
||||
TypeUtils::CheckAndSetBodyUsed(Request* aRequest, BodyAction aBodyAction,
|
||||
ErrorResult& aRv)
|
||||
TypeUtils::CheckAndSetBodyUsed(JSContext* aCx, Request* aRequest,
|
||||
BodyAction aBodyAction, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(aRequest);
|
||||
|
||||
@@ -443,7 +447,10 @@ TypeUtils::CheckAndSetBodyUsed(Request* aRequest, BodyAction aBodyAction,
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
aRequest->GetBody(getter_AddRefs(stream));
|
||||
if (stream) {
|
||||
aRequest->SetBodyUsed();
|
||||
aRequest->SetBodyUsed(aCx, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vendored
+6
-6
@@ -73,12 +73,12 @@ public:
|
||||
GetIPCManager() = 0;
|
||||
|
||||
already_AddRefed<InternalRequest>
|
||||
ToInternalRequest(const RequestOrUSVString& aIn, BodyAction aBodyAction,
|
||||
ErrorResult& aRv);
|
||||
ToInternalRequest(JSContext* aCx, const RequestOrUSVString& aIn,
|
||||
BodyAction aBodyAction, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<InternalRequest>
|
||||
ToInternalRequest(const OwningRequestOrUSVString& aIn, BodyAction aBodyAction,
|
||||
ErrorResult& aRv);
|
||||
ToInternalRequest(JSContext* aCx, const OwningRequestOrUSVString& aIn,
|
||||
BodyAction aBodyAction, ErrorResult& aRv);
|
||||
|
||||
void
|
||||
ToCacheRequest(CacheRequest& aOut, InternalRequest* aIn,
|
||||
@@ -91,7 +91,7 @@ public:
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
ToCacheResponse(CacheResponse& aOut, Response& aIn,
|
||||
ToCacheResponse(JSContext* aCx, CacheResponse& aOut, Response& aIn,
|
||||
nsTArray<UniquePtr<mozilla::ipc::AutoIPCStream>>& aStreamCleanupList,
|
||||
ErrorResult& aRv);
|
||||
|
||||
@@ -133,7 +133,7 @@ public:
|
||||
|
||||
private:
|
||||
void
|
||||
CheckAndSetBodyUsed(Request* aRequest, BodyAction aBodyAction,
|
||||
CheckAndSetBodyUsed(JSContext* aCx, Request* aRequest, BodyAction aBodyAction,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<InternalRequest>
|
||||
|
||||
@@ -2974,8 +2974,8 @@ ValidateRect(double& aX, double& aY, double& aWidth, double& aHeight, bool aIsZe
|
||||
// The values of canvas API input are in double precision, but Moz2D APIs are
|
||||
// using float precision. Bypass canvas API calls when the input is out of
|
||||
// float precision to avoid precision problem
|
||||
if (!std::isfinite((float)aX) | !std::isfinite((float)aY) |
|
||||
!std::isfinite((float)aWidth) | !std::isfinite((float)aHeight)) {
|
||||
if (!std::isfinite((float)aX) || !std::isfinite((float)aY) ||
|
||||
!std::isfinite((float)aWidth) || !std::isfinite((float)aHeight)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -5012,13 +5012,6 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
if (video->ContainsRestrictedContent()) {
|
||||
aError.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t readyState;
|
||||
if (NS_SUCCEEDED(video->GetReadyState(&readyState)) &&
|
||||
readyState < nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA) {
|
||||
@@ -5959,7 +5952,7 @@ void
|
||||
CanvasRenderingContext2D::PutImageData(ImageData& aImageData, double aDx,
|
||||
double aDy, ErrorResult& aError)
|
||||
{
|
||||
RootedTypedArray<Uint8ClampedArray> arr(RootingCx());
|
||||
RootedSpiderMonkeyInterface<Uint8ClampedArray> arr(RootingCx());
|
||||
DebugOnly<bool> inited = arr.Init(aImageData.GetDataObject());
|
||||
MOZ_ASSERT(inited);
|
||||
|
||||
@@ -5975,7 +5968,7 @@ CanvasRenderingContext2D::PutImageData(ImageData& aImageData, double aDx,
|
||||
double aDirtyHeight,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
RootedTypedArray<Uint8ClampedArray> arr(RootingCx());
|
||||
RootedSpiderMonkeyInterface<Uint8ClampedArray> arr(RootingCx());
|
||||
DebugOnly<bool> inited = arr.Init(aImageData.GetDataObject());
|
||||
MOZ_ASSERT(inited);
|
||||
|
||||
|
||||
@@ -929,7 +929,7 @@ ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, ImageData& aImageData,
|
||||
const Maybe<IntRect>& aCropRect, ErrorResult& aRv)
|
||||
{
|
||||
// Copy data into SourceSurface.
|
||||
RootedTypedArray<Uint8ClampedArray> array(RootingCx());
|
||||
RootedSpiderMonkeyInterface<Uint8ClampedArray> array(RootingCx());
|
||||
DebugOnly<bool> inited = array.Init(aImageData.GetDataObject());
|
||||
MOZ_ASSERT(inited);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "gfxPrefs.h"
|
||||
#include "GLContextTypes.h"
|
||||
#include "GLDefs.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
@@ -1397,6 +1398,7 @@ protected:
|
||||
CheckedUint32 mGeneration;
|
||||
|
||||
WebGLContextOptions mOptions;
|
||||
const uint32_t mMaxVertIdsPerDraw = gfxPrefs::WebglMaxVertIDsPerDraw();
|
||||
|
||||
bool mInvalidated;
|
||||
bool mCapturedFrameInvalidated;
|
||||
|
||||
@@ -607,6 +607,12 @@ WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei vertCount,
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (vertCount > mMaxVertIdsPerDraw) {
|
||||
ErrorOutOfMemory(
|
||||
"Context's max vertCount is %u, but %u requested. [webgl.max-vert-ids-per-draw]", mMaxVertIdsPerDraw, vertCount);
|
||||
return;
|
||||
}
|
||||
|
||||
bool error = false;
|
||||
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
|
||||
@@ -849,6 +855,12 @@ WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei vertCount, GLenum type,
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (vertCount > mMaxVertIdsPerDraw) {
|
||||
ErrorOutOfMemory(
|
||||
"Context's max vertCount is %u, but %u requested. [webgl.max-vert-ids-per-draw]", mMaxVertIdsPerDraw, vertCount);
|
||||
return;
|
||||
}
|
||||
|
||||
bool error = false;
|
||||
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "angle/ShaderLang.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/gfx/Logging.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "MurmurHash3.h"
|
||||
#include "nsPrintfCString.h"
|
||||
@@ -135,9 +136,13 @@ ShaderOutput(gl::GLContext* gl)
|
||||
case 420: return SH_GLSL_420_CORE_OUTPUT;
|
||||
case 430: return SH_GLSL_430_CORE_OUTPUT;
|
||||
case 440: return SH_GLSL_440_CORE_OUTPUT;
|
||||
case 450: return SH_GLSL_450_CORE_OUTPUT;
|
||||
default:
|
||||
MOZ_ASSERT(false, "GFX: Unexpected GLSL version.");
|
||||
if (version >= 450) {
|
||||
// "OpenGL 4.6 is also guaranteed to support all previous versions of the
|
||||
// OpenGL Shading Language back to version 1.10."
|
||||
return SH_GLSL_450_CORE_OUTPUT;
|
||||
}
|
||||
gfxCriticalNote << "Unexpected GLSL version: " << version;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -475,7 +475,7 @@ WebGLTexture::TexImage(const char* funcName, TexImageTarget target, GLint level,
|
||||
GLsizei depth, GLint border, const webgl::PackingInfo& pi,
|
||||
const TexImageSource& src)
|
||||
{
|
||||
dom::RootedTypedArray<dom::Uint8ClampedArray> scopedArr(dom::RootingCx());
|
||||
dom::RootedSpiderMonkeyInterface<dom::Uint8ClampedArray> scopedArr(dom::RootingCx());
|
||||
const auto blob = ValidateTexOrSubImage(mContext, funcName, target, width, height,
|
||||
depth, border, pi, src, &scopedArr);
|
||||
if (!blob)
|
||||
@@ -491,7 +491,7 @@ WebGLTexture::TexSubImage(const char* funcName, TexImageTarget target, GLint lev
|
||||
const webgl::PackingInfo& pi, const TexImageSource& src)
|
||||
{
|
||||
const GLint border = 0;
|
||||
dom::RootedTypedArray<dom::Uint8ClampedArray> scopedArr(dom::RootingCx());
|
||||
dom::RootedSpiderMonkeyInterface<dom::Uint8ClampedArray> scopedArr(dom::RootingCx());
|
||||
const auto blob = ValidateTexOrSubImage(mContext, funcName, target, width, height,
|
||||
depth, border, pi, src, &scopedArr);
|
||||
if (!blob)
|
||||
|
||||
@@ -1366,7 +1366,7 @@ public:
|
||||
mDataIsJwk = false;
|
||||
|
||||
// Try ArrayBuffer
|
||||
RootedTypedArray<ArrayBuffer> ab(aCx);
|
||||
RootedSpiderMonkeyInterface<ArrayBuffer> ab(aCx);
|
||||
if (ab.Init(aKeyData)) {
|
||||
if (!mKeyData.Assign(ab)) {
|
||||
mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
|
||||
@@ -1375,7 +1375,7 @@ public:
|
||||
}
|
||||
|
||||
// Try ArrayBufferView
|
||||
RootedTypedArray<ArrayBufferView> abv(aCx);
|
||||
RootedSpiderMonkeyInterface<ArrayBufferView> abv(aCx);
|
||||
if (abv.Init(aKeyData)) {
|
||||
if (!mKeyData.Assign(abv)) {
|
||||
mEarlyRv = NS_ERROR_DOM_OPERATION_ERR;
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/* -*- 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 "BodyExtractor.h"
|
||||
#include "mozilla/dom/EncodingUtils.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FormData.h"
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
#include "mozilla/dom/URLSearchParams.h"
|
||||
#include "mozilla/dom/XMLHttpRequest.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDOMSerializer.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIStorageStream.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "nsIUnicodeEncoder.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
static nsresult
|
||||
GetBufferDataAsStream(const uint8_t* aData, uint32_t aDataLength,
|
||||
nsIInputStream** aResult, uint64_t* aContentLength,
|
||||
nsACString& aContentType, nsACString& aCharset)
|
||||
{
|
||||
aContentType.SetIsVoid(true);
|
||||
aCharset.Truncate();
|
||||
|
||||
*aContentLength = aDataLength;
|
||||
const char* data = reinterpret_cast<const char*>(aData);
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream), data, aDataLength,
|
||||
NS_ASSIGNMENT_COPY);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
stream.forget(aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
template<> nsresult
|
||||
BodyExtractor<const ArrayBuffer>::GetAsStream(nsIInputStream** aResult,
|
||||
uint64_t* aContentLength,
|
||||
nsACString& aContentTypeWithCharset,
|
||||
nsACString& aCharset) const
|
||||
{
|
||||
mBody->ComputeLengthAndData();
|
||||
return GetBufferDataAsStream(mBody->Data(), mBody->Length(),
|
||||
aResult, aContentLength, aContentTypeWithCharset,
|
||||
aCharset);
|
||||
}
|
||||
|
||||
template<> nsresult
|
||||
BodyExtractor<const ArrayBufferView>::GetAsStream(nsIInputStream** aResult,
|
||||
uint64_t* aContentLength,
|
||||
nsACString& aContentTypeWithCharset,
|
||||
nsACString& aCharset) const
|
||||
{
|
||||
mBody->ComputeLengthAndData();
|
||||
return GetBufferDataAsStream(mBody->Data(), mBody->Length(),
|
||||
aResult, aContentLength, aContentTypeWithCharset,
|
||||
aCharset);
|
||||
}
|
||||
|
||||
template<> nsresult
|
||||
BodyExtractor<nsIDocument>::GetAsStream(nsIInputStream** aResult,
|
||||
uint64_t* aContentLength,
|
||||
nsACString& aContentTypeWithCharset,
|
||||
nsACString& aCharset) const
|
||||
{
|
||||
nsCOMPtr<nsIDOMDocument> domdoc(do_QueryInterface(mBody));
|
||||
NS_ENSURE_STATE(domdoc);
|
||||
aCharset.AssignLiteral("UTF-8");
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIStorageStream> storStream;
|
||||
rv = NS_NewStorageStream(4096, UINT32_MAX, getter_AddRefs(storStream));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIOutputStream> output;
|
||||
rv = storStream->GetOutputStream(0, getter_AddRefs(output));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mBody->IsHTMLDocument()) {
|
||||
aContentTypeWithCharset.AssignLiteral("text/html;charset=UTF-8");
|
||||
|
||||
nsString serialized;
|
||||
if (!nsContentUtils::SerializeNodeToMarkup(mBody, true, serialized)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsAutoCString utf8Serialized;
|
||||
if (!AppendUTF16toUTF8(serialized, utf8Serialized, fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
uint32_t written;
|
||||
rv = output->Write(utf8Serialized.get(), utf8Serialized.Length(), &written);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
MOZ_ASSERT(written == utf8Serialized.Length());
|
||||
} else {
|
||||
aContentTypeWithCharset.AssignLiteral("application/xml;charset=UTF-8");
|
||||
|
||||
nsCOMPtr<nsIDOMSerializer> serializer =
|
||||
do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Make sure to use the encoding we'll send
|
||||
rv = serializer->SerializeToStream(domdoc, output, aCharset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
output->Close();
|
||||
|
||||
uint32_t length;
|
||||
rv = storStream->GetLength(&length);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
*aContentLength = length;
|
||||
|
||||
rv = storStream->NewInputStream(0, aResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
template<> nsresult
|
||||
BodyExtractor<const nsAString>::GetAsStream(nsIInputStream** aResult,
|
||||
uint64_t* aContentLength,
|
||||
nsACString& aContentTypeWithCharset,
|
||||
nsACString& aCharset) const
|
||||
{
|
||||
nsCOMPtr<nsIUnicodeEncoder> encoder =
|
||||
EncodingUtils::EncoderForEncoding("UTF-8");
|
||||
if (!encoder) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
int32_t destBufferLen;
|
||||
nsresult rv = encoder->GetMaxLength(mBody->BeginReading(), mBody->Length(),
|
||||
&destBufferLen);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCString encoded;
|
||||
if (!encoded.SetCapacity(destBufferLen, fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
char* destBuffer = encoded.BeginWriting();
|
||||
int32_t srcLen = (int32_t) mBody->Length();
|
||||
int32_t outLen = destBufferLen;
|
||||
rv = encoder->Convert(mBody->BeginReading(), &srcLen, destBuffer, &outLen);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(outLen <= destBufferLen);
|
||||
encoded.SetLength(outLen);
|
||||
|
||||
rv = NS_NewCStringInputStream(aResult, encoded);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
*aContentLength = outLen;
|
||||
aContentTypeWithCharset.AssignLiteral("text/plain;charset=UTF-8");
|
||||
aCharset.AssignLiteral("UTF-8");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
template<> nsresult
|
||||
BodyExtractor<nsIInputStream>::GetAsStream(nsIInputStream** aResult,
|
||||
uint64_t* aContentLength,
|
||||
nsACString& aContentTypeWithCharset,
|
||||
nsACString& aCharset) const
|
||||
{
|
||||
aContentTypeWithCharset.AssignLiteral("text/plain");
|
||||
aCharset.Truncate();
|
||||
|
||||
nsresult rv = mBody->Available(aContentLength);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream(mBody);
|
||||
stream.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
template<> nsresult
|
||||
BodyExtractor<nsIXHRSendable>::GetAsStream(nsIInputStream** aResult,
|
||||
uint64_t* aContentLength,
|
||||
nsACString& aContentTypeWithCharset,
|
||||
nsACString& aCharset) const
|
||||
{
|
||||
return mBody->GetSendInfo(aResult, aContentLength, aContentTypeWithCharset,
|
||||
aCharset);
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
@@ -0,0 +1,48 @@
|
||||
/* -*- 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 mozilla_dom_BodyExtractor_h
|
||||
#define mozilla_dom_BodyExtractor_h
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "nsString.h"
|
||||
|
||||
class nsIInputStream;
|
||||
class nsIGlobalObject;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class BodyExtractorBase
|
||||
{
|
||||
public:
|
||||
virtual nsresult GetAsStream(nsIInputStream** aResult,
|
||||
uint64_t* aContentLength,
|
||||
nsACString& aContentTypeWithCharset,
|
||||
nsACString& aCharset) const = 0;
|
||||
};
|
||||
|
||||
// The implementation versions of this template are:
|
||||
// ArrayBuffer, ArrayBufferView, nsIXHRSendable (Blob, FormData,
|
||||
// URLSearchParams), nsAString, nsIDocument, nsIInputStream.
|
||||
template<typename Type>
|
||||
class BodyExtractor final : public BodyExtractorBase
|
||||
{
|
||||
Type* mBody;
|
||||
public:
|
||||
explicit BodyExtractor(Type* aBody) : mBody(aBody)
|
||||
{}
|
||||
|
||||
nsresult GetAsStream(nsIInputStream** aResult,
|
||||
uint64_t* aContentLength,
|
||||
nsACString& aContentTypeWithCharset,
|
||||
nsACString& aCharset) const override;
|
||||
};
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
|
||||
#endif // mozilla_dom_BodyExtractor_h
|
||||
+381
-157
@@ -5,13 +5,13 @@
|
||||
|
||||
#include "Fetch.h"
|
||||
#include "FetchConsumer.h"
|
||||
#include "FetchStream.h"
|
||||
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIGlobalObject.h"
|
||||
#include "nsIStreamLoader.h"
|
||||
#include "nsIThreadRetargetableRequest.h"
|
||||
#include "nsIUnicodeDecoder.h"
|
||||
#include "nsIUnicodeEncoder.h"
|
||||
|
||||
#include "nsDOMString.h"
|
||||
#include "nsNetUtil.h"
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/BodyUtil.h"
|
||||
#include "mozilla/dom/EncodingUtils.h"
|
||||
#include "mozilla/dom/DOMError.h"
|
||||
#include "mozilla/dom/Exceptions.h"
|
||||
#include "mozilla/dom/FetchDriver.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
@@ -35,8 +35,10 @@
|
||||
#include "mozilla/dom/Response.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/URLSearchParams.h"
|
||||
#include "mozilla/dom/WorkerPrivate.h"
|
||||
#include "mozilla/dom/workers/ServiceWorkerManager.h"
|
||||
|
||||
#include "BodyExtractor.h"
|
||||
#include "FetchObserver.h"
|
||||
#include "InternalRequest.h"
|
||||
#include "InternalResponse.h"
|
||||
@@ -722,154 +724,48 @@ WorkerFetchResolver::FlushConsoleReport()
|
||||
mReporter->FlushConsoleReports(worker->GetDocument());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
nsresult
|
||||
ExtractFromArrayBuffer(const ArrayBuffer& aBuffer,
|
||||
nsIInputStream** aStream,
|
||||
uint64_t& aContentLength)
|
||||
{
|
||||
aBuffer.ComputeLengthAndData();
|
||||
aContentLength = aBuffer.Length();
|
||||
//XXXnsm reinterpret_cast<> is used in DOMParser, should be ok.
|
||||
return NS_NewByteInputStream(aStream,
|
||||
reinterpret_cast<char*>(aBuffer.Data()),
|
||||
aBuffer.Length(), NS_ASSIGNMENT_COPY);
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractFromArrayBufferView(const ArrayBufferView& aBuffer,
|
||||
nsIInputStream** aStream,
|
||||
uint64_t& aContentLength)
|
||||
{
|
||||
aBuffer.ComputeLengthAndData();
|
||||
aContentLength = aBuffer.Length();
|
||||
//XXXnsm reinterpret_cast<> is used in DOMParser, should be ok.
|
||||
return NS_NewByteInputStream(aStream,
|
||||
reinterpret_cast<char*>(aBuffer.Data()),
|
||||
aBuffer.Length(), NS_ASSIGNMENT_COPY);
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractFromBlob(const Blob& aBlob,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType,
|
||||
uint64_t& aContentLength)
|
||||
{
|
||||
RefPtr<BlobImpl> impl = aBlob.Impl();
|
||||
ErrorResult rv;
|
||||
aContentLength = impl->GetSize(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
impl->GetInternalStream(aStream, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
nsAutoString type;
|
||||
impl->GetType(type);
|
||||
aContentType = NS_ConvertUTF16toUTF8(type);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractFromFormData(FormData& aFormData,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType,
|
||||
uint64_t& aContentLength)
|
||||
{
|
||||
nsAutoCString unusedCharset;
|
||||
return aFormData.GetSendInfo(aStream, &aContentLength,
|
||||
aContentType, unusedCharset);
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractFromUSVString(const nsString& aStr,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType,
|
||||
uint64_t& aContentLength)
|
||||
{
|
||||
nsCOMPtr<nsIUnicodeEncoder> encoder = EncodingUtils::EncoderForEncoding("UTF-8");
|
||||
if (!encoder) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
int32_t destBufferLen;
|
||||
nsresult rv = encoder->GetMaxLength(aStr.get(), aStr.Length(), &destBufferLen);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCString encoded;
|
||||
if (!encoded.SetCapacity(destBufferLen, fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
char* destBuffer = encoded.BeginWriting();
|
||||
int32_t srcLen = (int32_t) aStr.Length();
|
||||
int32_t outLen = destBufferLen;
|
||||
rv = encoder->Convert(aStr.get(), &srcLen, destBuffer, &outLen);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(outLen <= destBufferLen);
|
||||
encoded.SetLength(outLen);
|
||||
|
||||
aContentType = NS_LITERAL_CSTRING("text/plain;charset=UTF-8");
|
||||
aContentLength = outLen;
|
||||
|
||||
return NS_NewCStringInputStream(aStream, encoded);
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractFromURLSearchParams(const URLSearchParams& aParams,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType,
|
||||
uint64_t& aContentLength)
|
||||
{
|
||||
nsAutoString serialized;
|
||||
aParams.Stringify(serialized);
|
||||
aContentType = NS_LITERAL_CSTRING("application/x-www-form-urlencoded;charset=UTF-8");
|
||||
aContentLength = serialized.Length();
|
||||
return NS_NewCStringInputStream(aStream, NS_ConvertUTF16toUTF8(serialized));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
nsresult
|
||||
ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& aBodyInit,
|
||||
ExtractByteStreamFromBody(const fetch::OwningBodyInit& aBodyInit,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType,
|
||||
nsCString& aContentTypeWithCharset,
|
||||
uint64_t& aContentLength)
|
||||
{
|
||||
MOZ_ASSERT(aStream);
|
||||
nsAutoCString charset;
|
||||
aContentTypeWithCharset.SetIsVoid(true);
|
||||
|
||||
if (aBodyInit.IsArrayBuffer()) {
|
||||
const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer();
|
||||
return ExtractFromArrayBuffer(buf, aStream, aContentLength);
|
||||
BodyExtractor<const ArrayBuffer> body(&aBodyInit.GetAsArrayBuffer());
|
||||
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||
charset);
|
||||
}
|
||||
if (aBodyInit.IsArrayBufferView()) {
|
||||
const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView();
|
||||
return ExtractFromArrayBufferView(buf, aStream, aContentLength);
|
||||
BodyExtractor<const ArrayBufferView> body(&aBodyInit.GetAsArrayBufferView());
|
||||
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||
charset);
|
||||
}
|
||||
if (aBodyInit.IsBlob()) {
|
||||
const Blob& blob = aBodyInit.GetAsBlob();
|
||||
return ExtractFromBlob(blob, aStream, aContentType, aContentLength);
|
||||
Blob& blob = aBodyInit.GetAsBlob();
|
||||
BodyExtractor<nsIXHRSendable> body(&blob);
|
||||
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||
charset);
|
||||
}
|
||||
if (aBodyInit.IsFormData()) {
|
||||
FormData& form = aBodyInit.GetAsFormData();
|
||||
return ExtractFromFormData(form, aStream, aContentType, aContentLength);
|
||||
FormData& formData = aBodyInit.GetAsFormData();
|
||||
BodyExtractor<nsIXHRSendable> body(&formData);
|
||||
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||
charset);
|
||||
}
|
||||
if (aBodyInit.IsUSVString()) {
|
||||
nsAutoString str;
|
||||
str.Assign(aBodyInit.GetAsUSVString());
|
||||
return ExtractFromUSVString(str, aStream, aContentType, aContentLength);
|
||||
BodyExtractor<const nsAString> body(&aBodyInit.GetAsUSVString());
|
||||
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||
charset);
|
||||
}
|
||||
if (aBodyInit.IsURLSearchParams()) {
|
||||
URLSearchParams& params = aBodyInit.GetAsURLSearchParams();
|
||||
return ExtractFromURLSearchParams(params, aStream, aContentType, aContentLength);
|
||||
URLSearchParams& usp = aBodyInit.GetAsURLSearchParams();
|
||||
BodyExtractor<nsIXHRSendable> body(&usp);
|
||||
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||
charset);
|
||||
}
|
||||
|
||||
NS_NOTREACHED("Should never reach here");
|
||||
@@ -877,69 +773,228 @@ ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDa
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& aBodyInit,
|
||||
ExtractByteStreamFromBody(const fetch::BodyInit& aBodyInit,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType,
|
||||
nsCString& aContentTypeWithCharset,
|
||||
uint64_t& aContentLength)
|
||||
{
|
||||
MOZ_ASSERT(aStream);
|
||||
MOZ_ASSERT(!*aStream);
|
||||
|
||||
nsAutoCString charset;
|
||||
aContentTypeWithCharset.SetIsVoid(true);
|
||||
|
||||
if (aBodyInit.IsArrayBuffer()) {
|
||||
const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer();
|
||||
return ExtractFromArrayBuffer(buf, aStream, aContentLength);
|
||||
BodyExtractor<const ArrayBuffer> body(&aBodyInit.GetAsArrayBuffer());
|
||||
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||
charset);
|
||||
}
|
||||
if (aBodyInit.IsArrayBufferView()) {
|
||||
const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView();
|
||||
return ExtractFromArrayBufferView(buf, aStream, aContentLength);
|
||||
BodyExtractor<const ArrayBufferView> body(&aBodyInit.GetAsArrayBufferView());
|
||||
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||
charset);
|
||||
}
|
||||
if (aBodyInit.IsBlob()) {
|
||||
const Blob& blob = aBodyInit.GetAsBlob();
|
||||
return ExtractFromBlob(blob, aStream, aContentType, aContentLength);
|
||||
BodyExtractor<nsIXHRSendable> body(&aBodyInit.GetAsBlob());
|
||||
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||
charset);
|
||||
}
|
||||
if (aBodyInit.IsFormData()) {
|
||||
FormData& form = aBodyInit.GetAsFormData();
|
||||
return ExtractFromFormData(form, aStream, aContentType, aContentLength);
|
||||
BodyExtractor<nsIXHRSendable> body(&aBodyInit.GetAsFormData());
|
||||
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||
charset);
|
||||
}
|
||||
if (aBodyInit.IsUSVString()) {
|
||||
nsAutoString str;
|
||||
str.Assign(aBodyInit.GetAsUSVString());
|
||||
return ExtractFromUSVString(str, aStream, aContentType, aContentLength);
|
||||
BodyExtractor<const nsAString> body(&aBodyInit.GetAsUSVString());
|
||||
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||
charset);
|
||||
}
|
||||
if (aBodyInit.IsURLSearchParams()) {
|
||||
URLSearchParams& params = aBodyInit.GetAsURLSearchParams();
|
||||
return ExtractFromURLSearchParams(params, aStream, aContentType, aContentLength);
|
||||
BodyExtractor<nsIXHRSendable> body(&aBodyInit.GetAsURLSearchParams());
|
||||
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||
charset);
|
||||
}
|
||||
|
||||
NS_NOTREACHED("Should never reach here");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ExtractByteStreamFromBody(const fetch::ResponseBodyInit& aBodyInit,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentTypeWithCharset,
|
||||
uint64_t& aContentLength)
|
||||
{
|
||||
MOZ_ASSERT(aStream);
|
||||
MOZ_ASSERT(!*aStream);
|
||||
|
||||
// ReadableStreams should be handled by
|
||||
// BodyExtractorReadableStream::GetAsStream.
|
||||
MOZ_ASSERT(!aBodyInit.IsReadableStream());
|
||||
|
||||
nsAutoCString charset;
|
||||
aContentTypeWithCharset.SetIsVoid(true);
|
||||
|
||||
if (aBodyInit.IsArrayBuffer()) {
|
||||
BodyExtractor<const ArrayBuffer> body(&aBodyInit.GetAsArrayBuffer());
|
||||
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||
charset);
|
||||
}
|
||||
|
||||
if (aBodyInit.IsArrayBufferView()) {
|
||||
BodyExtractor<const ArrayBufferView> body(&aBodyInit.GetAsArrayBufferView());
|
||||
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||
charset);
|
||||
}
|
||||
|
||||
if (aBodyInit.IsBlob()) {
|
||||
BodyExtractor<nsIXHRSendable> body(&aBodyInit.GetAsBlob());
|
||||
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||
charset);
|
||||
}
|
||||
|
||||
if (aBodyInit.IsFormData()) {
|
||||
BodyExtractor<nsIXHRSendable> body(&aBodyInit.GetAsFormData());
|
||||
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||
charset);
|
||||
}
|
||||
|
||||
if (aBodyInit.IsUSVString()) {
|
||||
BodyExtractor<const nsAString> body(&aBodyInit.GetAsUSVString());
|
||||
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||
charset);
|
||||
}
|
||||
|
||||
if (aBodyInit.IsURLSearchParams()) {
|
||||
BodyExtractor<nsIXHRSendable> body(&aBodyInit.GetAsURLSearchParams());
|
||||
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||
charset);
|
||||
}
|
||||
|
||||
NS_NOTREACHED("Should never reach here");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
template <class Derived>
|
||||
FetchBody<Derived>::FetchBody()
|
||||
FetchBody<Derived>::FetchBody(nsIGlobalObject* aOwner)
|
||||
: mWorkerPrivate(nullptr)
|
||||
, mOwner(aOwner)
|
||||
, mReadableStreamBody(nullptr)
|
||||
, mReadableStreamReader(nullptr)
|
||||
, mBodyUsed(false)
|
||||
{
|
||||
MOZ_ASSERT(aOwner);
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
mWorkerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
} else {
|
||||
mWorkerPrivate = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template
|
||||
FetchBody<Request>::FetchBody();
|
||||
FetchBody<Request>::FetchBody(nsIGlobalObject* aOwner);
|
||||
|
||||
template
|
||||
FetchBody<Response>::FetchBody();
|
||||
FetchBody<Response>::FetchBody(nsIGlobalObject* aOwner);
|
||||
|
||||
template <class Derived>
|
||||
FetchBody<Derived>::~FetchBody()
|
||||
{
|
||||
}
|
||||
|
||||
template
|
||||
FetchBody<Request>::~FetchBody();
|
||||
|
||||
template
|
||||
FetchBody<Response>::~FetchBody();
|
||||
|
||||
template <class Derived>
|
||||
bool
|
||||
FetchBody<Derived>::BodyUsed() const
|
||||
{
|
||||
if (mBodyUsed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If this object is disturbed or locked, return false.
|
||||
if (mReadableStreamBody) {
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(mOwner)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
JS::Rooted<JSObject*> body(cx, mReadableStreamBody);
|
||||
if (JS::ReadableStreamIsDisturbed(body) ||
|
||||
JS::ReadableStreamIsLocked(body) ||
|
||||
!JS::ReadableStreamIsReadable(body)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template
|
||||
bool
|
||||
FetchBody<Request>::BodyUsed() const;
|
||||
|
||||
template
|
||||
bool
|
||||
FetchBody<Response>::BodyUsed() const;
|
||||
|
||||
template <class Derived>
|
||||
void
|
||||
FetchBody<Derived>::SetBodyUsed(JSContext* aCx, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
|
||||
if (mBodyUsed) {
|
||||
return;
|
||||
}
|
||||
|
||||
mBodyUsed = true;
|
||||
|
||||
// If we already have a ReadableStreamBody and it has been created by DOM, we
|
||||
// have to lock it now because it can have been shared with other objects.
|
||||
if (mReadableStreamBody) {
|
||||
JS::Rooted<JSObject*> readableStreamObj(aCx, mReadableStreamBody);
|
||||
if (JS::ReadableStreamGetMode(readableStreamObj) ==
|
||||
JS::ReadableStreamMode::ExternalSource) {
|
||||
LockStream(aCx, readableStreamObj, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// If this is not a native ReadableStream, let's activate the
|
||||
// FetchStreamReader.
|
||||
MOZ_ASSERT(mFetchStreamReader);
|
||||
JS::Rooted<JSObject*> reader(aCx);
|
||||
mFetchStreamReader->StartConsuming(aCx, readableStreamObj, &reader, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
mReadableStreamReader = reader;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template
|
||||
void
|
||||
FetchBody<Request>::SetBodyUsed(JSContext* aCx, ErrorResult& aRv);
|
||||
|
||||
template
|
||||
void
|
||||
FetchBody<Response>::SetBodyUsed(JSContext* aCx, ErrorResult& aRv);
|
||||
|
||||
template <class Derived>
|
||||
already_AddRefed<Promise>
|
||||
FetchBody<Derived>::ConsumeBody(FetchConsumeType aType, ErrorResult& aRv)
|
||||
FetchBody<Derived>::ConsumeBody(JSContext* aCx, FetchConsumeType aType, ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<AbortSignal> signal = DerivedClass()->GetSignal();
|
||||
if (signal && signal->Aborted()) {
|
||||
@@ -952,11 +1007,15 @@ FetchBody<Derived>::ConsumeBody(FetchConsumeType aType, ErrorResult& aRv)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SetBodyUsed();
|
||||
SetBodyUsed(aCx, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = DerivedClass()->GetParentObject();
|
||||
|
||||
RefPtr<Promise> promise =
|
||||
FetchBodyConsumer<Derived>::Create(DerivedClass()->GetParentObject(),
|
||||
this, signal, aType, aRv);
|
||||
FetchBodyConsumer<Derived>::Create(global, this, signal, aType, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -966,11 +1025,11 @@ FetchBody<Derived>::ConsumeBody(FetchConsumeType aType, ErrorResult& aRv)
|
||||
|
||||
template
|
||||
already_AddRefed<Promise>
|
||||
FetchBody<Request>::ConsumeBody(FetchConsumeType aType, ErrorResult& aRv);
|
||||
FetchBody<Request>::ConsumeBody(JSContext* aCx, FetchConsumeType aType, ErrorResult& aRv);
|
||||
|
||||
template
|
||||
already_AddRefed<Promise>
|
||||
FetchBody<Response>::ConsumeBody(FetchConsumeType aType, ErrorResult& aRv);
|
||||
FetchBody<Response>::ConsumeBody(JSContext* aCx, FetchConsumeType aType, ErrorResult& aRv);
|
||||
|
||||
template <class Derived>
|
||||
void
|
||||
@@ -1000,5 +1059,170 @@ template
|
||||
void
|
||||
FetchBody<Response>::SetMimeType();
|
||||
|
||||
template <class Derived>
|
||||
void
|
||||
FetchBody<Derived>::SetReadableStreamBody(JSObject* aBody)
|
||||
{
|
||||
MOZ_ASSERT(!mReadableStreamBody);
|
||||
MOZ_ASSERT(aBody);
|
||||
mReadableStreamBody = aBody;
|
||||
}
|
||||
|
||||
template
|
||||
void
|
||||
FetchBody<Request>::SetReadableStreamBody(JSObject* aBody);
|
||||
|
||||
template
|
||||
void
|
||||
FetchBody<Response>::SetReadableStreamBody(JSObject* aBody);
|
||||
|
||||
template <class Derived>
|
||||
void
|
||||
FetchBody<Derived>::GetBody(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aBodyOut,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (mReadableStreamBody) {
|
||||
aBodyOut.set(mReadableStreamBody);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
DerivedClass()->GetBody(getter_AddRefs(inputStream));
|
||||
|
||||
if (!inputStream) {
|
||||
aBodyOut.set(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> body(aCx);
|
||||
FetchStream::Create(aCx, this, DerivedClass()->GetParentObject(),
|
||||
inputStream, &body, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(body);
|
||||
|
||||
// If the body has been already consumed, we lock the stream.
|
||||
if (BodyUsed()) {
|
||||
LockStream(aCx, body, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mReadableStreamBody = body;
|
||||
aBodyOut.set(mReadableStreamBody);
|
||||
}
|
||||
|
||||
template
|
||||
void
|
||||
FetchBody<Request>::GetBody(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aMessage,
|
||||
ErrorResult& aRv);
|
||||
|
||||
template
|
||||
void
|
||||
FetchBody<Response>::GetBody(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aMessage,
|
||||
ErrorResult& aRv);
|
||||
|
||||
template <class Derived>
|
||||
void
|
||||
FetchBody<Derived>::LockStream(JSContext* aCx,
|
||||
JS::HandleObject aStream,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(JS::ReadableStreamGetMode(aStream) ==
|
||||
JS::ReadableStreamMode::ExternalSource);
|
||||
|
||||
// This is native stream, creating a reader will not execute any JS code.
|
||||
JS::Rooted<JSObject*> reader(aCx,
|
||||
JS::ReadableStreamGetReader(aCx, aStream,
|
||||
JS::ReadableStreamReaderMode::Default));
|
||||
if (!reader) {
|
||||
aRv.StealExceptionFromJSContext(aCx);
|
||||
return;
|
||||
}
|
||||
|
||||
mReadableStreamReader = reader;
|
||||
}
|
||||
|
||||
template
|
||||
void
|
||||
FetchBody<Request>::LockStream(JSContext* aCx,
|
||||
JS::HandleObject aStream,
|
||||
ErrorResult& aRv);
|
||||
|
||||
template
|
||||
void
|
||||
FetchBody<Response>::LockStream(JSContext* aCx,
|
||||
JS::HandleObject aStream,
|
||||
ErrorResult& aRv);
|
||||
|
||||
template <class Derived>
|
||||
void
|
||||
FetchBody<Derived>::MaybeTeeReadableStreamBody(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aBodyOut,
|
||||
FetchStreamReader** aStreamReader,
|
||||
nsIInputStream** aInputStream,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(aStreamReader);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aInputStream);
|
||||
MOZ_DIAGNOSTIC_ASSERT(!BodyUsed());
|
||||
|
||||
aBodyOut.set(nullptr);
|
||||
*aStreamReader = nullptr;
|
||||
*aInputStream = nullptr;
|
||||
|
||||
if (!mReadableStreamBody) {
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> stream(aCx, mReadableStreamBody);
|
||||
|
||||
// If this is a ReadableStream with an external source, this has been
|
||||
// generated by a Fetch. In this case, Fetch will be able to recreate it
|
||||
// again when GetBody() is called.
|
||||
if (JS::ReadableStreamGetMode(stream) == JS::ReadableStreamMode::ExternalSource) {
|
||||
aBodyOut.set(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> branch1(aCx);
|
||||
JS::Rooted<JSObject*> branch2(aCx);
|
||||
|
||||
if (!JS::ReadableStreamTee(aCx, stream, &branch1, &branch2)) {
|
||||
aRv.StealExceptionFromJSContext(aCx);
|
||||
return;
|
||||
}
|
||||
|
||||
mReadableStreamBody = branch1;
|
||||
aBodyOut.set(branch2);
|
||||
|
||||
aRv = FetchStreamReader::Create(aCx, mOwner, aStreamReader, aInputStream);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
template
|
||||
void
|
||||
FetchBody<Request>::MaybeTeeReadableStreamBody(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aMessage,
|
||||
FetchStreamReader** aStreamReader,
|
||||
nsIInputStream** aInputStream,
|
||||
ErrorResult& aRv);
|
||||
|
||||
template
|
||||
void
|
||||
FetchBody<Response>::MaybeTeeReadableStreamBody(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aMessage,
|
||||
FetchStreamReader** aStreamReader,
|
||||
nsIInputStream** aInputStream,
|
||||
ErrorResult& aRv);
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
+312
-207
@@ -1,207 +1,312 @@
|
||||
/* -*- Mode: C++; tab-width: 8; 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/. */
|
||||
|
||||
#ifndef mozilla_dom_Fetch_h
|
||||
#define mozilla_dom_Fetch_h
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIStreamLoader.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsError.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/RequestBinding.h"
|
||||
|
||||
class nsIGlobalObject;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams;
|
||||
class BlobImpl;
|
||||
class InternalRequest;
|
||||
class OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams;
|
||||
class RequestOrUSVString;
|
||||
|
||||
namespace workers {
|
||||
class WorkerPrivate;
|
||||
} // namespace workers
|
||||
|
||||
already_AddRefed<Promise>
|
||||
FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
|
||||
const RequestInit& aInit, ErrorResult& aRv);
|
||||
|
||||
nsresult
|
||||
UpdateRequestReferrer(nsIGlobalObject* aGlobal, InternalRequest* aRequest);
|
||||
|
||||
/*
|
||||
* Creates an nsIInputStream based on the fetch specifications 'extract a byte
|
||||
* stream algorithm' - http://fetch.spec.whatwg.org/#concept-bodyinit-extract.
|
||||
* Stores content type in out param aContentType.
|
||||
*/
|
||||
nsresult
|
||||
ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& aBodyInit,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType,
|
||||
uint64_t& aContentLength);
|
||||
|
||||
/*
|
||||
* Non-owning version.
|
||||
*/
|
||||
nsresult
|
||||
ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& aBodyInit,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType,
|
||||
uint64_t& aContentLength);
|
||||
|
||||
template <class Derived> class FetchBodyConsumer;
|
||||
|
||||
enum FetchConsumeType
|
||||
{
|
||||
CONSUME_ARRAYBUFFER,
|
||||
CONSUME_BLOB,
|
||||
CONSUME_FORMDATA,
|
||||
CONSUME_JSON,
|
||||
CONSUME_TEXT,
|
||||
};
|
||||
|
||||
/*
|
||||
* FetchBody's body consumption uses nsIInputStreamPump to read from the
|
||||
* underlying stream to a block of memory, which is then adopted by
|
||||
* ContinueConsumeBody() and converted to the right type based on the JS
|
||||
* function called.
|
||||
*
|
||||
* Use of the nsIInputStreamPump complicates things on the worker thread.
|
||||
* The solution used here is similar to WebSockets.
|
||||
* The difference is that we are only interested in completion and not data
|
||||
* events, and nsIInputStreamPump can only deliver completion on the main thread.
|
||||
*
|
||||
* Before starting the pump on the main thread, we addref the FetchBody to keep
|
||||
* it alive. Then we add a feature, to track the status of the worker.
|
||||
*
|
||||
* ContinueConsumeBody() is the function that cleans things up in both success
|
||||
* and error conditions and so all callers call it with the appropriate status.
|
||||
*
|
||||
* Once the read is initiated on the main thread there are two possibilities.
|
||||
*
|
||||
* 1) Pump finishes before worker has finished Running.
|
||||
* In this case we adopt the data and dispatch a runnable to the worker,
|
||||
* which derefs FetchBody and removes the feature and resolves the Promise.
|
||||
*
|
||||
* 2) Pump still working while worker has stopped Running.
|
||||
* The feature is Notify()ed and ContinueConsumeBody() is called with
|
||||
* NS_BINDING_ABORTED. We first Cancel() the pump using a sync runnable to
|
||||
* ensure that mFetchBody remains alive (since mConsumeBodyPump is strongly
|
||||
* held by it) until pump->Cancel() is called. OnStreamComplete() will not
|
||||
* do anything if the error code is NS_BINDING_ABORTED, so we don't have to
|
||||
* worry about keeping anything alive.
|
||||
*
|
||||
* The pump is always released on the main thread.
|
||||
*/
|
||||
template <class Derived>
|
||||
class FetchBody
|
||||
{
|
||||
public:
|
||||
friend class FetchBodyConsumer<Derived>;
|
||||
|
||||
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0;
|
||||
NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0;
|
||||
|
||||
bool
|
||||
BodyUsed() const { return mBodyUsed; }
|
||||
|
||||
already_AddRefed<Promise>
|
||||
ArrayBuffer(ErrorResult& aRv)
|
||||
{
|
||||
return ConsumeBody(CONSUME_ARRAYBUFFER, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Blob(ErrorResult& aRv)
|
||||
{
|
||||
return ConsumeBody(CONSUME_BLOB, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
FormData(ErrorResult& aRv)
|
||||
{
|
||||
return ConsumeBody(CONSUME_FORMDATA, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Json(ErrorResult& aRv)
|
||||
{
|
||||
return ConsumeBody(CONSUME_JSON, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Text(ErrorResult& aRv)
|
||||
{
|
||||
return ConsumeBody(CONSUME_TEXT, aRv);
|
||||
}
|
||||
|
||||
// Utility public methods accessed by various runnables.
|
||||
|
||||
void
|
||||
SetBodyUsed()
|
||||
{
|
||||
mBodyUsed = true;
|
||||
}
|
||||
|
||||
const nsCString&
|
||||
MimeType() const
|
||||
{
|
||||
return mMimeType;
|
||||
}
|
||||
|
||||
virtual AbortSignal*
|
||||
GetSignal() const = 0;
|
||||
|
||||
protected:
|
||||
FetchBody();
|
||||
|
||||
// Always set whenever the FetchBody is created on the worker thread.
|
||||
workers::WorkerPrivate* mWorkerPrivate;
|
||||
|
||||
virtual ~FetchBody();
|
||||
|
||||
void
|
||||
SetMimeType();
|
||||
private:
|
||||
Derived*
|
||||
DerivedClass() const
|
||||
{
|
||||
return static_cast<Derived*>(const_cast<FetchBody*>(this));
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
ConsumeBody(FetchConsumeType aType, ErrorResult& aRv);
|
||||
|
||||
bool
|
||||
IsOnTargetThread()
|
||||
{
|
||||
return NS_IsMainThread() == !mWorkerPrivate;
|
||||
}
|
||||
|
||||
void
|
||||
AssertIsOnTargetThread()
|
||||
{
|
||||
MOZ_ASSERT(IsOnTargetThread());
|
||||
}
|
||||
|
||||
// Only ever set once, always on target thread.
|
||||
bool mBodyUsed;
|
||||
nsCString mMimeType;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_Fetch_h
|
||||
/* -*- Mode: C++; tab-width: 8; 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/. */
|
||||
|
||||
#ifndef mozilla_dom_Fetch_h
|
||||
#define mozilla_dom_Fetch_h
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIStreamLoader.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsError.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/FetchStreamReader.h"
|
||||
// Fix X11 header brain damage that conflicts with HeadersGuardEnum::None
|
||||
#undef None
|
||||
#include "mozilla/dom/RequestBinding.h"
|
||||
|
||||
class nsIGlobalObject;
|
||||
class nsIEventTarget;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString;
|
||||
class BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrReadableStreamOrUSVString;
|
||||
class BlobImpl;
|
||||
class InternalRequest;
|
||||
class OwningBlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString;
|
||||
struct ReadableStream;
|
||||
class RequestOrUSVString;
|
||||
|
||||
namespace workers {
|
||||
class WorkerPrivate;
|
||||
} // namespace workers
|
||||
|
||||
already_AddRefed<Promise>
|
||||
FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
|
||||
const RequestInit& aInit, ErrorResult& aRv);
|
||||
|
||||
nsresult
|
||||
UpdateRequestReferrer(nsIGlobalObject* aGlobal, InternalRequest* aRequest);
|
||||
|
||||
/* Deal with unwieldy long webIDL-generated type names */
|
||||
namespace fetch {
|
||||
typedef BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString BodyInit;
|
||||
typedef BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrReadableStreamOrUSVString ResponseBodyInit;
|
||||
typedef OwningBlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString OwningBodyInit;
|
||||
};
|
||||
|
||||
/*
|
||||
* Creates an nsIInputStream based on the fetch specifications 'extract a byte
|
||||
* stream algorithm' - http://fetch.spec.whatwg.org/#concept-bodyinit-extract.
|
||||
* Stores content type in out param aContentType.
|
||||
*/
|
||||
nsresult
|
||||
ExtractByteStreamFromBody(const fetch::OwningBodyInit& aBodyInit,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType,
|
||||
uint64_t& aContentLength);
|
||||
|
||||
/*
|
||||
* Non-owning version.
|
||||
*/
|
||||
nsresult
|
||||
ExtractByteStreamFromBody(const fetch::BodyInit& aBodyInit,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType,
|
||||
uint64_t& aContentLength);
|
||||
|
||||
/*
|
||||
* Non-owning version. This method should go away when BodyInit will contain
|
||||
* ReadableStream.
|
||||
*/
|
||||
nsresult
|
||||
ExtractByteStreamFromBody(const fetch::ResponseBodyInit& aBodyInit,
|
||||
nsIInputStream** aStream,
|
||||
nsCString& aContentType,
|
||||
uint64_t& aContentLength);
|
||||
|
||||
template <class Derived> class FetchBodyConsumer;
|
||||
|
||||
enum FetchConsumeType
|
||||
{
|
||||
CONSUME_ARRAYBUFFER,
|
||||
CONSUME_BLOB,
|
||||
CONSUME_FORMDATA,
|
||||
CONSUME_JSON,
|
||||
CONSUME_TEXT,
|
||||
};
|
||||
|
||||
class FetchStreamHolder
|
||||
{
|
||||
public:
|
||||
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0;
|
||||
NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0;
|
||||
|
||||
virtual void NullifyStream() = 0;
|
||||
|
||||
virtual void MarkAsRead() = 0;
|
||||
|
||||
virtual JSObject* ReadableStreamBody() = 0;
|
||||
};
|
||||
|
||||
/*
|
||||
* FetchBody's body consumption uses nsIInputStreamPump to read from the
|
||||
* underlying stream to a block of memory, which is then adopted by
|
||||
* ContinueConsumeBody() and converted to the right type based on the JS
|
||||
* function called.
|
||||
*
|
||||
* Use of the nsIInputStreamPump complicates things on the worker thread.
|
||||
* The solution used here is similar to WebSockets.
|
||||
* The difference is that we are only interested in completion and not data
|
||||
* events, and nsIInputStreamPump can only deliver completion on the main thread.
|
||||
*
|
||||
* Before starting the pump on the main thread, we addref the FetchBody to keep
|
||||
* it alive. Then we add a feature, to track the status of the worker.
|
||||
*
|
||||
* ContinueConsumeBody() is the function that cleans things up in both success
|
||||
* and error conditions and so all callers call it with the appropriate status.
|
||||
*
|
||||
* Once the read is initiated on the main thread there are two possibilities.
|
||||
*
|
||||
* 1) Pump finishes before worker has finished Running.
|
||||
* In this case we adopt the data and dispatch a runnable to the worker,
|
||||
* which derefs FetchBody and removes the feature and resolves the Promise.
|
||||
*
|
||||
* 2) Pump still working while worker has stopped Running.
|
||||
* The feature is Notify()ed and ContinueConsumeBody() is called with
|
||||
* NS_BINDING_ABORTED. We first Cancel() the pump using a sync runnable to
|
||||
* ensure that mFetchBody remains alive (since mConsumeBodyPump is strongly
|
||||
* held by it) until pump->Cancel() is called. OnStreamComplete() will not
|
||||
* do anything if the error code is NS_BINDING_ABORTED, so we don't have to
|
||||
* worry about keeping anything alive.
|
||||
*
|
||||
* The pump is always released on the main thread.
|
||||
*/
|
||||
template <class Derived>
|
||||
class FetchBody : public FetchStreamHolder
|
||||
{
|
||||
public:
|
||||
friend class FetchBodyConsumer<Derived>;
|
||||
|
||||
bool
|
||||
BodyUsed() const;
|
||||
|
||||
already_AddRefed<Promise>
|
||||
ArrayBuffer(JSContext* aCx, ErrorResult& aRv)
|
||||
{
|
||||
return ConsumeBody(aCx, CONSUME_ARRAYBUFFER, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Blob(JSContext* aCx, ErrorResult& aRv)
|
||||
{
|
||||
return ConsumeBody(aCx, CONSUME_BLOB, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
FormData(JSContext* aCx, ErrorResult& aRv)
|
||||
{
|
||||
return ConsumeBody(aCx, CONSUME_FORMDATA, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Json(JSContext* aCx, ErrorResult& aRv)
|
||||
{
|
||||
return ConsumeBody(aCx, CONSUME_JSON, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Text(JSContext* aCx, ErrorResult& aRv)
|
||||
{
|
||||
return ConsumeBody(aCx, CONSUME_TEXT, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
GetBody(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aBodyOut,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// If the body contains a ReadableStream body object, this method produces a
|
||||
// tee() of it.
|
||||
void
|
||||
MaybeTeeReadableStreamBody(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aBodyOut,
|
||||
FetchStreamReader** aStreamReader,
|
||||
nsIInputStream** aInputStream,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// Utility public methods accessed by various runnables.
|
||||
|
||||
// This method _must_ be called in order to set the body as used. If the body
|
||||
// is a ReadableStream, this method will start reading the stream.
|
||||
// More in details, this method does:
|
||||
// 1) It uses an internal flag to track if the body is used. This is tracked
|
||||
// separately from the ReadableStream disturbed state due to purely native
|
||||
// streams.
|
||||
// 2) If there is a ReadableStream reflector for the native stream it is
|
||||
// Locked.
|
||||
// 3) If there is a JS ReadableStream then we begin pumping it into the native
|
||||
// body stream. This effectively locks and disturbs the stream.
|
||||
//
|
||||
// Note that JSContext is used only if there is a ReadableStream (this can
|
||||
// happen because the body is a ReadableStream or because attribute body has
|
||||
// already been used by content). If something goes wrong using
|
||||
// ReadableStream, errors will be reported via ErrorResult and not as JS
|
||||
// exceptions in JSContext. This is done in order to have a centralized error
|
||||
// reporting way.
|
||||
//
|
||||
// Exceptions generated when reading from the ReadableStream are directly sent
|
||||
// to the Console.
|
||||
void
|
||||
SetBodyUsed(JSContext* aCx, ErrorResult& aRv);
|
||||
|
||||
const nsCString&
|
||||
MimeType() const
|
||||
{
|
||||
return mMimeType;
|
||||
}
|
||||
|
||||
// FetchStreamHolder
|
||||
void
|
||||
NullifyStream() override
|
||||
{
|
||||
mReadableStreamBody = nullptr;
|
||||
mReadableStreamReader = nullptr;
|
||||
mFetchStreamReader = nullptr;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
ReadableStreamBody() override
|
||||
{
|
||||
MOZ_ASSERT(mReadableStreamBody);
|
||||
return mReadableStreamBody;
|
||||
}
|
||||
|
||||
void
|
||||
MarkAsRead() override
|
||||
{
|
||||
mBodyUsed = true;
|
||||
}
|
||||
|
||||
virtual AbortSignal*
|
||||
GetSignal() const = 0;
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIGlobalObject> mOwner;
|
||||
|
||||
explicit FetchBody(nsIGlobalObject* aOwner);
|
||||
|
||||
// Always set whenever the FetchBody is created on the worker thread.
|
||||
workers::WorkerPrivate* mWorkerPrivate;
|
||||
|
||||
// This is the ReadableStream exposed to content. Its underlying source is a FetchStream object.
|
||||
JS::Heap<JSObject*> mReadableStreamBody;
|
||||
|
||||
// This is the Reader used to retrieve data from the body.
|
||||
JS::Heap<JSObject*> mReadableStreamReader;
|
||||
RefPtr<FetchStreamReader> mFetchStreamReader;
|
||||
|
||||
virtual ~FetchBody();
|
||||
|
||||
void
|
||||
SetMimeType();
|
||||
|
||||
void
|
||||
SetReadableStreamBody(JSObject* aBody);
|
||||
|
||||
private:
|
||||
Derived*
|
||||
DerivedClass() const
|
||||
{
|
||||
return static_cast<Derived*>(const_cast<FetchBody*>(this));
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
ConsumeBody(JSContext* aCx, FetchConsumeType aType, ErrorResult& aRv);
|
||||
|
||||
void
|
||||
LockStream(JSContext* aCx, JS::HandleObject aStream, ErrorResult& aRv);
|
||||
|
||||
bool
|
||||
IsOnTargetThread()
|
||||
{
|
||||
return NS_IsMainThread() == !mWorkerPrivate;
|
||||
}
|
||||
|
||||
void
|
||||
AssertIsOnTargetThread()
|
||||
{
|
||||
MOZ_ASSERT(IsOnTargetThread());
|
||||
}
|
||||
|
||||
// Only ever set once, always on target thread.
|
||||
bool mBodyUsed;
|
||||
nsCString mMimeType;
|
||||
|
||||
// The main-thread event target for runnable dispatching.
|
||||
nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_Fetch_h
|
||||
@@ -0,0 +1,640 @@
|
||||
/* -*- Mode: C; tab-width: 8; 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 "FetchStream.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsITransport.h"
|
||||
#include "nsIStreamTransportService.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "WorkerRunnable.h"
|
||||
#include "Workers.h"
|
||||
|
||||
#include "mozilla/dom/DOMError.h"
|
||||
|
||||
#define FETCH_STREAM_FLAG 0
|
||||
|
||||
static NS_DEFINE_CID(kStreamTransportServiceCID,
|
||||
NS_STREAMTRANSPORTSERVICE_CID);
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
using namespace workers;
|
||||
|
||||
namespace {
|
||||
|
||||
class FetchStreamWorkerHolder final : public WorkerHolder
|
||||
{
|
||||
public:
|
||||
explicit FetchStreamWorkerHolder(FetchStream* aStream)
|
||||
: WorkerHolder()
|
||||
, mStream(aStream)
|
||||
, mWasNotified(false)
|
||||
{}
|
||||
|
||||
bool Notify(Status aStatus) override
|
||||
{
|
||||
if (!mWasNotified) {
|
||||
mWasNotified = true;
|
||||
mStream->Close();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
WorkerPrivate* GetWorkerPrivate() const
|
||||
{
|
||||
return mWorkerPrivate;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<FetchStream> mStream;
|
||||
bool mWasNotified;
|
||||
};
|
||||
|
||||
class FetchStreamWorkerHolderShutdown final : public WorkerControlRunnable
|
||||
{
|
||||
public:
|
||||
FetchStreamWorkerHolderShutdown(WorkerPrivate* aWorkerPrivate,
|
||||
UniquePtr<WorkerHolder>&& aHolder,
|
||||
nsCOMPtr<nsIGlobalObject>&& aGlobal,
|
||||
RefPtr<FetchStreamHolder>&& aStreamHolder)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
|
||||
, mHolder(Move(aHolder))
|
||||
, mGlobal(Move(aGlobal))
|
||||
, mStreamHolder(Move(aStreamHolder))
|
||||
{}
|
||||
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
||||
{
|
||||
mHolder = nullptr;
|
||||
mGlobal = nullptr;
|
||||
|
||||
mStreamHolder->NullifyStream();
|
||||
mStreamHolder = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// This runnable starts from a JS Thread. We need to disable a couple of
|
||||
// assertions by overriding the following methods.
|
||||
|
||||
bool
|
||||
PreDispatch(WorkerPrivate* aWorkerPrivate) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
|
||||
{}
|
||||
|
||||
private:
|
||||
UniquePtr<WorkerHolder> mHolder;
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
RefPtr<FetchStreamHolder> mStreamHolder;
|
||||
};
|
||||
|
||||
} // anonymous
|
||||
|
||||
NS_IMPL_ISUPPORTS(FetchStream, nsIInputStreamCallback, nsIObserver,
|
||||
nsISupportsWeakReference)
|
||||
|
||||
/* static */ void
|
||||
FetchStream::Create(JSContext* aCx, FetchStreamHolder* aStreamHolder,
|
||||
nsIGlobalObject* aGlobal, nsIInputStream* aInputStream,
|
||||
JS::MutableHandle<JSObject*> aStream, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(aCx);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aInputStream);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aStreamHolder);
|
||||
|
||||
RefPtr<FetchStream> stream = new FetchStream(aGlobal, aStreamHolder, aInputStream);
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
if (NS_WARN_IF(!os)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
aRv = os->AddObserver(stream, DOM_WINDOW_DESTROYED_TOPIC, true);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
UniquePtr<FetchStreamWorkerHolder> holder(
|
||||
new FetchStreamWorkerHolder(stream));
|
||||
if (NS_WARN_IF(!holder->HoldWorker(workerPrivate, Closing))) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
// Note, this will create a ref-cycle between the holder and the stream.
|
||||
// The cycle is broken when the stream is closed or the worker begins
|
||||
// shutting down.
|
||||
stream->mWorkerHolder = Move(holder);
|
||||
}
|
||||
|
||||
if (!JS::HasReadableStreamCallbacks(aCx)) {
|
||||
JS::SetReadableStreamCallbacks(aCx,
|
||||
&FetchStream::RequestDataCallback,
|
||||
&FetchStream::WriteIntoReadRequestCallback,
|
||||
&FetchStream::CancelCallback,
|
||||
&FetchStream::ClosedCallback,
|
||||
&FetchStream::ErroredCallback,
|
||||
&FetchStream::FinalizeCallback);
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> body(aCx,
|
||||
JS::NewReadableExternalSourceStreamObject(aCx, stream, FETCH_STREAM_FLAG));
|
||||
if (!body) {
|
||||
aRv.StealExceptionFromJSContext(aCx);
|
||||
return;
|
||||
}
|
||||
|
||||
// This will be released in FetchStream::FinalizeCallback(). We are
|
||||
// guaranteed the jsapi will call FinalizeCallback when ReadableStream
|
||||
// js object is finalized.
|
||||
NS_ADDREF(stream.get());
|
||||
|
||||
aStream.set(body);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
FetchStream::RequestDataCallback(JSContext* aCx,
|
||||
JS::HandleObject aStream,
|
||||
void* aUnderlyingSource,
|
||||
uint8_t aFlags,
|
||||
size_t aDesiredSize)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(aUnderlyingSource);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aFlags == FETCH_STREAM_FLAG);
|
||||
MOZ_DIAGNOSTIC_ASSERT(JS::ReadableStreamIsDisturbed(aStream));
|
||||
|
||||
RefPtr<FetchStream> stream = static_cast<FetchStream*>(aUnderlyingSource);
|
||||
stream->AssertIsOnOwningThread();
|
||||
|
||||
MutexAutoLock lock(stream->mMutex);
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(stream->mState == eInitializing ||
|
||||
stream->mState == eWaiting ||
|
||||
stream->mState == eChecking ||
|
||||
stream->mState == eReading);
|
||||
|
||||
if (stream->mState == eReading) {
|
||||
// We are already reading data.
|
||||
return;
|
||||
}
|
||||
|
||||
if (stream->mState == eChecking) {
|
||||
// If we are looking for more data, there is nothing else we should do:
|
||||
// let's move this checking operation in a reading.
|
||||
MOZ_ASSERT(stream->mInputStream);
|
||||
stream->mState = eReading;
|
||||
return;
|
||||
}
|
||||
|
||||
if (stream->mState == eInitializing) {
|
||||
// The stream has been used for the first time.
|
||||
stream->mStreamHolder->MarkAsRead();
|
||||
}
|
||||
|
||||
stream->mState = eReading;
|
||||
|
||||
if (!stream->mInputStream) {
|
||||
// This is the first use of the stream. Let's convert the
|
||||
// mOriginalInputStream into an nsIAsyncInputStream.
|
||||
MOZ_ASSERT(stream->mOriginalInputStream);
|
||||
|
||||
bool nonBlocking = false;
|
||||
nsresult rv = stream->mOriginalInputStream->IsNonBlocking(&nonBlocking);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
stream->ErrorPropagation(aCx, lock, aStream, rv);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> asyncStream =
|
||||
do_QueryInterface(stream->mOriginalInputStream);
|
||||
if (!nonBlocking || !asyncStream) {
|
||||
nsCOMPtr<nsIStreamTransportService> sts =
|
||||
do_GetService(kStreamTransportServiceCID, &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
stream->ErrorPropagation(aCx, lock, aStream, rv);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITransport> transport;
|
||||
rv = sts->CreateInputTransport(stream->mOriginalInputStream,
|
||||
/* aStartOffset */ 0,
|
||||
/* aReadLimit */ -1,
|
||||
/* aCloseWhenDone */ true,
|
||||
getter_AddRefs(transport));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
stream->ErrorPropagation(aCx, lock, aStream, rv);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> wrapper;
|
||||
rv = transport->OpenInputStream(/* aFlags */ 0,
|
||||
/* aSegmentSize */ 0,
|
||||
/* aSegmentCount */ 0,
|
||||
getter_AddRefs(wrapper));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
stream->ErrorPropagation(aCx, lock, aStream, rv);
|
||||
return;
|
||||
}
|
||||
|
||||
asyncStream = do_QueryInterface(wrapper);
|
||||
}
|
||||
|
||||
stream->mInputStream = asyncStream;
|
||||
stream->mOriginalInputStream = nullptr;
|
||||
}
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(stream->mInputStream);
|
||||
MOZ_DIAGNOSTIC_ASSERT(!stream->mOriginalInputStream);
|
||||
|
||||
nsresult rv =
|
||||
stream->mInputStream->AsyncWait(stream, 0, 0, stream->mOwningEventTarget);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
stream->ErrorPropagation(aCx, lock, aStream, rv);
|
||||
return;
|
||||
}
|
||||
|
||||
// All good.
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
FetchStream::WriteIntoReadRequestCallback(JSContext* aCx,
|
||||
JS::HandleObject aStream,
|
||||
void* aUnderlyingSource,
|
||||
uint8_t aFlags, void* aBuffer,
|
||||
size_t aLength, size_t* aByteWritten)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(aUnderlyingSource);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aFlags == FETCH_STREAM_FLAG);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aBuffer);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aByteWritten);
|
||||
|
||||
RefPtr<FetchStream> stream = static_cast<FetchStream*>(aUnderlyingSource);
|
||||
stream->AssertIsOnOwningThread();
|
||||
|
||||
MutexAutoLock lock(stream->mMutex);
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(stream->mInputStream);
|
||||
MOZ_DIAGNOSTIC_ASSERT(stream->mState == eWriting);
|
||||
stream->mState = eChecking;
|
||||
|
||||
uint32_t written;
|
||||
nsresult rv =
|
||||
stream->mInputStream->Read(static_cast<char*>(aBuffer), aLength, &written);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
stream->ErrorPropagation(aCx, lock, aStream, rv);
|
||||
return;
|
||||
}
|
||||
|
||||
*aByteWritten = written;
|
||||
|
||||
if (written == 0) {
|
||||
stream->CloseAndReleaseObjects(aCx, lock, aStream);
|
||||
return;
|
||||
}
|
||||
|
||||
rv = stream->mInputStream->AsyncWait(stream, 0, 0, stream->mOwningEventTarget);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
stream->ErrorPropagation(aCx, lock, aStream, rv);
|
||||
return;
|
||||
}
|
||||
|
||||
// All good.
|
||||
}
|
||||
|
||||
/* static */ JS::Value
|
||||
FetchStream::CancelCallback(JSContext* aCx, JS::HandleObject aStream,
|
||||
void* aUnderlyingSource, uint8_t aFlags,
|
||||
JS::HandleValue aReason)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(aUnderlyingSource);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aFlags == FETCH_STREAM_FLAG);
|
||||
|
||||
// This is safe because we created an extra reference in FetchStream::Create()
|
||||
// that won't be released until FetchStream::FinalizeCallback() is called.
|
||||
// We are guaranteed that won't happen until the js ReadableStream object
|
||||
// is finalized.
|
||||
FetchStream* stream = static_cast<FetchStream*>(aUnderlyingSource);
|
||||
stream->AssertIsOnOwningThread();
|
||||
|
||||
if (stream->mInputStream) {
|
||||
stream->mInputStream->CloseWithStatus(NS_BASE_STREAM_CLOSED);
|
||||
}
|
||||
|
||||
stream->ReleaseObjects();
|
||||
|
||||
return JS::UndefinedValue();
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
FetchStream::ClosedCallback(JSContext* aCx, JS::HandleObject aStream,
|
||||
void* aUnderlyingSource, uint8_t aFlags)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(aUnderlyingSource);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aFlags == FETCH_STREAM_FLAG);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
FetchStream::ErroredCallback(JSContext* aCx, JS::HandleObject aStream,
|
||||
void* aUnderlyingSource, uint8_t aFlags,
|
||||
JS::HandleValue aReason)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(aUnderlyingSource);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aFlags == FETCH_STREAM_FLAG);
|
||||
|
||||
// This is safe because we created an extra reference in FetchStream::Create()
|
||||
// that won't be released until FetchStream::FinalizeCallback() is called.
|
||||
// We are guaranteed that won't happen until the js ReadableStream object
|
||||
// is finalized.
|
||||
FetchStream* stream = static_cast<FetchStream*>(aUnderlyingSource);
|
||||
stream->AssertIsOnOwningThread();
|
||||
|
||||
if (stream->mState == eInitializing) {
|
||||
// The stream has been used for the first time.
|
||||
stream->mStreamHolder->MarkAsRead();
|
||||
}
|
||||
|
||||
if (stream->mInputStream) {
|
||||
stream->mInputStream->CloseWithStatus(NS_BASE_STREAM_CLOSED);
|
||||
}
|
||||
|
||||
stream->ReleaseObjects();
|
||||
}
|
||||
|
||||
void
|
||||
FetchStream::FinalizeCallback(void* aUnderlyingSource, uint8_t aFlags)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(aUnderlyingSource);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aFlags == FETCH_STREAM_FLAG);
|
||||
|
||||
// This can be called in any thread.
|
||||
|
||||
// This takes ownership of the ref created in FetchStream::Create().
|
||||
RefPtr<FetchStream> stream =
|
||||
dont_AddRef(static_cast<FetchStream*>(aUnderlyingSource));
|
||||
|
||||
stream->ReleaseObjects();
|
||||
}
|
||||
|
||||
FetchStream::FetchStream(nsIGlobalObject* aGlobal,
|
||||
FetchStreamHolder* aStreamHolder,
|
||||
nsIInputStream* aInputStream)
|
||||
: mMutex("FetchStream::mMutex")
|
||||
, mState(eInitializing)
|
||||
, mGlobal(aGlobal)
|
||||
, mStreamHolder(aStreamHolder)
|
||||
, mOriginalInputStream(aInputStream)
|
||||
// TODO: Replace with mGlobal->EventTargetFor(TaskCategory::Other)
|
||||
// When we have the Dispatcher API in the tree, see Issue #1442
|
||||
, mOwningEventTarget(NS_GetCurrentThread())
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(aInputStream);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aStreamHolder);
|
||||
}
|
||||
|
||||
FetchStream::~FetchStream()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FetchStream::ErrorPropagation(JSContext* aCx,
|
||||
const MutexAutoLock& aProofOfLock,
|
||||
JS::HandleObject aStream,
|
||||
nsresult aError)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// Nothing to do.
|
||||
if (mState == eClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Let's close the stream.
|
||||
if (aError == NS_BASE_STREAM_CLOSED) {
|
||||
CloseAndReleaseObjects(aCx, aProofOfLock, aStream);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mGlobal);
|
||||
|
||||
// Let's use a generic error.
|
||||
RefPtr<DOMError> error = new DOMError(window, NS_ERROR_DOM_TYPE_ERR);
|
||||
|
||||
JS::Rooted<JS::Value> errorValue(aCx);
|
||||
if (ToJSValue(aCx, error, &errorValue)) {
|
||||
MutexAutoUnlock unlock(mMutex);
|
||||
JS::ReadableStreamError(aCx, aStream, errorValue);
|
||||
}
|
||||
|
||||
ReleaseObjects(aProofOfLock);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FetchStream::OnInputStreamReady(nsIAsyncInputStream* aStream)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_DIAGNOSTIC_ASSERT(aStream);
|
||||
|
||||
Maybe<MutexAutoLock> lock;
|
||||
lock.emplace(mMutex);
|
||||
|
||||
// Already closed. We have nothing else to do here.
|
||||
if (mState == eClosed) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoMicroTask mt;
|
||||
AutoEntryScript aes(mGlobal, "fetch body data available");
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(mInputStream);
|
||||
MOZ_DIAGNOSTIC_ASSERT(mState == eReading || mState == eChecking);
|
||||
|
||||
JSContext* cx = aes.cx();
|
||||
JS::Rooted<JSObject*> stream(cx, mStreamHolder->ReadableStreamBody());
|
||||
|
||||
uint64_t size = 0;
|
||||
nsresult rv = mInputStream->Available(&size);
|
||||
if (NS_SUCCEEDED(rv) && size == 0) {
|
||||
// In theory this should not happen. If size is 0, the stream should be
|
||||
// considered closed.
|
||||
rv = NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
// No warning for stream closed.
|
||||
if (rv == NS_BASE_STREAM_CLOSED || NS_WARN_IF(NS_FAILED(rv))) {
|
||||
ErrorPropagation(cx, *lock, stream, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// This extra checking is completed. Let's wait for the next read request.
|
||||
if (mState == eChecking) {
|
||||
mState = eWaiting;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mState = eWriting;
|
||||
|
||||
lock.reset();
|
||||
|
||||
JS::ReadableStreamUpdateDataAvailableFromSource(cx, stream, size);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
FetchStream::RetrieveInputStream(void* aUnderlyingReadableStreamSource,
|
||||
nsIInputStream** aInputStream)
|
||||
{
|
||||
MOZ_ASSERT(aUnderlyingReadableStreamSource);
|
||||
MOZ_ASSERT(aInputStream);
|
||||
|
||||
RefPtr<FetchStream> stream =
|
||||
static_cast<FetchStream*>(aUnderlyingReadableStreamSource);
|
||||
stream->AssertIsOnOwningThread();
|
||||
|
||||
// if mOriginalInputStream is null, the reading already started. We don't want
|
||||
// to expose the internal inputStream.
|
||||
if (NS_WARN_IF(!stream->mOriginalInputStream)) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream = stream->mOriginalInputStream;
|
||||
inputStream.forget(aInputStream);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
FetchStream::Close()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
if (mState == eClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(mGlobal))) {
|
||||
ReleaseObjects(lock);
|
||||
return;
|
||||
}
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JSObject*> stream(cx, mStreamHolder->ReadableStreamBody());
|
||||
|
||||
CloseAndReleaseObjects(cx, lock, stream);
|
||||
}
|
||||
|
||||
void
|
||||
FetchStream::CloseAndReleaseObjects(JSContext* aCx,
|
||||
const MutexAutoLock& aProofOfLock,
|
||||
JS::HandleObject aStream)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_DIAGNOSTIC_ASSERT(mState != eClosed);
|
||||
|
||||
ReleaseObjects(aProofOfLock);
|
||||
|
||||
MutexAutoUnlock unlock(mMutex);
|
||||
|
||||
if (JS::ReadableStreamIsReadable(aStream)) {
|
||||
JS::ReadableStreamClose(aCx, aStream);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FetchStream::ReleaseObjects()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
ReleaseObjects(lock);
|
||||
}
|
||||
|
||||
void
|
||||
FetchStream::ReleaseObjects(const MutexAutoLock& aProofOfLock)
|
||||
{
|
||||
// This method can be called on 2 possible threads: the owning one and a JS
|
||||
// thread used to release resources. If we are on the JS thread, we need to
|
||||
// dispatch a runnable to go back to the owning thread in order to release
|
||||
// resources correctly.
|
||||
|
||||
if (mState == eClosed) {
|
||||
// Already gone. Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
mState = eClosed;
|
||||
|
||||
if (mWorkerHolder) {
|
||||
RefPtr<FetchStreamWorkerHolderShutdown> r =
|
||||
new FetchStreamWorkerHolderShutdown(
|
||||
static_cast<FetchStreamWorkerHolder*>(mWorkerHolder.get())->GetWorkerPrivate(),
|
||||
Move(mWorkerHolder), Move(mGlobal), Move(mStreamHolder));
|
||||
r->Dispatch();
|
||||
} else {
|
||||
RefPtr<FetchStream> self = this;
|
||||
RefPtr<Runnable> r = NS_NewRunnableFunction(
|
||||
[self] () {
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
if (os) {
|
||||
os->RemoveObserver(self, DOM_WINDOW_DESTROYED_TOPIC);
|
||||
}
|
||||
self->mGlobal = nullptr;
|
||||
|
||||
self->mStreamHolder->NullifyStream();
|
||||
self->mStreamHolder = nullptr;
|
||||
});
|
||||
|
||||
NS_DispatchToMainThread(r);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
FetchStream::AssertIsOnOwningThread()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(FetchStream);
|
||||
}
|
||||
#endif
|
||||
|
||||
// nsIObserver
|
||||
// -----------
|
||||
|
||||
NS_IMETHODIMP
|
||||
FetchStream::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
MOZ_ASSERT(strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC) == 0);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mGlobal);
|
||||
if (SameCOMIdentity(aSubject, window)) {
|
||||
Close();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
@@ -0,0 +1,158 @@
|
||||
/* -*- Mode: C; tab-width: 8; 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/. */
|
||||
|
||||
#ifndef mozilla_dom_FetchStream_h
|
||||
#define mozilla_dom_FetchStream_h
|
||||
|
||||
#include "Fetch.h"
|
||||
#include "jsapi.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
class nsIGlobalObject;
|
||||
|
||||
class nsIInputStream;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
namespace workers {
|
||||
class WorkerHolder;
|
||||
}
|
||||
|
||||
class FetchStreamHolder;
|
||||
|
||||
class FetchStream final : public nsIInputStreamCallback
|
||||
, public nsIObserver
|
||||
, public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIINPUTSTREAMCALLBACK
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
static void
|
||||
Create(JSContext* aCx, FetchStreamHolder* aStreamHolder,
|
||||
nsIGlobalObject* aGlobal, nsIInputStream* aInputStream,
|
||||
JS::MutableHandle<JSObject*> aStream, ErrorResult& aRv);
|
||||
|
||||
void
|
||||
Close();
|
||||
|
||||
static nsresult
|
||||
RetrieveInputStream(void* aUnderlyingReadableStreamSource,
|
||||
nsIInputStream** aInputStream);
|
||||
private:
|
||||
FetchStream(nsIGlobalObject* aGlobal,
|
||||
FetchStreamHolder* aStreamHolder,
|
||||
nsIInputStream* aInputStream);
|
||||
~FetchStream();
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
AssertIsOnOwningThread();
|
||||
#else
|
||||
void
|
||||
AssertIsOnOwningThread() {}
|
||||
#endif
|
||||
|
||||
static void
|
||||
RequestDataCallback(JSContext* aCx, JS::HandleObject aStream,
|
||||
void* aUnderlyingSource, uint8_t aFlags,
|
||||
size_t aDesiredSize);
|
||||
|
||||
static void
|
||||
WriteIntoReadRequestCallback(JSContext* aCx, JS::HandleObject aStream,
|
||||
void* aUnderlyingSource, uint8_t aFlags,
|
||||
void* aBuffer, size_t aLength,
|
||||
size_t* aByteWritten);
|
||||
|
||||
static JS::Value
|
||||
CancelCallback(JSContext* aCx, JS::HandleObject aStream,
|
||||
void* aUnderlyingSource, uint8_t aFlags,
|
||||
JS::HandleValue aReason);
|
||||
|
||||
static void
|
||||
ClosedCallback(JSContext* aCx, JS::HandleObject aStream,
|
||||
void* aUnderlyingSource, uint8_t aFlags);
|
||||
|
||||
static void
|
||||
ErroredCallback(JSContext* aCx, JS::HandleObject aStream,
|
||||
void* aUnderlyingSource, uint8_t aFlags,
|
||||
JS::HandleValue reason);
|
||||
|
||||
static void
|
||||
FinalizeCallback(void* aUnderlyingSource, uint8_t aFlags);
|
||||
|
||||
void
|
||||
ErrorPropagation(JSContext* aCx,
|
||||
const MutexAutoLock& aProofOfLock,
|
||||
JS::HandleObject aStream, nsresult aRv);
|
||||
|
||||
void
|
||||
CloseAndReleaseObjects(JSContext* aCx,
|
||||
const MutexAutoLock& aProofOfLock,
|
||||
JS::HandleObject aSteam);
|
||||
|
||||
class WorkerShutdown;
|
||||
|
||||
void
|
||||
ReleaseObjects(const MutexAutoLock& aProofOfLock);
|
||||
|
||||
void
|
||||
ReleaseObjects();
|
||||
|
||||
// Common methods
|
||||
|
||||
enum State {
|
||||
// This is the beginning state before any reading operation.
|
||||
eInitializing,
|
||||
|
||||
// RequestDataCallback has not been called yet. We haven't started to read
|
||||
// data from the stream yet.
|
||||
eWaiting,
|
||||
|
||||
// We are reading data in a separate I/O thread.
|
||||
eReading,
|
||||
|
||||
// We are ready to write something in the JS Buffer.
|
||||
eWriting,
|
||||
|
||||
// After a writing, we want to check if the stream is closed. After the
|
||||
// check, we go back to eWaiting. If a reading request happens in the
|
||||
// meantime, we move to eReading state.
|
||||
eChecking,
|
||||
|
||||
// Operation completed.
|
||||
eClosed,
|
||||
};
|
||||
|
||||
// We need a mutex because JS engine can release FetchStream on a non-owning
|
||||
// thread. We must be sure that the releasing of resources doesn't trigger
|
||||
// race conditions.
|
||||
Mutex mMutex;
|
||||
|
||||
// Protected by mutex.
|
||||
State mState;
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
RefPtr<FetchStreamHolder> mStreamHolder;
|
||||
nsCOMPtr<nsIEventTarget> mOwningEventTarget;
|
||||
|
||||
// This is the original inputStream received during the CTOR. It will be
|
||||
// converted into an nsIAsyncInputStream and stored into mInputStream at the
|
||||
// first use.
|
||||
nsCOMPtr<nsIInputStream> mOriginalInputStream;
|
||||
nsCOMPtr<nsIAsyncInputStream> mInputStream;
|
||||
|
||||
UniquePtr<workers::WorkerHolder> mWorkerHolder;
|
||||
};
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
|
||||
#endif // mozilla_dom_FetchStream_h
|
||||
@@ -0,0 +1,405 @@
|
||||
/* -*- 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 "FetchStreamReader.h"
|
||||
#include "InternalResponse.h"
|
||||
#include "mozilla/dom/PromiseBinding.h"
|
||||
#include "mozilla/dom/DOMException.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
using namespace workers;
|
||||
|
||||
namespace {
|
||||
|
||||
class FetchStreamReaderWorkerHolder final : public WorkerHolder
|
||||
{
|
||||
public:
|
||||
explicit FetchStreamReaderWorkerHolder(FetchStreamReader* aReader)
|
||||
: WorkerHolder(WorkerHolder::Behavior::AllowIdleShutdownStart)
|
||||
, mReader(aReader)
|
||||
, mWasNotified(false)
|
||||
{}
|
||||
|
||||
bool Notify(Status aStatus) override
|
||||
{
|
||||
if (!mWasNotified) {
|
||||
mWasNotified = true;
|
||||
// The WorkerPrivate does have a context available, and we could pass it
|
||||
// here to trigger cancellation of the reader, but the author of this
|
||||
// comment chickened out.
|
||||
mReader->CloseAndRelease(nullptr, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<FetchStreamReader> mReader;
|
||||
bool mWasNotified;
|
||||
};
|
||||
|
||||
} // anonymous
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(FetchStreamReader)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(FetchStreamReader)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(FetchStreamReader)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FetchStreamReader)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(FetchStreamReader)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(FetchStreamReader)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mReader)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FetchStreamReader)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIOutputStreamCallback)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIOutputStreamCallback)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
/* static */ nsresult
|
||||
FetchStreamReader::Create(JSContext* aCx, nsIGlobalObject* aGlobal,
|
||||
FetchStreamReader** aStreamReader,
|
||||
nsIInputStream** aInputStream)
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
MOZ_ASSERT(aGlobal);
|
||||
MOZ_ASSERT(aStreamReader);
|
||||
MOZ_ASSERT(aInputStream);
|
||||
|
||||
RefPtr<FetchStreamReader> streamReader = new FetchStreamReader(aGlobal);
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> pipeIn;
|
||||
|
||||
nsresult rv = NS_NewPipe2(getter_AddRefs(pipeIn),
|
||||
getter_AddRefs(streamReader->mPipeOut),
|
||||
true, true, 0, 0);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
// We need to know when the worker goes away.
|
||||
UniquePtr<FetchStreamReaderWorkerHolder> holder(
|
||||
new FetchStreamReaderWorkerHolder(streamReader));
|
||||
if (NS_WARN_IF(!holder->HoldWorker(workerPrivate, Closing))) {
|
||||
streamReader->mPipeOut->CloseWithStatus(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
// These 2 objects create a ref-cycle here that is broken when the stream is
|
||||
// closed or the worker shutsdown.
|
||||
streamReader->mWorkerHolder = Move(holder);
|
||||
}
|
||||
|
||||
pipeIn.forget(aInputStream);
|
||||
streamReader.forget(aStreamReader);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
FetchStreamReader::FetchStreamReader(nsIGlobalObject* aGlobal)
|
||||
: mGlobal(aGlobal)
|
||||
// TODO: Replace with mGlobal->EventTargetFor(TaskCategory::Other)
|
||||
// When we have the Dispatcher API in the tree, see Issue #1442
|
||||
, mOwningEventTarget(NS_GetCurrentThread())
|
||||
, mBufferRemaining(0)
|
||||
, mBufferOffset(0)
|
||||
, mStreamClosed(false)
|
||||
{
|
||||
MOZ_ASSERT(aGlobal);
|
||||
}
|
||||
|
||||
FetchStreamReader::~FetchStreamReader()
|
||||
{
|
||||
CloseAndRelease(nullptr, NS_BASE_STREAM_CLOSED);
|
||||
}
|
||||
|
||||
// If a context is provided, an attempt will be made to cancel the reader. The
|
||||
// only situation where we don't expect to have a context is when closure is
|
||||
// being triggered from the destructor or the WorkerHolder is notifying. If
|
||||
// we're at the destructor, it's far too late to cancel anything. And if the
|
||||
// WorkerHolder is being notified, the global is going away, so there's also
|
||||
// no need to do further JS work.
|
||||
void
|
||||
FetchStreamReader::CloseAndRelease(JSContext* aCx, nsresult aStatus)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(FetchStreamReader);
|
||||
|
||||
if (mStreamClosed) {
|
||||
// Already closed.
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<FetchStreamReader> kungFuDeathGrip = this;
|
||||
|
||||
if (aCx) {
|
||||
MOZ_ASSERT(mReader);
|
||||
|
||||
RefPtr<DOMException> error = DOMException::Create(aStatus);
|
||||
|
||||
JS::Rooted<JS::Value> errorValue(aCx);
|
||||
if (ToJSValue(aCx, error, &errorValue)) {
|
||||
JS::Rooted<JSObject*> reader(aCx, mReader);
|
||||
// It's currently safe to cancel an already closed reader because, per the
|
||||
// comments in ReadableStream::cancel() conveying the spec, step 2 of
|
||||
// 3.4.3 that specified ReadableStreamCancel is: If stream.[[state]] is
|
||||
// "closed", return a new promise resolved with undefined.
|
||||
JS::ReadableStreamReaderCancel(aCx, reader, errorValue);
|
||||
}
|
||||
}
|
||||
mStreamClosed = true;
|
||||
|
||||
mGlobal = nullptr;
|
||||
|
||||
mPipeOut->CloseWithStatus(aStatus);
|
||||
mPipeOut = nullptr;
|
||||
|
||||
mWorkerHolder = nullptr;
|
||||
|
||||
mReader = nullptr;
|
||||
mBuffer = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
FetchStreamReader::StartConsuming(JSContext* aCx,
|
||||
JS::HandleObject aStream,
|
||||
JS::MutableHandle<JSObject*> aReader,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mReader);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aStream);
|
||||
|
||||
JS::Rooted<JSObject*> reader(aCx,
|
||||
JS::ReadableStreamGetReader(aCx, aStream,
|
||||
JS::ReadableStreamReaderMode::Default));
|
||||
if (!reader) {
|
||||
aRv.StealExceptionFromJSContext(aCx);
|
||||
CloseAndRelease(aCx, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
mReader = reader;
|
||||
aReader.set(reader);
|
||||
|
||||
aRv = mPipeOut->AsyncWait(this, 0, 0, mOwningEventTarget);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// nsIOutputStreamCallback interface
|
||||
|
||||
NS_IMETHODIMP
|
||||
FetchStreamReader::OnOutputStreamReady(nsIAsyncOutputStream* aStream)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(FetchStreamReader);
|
||||
MOZ_ASSERT(aStream == mPipeOut);
|
||||
MOZ_ASSERT(mReader);
|
||||
|
||||
if (mStreamClosed) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mBuffer) {
|
||||
return WriteBuffer();
|
||||
}
|
||||
|
||||
// TODO: We need to verify this is the correct global per the spec.
|
||||
// See bug 1385890.
|
||||
AutoEntryScript aes(mGlobal, "ReadableStreamReader.read", !mWorkerHolder);
|
||||
|
||||
JS::Rooted<JSObject*> reader(aes.cx(), mReader);
|
||||
JS::Rooted<JSObject*> promise(aes.cx(),
|
||||
JS::ReadableStreamDefaultReaderRead(aes.cx(),
|
||||
reader));
|
||||
if (NS_WARN_IF(!promise)) {
|
||||
// Let's close the stream.
|
||||
CloseAndRelease(aes.cx(), NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RefPtr<Promise> domPromise = Promise::CreateFromExisting(mGlobal, promise);
|
||||
if (NS_WARN_IF(!domPromise)) {
|
||||
// Let's close the stream.
|
||||
CloseAndRelease(aes.cx(), NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Let's wait.
|
||||
domPromise->AppendNativeHandler(this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
FetchStreamReader::ResolvedCallback(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue)
|
||||
{
|
||||
if (mStreamClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This promise should be resolved with { done: boolean, value: something },
|
||||
// "value" is interesting only if done is false.
|
||||
|
||||
// We don't want to play with JS api, let's WebIDL bindings doing it for us.
|
||||
// FetchReadableStreamReadDataDone is a dictionary with just a boolean, if the
|
||||
// parsing succeeded, we can proceed with the parsing of the "value", which it
|
||||
// must be a Uint8Array.
|
||||
FetchReadableStreamReadDataDone valueDone;
|
||||
if (!valueDone.Init(aCx, aValue)) {
|
||||
JS_ClearPendingException(aCx);
|
||||
CloseAndRelease(aCx, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (valueDone.mDone) {
|
||||
// Stream is completed.
|
||||
CloseAndRelease(aCx, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
UniquePtr<FetchReadableStreamReadDataArray> value(
|
||||
new FetchReadableStreamReadDataArray);
|
||||
if (!value->Init(aCx, aValue) || !value->mValue.WasPassed()) {
|
||||
JS_ClearPendingException(aCx);
|
||||
CloseAndRelease(aCx, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
Uint8Array& array = value->mValue.Value();
|
||||
array.ComputeLengthAndData();
|
||||
uint32_t len = array.Length();
|
||||
|
||||
if (len == 0) {
|
||||
// If there is nothing to read, let's do another reading.
|
||||
OnOutputStreamReady(mPipeOut);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mBuffer);
|
||||
mBuffer = Move(value);
|
||||
|
||||
mBufferOffset = 0;
|
||||
mBufferRemaining = len;
|
||||
|
||||
nsresult rv = WriteBuffer();
|
||||
if (NS_FAILED(rv)) {
|
||||
// DOMException only understands errors from domerr.msg, so we normalize to
|
||||
// identifying an abort if the write fails.
|
||||
CloseAndRelease(aCx, NS_ERROR_DOM_ABORT_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
FetchStreamReader::WriteBuffer()
|
||||
{
|
||||
MOZ_ASSERT(mBuffer);
|
||||
MOZ_ASSERT(mBuffer->mValue.WasPassed());
|
||||
|
||||
Uint8Array& array = mBuffer->mValue.Value();
|
||||
char* data = reinterpret_cast<char*>(array.Data());
|
||||
|
||||
while (1) {
|
||||
uint32_t written = 0;
|
||||
nsresult rv =
|
||||
mPipeOut->Write(data + mBufferOffset, mBufferRemaining, &written);
|
||||
|
||||
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(written <= mBufferRemaining);
|
||||
mBufferRemaining -= written;
|
||||
mBufferOffset += written;
|
||||
|
||||
if (mBufferRemaining == 0) {
|
||||
mBuffer = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv = mPipeOut->AsyncWait(this, 0, 0, mOwningEventTarget);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
FetchStreamReader::RejectedCallback(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue)
|
||||
{
|
||||
ReportErrorToConsole(aCx, aValue);
|
||||
CloseAndRelease(aCx, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
void
|
||||
FetchStreamReader::ReportErrorToConsole(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue)
|
||||
{
|
||||
nsCString sourceSpec;
|
||||
uint32_t line = 0;
|
||||
uint32_t column = 0;
|
||||
nsString valueString;
|
||||
|
||||
nsContentUtils::ExtractErrorValues(aCx, aValue, sourceSpec, &line,
|
||||
&column, valueString);
|
||||
|
||||
nsTArray<nsString> params;
|
||||
params.AppendElement(valueString);
|
||||
|
||||
RefPtr<ConsoleReportCollector> reporter = new ConsoleReportCollector();
|
||||
reporter->AddConsoleReport(nsIScriptError::errorFlag,
|
||||
NS_LITERAL_CSTRING("ReadableStreamReader.read"),
|
||||
nsContentUtils::eDOM_PROPERTIES,
|
||||
sourceSpec, line, column,
|
||||
NS_LITERAL_CSTRING("ReadableStreamReadingFailed"),
|
||||
params);
|
||||
|
||||
uint64_t innerWindowId = 0;
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mGlobal);
|
||||
if (window) {
|
||||
innerWindowId = window->WindowID();
|
||||
}
|
||||
reporter->FlushReportsByWindowId(innerWindowId);
|
||||
return;
|
||||
}
|
||||
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
|
||||
if (workerPrivate) {
|
||||
innerWindowId = workerPrivate->WindowID();
|
||||
}
|
||||
|
||||
RefPtr<Runnable> r = NS_NewRunnableFunction(
|
||||
[reporter, innerWindowId] () {
|
||||
reporter->FlushReportsByWindowId(innerWindowId);
|
||||
});
|
||||
|
||||
workerPrivate->DispatchToMainThread(r.forget());
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
@@ -0,0 +1,85 @@
|
||||
/* -*- 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 mozilla_dom_FetchStreamReader_h
|
||||
#define mozilla_dom_FetchStreamReader_h
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "mozilla/dom/FetchBinding.h"
|
||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
||||
#include "nsIAsyncOutputStream.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
namespace workers {
|
||||
class WorkerHolder;
|
||||
}
|
||||
|
||||
class FetchStreamReader final : public nsIOutputStreamCallback
|
||||
, public PromiseNativeHandler
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(FetchStreamReader, nsIOutputStreamCallback)
|
||||
NS_DECL_NSIOUTPUTSTREAMCALLBACK
|
||||
|
||||
// This creates a nsIInputStream able to retrieve data from the ReadableStream
|
||||
// object. The reading starts when StartConsuming() is called.
|
||||
static nsresult
|
||||
Create(JSContext* aCx, nsIGlobalObject* aGlobal,
|
||||
FetchStreamReader** aStreamReader,
|
||||
nsIInputStream** aInputStream);
|
||||
|
||||
void
|
||||
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
|
||||
|
||||
void
|
||||
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
|
||||
|
||||
// Idempotently close the output stream and null out all state. If aCx is
|
||||
// provided, the reader will also be canceled. aStatus must be a DOM error
|
||||
// as understood by DOMException because it will be provided as the
|
||||
// cancellation reason.
|
||||
void
|
||||
CloseAndRelease(JSContext* aCx, nsresult aStatus);
|
||||
|
||||
void
|
||||
StartConsuming(JSContext* aCx,
|
||||
JS::HandleObject aStream,
|
||||
JS::MutableHandle<JSObject*> aReader,
|
||||
ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
explicit FetchStreamReader(nsIGlobalObject* aGlobal);
|
||||
~FetchStreamReader();
|
||||
|
||||
nsresult
|
||||
WriteBuffer();
|
||||
|
||||
void
|
||||
ReportErrorToConsole(JSContext* aCx, JS::Handle<JS::Value> aValue);
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
nsCOMPtr<nsIEventTarget> mOwningEventTarget;
|
||||
|
||||
nsCOMPtr<nsIAsyncOutputStream> mPipeOut;
|
||||
|
||||
UniquePtr<workers::WorkerHolder> mWorkerHolder;
|
||||
|
||||
JS::Heap<JSObject*> mReader;
|
||||
|
||||
UniquePtr<FetchReadableStreamReadDataArray> mBuffer;
|
||||
uint32_t mBufferRemaining;
|
||||
uint32_t mBufferOffset;
|
||||
|
||||
bool mStreamClosed;
|
||||
};
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
|
||||
#endif // mozilla_dom_FetchStreamReader_h
|
||||
@@ -139,18 +139,18 @@ InternalResponse::ToIPC(IPCInternalResponse* aIPCResponse,
|
||||
}
|
||||
|
||||
already_AddRefed<InternalResponse>
|
||||
InternalResponse::Clone()
|
||||
InternalResponse::Clone(CloneType aCloneType)
|
||||
{
|
||||
RefPtr<InternalResponse> clone = CreateIncompleteCopy();
|
||||
|
||||
clone->mHeaders = new InternalHeaders(*mHeaders);
|
||||
if (mWrappedResponse) {
|
||||
clone->mWrappedResponse = mWrappedResponse->Clone();
|
||||
clone->mWrappedResponse = mWrappedResponse->Clone(aCloneType);
|
||||
MOZ_ASSERT(!mBody);
|
||||
return clone.forget();
|
||||
}
|
||||
|
||||
if (!mBody) {
|
||||
if (!mBody || aCloneType == eDontCloneInputStream) {
|
||||
return clone.forget();
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,13 @@ public:
|
||||
M* aManager,
|
||||
UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoStream);
|
||||
|
||||
already_AddRefed<InternalResponse> Clone();
|
||||
enum CloneType
|
||||
{
|
||||
eCloneInputStream,
|
||||
eDontCloneInputStream,
|
||||
};
|
||||
|
||||
already_AddRefed<InternalResponse> Clone(CloneType eCloneType);
|
||||
|
||||
static already_AddRefed<InternalResponse>
|
||||
NetworkError()
|
||||
|
||||
+30
-12
@@ -29,7 +29,25 @@ using namespace workers;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(Request)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(Request)
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Request, mOwner, mHeaders)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(Request)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Request)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mHeaders)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Request)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHeaders)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Request)
|
||||
MOZ_DIAGNOSTIC_ASSERT(!tmp->mReadableStreamReader);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mReadableStreamReader)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Request)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
@@ -37,8 +55,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Request)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
Request::Request(nsIGlobalObject* aOwner, InternalRequest* aRequest, AbortSignal* aSignal)
|
||||
: FetchBody<Request>()
|
||||
, mOwner(aOwner)
|
||||
: FetchBody<Request>(aOwner)
|
||||
, mRequest(aRequest)
|
||||
, mSignal(aSignal)
|
||||
{
|
||||
@@ -557,17 +574,15 @@ Request::Constructor(const GlobalObject& aGlobal,
|
||||
}
|
||||
|
||||
if (aInit.mBody.WasPassed()) {
|
||||
const Nullable<OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>& bodyInitNullable =
|
||||
aInit.mBody.Value();
|
||||
const Nullable<fetch::OwningBodyInit>& bodyInitNullable = aInit.mBody.Value();
|
||||
if (!bodyInitNullable.IsNull()) {
|
||||
const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& bodyInit =
|
||||
bodyInitNullable.Value();
|
||||
const fetch::OwningBodyInit& bodyInit = bodyInitNullable.Value();
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
nsAutoCString contentType;
|
||||
nsAutoCString contentTypeWithCharset;
|
||||
uint64_t contentLengthUnused;
|
||||
aRv = ExtractByteStreamFromBody(bodyInit,
|
||||
getter_AddRefs(stream),
|
||||
contentType,
|
||||
contentTypeWithCharset,
|
||||
contentLengthUnused);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
@@ -575,10 +590,10 @@ Request::Constructor(const GlobalObject& aGlobal,
|
||||
|
||||
temporaryBody = stream;
|
||||
|
||||
if (!contentType.IsVoid() &&
|
||||
if (!contentTypeWithCharset.IsVoid() &&
|
||||
!requestHeaders->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) {
|
||||
requestHeaders->Append(NS_LITERAL_CSTRING("Content-Type"),
|
||||
contentType, aRv);
|
||||
contentTypeWithCharset, aRv);
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
@@ -599,7 +614,10 @@ Request::Constructor(const GlobalObject& aGlobal,
|
||||
inputReq->GetBody(getter_AddRefs(body));
|
||||
if (body) {
|
||||
inputReq->SetBody(nullptr);
|
||||
inputReq->SetBodyUsed();
|
||||
inputReq->SetBodyUsed(aGlobal.Context(), aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return domRequest.forget();
|
||||
|
||||
+2
-1
@@ -128,6 +128,8 @@ public:
|
||||
void
|
||||
GetBody(nsIInputStream** aStream) { return mRequest->GetBody(aStream); }
|
||||
|
||||
using FetchBody::GetBody;
|
||||
|
||||
void
|
||||
SetBody(nsIInputStream* aStream) { return mRequest->SetBody(aStream); }
|
||||
|
||||
@@ -162,7 +164,6 @@ public:
|
||||
private:
|
||||
~Request();
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> mOwner;
|
||||
RefPtr<InternalRequest> mRequest;
|
||||
|
||||
// Lazily created.
|
||||
|
||||
+168
-22
@@ -12,12 +12,16 @@
|
||||
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/FetchBinding.h"
|
||||
#include "mozilla/dom/ResponseBinding.h"
|
||||
#include "mozilla/dom/Headers.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/URL.h"
|
||||
|
||||
#include "nsDOMString.h"
|
||||
|
||||
#include "BodyExtractor.h"
|
||||
#include "FetchStream.h"
|
||||
#include "FetchStreamReader.h"
|
||||
#include "InternalResponse.h"
|
||||
#include "WorkerPrivate.h"
|
||||
|
||||
@@ -26,7 +30,31 @@ namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(Response)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(Response)
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Response, mOwner, mHeaders)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(Response)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Response)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mHeaders)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFetchStreamReader)
|
||||
|
||||
tmp->mReadableStreamBody = nullptr;
|
||||
tmp->mReadableStreamReader = nullptr;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Response)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHeaders)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFetchStreamReader)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Response)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mReadableStreamBody)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mReadableStreamReader)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Response)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
@@ -34,18 +62,21 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Response)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
Response::Response(nsIGlobalObject* aGlobal, InternalResponse* aInternalResponse, AbortSignal* aSignal)
|
||||
: FetchBody<Response>()
|
||||
, mOwner(aGlobal)
|
||||
: FetchBody<Response>(aGlobal)
|
||||
, mInternalResponse(aInternalResponse)
|
||||
, mSignal(aSignal)
|
||||
{
|
||||
MOZ_ASSERT(aInternalResponse->Headers()->Guard() == HeadersGuardEnum::Immutable ||
|
||||
aInternalResponse->Headers()->Guard() == HeadersGuardEnum::Response);
|
||||
SetMimeType();
|
||||
|
||||
// Keep a firm grip!
|
||||
mozilla::HoldJSObjects(this);
|
||||
}
|
||||
|
||||
Response::~Response()
|
||||
{
|
||||
mozilla::DropJSObjects(this);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<Response>
|
||||
@@ -106,7 +137,7 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Optional<Nullable<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>> body;
|
||||
Optional<fetch::ResponseBodyInit> body;
|
||||
ResponseInit init;
|
||||
init.mStatus = aStatus;
|
||||
RefPtr<Response> r = Response::Constructor(aGlobal, body, init, aRv);
|
||||
@@ -127,7 +158,7 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl,
|
||||
|
||||
/*static*/ already_AddRefed<Response>
|
||||
Response::Constructor(const GlobalObject& aGlobal,
|
||||
const Optional<Nullable<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>>& aBody,
|
||||
const Optional<fetch::ResponseBodyInit>& aBody,
|
||||
const ResponseInit& aInit, ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
@@ -193,29 +224,86 @@ Response::Constructor(const GlobalObject& aGlobal,
|
||||
}
|
||||
}
|
||||
|
||||
if (aBody.WasPassed() && !aBody.Value().IsNull()) {
|
||||
if (aBody.WasPassed()) {
|
||||
if (aInit.mStatus == 204 || aInit.mStatus == 205 || aInit.mStatus == 304) {
|
||||
aRv.ThrowTypeError<MSG_RESPONSE_NULL_STATUS_WITH_BODY>();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCString contentTypeWithCharset;
|
||||
nsCOMPtr<nsIInputStream> bodyStream;
|
||||
nsCString contentType;
|
||||
uint64_t bodySize = 0;
|
||||
aRv = ExtractByteStreamFromBody(aBody.Value().Value(),
|
||||
getter_AddRefs(bodyStream),
|
||||
contentType,
|
||||
bodySize);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
int64_t bodySize = InternalResponse::UNKNOWN_BODY_SIZE;
|
||||
|
||||
if (aBody.Value().IsReadableStream()) {
|
||||
const ReadableStream& readableStream =
|
||||
aBody.Value().GetAsReadableStream();
|
||||
|
||||
JS::Rooted<JSObject*> readableStreamObj(aGlobal.Context(),
|
||||
readableStream.Obj());
|
||||
|
||||
if (JS::ReadableStreamIsDisturbed(readableStreamObj) ||
|
||||
JS::ReadableStreamIsLocked(readableStreamObj) ||
|
||||
!JS::ReadableStreamIsReadable(readableStreamObj)) {
|
||||
aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
r->SetReadableStreamBody(readableStreamObj);
|
||||
|
||||
if (JS::ReadableStreamGetMode(readableStreamObj) ==
|
||||
JS::ReadableStreamMode::ExternalSource) {
|
||||
// If this is a DOM generated ReadableStream, we can extract the
|
||||
// inputStream directly.
|
||||
void* underlyingSource = nullptr;
|
||||
if (!JS::ReadableStreamGetExternalUnderlyingSource(aGlobal.Context(),
|
||||
readableStreamObj,
|
||||
&underlyingSource)) {
|
||||
aRv.StealExceptionFromJSContext(aGlobal.Context());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(underlyingSource);
|
||||
|
||||
aRv = FetchStream::RetrieveInputStream(underlyingSource,
|
||||
getter_AddRefs(bodyStream));
|
||||
|
||||
// The releasing of the external source is needed in order to avoid an
|
||||
// extra stream lock.
|
||||
JS::ReadableStreamReleaseExternalUnderlyingSource(readableStreamObj);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
// If this is a JS-created ReadableStream, let's create a
|
||||
// FetchStreamReader.
|
||||
aRv = FetchStreamReader::Create(aGlobal.Context(), global,
|
||||
getter_AddRefs(r->mFetchStreamReader),
|
||||
getter_AddRefs(bodyStream));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uint64_t size = 0;
|
||||
aRv = ExtractByteStreamFromBody(aBody.Value(),
|
||||
getter_AddRefs(bodyStream),
|
||||
contentTypeWithCharset,
|
||||
size);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bodySize = size;
|
||||
}
|
||||
|
||||
internalResponse->SetBody(bodyStream, bodySize);
|
||||
|
||||
if (!contentType.IsVoid() &&
|
||||
if (!contentTypeWithCharset.IsVoid() &&
|
||||
!internalResponse->Headers()->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) {
|
||||
// Ignore Append() failing here.
|
||||
ErrorResult error;
|
||||
internalResponse->Headers()->Append(NS_LITERAL_CSTRING("Content-Type"), contentType, error);
|
||||
internalResponse->Headers()->Append(NS_LITERAL_CSTRING("Content-Type"),
|
||||
contentTypeWithCharset, error);
|
||||
error.SuppressException();
|
||||
}
|
||||
|
||||
@@ -229,29 +317,87 @@ Response::Constructor(const GlobalObject& aGlobal,
|
||||
}
|
||||
|
||||
already_AddRefed<Response>
|
||||
Response::Clone(ErrorResult& aRv) const
|
||||
Response::Clone(JSContext* aCx, ErrorResult& aRv)
|
||||
{
|
||||
if (BodyUsed()) {
|
||||
aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<InternalResponse> ir = mInternalResponse->Clone();
|
||||
RefPtr<Response> response = new Response(mOwner, ir, mSignal);
|
||||
RefPtr<FetchStreamReader> streamReader;
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
|
||||
JS::Rooted<JSObject*> body(aCx);
|
||||
MaybeTeeReadableStreamBody(aCx, &body,
|
||||
getter_AddRefs(streamReader),
|
||||
getter_AddRefs(inputStream), aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(body, streamReader);
|
||||
MOZ_ASSERT_IF(body, inputStream);
|
||||
|
||||
RefPtr<InternalResponse> ir =
|
||||
mInternalResponse->Clone(body
|
||||
? InternalResponse::eDontCloneInputStream
|
||||
: InternalResponse::eCloneInputStream);
|
||||
|
||||
RefPtr<Response> response = new Response(mOwner, ir, nullptr);
|
||||
|
||||
if (body) {
|
||||
// Maybe we have a body, but we receive null from MaybeTeeReadableStreamBody
|
||||
// if this body is a native stream. In this case, the InternalResponse will
|
||||
// have a clone of the native body and the ReadableStream will be created
|
||||
// lazily if needed.
|
||||
response->SetReadableStreamBody(body);
|
||||
response->mFetchStreamReader = streamReader;
|
||||
ir->SetBody(inputStream, InternalResponse::UNKNOWN_BODY_SIZE);
|
||||
}
|
||||
|
||||
return response.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Response>
|
||||
Response::CloneUnfiltered(ErrorResult& aRv) const
|
||||
Response::CloneUnfiltered(JSContext* aCx, ErrorResult& aRv)
|
||||
{
|
||||
if (BodyUsed()) {
|
||||
aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<InternalResponse> clone = mInternalResponse->Clone();
|
||||
RefPtr<FetchStreamReader> streamReader;
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
|
||||
JS::Rooted<JSObject*> body(aCx);
|
||||
MaybeTeeReadableStreamBody(aCx, &body,
|
||||
getter_AddRefs(streamReader),
|
||||
getter_AddRefs(inputStream), aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(body, streamReader);
|
||||
MOZ_ASSERT_IF(body, inputStream);
|
||||
|
||||
RefPtr<InternalResponse> clone =
|
||||
mInternalResponse->Clone(body
|
||||
? InternalResponse::eDontCloneInputStream
|
||||
: InternalResponse::eCloneInputStream);
|
||||
|
||||
RefPtr<InternalResponse> ir = clone->Unfiltered();
|
||||
RefPtr<Response> ref = new Response(mOwner, ir, mSignal);
|
||||
RefPtr<Response> ref = new Response(mOwner, ir, nullptr);
|
||||
|
||||
if (body) {
|
||||
// Maybe we have a body, but we receive null from MaybeTeeReadableStreamBody
|
||||
// if this body is a native stream. In this case, the InternalResponse will
|
||||
// have a clone of the native body and the ReadableStream will be created
|
||||
// lazily if needed.
|
||||
ref->SetReadableStreamBody(body);
|
||||
ref->mFetchStreamReader = streamReader;
|
||||
ir->SetBody(inputStream, InternalResponse::UNKNOWN_BODY_SIZE);
|
||||
}
|
||||
|
||||
return ref.forget();
|
||||
}
|
||||
|
||||
|
||||
@@ -105,6 +105,8 @@ public:
|
||||
void
|
||||
GetBody(nsIInputStream** aStream) { return mInternalResponse->GetBody(aStream); }
|
||||
|
||||
using FetchBody::GetBody;
|
||||
|
||||
static already_AddRefed<Response>
|
||||
Error(const GlobalObject& aGlobal);
|
||||
|
||||
@@ -113,7 +115,7 @@ public:
|
||||
|
||||
static already_AddRefed<Response>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
const Optional<Nullable<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>>& aBody,
|
||||
const Optional<fetch::ResponseBodyInit>& aBody,
|
||||
const ResponseInit& aInit, ErrorResult& rv);
|
||||
|
||||
nsIGlobalObject* GetParentObject() const
|
||||
@@ -122,10 +124,10 @@ public:
|
||||
}
|
||||
|
||||
already_AddRefed<Response>
|
||||
Clone(ErrorResult& aRv) const;
|
||||
Clone(JSContext* aCx, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Response>
|
||||
CloneUnfiltered(ErrorResult& aRv) const;
|
||||
CloneUnfiltered(JSContext* aCx, ErrorResult& aRv);
|
||||
|
||||
void
|
||||
SetBody(nsIInputStream* aBody, int64_t aBodySize);
|
||||
@@ -142,7 +144,6 @@ public:
|
||||
private:
|
||||
~Response();
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> mOwner;
|
||||
RefPtr<InternalResponse> mInternalResponse;
|
||||
|
||||
// Lazily created
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'BodyExtractor.h',
|
||||
'ChannelInfo.h',
|
||||
'Fetch.h',
|
||||
'FetchDriver.h',
|
||||
'FetchIPCTypes.h',
|
||||
'FetchObserver.h',
|
||||
'FetchStreamReader.h',
|
||||
'FetchUtil.h',
|
||||
'Headers.h',
|
||||
'InternalHeaders.h',
|
||||
@@ -19,11 +21,14 @@ EXPORTS.mozilla.dom += [
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'BodyExtractor.cpp',
|
||||
'ChannelInfo.cpp',
|
||||
'Fetch.cpp',
|
||||
'FetchConsumer.cpp',
|
||||
'FetchDriver.cpp',
|
||||
'FetchObserver.cpp',
|
||||
'FetchStream.cpp',
|
||||
'FetchStreamReader.cpp',
|
||||
'FetchUtil.cpp',
|
||||
'Headers.cpp',
|
||||
'InternalHeaders.cpp',
|
||||
|
||||
@@ -12,9 +12,6 @@
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
#ifdef MOZ_EME
|
||||
#include "mozilla/dom/MediaEncryptedEvent.h"
|
||||
#endif
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "nsIDOMHTMLMediaElement.h"
|
||||
@@ -877,9 +874,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTM
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTextTrackManager)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioTrackList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVideoTrackList)
|
||||
#ifdef MOZ_EME
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaKeys)
|
||||
#endif
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelectedVideoStreamTrack)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingPlayPromises)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
@@ -905,9 +899,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLE
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTextTrackManager)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAudioTrackList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mVideoTrackList)
|
||||
#ifdef MOZ_EME
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMediaKeys)
|
||||
#endif
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelectedVideoStreamTrack)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingPlayPromises)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
@@ -1160,9 +1151,6 @@ void HTMLMediaElement::AbortExistingLoads()
|
||||
mDownloadSuspendedByCache = false;
|
||||
mMediaInfo = MediaInfo();
|
||||
mIsEncrypted = false;
|
||||
#ifdef MOZ_EME
|
||||
mPendingEncryptedInitData.mInitDatas.Clear();
|
||||
#endif
|
||||
mWaitingForKey = NOT_WAITING_FOR_KEY;
|
||||
mSourcePointer = nullptr;
|
||||
|
||||
@@ -1851,20 +1839,6 @@ nsresult HTMLMediaElement::LoadResource()
|
||||
// Set the media element's CORS mode only when loading a resource
|
||||
mCORSMode = AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
|
||||
|
||||
#ifdef MOZ_EME
|
||||
bool isBlob = false;
|
||||
if (mMediaKeys &&
|
||||
Preferences::GetBool("media.eme.mse-only", true) &&
|
||||
// We only want mediaSource URLs, but they are BlobURL, so we have to
|
||||
// check the schema and abort if they are not MediaStream or real Blob.
|
||||
(NS_FAILED(mLoadingSrc->SchemeIs(BLOBURI_SCHEME, &isBlob)) ||
|
||||
!isBlob ||
|
||||
IsMediaStreamURI(mLoadingSrc) ||
|
||||
IsBlobURI(mLoadingSrc))) {
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
#endif
|
||||
|
||||
HTMLMediaElement* other = LookupMediaElementURITable(mLoadingSrc);
|
||||
if (other && other->mDecoder) {
|
||||
// Clone it.
|
||||
@@ -2780,11 +2754,6 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded,
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
#ifdef MOZ_EME
|
||||
if (ContainsRestrictedContent()) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!mOutputStreams.IsEmpty() &&
|
||||
aGraph != mOutputStreams[0].mStream->GetInputStream()->Graph()) {
|
||||
@@ -3981,25 +3950,6 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
|
||||
ms.mFinishWhenEnded);
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
if (mMediaKeys) {
|
||||
if (mMediaKeys->GetCDMProxy()) {
|
||||
mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy());
|
||||
} else {
|
||||
// CDM must have crashed.
|
||||
ShutdownDecoder();
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
MediaEventSource<void>* waitingForKeyProducer = mDecoder->WaitingForKeyEvent();
|
||||
// Not every decoder will produce waitingForKey events, only add ones that can
|
||||
if (waitingForKeyProducer) {
|
||||
mWaitingForKeyListener = waitingForKeyProducer->Connect(
|
||||
AbstractThread::MainThread(), this, &HTMLMediaElement::CannotDecryptWaitingForKey);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mChannelLoader) {
|
||||
mChannelLoader->Done();
|
||||
mChannelLoader = nullptr;
|
||||
@@ -4454,11 +4404,7 @@ void HTMLMediaElement::MetadataLoaded(const MediaInfo* aInfo,
|
||||
|
||||
SetMediaInfo(*aInfo);
|
||||
|
||||
mIsEncrypted = aInfo->IsEncrypted()
|
||||
#ifdef MOZ_EME
|
||||
|| mPendingEncryptedInitData.IsEncrypted()
|
||||
#endif
|
||||
;
|
||||
mIsEncrypted = aInfo->IsEncrypted();
|
||||
mTags = aTags.forget();
|
||||
mLoadedDataFired = false;
|
||||
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
|
||||
@@ -4483,14 +4429,6 @@ void HTMLMediaElement::MetadataLoaded(const MediaInfo* aInfo,
|
||||
"Encrypted content not supported outside of MSE"));
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
// Dispatch a distinct 'encrypted' event for each initData we have.
|
||||
for (const auto& initData : mPendingEncryptedInitData.mInitDatas) {
|
||||
DispatchEncrypted(initData.mInitData, initData.mType);
|
||||
}
|
||||
mPendingEncryptedInitData.mInitDatas.Clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
mWatchManager.ManualNotify(&HTMLMediaElement::UpdateReadyStateInternal);
|
||||
@@ -5424,29 +5362,12 @@ void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendE
|
||||
UpdateSrcMediaStreamPlaying();
|
||||
UpdateAudioChannelPlayingState();
|
||||
if (aPauseElement) {
|
||||
#ifdef MOZ_EME
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (mDecoder) {
|
||||
mDecoder->Pause();
|
||||
mDecoder->Suspend();
|
||||
}
|
||||
mEventDeliveryPaused = aSuspendEvents;
|
||||
} else {
|
||||
#ifdef MOZ_EME
|
||||
MOZ_ASSERT(!mMediaKeys);
|
||||
#endif
|
||||
if (mDecoder) {
|
||||
mDecoder->Resume();
|
||||
if (!mPaused && !mDecoder->IsEnded()) {
|
||||
@@ -5483,17 +5404,6 @@ void HTMLMediaElement::NotifyOwnerDocumentActivityChanged()
|
||||
bool pauseElement = ShouldElementBePaused();
|
||||
SuspendOrResumeElement(pauseElement, !IsActive());
|
||||
|
||||
#ifdef MOZ_EME
|
||||
// If the owning document has become inactive we should shutdown the CDM.
|
||||
if (!OwnerDoc()->IsCurrentActiveDocument() && mMediaKeys) {
|
||||
mMediaKeys->Shutdown();
|
||||
mMediaKeys = nullptr;
|
||||
if (mDecoder) {
|
||||
ShutdownDecoder();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
AddRemoveSelfReference();
|
||||
}
|
||||
|
||||
@@ -6254,236 +6164,6 @@ HTMLMediaElement::OnVisibilityChange(Visibility aNewVisibility)
|
||||
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
MediaKeys*
|
||||
HTMLMediaElement::GetMediaKeys() const
|
||||
{
|
||||
return mMediaKeys;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLMediaElement::ContainsRestrictedContent()
|
||||
{
|
||||
return GetMediaKeys() != nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
HTMLMediaElement::SetMediaKeys(mozilla::dom::MediaKeys* aMediaKeys,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
LOG(LogLevel::Debug, ("%p SetMediaKeys(%p) mMediaKeys=%p mDecoder=%p",
|
||||
this, aMediaKeys, mMediaKeys.get(), mDecoder.get()));
|
||||
|
||||
if (MozAudioCaptured()) {
|
||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global =
|
||||
do_QueryInterface(OwnerDoc()->GetInnerWindow());
|
||||
if (!global) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
RefPtr<DetailedPromise> promise = DetailedPromise::Create(global, aRv,
|
||||
NS_LITERAL_CSTRING("HTMLMediaElement.setMediaKeys"));
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 1. If mediaKeys and the mediaKeys attribute are the same object,
|
||||
// return a resolved promise.
|
||||
if (mMediaKeys == aMediaKeys) {
|
||||
promise->MaybeResolveWithUndefined();
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
// Note: Our attaching code is synchronous, so we can skip the following steps.
|
||||
|
||||
// 2. If this object's attaching media keys value is true, return a
|
||||
// promise rejected with a new DOMException whose name is InvalidStateError.
|
||||
// 3. Let this object's attaching media keys value be true.
|
||||
// 4. Let promise be a new promise.
|
||||
// 5. Run the following steps in parallel:
|
||||
|
||||
// 5.1 If mediaKeys is not null, CDM instance represented by mediaKeys is
|
||||
// already in use by another media element, and the user agent is unable
|
||||
// to use it with this element, let this object's attaching media keys
|
||||
// value be false and reject promise with a new DOMException whose name
|
||||
// is QuotaExceededError.
|
||||
if (aMediaKeys && aMediaKeys->IsBoundToMediaElement()) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR,
|
||||
NS_LITERAL_CSTRING("MediaKeys object is already bound to another HTMLMediaElement"));
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
// 5.2 If the mediaKeys attribute is not null, run the following steps:
|
||||
if (mMediaKeys) {
|
||||
// 5.2.1 If the user agent or CDM do not support removing the association,
|
||||
// let this object's attaching media keys value be false and reject promise
|
||||
// with a new DOMException whose name is NotSupportedError.
|
||||
|
||||
// 5.2.2 If the association cannot currently be removed, let this object's
|
||||
// attaching media keys value be false and reject promise with a new
|
||||
// DOMException whose name is InvalidStateError.
|
||||
if (mDecoder) {
|
||||
// We don't support swapping out the MediaKeys once we've started to
|
||||
// setup the playback pipeline. Note this also means we don't need to worry
|
||||
// about handling disassociating the MediaKeys from the MediaDecoder.
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
|
||||
NS_LITERAL_CSTRING("Can't change MediaKeys on HTMLMediaElement after load has started"));
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
// 5.2.3 Stop using the CDM instance represented by the mediaKeys attribute
|
||||
// to decrypt media data and remove the association with the media element.
|
||||
mMediaKeys->Unbind();
|
||||
mMediaKeys = nullptr;
|
||||
|
||||
// 5.2.4 If the preceding step failed, let this object's attaching media
|
||||
// keys value be false and reject promise with a new DOMException whose
|
||||
// name is the appropriate error name.
|
||||
}
|
||||
|
||||
// 5.3. If mediaKeys is not null, run the following steps:
|
||||
if (aMediaKeys) {
|
||||
if (!aMediaKeys->GetCDMProxy()) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
|
||||
NS_LITERAL_CSTRING("CDM crashed before binding MediaKeys object to HTMLMediaElement"));
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
// 5.3.1 Associate the CDM instance represented by mediaKeys with the
|
||||
// media element for decrypting media data.
|
||||
if (NS_FAILED(aMediaKeys->Bind(this))) {
|
||||
// 5.3.2 If the preceding step failed, run the following steps:
|
||||
// 5.3.2.1 Set the mediaKeys attribute to null.
|
||||
mMediaKeys = nullptr;
|
||||
// 5.3.2.2 Let this object's attaching media keys value be false.
|
||||
// 5.3.2.3 Reject promise with a new DOMException whose name is
|
||||
// the appropriate error name.
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
|
||||
NS_LITERAL_CSTRING("Failed to bind MediaKeys object to HTMLMediaElement"));
|
||||
return promise.forget();
|
||||
}
|
||||
// 5.3.3 Queue a task to run the "Attempt to Resume Playback If Necessary"
|
||||
// algorithm on the media element.
|
||||
// Note: Setting the CDMProxy on the MediaDecoder will unblock playback.
|
||||
if (mDecoder) {
|
||||
mDecoder->SetCDMProxy(aMediaKeys->GetCDMProxy());
|
||||
}
|
||||
}
|
||||
|
||||
// 5.4 Set the mediaKeys attribute to mediaKeys.
|
||||
mMediaKeys = aMediaKeys;
|
||||
|
||||
// 5.5 Let this object's attaching media keys value be false.
|
||||
|
||||
// 5.6 Resolve promise.
|
||||
promise->MaybeResolveWithUndefined();
|
||||
|
||||
// 6. Return promise.
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
EventHandlerNonNull*
|
||||
HTMLMediaElement::GetOnencrypted()
|
||||
{
|
||||
return EventTarget::GetEventHandler(nsGkAtoms::onencrypted, EmptyString());
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::SetOnencrypted(EventHandlerNonNull* aCallback)
|
||||
{
|
||||
EventTarget::SetEventHandler(nsGkAtoms::onencrypted, EmptyString(), aCallback);
|
||||
}
|
||||
|
||||
EventHandlerNonNull*
|
||||
HTMLMediaElement::GetOnwaitingforkey()
|
||||
{
|
||||
return EventTarget::GetEventHandler(nsGkAtoms::onwaitingforkey, EmptyString());
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::SetOnwaitingforkey(EventHandlerNonNull* aCallback)
|
||||
{
|
||||
EventTarget::SetEventHandler(nsGkAtoms::onwaitingforkey, EmptyString(), aCallback);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::DispatchEncrypted(const nsTArray<uint8_t>& aInitData,
|
||||
const nsAString& aInitDataType)
|
||||
{
|
||||
LOG(LogLevel::Debug,
|
||||
("%p DispatchEncrypted initDataType='%s'",
|
||||
this, NS_ConvertUTF16toUTF8(aInitDataType).get()));
|
||||
|
||||
if (mReadyState == nsIDOMHTMLMediaElement::HAVE_NOTHING) {
|
||||
// Ready state not HAVE_METADATA (yet), don't dispatch encrypted now.
|
||||
// Queueing for later dispatch in MetadataLoaded.
|
||||
mPendingEncryptedInitData.AddInitData(aInitDataType, aInitData);
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<MediaEncryptedEvent> event;
|
||||
if (IsCORSSameOrigin()) {
|
||||
event = MediaEncryptedEvent::Constructor(this, aInitDataType, aInitData);
|
||||
} else {
|
||||
event = MediaEncryptedEvent::Constructor(this);
|
||||
}
|
||||
|
||||
RefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(this, event);
|
||||
asyncDispatcher->PostDOMEvent();
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLMediaElement::IsEventAttributeName(nsIAtom* aName)
|
||||
{
|
||||
return aName == nsGkAtoms::onencrypted ||
|
||||
nsGenericHTMLElement::IsEventAttributeName(aName);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIPrincipal>
|
||||
HTMLMediaElement::GetTopLevelPrincipal()
|
||||
{
|
||||
RefPtr<nsIPrincipal> principal;
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = OwnerDoc()->GetInnerWindow();
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
// XXXkhuey better hope we always have an outer ...
|
||||
nsCOMPtr<nsPIDOMWindowOuter> top = window->GetOuterWindow()->GetTop();
|
||||
if (!top) {
|
||||
return nullptr;
|
||||
}
|
||||
nsIDocument* doc = top->GetExtantDoc();
|
||||
if (!doc) {
|
||||
return nullptr;
|
||||
}
|
||||
principal = doc->NodePrincipal();
|
||||
return principal.forget();
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::CannotDecryptWaitingForKey()
|
||||
{
|
||||
LOG(LogLevel::Debug, ("%p, CannotDecryptWaitingForKey()", this));
|
||||
|
||||
// http://w3c.github.io/encrypted-media/#wait-for-key
|
||||
// 7.3.4 Queue a "waitingforkey" Event
|
||||
// 1. Let the media element be the specified HTMLMediaElement object.
|
||||
// 2. If the media element's waiting for key value is true, abort these steps.
|
||||
if (mWaitingForKey == NOT_WAITING_FOR_KEY) {
|
||||
// 3. Set the media element's waiting for key value to true.
|
||||
// Note: algorithm continues in UpdateReadyStateInternal() when all decoded
|
||||
// data enqueued in the MDSM is consumed.
|
||||
mWaitingForKey = WAITING_FOR_KEY;
|
||||
UpdateReadyStateInternal();
|
||||
}
|
||||
}
|
||||
#endif //MOZ_EME
|
||||
|
||||
NS_IMETHODIMP HTMLMediaElement::WindowAudioCaptureChanged(bool aCapture)
|
||||
{
|
||||
MOZ_ASSERT(mAudioChannelAgent);
|
||||
|
||||
@@ -18,9 +18,6 @@
|
||||
#include "mozilla/dom/TextTrackManager.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "MediaDecoder.h"
|
||||
#ifdef MOZ_EME
|
||||
#include "mozilla/dom/MediaKeys.h"
|
||||
#endif
|
||||
#include "mozilla/StateWatching.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "PrincipalChangeObserver.h"
|
||||
@@ -616,30 +613,6 @@ public:
|
||||
|
||||
// XPCOM MozPreservesPitch() is OK
|
||||
|
||||
#ifdef MOZ_EME
|
||||
MediaKeys* GetMediaKeys() const;
|
||||
|
||||
already_AddRefed<Promise> SetMediaKeys(MediaKeys* mediaKeys,
|
||||
ErrorResult& aRv);
|
||||
|
||||
mozilla::dom::EventHandlerNonNull* GetOnencrypted();
|
||||
void SetOnencrypted(mozilla::dom::EventHandlerNonNull* aCallback);
|
||||
|
||||
mozilla::dom::EventHandlerNonNull* GetOnwaitingforkey();
|
||||
void SetOnwaitingforkey(mozilla::dom::EventHandlerNonNull* aCallback);
|
||||
|
||||
void DispatchEncrypted(const nsTArray<uint8_t>& aInitData,
|
||||
const nsAString& aInitDataType) override;
|
||||
|
||||
bool IsEventAttributeName(nsIAtom* aName) override;
|
||||
|
||||
// Returns the principal of the "top level" document; the origin displayed
|
||||
// in the URL bar of the browser window.
|
||||
already_AddRefed<nsIPrincipal> GetTopLevelPrincipal();
|
||||
|
||||
bool ContainsRestrictedContent();
|
||||
#endif // MOZ_EME
|
||||
|
||||
void CannotDecryptWaitingForKey();
|
||||
|
||||
bool MozAutoplayEnabled() const
|
||||
@@ -1474,11 +1447,6 @@ protected:
|
||||
// Timer used for updating progress events.
|
||||
nsCOMPtr<nsITimer> mProgressTimer;
|
||||
|
||||
#ifdef MOZ_EME
|
||||
// Encrypted Media Extension media keys.
|
||||
RefPtr<MediaKeys> mMediaKeys;
|
||||
#endif
|
||||
|
||||
// Stores the time at the start of the current 'played' range.
|
||||
double mCurrentPlayRangeStart;
|
||||
|
||||
@@ -1632,11 +1600,6 @@ protected:
|
||||
// Listens for waitingForKey events from the owned decoder.
|
||||
MediaEventListener mWaitingForKeyListener;
|
||||
|
||||
#ifdef MOZ_EME
|
||||
// Init Data that needs to be sent in 'encrypted' events in MetadataLoaded().
|
||||
EncryptionInfo mPendingEncryptedInitData;
|
||||
#endif
|
||||
|
||||
// True if the media's channel's download has been suspended.
|
||||
Watchable<bool> mDownloadSuspendedByCache;
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ public:
|
||||
// Whether the value change should be notified to the frame/contet nor not.
|
||||
eSetValue_Notify = 1 << 2
|
||||
};
|
||||
MOZ_MUST_USE bool SetValue(const nsAString& aValue, uint32_t aFlags);
|
||||
[[nodiscard]] bool SetValue(const nsAString& aValue, uint32_t aFlags);
|
||||
void GetValue(nsAString& aValue, bool aIgnoreWrap) const;
|
||||
bool HasNonEmptyValue();
|
||||
// The following methods are for textarea element to use whether default
|
||||
|
||||
@@ -59,7 +59,9 @@
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "mozilla/WebBrowserPersistDocumentChild.h"
|
||||
#include "imgLoader.h"
|
||||
#ifdef MOZ_GMP
|
||||
#include "GMPServiceChild.h"
|
||||
#endif
|
||||
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
@@ -161,7 +163,9 @@
|
||||
#include "mozilla/net/NeckoMessageUtils.h"
|
||||
#include "mozilla/widget/PuppetBidiKeyboard.h"
|
||||
#include "mozilla/mozSpellChecker.h"
|
||||
#ifdef MOZ_GMP
|
||||
#include "GMPServiceChild.h"
|
||||
#endif
|
||||
#include "gfxPlatform.h"
|
||||
#include "nscore.h" // for NS_FREE_PERMANENT_DATA
|
||||
|
||||
@@ -171,7 +175,9 @@ using namespace mozilla::dom::ipc;
|
||||
using namespace mozilla::dom::workers;
|
||||
using namespace mozilla::media;
|
||||
using namespace mozilla::embedding;
|
||||
#ifdef MOZ_GMP
|
||||
using namespace mozilla::gmp;
|
||||
#endif
|
||||
using namespace mozilla::hal_sandbox;
|
||||
using namespace mozilla::ipc;
|
||||
using namespace mozilla::layers;
|
||||
@@ -1123,6 +1129,7 @@ ContentChild::AllocPContentBridgeParent(mozilla::ipc::Transport* aTransport,
|
||||
return mLastBridge;
|
||||
}
|
||||
|
||||
#ifdef MOZ_GMP
|
||||
PGMPServiceChild*
|
||||
ContentChild::AllocPGMPServiceChild(mozilla::ipc::Transport* aTransport,
|
||||
base::ProcessId aOtherProcess)
|
||||
@@ -1136,6 +1143,7 @@ ContentChild::RecvGMPsChanged(nsTArray<GMPCapabilityData>&& capabilities)
|
||||
GeckoMediaPluginServiceChild::UpdateGMPCapabilities(Move(capabilities));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
ContentChild::RecvInitRendering(Endpoint<PCompositorBridgeChild>&& aCompositor,
|
||||
|
||||
@@ -140,12 +140,14 @@ public:
|
||||
AllocPContentBridgeChild(mozilla::ipc::Transport* transport,
|
||||
base::ProcessId otherProcess) override;
|
||||
|
||||
#ifdef MOZ_GMP
|
||||
PGMPServiceChild*
|
||||
AllocPGMPServiceChild(mozilla::ipc::Transport* transport,
|
||||
base::ProcessId otherProcess) override;
|
||||
|
||||
bool
|
||||
RecvGMPsChanged(nsTArray<GMPCapabilityData>&& capabilities) override;
|
||||
#endif
|
||||
|
||||
bool
|
||||
RecvInitRendering(
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
#include "AppProcessChecker.h"
|
||||
#include "AudioChannelService.h"
|
||||
#include "BlobParent.h"
|
||||
#ifdef MOZ_GMP
|
||||
#include "GMPServiceParent.h"
|
||||
#endif
|
||||
#include "HandlerServiceParent.h"
|
||||
#include "IHistory.h"
|
||||
#include "imgIContainer.h"
|
||||
@@ -226,7 +228,9 @@ using namespace mozilla::dom::power;
|
||||
using namespace mozilla::media;
|
||||
using namespace mozilla::embedding;
|
||||
using namespace mozilla::gfx;
|
||||
#ifdef MOZ_GMP
|
||||
using namespace mozilla::gmp;
|
||||
#endif
|
||||
using namespace mozilla::hal;
|
||||
using namespace mozilla::ipc;
|
||||
using namespace mozilla::layers;
|
||||
@@ -862,11 +866,13 @@ static nsIDocShell* GetOpenerDocShellHelper(Element* aFrameElement)
|
||||
return docShell;
|
||||
}
|
||||
|
||||
#ifdef MOZ_GMP
|
||||
bool
|
||||
ContentParent::RecvCreateGMPService()
|
||||
{
|
||||
return PGMPService::Open(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
ContentParent::RecvLoadPlugin(const uint32_t& aPluginId, nsresult* aRv, uint32_t* aRunID)
|
||||
@@ -1264,8 +1270,10 @@ ContentParent::Init()
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_GMP
|
||||
RefPtr<GeckoMediaPluginServiceParent> gmps(GeckoMediaPluginServiceParent::GetSingleton());
|
||||
gmps->UpdateContentProcessGMPCapabilities();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2534,12 +2542,14 @@ ContentParent::Observe(nsISupports* aSubject,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef MOZ_GMP
|
||||
PGMPServiceParent*
|
||||
ContentParent::AllocPGMPServiceParent(mozilla::ipc::Transport* aTransport,
|
||||
base::ProcessId aOtherProcess)
|
||||
{
|
||||
return GMPServiceParent::Create(aTransport, aOtherProcess);
|
||||
}
|
||||
#endif
|
||||
|
||||
PBackgroundParent*
|
||||
ContentParent::AllocPBackgroundParent(Transport* aTransport,
|
||||
|
||||
@@ -237,7 +237,9 @@ public:
|
||||
|
||||
virtual bool RecvBridgeToChildProcess(const ContentParentId& aCpId) override;
|
||||
|
||||
#ifdef MOZ_GMP
|
||||
virtual bool RecvCreateGMPService() override;
|
||||
#endif
|
||||
|
||||
virtual bool RecvLoadPlugin(const uint32_t& aPluginId, nsresult* aRv,
|
||||
uint32_t* aRunID) override;
|
||||
@@ -670,9 +672,11 @@ private:
|
||||
TabParent* aTopLevel, const TabId& aTabId,
|
||||
uint64_t* aId);
|
||||
|
||||
#ifdef MOZ_GMP
|
||||
PGMPServiceParent*
|
||||
AllocPGMPServiceParent(mozilla::ipc::Transport* aTransport,
|
||||
base::ProcessId aOtherProcess) override;
|
||||
#endif
|
||||
|
||||
PBackgroundParent*
|
||||
AllocPBackgroundParent(Transport* aTransport, ProcessId aOtherProcess)
|
||||
|
||||
+12
-1
@@ -26,10 +26,14 @@ include protocol PNecko;
|
||||
// bridging PContent and PGMP. As soon as it registers the bridge between
|
||||
// PContent and PPluginModule it seems to think that PContent's parent and
|
||||
// child live in the same process!
|
||||
#ifdef MOZ_GMP
|
||||
include protocol PGMPContent;
|
||||
include protocol PGMPService;
|
||||
include protocol PPluginModule;
|
||||
include protocol PGMP;
|
||||
#else
|
||||
include protocol PPluginModule;
|
||||
#endif
|
||||
include protocol PPrinting;
|
||||
include protocol PSendStream;
|
||||
include protocol POfflineCacheUpdate;
|
||||
@@ -211,6 +215,7 @@ struct BlobURLRegistrationData
|
||||
Principal principal;
|
||||
};
|
||||
|
||||
#ifdef MOZ_GMP
|
||||
struct GMPAPITags
|
||||
{
|
||||
nsCString api;
|
||||
@@ -223,13 +228,16 @@ struct GMPCapabilityData
|
||||
nsCString version;
|
||||
GMPAPITags[] capabilities;
|
||||
};
|
||||
#endif
|
||||
|
||||
nested(upto inside_cpow) sync protocol PContent
|
||||
{
|
||||
parent spawns PPluginModule;
|
||||
|
||||
parent opens PProcessHangMonitor;
|
||||
#ifdef MOZ_GMP
|
||||
parent opens PGMPService;
|
||||
#endif
|
||||
child opens PBackground;
|
||||
|
||||
manages PBlob;
|
||||
@@ -516,8 +524,9 @@ child:
|
||||
|
||||
async BlobURLUnregistration(nsCString aURI);
|
||||
|
||||
|
||||
#ifdef MOZ_GMP
|
||||
async GMPsChanged(GMPCapabilityData[] capabilities);
|
||||
#endif
|
||||
|
||||
parent:
|
||||
/**
|
||||
@@ -550,7 +559,9 @@ parent:
|
||||
returns (ContentParentId cpId, bool isForApp, bool isForBrowser, TabId tabId);
|
||||
sync BridgeToChildProcess(ContentParentId cpId);
|
||||
|
||||
#ifdef MOZ_GMP
|
||||
async CreateGMPService();
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This call connects the content process to a plugin process. While this
|
||||
|
||||
+1
-1
@@ -73,7 +73,7 @@ SOURCES += [
|
||||
'ProcessHangMonitor.cpp',
|
||||
]
|
||||
|
||||
IPDL_SOURCES += [
|
||||
PREPROCESSED_IPDL_SOURCES += [
|
||||
'BlobTypes.ipdlh',
|
||||
'DOMTypes.ipdlh',
|
||||
'PBlob.ipdl',
|
||||
|
||||
@@ -63,11 +63,11 @@ public:
|
||||
virtual bool IsForApp() const = 0;
|
||||
virtual bool IsForBrowser() const = 0;
|
||||
|
||||
MOZ_MUST_USE virtual PBlobParent*
|
||||
[[nodiscard]] virtual PBlobParent*
|
||||
SendPBlobConstructor(PBlobParent* aActor,
|
||||
const BlobConstructorParams& aParams) = 0;
|
||||
|
||||
MOZ_MUST_USE virtual PBrowserParent*
|
||||
[[nodiscard]] virtual PBrowserParent*
|
||||
SendPBrowserConstructor(PBrowserParent* actor,
|
||||
const TabId& aTabId,
|
||||
const IPCTabContext& context,
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#ifdef MOZ_GMP
|
||||
class GMPCrashHelper;
|
||||
#endif
|
||||
|
||||
namespace mozilla
|
||||
{
|
||||
@@ -30,9 +32,6 @@ class MediaResource;
|
||||
class ReentrantMonitor;
|
||||
class VideoFrameContainer;
|
||||
class MediaDecoderOwner;
|
||||
#ifdef MOZ_EME
|
||||
class CDMProxy;
|
||||
#endif
|
||||
|
||||
typedef nsDataHashtable<nsCStringHashKey, nsCString> MetadataTags;
|
||||
|
||||
@@ -112,7 +111,9 @@ public:
|
||||
// Set by Reader if the current audio track can be offloaded
|
||||
virtual void SetPlatformCanOffloadAudio(bool aCanOffloadAudio) {}
|
||||
|
||||
#ifdef MOZ_GMP
|
||||
virtual already_AddRefed<GMPCrashHelper> GetCrashHelper() { return nullptr; }
|
||||
#endif
|
||||
|
||||
// Stack based class to assist in notifying the frame statistics of
|
||||
// parsed and decoded frames. Use inside video demux & decode functions
|
||||
|
||||
@@ -838,6 +838,7 @@ DecoderDoctorDiagnostics::GetDescription() const
|
||||
if (mFFmpegFailedToLoad) {
|
||||
s += ", Linux platform decoder failed to load";
|
||||
}
|
||||
#ifdef MOZ_GMP
|
||||
if (mGMPPDMFailedToStartup) {
|
||||
s += ", GMP PDM failed to startup";
|
||||
} else if (!mGMP.IsEmpty()) {
|
||||
@@ -845,6 +846,7 @@ DecoderDoctorDiagnostics::GetDescription() const
|
||||
s += mGMP;
|
||||
s += "'";
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case eMediaKeySystemAccessRequest:
|
||||
s = "key system='";
|
||||
|
||||
@@ -78,14 +78,18 @@ public:
|
||||
void SetFFmpegFailedToLoad() { mFFmpegFailedToLoad = true; }
|
||||
bool DidFFmpegFailToLoad() const { return mFFmpegFailedToLoad; }
|
||||
|
||||
#ifdef MOZ_GMP
|
||||
void SetGMPPDMFailedToStartup() { mGMPPDMFailedToStartup = true; }
|
||||
bool DidGMPPDMFailToStartup() const { return mGMPPDMFailedToStartup; }
|
||||
#endif
|
||||
|
||||
void SetVideoNotSupported() { mVideoNotSupported = true; }
|
||||
void SetAudioNotSupported() { mAudioNotSupported = true; }
|
||||
|
||||
#ifdef MOZ_GMP
|
||||
void SetGMP(const nsACString& aGMP) { mGMP = aGMP; }
|
||||
const nsACString& GMP() const { return mGMP; }
|
||||
#endif
|
||||
|
||||
const nsAString& KeySystem() const { return mKeySystem; }
|
||||
bool IsKeySystemSupported() const { return mIsKeySystemSupported; }
|
||||
@@ -119,10 +123,14 @@ private:
|
||||
|
||||
bool mWMFFailedToLoad = false;
|
||||
bool mFFmpegFailedToLoad = false;
|
||||
#ifdef MOZ_GMP
|
||||
bool mGMPPDMFailedToStartup = false;
|
||||
#endif
|
||||
bool mVideoNotSupported = false;
|
||||
bool mAudioNotSupported = false;
|
||||
#ifdef MOZ_GMP
|
||||
nsCString mGMP;
|
||||
#endif
|
||||
|
||||
nsString mKeySystem;
|
||||
bool mIsKeySystemSupported = false;
|
||||
|
||||
+121
-30
@@ -7,6 +7,8 @@
|
||||
#include "MediaInfo.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "mozilla/layers/SharedRGBImage.h"
|
||||
#include "YCbCrUtils.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -89,6 +91,45 @@ ValidatePlane(const VideoData::YCbCrBuffer::Plane& aPlane)
|
||||
aPlane.mStride > 0 && aPlane.mWidth <= aPlane.mStride;
|
||||
}
|
||||
|
||||
static bool ValidateBufferAndPicture(const VideoData::YCbCrBuffer& aBuffer,
|
||||
const IntRect& aPicture)
|
||||
{
|
||||
// The following situation should never happen unless there is a bug
|
||||
// in the decoder
|
||||
if (aBuffer.mPlanes[1].mWidth != aBuffer.mPlanes[2].mWidth ||
|
||||
aBuffer.mPlanes[1].mHeight != aBuffer.mPlanes[2].mHeight) {
|
||||
NS_ERROR("C planes with different sizes");
|
||||
return false;
|
||||
}
|
||||
|
||||
// The following situations could be triggered by invalid input
|
||||
if (aPicture.width <= 0 || aPicture.height <= 0) {
|
||||
// In debug mode, makes the error more noticeable
|
||||
MOZ_ASSERT(false, "Empty picture rect");
|
||||
return false;
|
||||
}
|
||||
if (!ValidatePlane(aBuffer.mPlanes[0]) ||
|
||||
!ValidatePlane(aBuffer.mPlanes[1]) ||
|
||||
!ValidatePlane(aBuffer.mPlanes[2])) {
|
||||
NS_WARNING("Invalid plane size");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure the picture size specified in the headers can be extracted out of
|
||||
// the frame we've been supplied without indexing out of bounds.
|
||||
CheckedUint32 xLimit = aPicture.x + CheckedUint32(aPicture.width);
|
||||
CheckedUint32 yLimit = aPicture.y + CheckedUint32(aPicture.height);
|
||||
if (!xLimit.isValid() || xLimit.value() > aBuffer.mPlanes[0].mStride ||
|
||||
!yLimit.isValid() || yLimit.value() > aBuffer.mPlanes[0].mHeight)
|
||||
{
|
||||
// The specified picture dimensions can't be contained inside the video
|
||||
// frame, we'll stomp memory if we try to copy it. Fail.
|
||||
NS_WARNING("Overflowing picture rect");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
VideoData::VideoData(int64_t aOffset,
|
||||
int64_t aTime,
|
||||
int64_t aDuration,
|
||||
@@ -242,36 +283,7 @@ VideoData::CreateAndCopyData(const VideoInfo& aInfo,
|
||||
return v.forget();
|
||||
}
|
||||
|
||||
// The following situation should never happen unless there is a bug
|
||||
// in the decoder
|
||||
if (aBuffer.mPlanes[1].mWidth != aBuffer.mPlanes[2].mWidth ||
|
||||
aBuffer.mPlanes[1].mHeight != aBuffer.mPlanes[2].mHeight) {
|
||||
NS_ERROR("C planes with different sizes");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// The following situations could be triggered by invalid input
|
||||
if (aPicture.width <= 0 || aPicture.height <= 0) {
|
||||
// In debug mode, makes the error more noticeable
|
||||
MOZ_ASSERT(false, "Empty picture rect");
|
||||
return nullptr;
|
||||
}
|
||||
if (!ValidatePlane(aBuffer.mPlanes[0]) || !ValidatePlane(aBuffer.mPlanes[1]) ||
|
||||
!ValidatePlane(aBuffer.mPlanes[2])) {
|
||||
NS_WARNING("Invalid plane size");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Ensure the picture size specified in the headers can be extracted out of
|
||||
// the frame we've been supplied without indexing out of bounds.
|
||||
CheckedUint32 xLimit = aPicture.x + CheckedUint32(aPicture.width);
|
||||
CheckedUint32 yLimit = aPicture.y + CheckedUint32(aPicture.height);
|
||||
if (!xLimit.isValid() || xLimit.value() > aBuffer.mPlanes[0].mStride ||
|
||||
!yLimit.isValid() || yLimit.value() > aBuffer.mPlanes[0].mHeight)
|
||||
{
|
||||
// The specified picture dimensions can't be contained inside the video
|
||||
// frame, we'll stomp memory if we try to copy it. Fail.
|
||||
NS_WARNING("Overflowing picture rect");
|
||||
if (!ValidateBufferAndPicture(aBuffer, aPicture)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -305,6 +317,73 @@ VideoData::CreateAndCopyData(const VideoInfo& aInfo,
|
||||
return v.forget();
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<VideoData>
|
||||
VideoData::CreateAndCopyData(const VideoInfo& aInfo,
|
||||
ImageContainer* aContainer,
|
||||
int64_t aOffset,
|
||||
int64_t aTime,
|
||||
int64_t aDuration,
|
||||
const YCbCrBuffer& aBuffer,
|
||||
const YCbCrBuffer::Plane &aAlphaPlane,
|
||||
bool aKeyframe,
|
||||
int64_t aTimecode,
|
||||
const IntRect& aPicture)
|
||||
{
|
||||
if (!aContainer) {
|
||||
// Create a dummy VideoData with no image. This gives us something to
|
||||
// send to media streams if necessary.
|
||||
RefPtr<VideoData> v(new VideoData(aOffset,
|
||||
aTime,
|
||||
aDuration,
|
||||
aKeyframe,
|
||||
aTimecode,
|
||||
aInfo.mDisplay,
|
||||
0));
|
||||
return v.forget();
|
||||
}
|
||||
|
||||
if (!ValidateBufferAndPicture(aBuffer, aPicture)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<VideoData> v(new VideoData(aOffset,
|
||||
aTime,
|
||||
aDuration,
|
||||
aKeyframe,
|
||||
aTimecode,
|
||||
aInfo.mDisplay,
|
||||
0));
|
||||
|
||||
// Convert from YUVA to BGRA format on the software side.
|
||||
RefPtr<layers::SharedRGBImage> videoImage =
|
||||
aContainer->CreateSharedRGBImage();
|
||||
v->mImage = videoImage;
|
||||
|
||||
if (!v->mImage) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!videoImage->Allocate(IntSize(aBuffer.mPlanes[0].mWidth,
|
||||
aBuffer.mPlanes[0].mHeight),
|
||||
SurfaceFormat::B8G8R8A8)) {
|
||||
return nullptr;
|
||||
}
|
||||
uint8_t* argb_buffer = videoImage->GetBuffer();
|
||||
IntSize size = videoImage->GetSize();
|
||||
|
||||
// The naming convention for libyuv and associated utils is word-order.
|
||||
// The naming convention in the gfx stack is byte-order.
|
||||
ConvertYCbCrAToARGB(aBuffer.mPlanes[0].mData,
|
||||
aBuffer.mPlanes[1].mData,
|
||||
aBuffer.mPlanes[2].mData,
|
||||
aAlphaPlane.mData,
|
||||
aBuffer.mPlanes[0].mStride, aBuffer.mPlanes[1].mStride,
|
||||
argb_buffer, size.width * 4,
|
||||
size.width, size.height);
|
||||
|
||||
return v.forget();
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<VideoData>
|
||||
VideoData::CreateFromImage(const VideoInfo& aInfo,
|
||||
@@ -340,6 +419,15 @@ MediaRawData::MediaRawData(const uint8_t* aData, size_t aSize)
|
||||
{
|
||||
}
|
||||
|
||||
MediaRawData::MediaRawData(const uint8_t* aData, size_t aSize,
|
||||
const uint8_t* aAlphaData, size_t aAlphaSize)
|
||||
: MediaData(RAW_DATA, 0)
|
||||
, mCrypto(mCryptoInternal)
|
||||
, mBuffer(aData, aSize)
|
||||
, mAlphaBuffer(aAlphaData, aAlphaSize)
|
||||
{
|
||||
}
|
||||
|
||||
already_AddRefed<MediaRawData>
|
||||
MediaRawData::Clone() const
|
||||
{
|
||||
@@ -356,6 +444,9 @@ MediaRawData::Clone() const
|
||||
if (!s->mBuffer.Append(mBuffer.Data(), mBuffer.Length())) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!s->mAlphaBuffer.Append(mAlphaBuffer.Data(), mAlphaBuffer.Length())) {
|
||||
return nullptr;
|
||||
}
|
||||
return s.forget();
|
||||
}
|
||||
|
||||
|
||||
+21
-2
@@ -474,6 +474,17 @@ public:
|
||||
int64_t aTimecode,
|
||||
const IntRect& aPicture);
|
||||
|
||||
static already_AddRefed<VideoData> CreateAndCopyData(const VideoInfo& aInfo,
|
||||
ImageContainer* aContainer,
|
||||
int64_t aOffset,
|
||||
int64_t aTime,
|
||||
int64_t aDuration,
|
||||
const YCbCrBuffer &aBuffer,
|
||||
const YCbCrBuffer::Plane &aAlphaPlane,
|
||||
bool aKeyframe,
|
||||
int64_t aTimecode,
|
||||
const IntRect& aPicture);
|
||||
|
||||
static already_AddRefed<VideoData> CreateAndCopyIntoTextureClient(const VideoInfo& aInfo,
|
||||
int64_t aOffset,
|
||||
int64_t aTime,
|
||||
@@ -622,15 +633,22 @@ private:
|
||||
class MediaRawData : public MediaData {
|
||||
public:
|
||||
MediaRawData();
|
||||
MediaRawData(const uint8_t* aData, size_t mSize);
|
||||
MediaRawData(const uint8_t* aData, size_t aSize);
|
||||
MediaRawData(const uint8_t* aData, size_t aSize,
|
||||
const uint8_t* aAlphaData, size_t aAlphaSize);
|
||||
|
||||
// Pointer to data or null if not-yet allocated
|
||||
const uint8_t* Data() const { return mBuffer.Data(); }
|
||||
// Pointer to alpha data or null if not-yet allocated
|
||||
const uint8_t* AlphaData() const { return mAlphaBuffer.Data(); }
|
||||
// Size of buffer.
|
||||
size_t Size() const { return mBuffer.Length(); }
|
||||
size_t AlphaSize() const { return mAlphaBuffer.Length(); }
|
||||
size_t ComputedSizeOfIncludingThis() const
|
||||
{
|
||||
return sizeof(*this) + mBuffer.ComputedSizeOfExcludingThis();
|
||||
return sizeof(*this)
|
||||
+ mBuffer.ComputedSizeOfExcludingThis()
|
||||
+ mAlphaBuffer.ComputedSizeOfExcludingThis();
|
||||
}
|
||||
// Access the buffer as a Span.
|
||||
operator Span<const uint8_t>() { return MakeSpan(Data(), Size()); }
|
||||
@@ -661,6 +679,7 @@ protected:
|
||||
private:
|
||||
friend class MediaRawDataWriter;
|
||||
AlignedByteBuffer mBuffer;
|
||||
AlignedByteBuffer mAlphaBuffer;
|
||||
CryptoSample mCryptoInternal;
|
||||
MediaRawData(const MediaRawData&); // Not implemented
|
||||
};
|
||||
|
||||
@@ -29,7 +29,9 @@
|
||||
#include "mozilla/dom/VideoTrack.h"
|
||||
#include "mozilla/dom/VideoTrackList.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#ifdef MOZ_GMP
|
||||
#include "GMPService.h"
|
||||
#endif
|
||||
#include "Layers.h"
|
||||
#include "mozilla/layers/ShadowLayers.h"
|
||||
|
||||
@@ -386,9 +388,6 @@ MediaDecoder::MediaDecoder(MediaDecoderOwner* aOwner)
|
||||
, mLogicalPosition(0.0)
|
||||
, mDuration(std::numeric_limits<double>::quiet_NaN())
|
||||
, mResourceCallback(new ResourceCallback())
|
||||
#ifdef MOZ_EME
|
||||
, mCDMProxyPromise(mCDMProxyPromiseHolder.Ensure(__func__))
|
||||
#endif
|
||||
, mIgnoreProgressData(false)
|
||||
, mInfiniteStream(false)
|
||||
, mOwner(aOwner)
|
||||
@@ -473,10 +472,6 @@ MediaDecoder::Shutdown()
|
||||
|
||||
mResourceCallback->Disconnect();
|
||||
|
||||
#ifdef MOZ_EME
|
||||
mCDMProxyPromiseHolder.RejectIfExists(true, __func__);
|
||||
#endif
|
||||
|
||||
DiscardOngoingSeekIfExists();
|
||||
|
||||
// This changes the decoder state to SHUTDOWN and does other things
|
||||
@@ -933,6 +928,7 @@ MediaDecoder::OwnerHasError() const
|
||||
return mOwner->HasError();
|
||||
}
|
||||
|
||||
#ifdef MOZ_GMP
|
||||
class MediaElementGMPCrashHelper : public GMPCrashHelper
|
||||
{
|
||||
public:
|
||||
@@ -960,6 +956,7 @@ MediaDecoder::GetCrashHelper()
|
||||
return mOwner->GetMediaElement() ?
|
||||
MakeAndAddRef<MediaElementGMPCrashHelper>(mOwner->GetMediaElement()) : nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
MediaDecoder::IsEnded() const
|
||||
@@ -1547,23 +1544,6 @@ MediaDecoder::CanPlayThrough()
|
||||
return GetStatistics().CanPlayThrough();
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
RefPtr<MediaDecoder::CDMProxyPromise>
|
||||
MediaDecoder::RequestCDMProxy() const
|
||||
{
|
||||
return mCDMProxyPromise;
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoder::SetCDMProxy(CDMProxy* aProxy)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aProxy);
|
||||
|
||||
mCDMProxyPromiseHolder.ResolveIfExists(aProxy, __func__);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
MediaDecoder::IsOpusEnabled()
|
||||
{
|
||||
|
||||
@@ -8,10 +8,6 @@
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
|
||||
#ifdef MOZ_EME
|
||||
#include "mozilla/CDMProxy.h"
|
||||
#endif
|
||||
|
||||
#include "mozilla/MozPromise.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "mozilla/StateMirroring.h"
|
||||
@@ -246,7 +242,9 @@ public:
|
||||
// Must be called before Shutdown().
|
||||
bool OwnerHasError() const;
|
||||
|
||||
#ifdef MOZ_GMP
|
||||
already_AddRefed<GMPCrashHelper> GetCrashHelper() override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// Updates the media duration. This is called while the media is being
|
||||
@@ -435,16 +433,6 @@ private:
|
||||
|
||||
MediaDecoderOwner* GetOwner() const override;
|
||||
|
||||
#ifdef MOZ_EME
|
||||
typedef MozPromise<RefPtr<CDMProxy>, bool /* aIgnored */, /* IsExclusive = */ true> CDMProxyPromise;
|
||||
|
||||
// Resolved when a CDMProxy is available and the capabilities are known or
|
||||
// rejected when this decoder is about to shut down.
|
||||
RefPtr<CDMProxyPromise> RequestCDMProxy() const;
|
||||
|
||||
void SetCDMProxy(CDMProxy* aProxy);
|
||||
#endif
|
||||
|
||||
static bool IsOggEnabled();
|
||||
static bool IsOpusEnabled();
|
||||
static bool IsWaveEnabled();
|
||||
@@ -594,11 +582,6 @@ private:
|
||||
|
||||
RefPtr<ResourceCallback> mResourceCallback;
|
||||
|
||||
#ifdef MOZ_EME
|
||||
MozPromiseHolder<CDMProxyPromise> mCDMProxyPromiseHolder;
|
||||
RefPtr<CDMProxyPromise> mCDMProxyPromise;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// The promise resolving/rejection is queued as a "micro-task" which will be
|
||||
// handled immediately after the current JS task and before any pending JS
|
||||
|
||||
@@ -141,14 +141,6 @@ public:
|
||||
// The decoder owner should call Shutdown() on the decoder and drop the
|
||||
// reference to the decoder to prevent further calls into the decoder.
|
||||
virtual void NotifyXPCOMShutdown() = 0;
|
||||
|
||||
#ifdef MOZ_EME
|
||||
// Dispatches a "encrypted" event to the HTMLMediaElement, with the
|
||||
// provided init data. Actual dispatch may be delayed until HAVE_METADATA.
|
||||
// Main thread only.
|
||||
virtual void DispatchEncrypted(const nsTArray<uint8_t>& aInitData,
|
||||
const nsAString& aInitDataType) = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -24,9 +24,6 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
#ifdef MOZ_EME
|
||||
class CDMProxy;
|
||||
#endif
|
||||
class MediaDecoderReader;
|
||||
|
||||
struct WaitForDataRejectValue
|
||||
@@ -188,10 +185,6 @@ public:
|
||||
// when to call SetIdle().
|
||||
virtual void SetIdle() {}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
virtual void SetCDMProxy(CDMProxy* aProxy) {}
|
||||
#endif
|
||||
|
||||
// Tell the reader that the data decoded are not for direct playback, so it
|
||||
// can accept more files, in particular those which have more channels than
|
||||
// available in the audio output.
|
||||
|
||||
@@ -112,10 +112,6 @@ public:
|
||||
return mReader->CanonicalBuffered();
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
void SetCDMProxy(CDMProxy* aProxy) { mReader->SetCDMProxy(aProxy); }
|
||||
#endif
|
||||
|
||||
void SetVideoBlankDecode(bool aIsBlankDecode);
|
||||
|
||||
private:
|
||||
|
||||
@@ -271,7 +271,6 @@ protected:
|
||||
*
|
||||
* Transition to other states when decoding metadata is done:
|
||||
* SHUTDOWN if failing to decode metadata.
|
||||
* WAIT_FOR_CDM if the media is encrypted and CDM is not available.
|
||||
* DECODING_FIRSTFRAME otherwise.
|
||||
*/
|
||||
class MediaDecoderStateMachine::DecodeMetadataState
|
||||
@@ -341,60 +340,6 @@ private:
|
||||
MozPromiseRequestHolder<MediaDecoderReader::MetadataPromise> mMetadataRequest;
|
||||
};
|
||||
|
||||
/**
|
||||
* Purpose: wait for the CDM to start decoding.
|
||||
*
|
||||
* Transition to other states when CDM is ready:
|
||||
* DECODING_FIRSTFRAME otherwise.
|
||||
*/
|
||||
class MediaDecoderStateMachine::WaitForCDMState
|
||||
: public MediaDecoderStateMachine::StateObject
|
||||
{
|
||||
public:
|
||||
explicit WaitForCDMState(Master* aPtr) : StateObject(aPtr) {}
|
||||
|
||||
void Enter()
|
||||
{
|
||||
MOZ_ASSERT(!mMaster->mVideoDecodeSuspended);
|
||||
}
|
||||
|
||||
void Exit() override
|
||||
{
|
||||
// mPendingSeek is either moved in HandleCDMProxyReady() or should be
|
||||
// rejected here before transition to SHUTDOWN.
|
||||
mPendingSeek.RejectIfExists(__func__);
|
||||
}
|
||||
|
||||
State GetState() const override
|
||||
{
|
||||
return DECODER_STATE_WAIT_FOR_CDM;
|
||||
}
|
||||
|
||||
void HandleCDMProxyReady() override;
|
||||
|
||||
RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
|
||||
{
|
||||
SLOG("Not Enough Data to seek at this stage, queuing seek");
|
||||
mPendingSeek.RejectIfExists(__func__);
|
||||
mPendingSeek.mTarget = aTarget;
|
||||
return mPendingSeek.mPromise.Ensure(__func__);
|
||||
}
|
||||
|
||||
void HandleVideoSuspendTimeout() override
|
||||
{
|
||||
// Do nothing since no decoders are created yet.
|
||||
}
|
||||
|
||||
void HandleResumeVideoDecoding() override
|
||||
{
|
||||
// We never suspend video decoding in this state.
|
||||
MOZ_ASSERT(false, "Shouldn't have suspended video decoding.");
|
||||
}
|
||||
|
||||
private:
|
||||
SeekJob mPendingSeek;
|
||||
};
|
||||
|
||||
/**
|
||||
* Purpose: release decoder resources to save memory and hardware resources.
|
||||
*
|
||||
@@ -1231,33 +1176,14 @@ DecodeMetadataState::OnMetadataRead(MetadataHolder* aMetadata)
|
||||
mMaster->GetAmpleVideoFrames());
|
||||
}
|
||||
|
||||
// In general, we wait until we know the duration before notifying the decoder.
|
||||
// However, we notify unconditionally in this case without waiting for the start
|
||||
// time, since the caller might be waiting on metadataloaded to be fired before
|
||||
// feeding in the CDM, which we need to decode the first frame (and
|
||||
// thus get the metadata). We could fix this if we could compute the start
|
||||
// time by demuxing without necessaring decoding.
|
||||
bool waitingForCDM =
|
||||
#ifdef MOZ_EME
|
||||
mMaster->Info().IsEncrypted() && !mMaster->mCDMProxy;
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
|
||||
mMaster->mNotifyMetadataBeforeFirstFrame =
|
||||
mMaster->mDuration.Ref().isSome() || waitingForCDM;
|
||||
mMaster->mDuration.Ref().isSome();
|
||||
|
||||
if (mMaster->mNotifyMetadataBeforeFirstFrame) {
|
||||
mMaster->EnqueueLoadedMetadataEvent();
|
||||
}
|
||||
|
||||
if (waitingForCDM) {
|
||||
// Metadata parsing was successful but we're still waiting for CDM caps
|
||||
// to become available so that we can build the correct decryptor/decoder.
|
||||
SetState<WaitForCDMState>();
|
||||
} else {
|
||||
SetState<DecodingFirstFrameState>(SeekJob{});
|
||||
}
|
||||
SetState<DecodingFirstFrameState>(SeekJob{});
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1266,21 +1192,11 @@ DormantState::HandlePlayStateChanged(MediaDecoder::PlayState aPlayState)
|
||||
{
|
||||
if (aPlayState == MediaDecoder::PLAY_STATE_PLAYING) {
|
||||
// Exit dormant when the user wants to play.
|
||||
#ifdef MOZ_EME
|
||||
MOZ_ASSERT(!Info().IsEncrypted() || mMaster->mCDMProxy);
|
||||
#endif
|
||||
MOZ_ASSERT(mMaster->mSentFirstFrameLoadedEvent);
|
||||
SetState<SeekingState>(Move(mPendingSeek), EventVisibility::Suppressed);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::
|
||||
WaitForCDMState::HandleCDMProxyReady()
|
||||
{
|
||||
SetState<DecodingFirstFrameState>(Move(mPendingSeek));
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::
|
||||
DecodingFirstFrameState::Enter(SeekJob aPendingSeek)
|
||||
@@ -1581,10 +1497,6 @@ ShutdownState::Enter()
|
||||
// dispose of the timer.
|
||||
master->mVideoDecodeSuspendTimer.Reset();
|
||||
|
||||
#ifdef MOZ_EME
|
||||
master->mCDMProxyPromise.DisconnectIfExists();
|
||||
#endif
|
||||
|
||||
if (master->IsPlaying()) {
|
||||
master->StopPlayback();
|
||||
}
|
||||
@@ -2137,13 +2049,6 @@ nsresult MediaDecoderStateMachine::Init(MediaDecoder* aDecoder)
|
||||
|
||||
mMediaSink = CreateMediaSink(mAudioCaptured);
|
||||
|
||||
#ifdef MOZ_EME
|
||||
mCDMProxyPromise.Begin(aDecoder->RequestCDMProxy()->Then(
|
||||
OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnCDMProxyReady,
|
||||
&MediaDecoderStateMachine::OnCDMProxyNotReady));
|
||||
#endif
|
||||
|
||||
nsresult rv = mReader->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@@ -2267,7 +2172,6 @@ MediaDecoderStateMachine::ToStateStr(State aState)
|
||||
{
|
||||
switch (aState) {
|
||||
case DECODER_STATE_DECODING_METADATA: return "DECODING_METADATA";
|
||||
case DECODER_STATE_WAIT_FOR_CDM: return "WAIT_FOR_CDM";
|
||||
case DECODER_STATE_DORMANT: return "DORMANT";
|
||||
case DECODER_STATE_DECODING_FIRSTFRAME: return "DECODING_FIRSTFRAME";
|
||||
case DECODER_STATE_DECODING: return "DECODING";
|
||||
@@ -3118,25 +3022,6 @@ void MediaDecoderStateMachine::OnMediaSinkAudioError(nsresult aResult)
|
||||
DecodeError(MediaResult(NS_ERROR_DOM_MEDIA_MEDIASINK_ERR, __func__));
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
void
|
||||
MediaDecoderStateMachine::OnCDMProxyReady(RefPtr<CDMProxy> aProxy)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
mCDMProxyPromise.Complete();
|
||||
mCDMProxy = aProxy;
|
||||
mReader->SetCDMProxy(aProxy);
|
||||
mStateObj->HandleCDMProxyReady();
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::OnCDMProxyNotReady()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
mCDMProxyPromise.Complete();
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::SetAudioCaptured(bool aCaptured)
|
||||
{
|
||||
|
||||
Loaded 100 of 2726 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user