author | Carsten "Tomcat" Book <cbook@mozilla.com> |
Thu, 29 Sep 2016 11:44:58 +0200 | |
changeset 315727 | f7d5008ee2ab9200052e45ad6ecc3f3a348f7f86 |
parent 315607 | 3fd3ee1ef53acb0dfce3df16a84b9dbe43e13d8b (current diff) |
parent 315726 | cb3ef16e764888c5b470e423b6af38572f0d2d6f (diff) |
child 315728 | 9baec74b3db1bf005c66ae2f50bafbdb02c3be38 |
child 315740 | c81754c082f08d5e95595cb1ee09d67f17eaa7b0 |
child 315798 | dc21ccd6a304df32cdec43a71f01bdf80288ee98 |
child 315811 | 6a996a75330fb7d4376b4ed6d439126d8b5a50a2 |
push id | 30753 |
push user | cbook@mozilla.com |
push date | Thu, 29 Sep 2016 09:45:12 +0000 |
treeherder | mozilla-central@f7d5008ee2ab [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 52.0a1 |
first release with | nightly linux32
f7d5008ee2ab
/
52.0a1
/
20160929030426
/
files
nightly linux64
f7d5008ee2ab
/
52.0a1
/
20160929030426
/
files
nightly mac
f7d5008ee2ab
/
52.0a1
/
20160929030426
/
files
nightly win32
f7d5008ee2ab
/
52.0a1
/
20160929030426
/
files
nightly win64
f7d5008ee2ab
/
52.0a1
/
20160929030426
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
52.0a1
/
20160929030426
/
pushlog to previous
nightly linux64
52.0a1
/
20160929030426
/
pushlog to previous
nightly mac
52.0a1
/
20160929030426
/
pushlog to previous
nightly win32
52.0a1
/
20160929030426
/
pushlog to previous
nightly win64
52.0a1
/
20160929030426
/
pushlog to previous
|
--- a/accessible/windows/msaa/EnumVariant.cpp +++ b/accessible/windows/msaa/EnumVariant.cpp @@ -9,20 +9,18 @@ using namespace mozilla; using namespace mozilla::a11y; //////////////////////////////////////////////////////////////////////////////// // ChildrenEnumVariant //////////////////////////////////////////////////////////////////////////////// IMPL_IUNKNOWN_QUERY_HEAD(ChildrenEnumVariant) -IMPL_IUNKNOWN_QUERY_IFACE(IEnumVARIANT); -IMPL_IUNKNOWN_QUERY_IFACE(IUnknown); -IMPL_IUNKNOWN_QUERY_AGGR_COND(mAnchorAcc, !mAnchorAcc->IsDefunct()); -IMPL_IUNKNOWN_QUERY_TAIL +IMPL_IUNKNOWN_QUERY_IFACE(IEnumVARIANT) +IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(mAnchorAcc) STDMETHODIMP ChildrenEnumVariant::Next(ULONG aCount, VARIANT FAR* aItems, ULONG FAR* aCountFetched) { A11Y_TRYBLOCK_BEGIN if (!aItems || !aCountFetched)
--- a/caps/BasePrincipal.cpp +++ b/caps/BasePrincipal.cpp @@ -61,16 +61,23 @@ PrincipalOriginAttributes::InheritFromNe mUserContextId = aAttrs.mUserContextId; mSignedPkg = aAttrs.mSignedPkg; mPrivateBrowsingId = aAttrs.mPrivateBrowsingId; mFirstPartyDomain = aAttrs.mFirstPartyDomain; } void +PrincipalOriginAttributes::StripUserContextIdAndFirstPartyDomain() +{ + mUserContextId = nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID; + mFirstPartyDomain.Truncate(); +} + +void DocShellOriginAttributes::InheritFromDocToChildDocShell(const PrincipalOriginAttributes& aAttrs) { mAppId = aAttrs.mAppId; mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser; // addonId is computed from the principal URI and never propagated mUserContextId = aAttrs.mUserContextId; @@ -712,16 +719,33 @@ BasePrincipal::CreateCodebasePrincipal(c nsCOMPtr<nsIURI> uri; nsresult rv = NS_NewURI(getter_AddRefs(uri), originNoSuffix); NS_ENSURE_SUCCESS(rv, nullptr); return BasePrincipal::CreateCodebasePrincipal(uri, attrs); } +already_AddRefed<BasePrincipal> +BasePrincipal::CloneStrippingUserContextIdAndFirstPartyDomain() +{ + PrincipalOriginAttributes attrs = OriginAttributesRef(); + attrs.StripUserContextIdAndFirstPartyDomain(); + + nsAutoCString originNoSuffix; + nsresult rv = GetOriginNoSuffix(originNoSuffix); + NS_ENSURE_SUCCESS(rv, nullptr); + + nsCOMPtr<nsIURI> uri; + rv = NS_NewURI(getter_AddRefs(uri), originNoSuffix); + NS_ENSURE_SUCCESS(rv, nullptr); + + return BasePrincipal::CreateCodebasePrincipal(uri, attrs); +} + bool BasePrincipal::AddonAllowsLoad(nsIURI* aURI) { if (mOriginAttributes.mAddonId.IsEmpty()) { return false; } nsCOMPtr<nsIAddonPolicyService> aps = do_GetService("@mozilla.org/addons/policy-service;1");
--- a/caps/BasePrincipal.h +++ b/caps/BasePrincipal.h @@ -99,16 +99,18 @@ public: // // @param aAttrs Origin Attributes of the docshell. // @param aURI The URI of the document. void InheritFromDocShellToDoc(const DocShellOriginAttributes& aAttrs, const nsIURI* aURI); // Inherit OriginAttributes from Necko. void InheritFromNecko(const NeckoOriginAttributes& aAttrs); + + void StripUserContextIdAndFirstPartyDomain(); }; // For OriginAttributes stored on docshells / loadcontexts / browsing contexts. class DocShellOriginAttributes : public OriginAttributes { public: DocShellOriginAttributes() {} DocShellOriginAttributes(uint32_t aAppId, bool aInIsolatedMozBrowser) @@ -309,16 +311,18 @@ public: eNullPrincipal, eCodebasePrincipal, eExpandedPrincipal, eSystemPrincipal }; virtual PrincipalKind Kind() = 0; + already_AddRefed<BasePrincipal> CloneStrippingUserContextIdAndFirstPartyDomain(); + protected: virtual ~BasePrincipal(); virtual nsresult GetOriginInternal(nsACString& aOrigin) = 0; virtual bool SubsumesInternal(nsIPrincipal* aOther, DocumentDomainConsideration aConsider) = 0; // Internal, side-effect-free check to determine whether the concrete // principal would allow the load ignoring any common behavior implemented in
--- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -142,24 +142,25 @@ GetPrincipalDomainOrigin(nsIPrincipal* a if (!uri) { aPrincipal->GetURI(getter_AddRefs(uri)); } NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED); return GetOriginFromURI(uri, aOrigin); } -inline void SetPendingException(JSContext *cx, const char *aMsg) +inline void SetPendingExceptionASCII(JSContext *cx, const char *aMsg) { - JS_ReportError(cx, "%s", aMsg); + JS_ReportErrorASCII(cx, "%s", aMsg); } inline void SetPendingException(JSContext *cx, const char16_t *aMsg) { - JS_ReportError(cx, "%hs", aMsg); + // FIXME: Need to convert to UTF-8 (bug XXX). + JS_ReportErrorLatin1(cx, "%hs", aMsg); } // Helper class to get stuff from the ClassInfo and not waste extra time with // virtual method calls for things it has already gotten class ClassInfoData { public: ClassInfoData(nsIClassInfo *aClassInfo, const char *aName) @@ -591,17 +592,17 @@ nsScriptSecurityManager::CheckLoadURIFro // Report error. nsAutoCString spec; if (NS_FAILED(aURI->GetAsciiSpec(spec))) return NS_ERROR_FAILURE; nsAutoCString msg("Access to '"); msg.Append(spec); msg.AppendLiteral("' from script denied"); - SetPendingException(cx, msg.get()); + SetPendingExceptionASCII(cx, msg.get()); return NS_ERROR_DOM_BAD_URI; } /** * Helper method to handle cases where a flag passed to * CheckLoadURIWithPrincipal means denying loading if the given URI has certain * nsIProtocolHandler flags set. * @return if success, access is allowed. Otherwise, deny access @@ -1300,34 +1301,34 @@ nsScriptSecurityManager::CanCreateInstan return NS_OK; } //-- Access denied, report an error nsAutoCString errorMsg("Permission denied to create instance of class. CID="); char cidStr[NSID_LENGTH]; aCID.ToProvidedString(cidStr); errorMsg.Append(cidStr); - SetPendingException(cx, errorMsg.get()); + SetPendingExceptionASCII(cx, errorMsg.get()); return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED; } NS_IMETHODIMP nsScriptSecurityManager::CanGetService(JSContext *cx, const nsCID &aCID) { if (nsContentUtils::IsCallerChrome()) { return NS_OK; } //-- Access denied, report an error nsAutoCString errorMsg("Permission denied to get service. CID="); char cidStr[NSID_LENGTH]; aCID.ToProvidedString(cidStr); errorMsg.Append(cidStr); - SetPendingException(cx, errorMsg.get()); + SetPendingExceptionASCII(cx, errorMsg.get()); return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED; } ///////////////////////////////////// // Method implementing nsIObserver // ///////////////////////////////////// const char sJSEnabledPrefName[] = "javascript.enabled"; const char sFileOriginPolicyPrefName[] =
deleted file mode 100644 --- a/config/external/sqlite/Makefile.in +++ /dev/null @@ -1,5 +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/. - -LIB_IS_C_ONLY = 1
--- a/devtools/client/webconsole/test/browser_webconsole_inspect-parsed-documents.js +++ b/devtools/client/webconsole/test/browser_webconsole_inspect-parsed-documents.js @@ -16,17 +16,17 @@ const TEST_CASES = [ }, { input: '(new DOMParser()).parseFromString("<a />", "application/xml")', output: "XMLDocument", inspectable: true, }, { input: '(new DOMParser()).parseFromString("<svg></svg>", "image/svg+xml")', - output: "SVGDocument", + output: "XMLDocument", inspectable: true, }, ]; const TEST_URI = "data:text/html;charset=utf8," + "browser_webconsole_inspect-parsed-documents.js"; add_task(function* () { let {tab} = yield loadTab(TEST_URI);
--- a/dom/animation/test/css-transitions/file_animation-cancel.html +++ b/dom/animation/test/css-transitions/file_animation-cancel.html @@ -113,25 +113,53 @@ test(function(t) { assert_equals(getComputedStyle(div).marginLeft, '1000px', 'margin-left style is still not animated after updating' + ' transition-duration'); assert_equals(animation.playState, 'idle', 'Transition is still idle after updating transition-duration'); }, 'After cancelling a transition, updating transition properties doesn\'t make' + ' it live again'); -test(function(t) { +promise_test(function(t) { var div = addDiv(t, { style: 'margin-left: 0px' }); flushComputedStyle(div); div.style.transition = 'margin-left 100s'; div.style.marginLeft = '1000px'; flushComputedStyle(div); var animation = div.getAnimations()[0]; - div.style.display = 'none'; - assert_equals(animation.playState, 'idle'); - assert_equals(getComputedStyle(div).marginLeft, '1000px'); + return animation.ready.then(function() { + assert_equals(animation.playState, 'running'); + div.style.display = 'none'; + return waitForFrame(); + }).then(function() { + assert_equals(animation.playState, 'idle'); + assert_equals(getComputedStyle(div).marginLeft, '1000px'); + }); }, 'Setting display:none on an element cancels its transitions'); +promise_test(function(t) { + var parentDiv = addDiv(t); + var childDiv = document.createElement('div'); + parentDiv.appendChild(childDiv); + childDiv.setAttribute('style', 'margin-left: 0px'); + + flushComputedStyle(childDiv); + + childDiv.style.transition = 'margin-left 100s'; + childDiv.style.marginLeft = '1000px'; + flushComputedStyle(childDiv); + + var animation = childDiv.getAnimations()[0]; + return animation.ready.then(function() { + assert_equals(animation.playState, 'running'); + parentDiv.style.display = 'none'; + return waitForFrame(); + }).then(function() { + assert_equals(animation.playState, 'idle'); + assert_equals(getComputedStyle(childDiv).marginLeft, '1000px'); + }); +}, 'Setting display:none cancels transitions on a child element'); + done(); </script> </body>
--- a/dom/base/BlobSet.cpp +++ b/dom/base/BlobSet.cpp @@ -7,49 +7,34 @@ #include "mozilla/dom/BlobSet.h" #include "mozilla/CheckedInt.h" #include "mozilla/dom/File.h" #include "MultipartBlobImpl.h" namespace mozilla { namespace dom { -already_AddRefed<Blob> -BlobSet::GetBlobInternal(nsISupports* aParent, - const nsACString& aContentType, - ErrorResult& aRv) -{ - nsTArray<RefPtr<BlobImpl>> subImpls(GetBlobImpls()); - RefPtr<BlobImpl> blobImpl = - MultipartBlobImpl::Create(Move(subImpls), - NS_ConvertASCIItoUTF16(aContentType), - aRv); - if (NS_WARN_IF(aRv.Failed())) { - return nullptr; - } - - RefPtr<Blob> blob = Blob::Create(aParent, blobImpl); - return blob.forget(); -} - nsresult BlobSet::AppendVoidPtr(const void* aData, uint32_t aLength) { NS_ENSURE_ARG_POINTER(aData); if (!aLength) { return NS_OK; } - uint64_t offset = mDataLen; - - if (!ExpandBufferSize(aLength)) { + void* data = malloc(aLength); + if (!data) { return NS_ERROR_OUT_OF_MEMORY; } - memcpy((char*)mData + offset, aData, aLength); + memcpy((char*)data, aData, aLength); + + RefPtr<BlobImpl> blobImpl = new BlobImplMemory(data, aLength, EmptyString()); + mBlobImpls.AppendElement(blobImpl); + return NS_OK; } nsresult BlobSet::AppendString(const nsAString& aString, bool nativeEOL, JSContext* aCx) { nsCString utf8Str = NS_ConvertUTF16toUTF8(aString); @@ -66,74 +51,14 @@ BlobSet::AppendString(const nsAString& a return AppendVoidPtr((void*)utf8Str.Data(), utf8Str.Length()); } nsresult BlobSet::AppendBlobImpl(BlobImpl* aBlobImpl) { NS_ENSURE_ARG_POINTER(aBlobImpl); - - Flush(); mBlobImpls.AppendElement(aBlobImpl); - - return NS_OK; -} - -nsresult -BlobSet::AppendBlobImpls(const nsTArray<RefPtr<BlobImpl>>& aBlobImpls) -{ - Flush(); - mBlobImpls.AppendElements(aBlobImpls); - return NS_OK; } -bool -BlobSet::ExpandBufferSize(uint64_t aSize) -{ - if (mDataBufferLen >= mDataLen + aSize) { - mDataLen += aSize; - return true; - } - - // Start at 1 or we'll loop forever. - CheckedUint32 bufferLen = - std::max<uint32_t>(static_cast<uint32_t>(mDataBufferLen), 1); - while (bufferLen.isValid() && bufferLen.value() < mDataLen + aSize) { - bufferLen *= 2; - } - - if (!bufferLen.isValid()) { - return false; - } - - void* data = realloc(mData, bufferLen.value()); - if (!data) { - return false; - } - - mData = data; - mDataBufferLen = bufferLen.value(); - mDataLen += aSize; - return true; -} - -void -BlobSet::Flush() -{ - if (mData) { - // If we have some data, create a blob for it - // and put it on the stack - - RefPtr<BlobImpl> blobImpl = - new BlobImplMemory(mData, mDataLen, EmptyString()); - mBlobImpls.AppendElement(blobImpl); - - mData = nullptr; // The nsDOMMemoryFile takes ownership of the buffer - mDataLen = 0; - mDataBufferLen = 0; - return; - } -} - } // dom namespace } // mozilla namespace
--- a/dom/base/BlobSet.h +++ b/dom/base/BlobSet.h @@ -7,55 +7,30 @@ #ifndef mozilla_dom_BlobSet_h #define mozilla_dom_BlobSet_h #include "mozilla/RefPtr.h" namespace mozilla { namespace dom { -class Blob; class BlobImpl; class BlobSet final { public: - BlobSet() - : mData(nullptr) - , mDataLen(0) - , mDataBufferLen(0) - {} - - ~BlobSet() - { - free(mData); - } - nsresult AppendVoidPtr(const void* aData, uint32_t aLength); nsresult AppendString(const nsAString& aString, bool nativeEOL, JSContext* aCx); nsresult AppendBlobImpl(BlobImpl* aBlobImpl); - nsresult AppendBlobImpls(const nsTArray<RefPtr<BlobImpl>>& aBlobImpls); - - nsTArray<RefPtr<BlobImpl>>& GetBlobImpls() { Flush(); return mBlobImpls; } - - already_AddRefed<Blob> GetBlobInternal(nsISupports* aParent, - const nsACString& aContentType, - ErrorResult& aRv); + nsTArray<RefPtr<BlobImpl>>& GetBlobImpls() { return mBlobImpls; } private: - bool ExpandBufferSize(uint64_t aSize); - - void Flush(); - nsTArray<RefPtr<BlobImpl>> mBlobImpls; - void* mData; - uint64_t mDataLen; - uint64_t mDataBufferLen; }; } // namespace dom } // namespace mozilla #endif // mozilla_dom_BlobSet_h
--- a/dom/base/Location.cpp +++ b/dom/base/Location.cpp @@ -905,30 +905,33 @@ Location::GetSourceBaseURL(JSContext* cx } } NS_ENSURE_TRUE(doc, NS_OK); *sourceURL = doc->GetBaseURI().take(); return NS_OK; } bool -Location::CallerSubsumes() +Location::CallerSubsumes(nsIPrincipal* aSubjectPrincipal) { + MOZ_ASSERT(aSubjectPrincipal); + // Get the principal associated with the location object. Note that this is // the principal of the page which will actually be navigated, not the // principal of the Location object itself. This is why we need this check // even though we only allow limited cross-origin access to Location objects // in general. nsCOMPtr<nsPIDOMWindowOuter> outer = mInnerWindow->GetOuterWindow(); if (MOZ_UNLIKELY(!outer)) return false; nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(outer); bool subsumes = false; nsresult rv = - nsContentUtils::SubjectPrincipal()->SubsumesConsideringDomain(sop->GetPrincipal(), &subsumes); + aSubjectPrincipal->SubsumesConsideringDomain(sop->GetPrincipal(), + &subsumes); NS_ENSURE_SUCCESS(rv, false); return subsumes; } JSObject* Location::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { return LocationBinding::Wrap(aCx, this, aGivenProto);
--- a/dom/base/Location.h +++ b/dom/base/Location.h @@ -39,129 +39,190 @@ public: void SetDocShell(nsIDocShell *aDocShell); nsIDocShell *GetDocShell(); // nsIDOMLocation NS_DECL_NSIDOMLOCATION #define THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME() { \ - if (!CallerSubsumes()) { \ + MOZ_ASSERT(aSubjectPrincipal.isSome()); \ + if (!CallerSubsumes(aSubjectPrincipal.value())) { \ aError.Throw(NS_ERROR_DOM_SECURITY_ERR); \ return; \ } \ } // WebIDL API: - void Assign(const nsAString& aUrl, ErrorResult& aError) + void Assign(const nsAString& aUrl, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = Assign(aUrl); } - void Replace(const nsAString& aUrl, ErrorResult& aError) + void Replace(const nsAString& aUrl, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aError) { aError = Replace(aUrl); } - void Reload(bool aForceget, ErrorResult& aError) + void Reload(bool aForceget, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = Reload(aForceget); } - void GetHref(nsAString& aHref, ErrorResult& aError) + + void GetHref(nsAString& aHref, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetHref(aHref); } - void SetHref(const nsAString& aHref, ErrorResult& aError) + + void SetHref(const nsAString& aHref, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aError) { aError = SetHref(aHref); } - void GetOrigin(nsAString& aOrigin, ErrorResult& aError) + + void GetOrigin(nsAString& aOrigin, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetOrigin(aOrigin); } - void GetProtocol(nsAString& aProtocol, ErrorResult& aError) + + void GetProtocol(nsAString& aProtocol, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetProtocol(aProtocol); } - void SetProtocol(const nsAString& aProtocol, ErrorResult& aError) + + void SetProtocol(const nsAString& aProtocol, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = SetProtocol(aProtocol); } - void GetHost(nsAString& aHost, ErrorResult& aError) + + void GetHost(nsAString& aHost, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetHost(aHost); } - void SetHost(const nsAString& aHost, ErrorResult& aError) + + void SetHost(const nsAString& aHost, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = SetHost(aHost); } - void GetHostname(nsAString& aHostname, ErrorResult& aError) + + void GetHostname(nsAString& aHostname, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetHostname(aHostname); } - void SetHostname(const nsAString& aHostname, ErrorResult& aError) + + void SetHostname(const nsAString& aHostname, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = SetHostname(aHostname); } - void GetPort(nsAString& aPort, ErrorResult& aError) + + void GetPort(nsAString& aPort, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetPort(aPort); } - void SetPort(const nsAString& aPort, ErrorResult& aError) + + void SetPort(const nsAString& aPort, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = SetPort(aPort); } - void GetPathname(nsAString& aPathname, ErrorResult& aError) + + void GetPathname(nsAString& aPathname, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetPathname(aPathname); } - void SetPathname(const nsAString& aPathname, ErrorResult& aError) + + void SetPathname(const nsAString& aPathname, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = SetPathname(aPathname); } - void GetSearch(nsAString& aSeach, ErrorResult& aError) + + void GetSearch(nsAString& aSeach, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetSearch(aSeach); } - void SetSearch(const nsAString& aSeach, ErrorResult& aError) + + void SetSearch(const nsAString& aSeach, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = SetSearch(aSeach); } - void GetHash(nsAString& aHash, ErrorResult& aError) + void GetHash(nsAString& aHash, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetHash(aHash); } - void SetHash(const nsAString& aHash, ErrorResult& aError) + + void SetHash(const nsAString& aHash, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aError) { THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = SetHash(aHash); } - void Stringify(nsAString& aRetval, ErrorResult& aError) + + void Stringify(nsAString& aRetval, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aError) { // GetHref checks CallerSubsumes. - GetHref(aRetval, aError); + GetHref(aRetval, aSubjectPrincipal, aError); } + nsPIDOMWindowInner* GetParentObject() const { return mInnerWindow; } virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; @@ -180,17 +241,17 @@ protected: nsresult SetURI(nsIURI* aURL, bool aReplace = false); nsresult SetHrefWithBase(const nsAString& aHref, nsIURI* aBase, bool aReplace); nsresult SetHrefWithContext(JSContext* cx, const nsAString& aHref, bool aReplace); nsresult GetSourceBaseURL(JSContext* cx, nsIURI** sourceURL); nsresult CheckURL(nsIURI *url, nsIDocShellLoadInfo** aLoadInfo); - bool CallerSubsumes(); + bool CallerSubsumes(nsIPrincipal* aSubjectPrincipal); nsString mCachedHash; nsCOMPtr<nsPIDOMWindowInner> mInnerWindow; nsWeakPtr mDocShell; }; } // dom namespace } // mozilla namespace
copy from dom/base/BlobSet.cpp copy to dom/base/MutableBlobStorage.cpp --- a/dom/base/BlobSet.cpp +++ b/dom/base/MutableBlobStorage.cpp @@ -1,100 +1,497 @@ /* -*- 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 "mozilla/dom/BlobSet.h" +#include "mozilla/dom/MutableBlobStorage.h" #include "mozilla/CheckedInt.h" #include "mozilla/dom/File.h" -#include "MultipartBlobImpl.h" +#include "nsAnonymousTemporaryFile.h" +#include "nsNetCID.h" +#include "WorkerPrivate.h" + +#define BLOB_MEMORY_TEMPORARY_FILE 1048576 namespace mozilla { namespace dom { -already_AddRefed<Blob> -BlobSet::GetBlobInternal(nsISupports* aParent, - const nsACString& aContentType, - ErrorResult& aRv) +namespace { + +// This class uses the callback to inform when the Blob is created or when the +// error must be propagated. +class BlobCreationDoneRunnable final : public Runnable +{ +public: + BlobCreationDoneRunnable(MutableBlobStorage* aBlobStorage, + MutableBlobStorageCallback* aCallback, + Blob* aBlob, + nsresult aRv) + : mBlobStorage(aBlobStorage) + , mCallback(aCallback) + , mBlob(aBlob) + , mRv(aRv) + { + MOZ_ASSERT(aBlobStorage); + MOZ_ASSERT(aCallback); + MOZ_ASSERT((NS_FAILED(aRv) && !aBlob) || + (NS_SUCCEEDED(aRv) && aBlob)); + } + + NS_IMETHOD + Run() override + { + MOZ_ASSERT(NS_IsMainThread()); + mCallback->BlobStoreCompleted(mBlobStorage, mBlob, mRv); + mCallback = nullptr; + mBlob = nullptr; + return NS_OK; + } + +private: + ~BlobCreationDoneRunnable() + { + // If something when wrong, we still have to release these objects in the + // correct thread. + NS_ReleaseOnMainThread(mCallback.forget()); + NS_ReleaseOnMainThread(mBlob.forget()); + } + + RefPtr<MutableBlobStorage> mBlobStorage; + RefPtr<MutableBlobStorageCallback> mCallback; + RefPtr<Blob> mBlob; + nsresult mRv; +}; + +// This runnable goes back to the main-thread and informs the BlobStorage about +// the temporary file. +class FileCreatedRunnable final : public Runnable +{ +public: + FileCreatedRunnable(MutableBlobStorage* aBlobStorage, PRFileDesc* aFD) + : mBlobStorage(aBlobStorage) + , mFD(aFD) + { + MOZ_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(aBlobStorage); + MOZ_ASSERT(aFD); + } + + NS_IMETHOD + Run() override + { + MOZ_ASSERT(NS_IsMainThread()); + mBlobStorage->TemporaryFileCreated(mFD); + mFD = nullptr; + return NS_OK; + } + +private: + ~FileCreatedRunnable() + { + // If something when wrong, we still have to close the FileDescriptor. + if (mFD) { + PR_Close(mFD); + } + } + + RefPtr<MutableBlobStorage> mBlobStorage; + PRFileDesc* mFD; +}; + +// This runnable creates the temporary file. When done, FileCreatedRunnable is +// dispatched back to the main-thread. +class CreateTemporaryFileRunnable final : public Runnable +{ +public: + explicit CreateTemporaryFileRunnable(MutableBlobStorage* aBlobStorage) + : mBlobStorage(aBlobStorage) + { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aBlobStorage); + } + + NS_IMETHOD + Run() override + { + MOZ_ASSERT(!NS_IsMainThread()); + + PRFileDesc* tempFD = nullptr; + nsresult rv = NS_OpenAnonymousTemporaryFile(&tempFD); + if (NS_WARN_IF(NS_FAILED(rv))) { + // In sandboxed context we are not allowed to create temporary files, but + // this doesn't mean that BlobStorage should fail. We can continue to + // store data in memory. We don't change the storageType so that we don't + // try to create a temporary file again. + return NS_OK; + } + + // The ownership of the tempFD is moved to the FileCreatedRunnable. + return NS_DispatchToMainThread(new FileCreatedRunnable(mBlobStorage, tempFD)); + } + +private: + RefPtr<MutableBlobStorage> mBlobStorage; +}; + +// Simple runnable to propagate the error to the BlobStorage. +class ErrorPropagationRunnable final : public Runnable +{ +public: + ErrorPropagationRunnable(MutableBlobStorage* aBlobStorage, nsresult aRv) + : mBlobStorage(aBlobStorage) + , mRv(aRv) + {} + + NS_IMETHOD + Run() override + { + mBlobStorage->ErrorPropagated(mRv); + return NS_OK; + } + +private: + RefPtr<MutableBlobStorage> mBlobStorage; + nsresult mRv; +}; + +// This runnable moves a buffer to the IO thread and there, it writes it into +// the temporary file. +class WriteRunnable final : public Runnable { - nsTArray<RefPtr<BlobImpl>> subImpls(GetBlobImpls()); - RefPtr<BlobImpl> blobImpl = - MultipartBlobImpl::Create(Move(subImpls), - NS_ConvertASCIItoUTF16(aContentType), - aRv); - if (NS_WARN_IF(aRv.Failed())) { - return nullptr; +public: + static WriteRunnable* + CopyBuffer(MutableBlobStorage* aBlobStorage, PRFileDesc* aFD, + const void* aData, uint32_t aLength) + { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aBlobStorage); + MOZ_ASSERT(aFD); + MOZ_ASSERT(aData); + + // We have to take a copy of this buffer. + void* data = malloc(aLength); + if (!data) { + return nullptr; + } + + memcpy((char*)data, aData, aLength); + return new WriteRunnable(aBlobStorage, aFD, data, aLength); + } + + static WriteRunnable* + AdoptBuffer(MutableBlobStorage* aBlobStorage, PRFileDesc* aFD, + void* aData, uint32_t aLength) + { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aBlobStorage); + MOZ_ASSERT(aFD); + MOZ_ASSERT(aData); + + return new WriteRunnable(aBlobStorage, aFD, aData, aLength); + } + + NS_IMETHOD + Run() override + { + MOZ_ASSERT(!NS_IsMainThread()); + + int32_t written = PR_Write(mFD, mData, mLength); + if (NS_WARN_IF(written < 0 || uint32_t(written) != mLength)) { + return NS_DispatchToMainThread( + new ErrorPropagationRunnable(mBlobStorage, NS_ERROR_FAILURE)); + } + + return NS_OK; + } + +private: + WriteRunnable(MutableBlobStorage* aBlobStorage, PRFileDesc* aFD, + void* aData, uint32_t aLength) + : mBlobStorage(aBlobStorage) + , mFD(aFD) + , mData(aData) + , mLength(aLength) + { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mBlobStorage); + MOZ_ASSERT(aFD); + MOZ_ASSERT(aData); + } + + ~WriteRunnable() + { + free(mData); + } + + RefPtr<MutableBlobStorage> mBlobStorage; + PRFileDesc* mFD; + void* mData; + uint32_t mLength; +}; + +// This runnable closes the FD in case something goes wrong or the temporary +// file is not needed anymore. +class CloseFileRunnable final : public Runnable +{ +public: + explicit CloseFileRunnable(PRFileDesc* aFD) + : mFD(aFD) + {} + + NS_IMETHOD + Run() override + { + MOZ_ASSERT(!NS_IsMainThread()); + PR_Close(mFD); + mFD = nullptr; + return NS_OK; + } + +private: + ~CloseFileRunnable() + { + if (mFD) { + PR_Close(mFD); + } + } + + PRFileDesc* mFD; +}; + +// This runnable is dispatched to the main-thread from the IO thread and its +// task is to create the blob and inform the callback. +class CreateBlobRunnable final : public Runnable +{ +public: + CreateBlobRunnable(MutableBlobStorage* aBlobStorage, + already_AddRefed<nsISupports> aParent, + const nsACString& aContentType, + already_AddRefed<MutableBlobStorageCallback> aCallback) + : mBlobStorage(aBlobStorage) + , mParent(aParent) + , mContentType(aContentType) + , mCallback(aCallback) + { + MOZ_ASSERT(!NS_IsMainThread()); + } + + NS_IMETHOD + Run() override + { + MOZ_ASSERT(NS_IsMainThread()); + mBlobStorage->CreateBlobAndRespond(mParent.forget(), mContentType, + mCallback.forget()); + return NS_OK; + } + +private: + ~CreateBlobRunnable() + { + // If something when wrong, we still have to release data in the correct + // thread. + NS_ReleaseOnMainThread(mParent.forget()); + NS_ReleaseOnMainThread(mCallback.forget()); + } + + RefPtr<MutableBlobStorage> mBlobStorage; + nsCOMPtr<nsISupports> mParent; + nsCString mContentType; + RefPtr<MutableBlobStorageCallback> mCallback; +}; + +// This task is used to know when the writing is completed. From the IO thread +// it dispatches a CreateBlobRunnable to the main-thread. +class LastRunnable final : public Runnable +{ +public: + LastRunnable(MutableBlobStorage* aBlobStorage, + nsISupports* aParent, + const nsACString& aContentType, + MutableBlobStorageCallback* aCallback) + : mBlobStorage(aBlobStorage) + , mParent(aParent) + , mContentType(aContentType) + , mCallback(aCallback) + { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mBlobStorage); + MOZ_ASSERT(aParent); + MOZ_ASSERT(aCallback); + } + + NS_IMETHOD + Run() override + { + MOZ_ASSERT(!NS_IsMainThread()); + RefPtr<Runnable> runnable = + new CreateBlobRunnable(mBlobStorage, mParent.forget(), + mContentType, mCallback.forget()); + return NS_DispatchToMainThread(runnable); + } + +private: + ~LastRunnable() + { + // If something when wrong, we still have to release data in the correct + // thread. + NS_ReleaseOnMainThread(mParent.forget()); + NS_ReleaseOnMainThread(mCallback.forget()); + } + + RefPtr<MutableBlobStorage> mBlobStorage; + nsCOMPtr<nsISupports> mParent; + nsCString mContentType; + RefPtr<MutableBlobStorageCallback> mCallback; +}; + +} // anonymous namespace + +MutableBlobStorage::MutableBlobStorage(MutableBlobStorageType aType) + : mData(nullptr) + , mDataLen(0) + , mDataBufferLen(0) + , mStorageState(aType == eOnlyInMemory ? eKeepInMemory : eInMemory) + , mFD(nullptr) + , mErrorResult(NS_OK) +{ + MOZ_ASSERT(NS_IsMainThread()); +} + +MutableBlobStorage::~MutableBlobStorage() +{ + free(mData); + + if (mFD) { + DispatchToIOThread(new CloseFileRunnable(mFD)); + } +} + +uint64_t +MutableBlobStorage::GetBlobWhenReady(nsISupports* aParent, + const nsACString& aContentType, + MutableBlobStorageCallback* aCallback) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aParent); + MOZ_ASSERT(aCallback); + + // GetBlob can be called just once. + MOZ_ASSERT(mStorageState != eClosed); + StorageState previousState = mStorageState; + mStorageState = eClosed; + + if (previousState == eInTemporaryFile) { + MOZ_ASSERT(mFD); + + if (NS_FAILED(mErrorResult)) { + NS_DispatchToMainThread( + new BlobCreationDoneRunnable(this, aCallback, nullptr, mErrorResult)); + return 0; + } + + // We want to wait until all the WriteRunnable are completed. The way we do + // this is to go to the I/O thread and then we come back: the runnables are + // executed in order and this LastRunnable will be... the last one. + nsresult rv = DispatchToIOThread(new LastRunnable(this, aParent, + aContentType, aCallback)); + if (NS_WARN_IF(NS_FAILED(rv))) { + NS_DispatchToMainThread( + new BlobCreationDoneRunnable(this, aCallback, nullptr, rv)); + return 0; + } + + return mDataLen; + } + + RefPtr<BlobImpl> blobImpl; + + if (mData) { + blobImpl = new BlobImplMemory(mData, mDataLen, + NS_ConvertUTF8toUTF16(aContentType)); + + mData = nullptr; // The BlobImplMemory takes ownership of the buffer + mDataLen = 0; + mDataBufferLen = 0; + } else { + blobImpl = new EmptyBlobImpl(NS_ConvertUTF8toUTF16(aContentType)); } RefPtr<Blob> blob = Blob::Create(aParent, blobImpl); - return blob.forget(); + RefPtr<BlobCreationDoneRunnable> runnable = + new BlobCreationDoneRunnable(this, aCallback, blob, NS_OK); + + nsresult error = NS_DispatchToMainThread(runnable); + if (NS_WARN_IF(NS_FAILED(error))) { + return 0; + } + + return mDataLen; } nsresult -BlobSet::AppendVoidPtr(const void* aData, uint32_t aLength) +MutableBlobStorage::Append(const void* aData, uint32_t aLength) { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mStorageState != eClosed); NS_ENSURE_ARG_POINTER(aData); + if (!aLength) { return NS_OK; } + // If eInMemory is the current Storage state, we could maybe migrate to + // a temporary file. + if (mStorageState == eInMemory && ShouldBeTemporaryStorage(aLength)) { + nsresult rv = MaybeCreateTemporaryFile(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + + // If we are already in the temporaryFile mode, we have to dispatch a + // runnable. + if (mStorageState == eInTemporaryFile) { + MOZ_ASSERT(mFD); + + RefPtr<WriteRunnable> runnable = + WriteRunnable::CopyBuffer(this, mFD, aData, aLength); + if (NS_WARN_IF(!runnable)) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult rv = DispatchToIOThread(runnable); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + mDataLen += aLength; + return NS_OK; + } + + // By default, we store in memory. + uint64_t offset = mDataLen; if (!ExpandBufferSize(aLength)) { return NS_ERROR_OUT_OF_MEMORY; } memcpy((char*)mData + offset, aData, aLength); return NS_OK; } -nsresult -BlobSet::AppendString(const nsAString& aString, bool nativeEOL, JSContext* aCx) +bool +MutableBlobStorage::ExpandBufferSize(uint64_t aSize) { - nsCString utf8Str = NS_ConvertUTF16toUTF8(aString); - - if (nativeEOL) { - if (utf8Str.Contains('\r')) { - utf8Str.ReplaceSubstring("\r\n", "\n"); - utf8Str.ReplaceSubstring("\r", "\n"); - } -#ifdef XP_WIN - utf8Str.ReplaceSubstring("\n", "\r\n"); -#endif - } - - return AppendVoidPtr((void*)utf8Str.Data(), - utf8Str.Length()); -} + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mStorageState < eInTemporaryFile); -nsresult -BlobSet::AppendBlobImpl(BlobImpl* aBlobImpl) -{ - NS_ENSURE_ARG_POINTER(aBlobImpl); - - Flush(); - mBlobImpls.AppendElement(aBlobImpl); - - return NS_OK; -} - -nsresult -BlobSet::AppendBlobImpls(const nsTArray<RefPtr<BlobImpl>>& aBlobImpls) -{ - Flush(); - mBlobImpls.AppendElements(aBlobImpls); - - return NS_OK; -} - -bool -BlobSet::ExpandBufferSize(uint64_t aSize) -{ if (mDataBufferLen >= mDataLen + aSize) { mDataLen += aSize; return true; } // Start at 1 or we'll loop forever. CheckedUint32 bufferLen = std::max<uint32_t>(static_cast<uint32_t>(mDataBufferLen), 1); @@ -112,28 +509,109 @@ BlobSet::ExpandBufferSize(uint64_t aSize } mData = data; mDataBufferLen = bufferLen.value(); mDataLen += aSize; return true; } -void -BlobSet::Flush() +bool +MutableBlobStorage::ShouldBeTemporaryStorage(uint64_t aSize) const { - if (mData) { - // If we have some data, create a blob for it - // and put it on the stack + MOZ_ASSERT(mStorageState == eInMemory); + + CheckedUint32 bufferSize = mDataLen; + bufferSize += aSize; + + if (!bufferSize.isValid()) { + return false; + } + + return bufferSize.value() >= Preferences::GetUint("dom.blob.memoryToTemporaryFile", + BLOB_MEMORY_TEMPORARY_FILE); +} + +nsresult +MutableBlobStorage::MaybeCreateTemporaryFile() +{ + nsresult rv = DispatchToIOThread(new CreateTemporaryFileRunnable(this)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } - RefPtr<BlobImpl> blobImpl = - new BlobImplMemory(mData, mDataLen, EmptyString()); - mBlobImpls.AppendElement(blobImpl); + mStorageState = eWaitingForTemporaryFile; + return NS_OK; +} + +void +MutableBlobStorage::TemporaryFileCreated(PRFileDesc* aFD) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mStorageState == eWaitingForTemporaryFile || + mStorageState == eClosed); - mData = nullptr; // The nsDOMMemoryFile takes ownership of the buffer - mDataLen = 0; - mDataBufferLen = 0; + if (mStorageState == eClosed) { + DispatchToIOThread(new CloseFileRunnable(aFD)); + return; + } + + mStorageState = eInTemporaryFile; + mFD = aFD; + + RefPtr<WriteRunnable> runnable = + WriteRunnable::AdoptBuffer(this, mFD, mData, mDataLen); + MOZ_ASSERT(runnable); + + mData = nullptr; + + nsresult rv = DispatchToIOThread(runnable); + if (NS_WARN_IF(NS_FAILED(rv))) { + mErrorResult = rv; return; } } +void +MutableBlobStorage::CreateBlobAndRespond(already_AddRefed<nsISupports> aParent, + const nsACString& aContentType, + already_AddRefed<MutableBlobStorageCallback> aCallback) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mStorageState == eClosed); + MOZ_ASSERT(mFD); + + nsCOMPtr<nsISupports> parent(aParent); + RefPtr<MutableBlobStorageCallback> callback(aCallback); + + RefPtr<Blob> blob = + File::CreateTemporaryBlob(parent, mFD, 0, mDataLen, + NS_ConvertUTF8toUTF16(aContentType)); + callback->BlobStoreCompleted(this, blob, NS_OK); + + // ownership of this FD is moved to the BlobImpl. + mFD = nullptr; +} + +void +MutableBlobStorage::ErrorPropagated(nsresult aRv) +{ + MOZ_ASSERT(NS_IsMainThread()); + mErrorResult = aRv; +} + +/* static */ nsresult +MutableBlobStorage::DispatchToIOThread(Runnable* aRunnable) +{ + nsCOMPtr<nsIEventTarget> target + = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); + MOZ_ASSERT(target); + + nsresult rv = target->Dispatch(aRunnable, NS_DISPATCH_NORMAL); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + } // dom namespace } // mozilla namespace
copy from dom/base/BlobSet.h copy to dom/base/MutableBlobStorage.h --- a/dom/base/BlobSet.h +++ b/dom/base/MutableBlobStorage.h @@ -1,61 +1,98 @@ /* -*- 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_BlobSet_h -#define mozilla_dom_BlobSet_h +#ifndef mozilla_dom_MutableBlobStorage_h +#define mozilla_dom_MutableBlobStorage_h #include "mozilla/RefPtr.h" +#include "prio.h" namespace mozilla { namespace dom { class Blob; class BlobImpl; +class MutableBlobStorage; -class BlobSet final +class MutableBlobStorageCallback +{ +public: + NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0; + + NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0; + + virtual void BlobStoreCompleted(MutableBlobStorage* aBlobStorage, + Blob* aBlob, + nsresult aRv) = 0; +}; + +// This class is main-thread only. +class MutableBlobStorage final { public: - BlobSet() - : mData(nullptr) - , mDataLen(0) - , mDataBufferLen(0) - {} + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MutableBlobStorage); - ~BlobSet() + enum MutableBlobStorageType { - free(mData); - } + eOnlyInMemory, + eCouldBeInTemporaryFile, + }; - nsresult AppendVoidPtr(const void* aData, uint32_t aLength); + explicit MutableBlobStorage(MutableBlobStorageType aType); + + nsresult Append(const void* aData, uint32_t aLength); - nsresult AppendString(const nsAString& aString, bool nativeEOL, - JSContext* aCx); - - nsresult AppendBlobImpl(BlobImpl* aBlobImpl); + // This method can be called just once. + // The callback will be called when the Blob is ready. + // The return value is the total size of the blob, when created. + uint64_t GetBlobWhenReady(nsISupports* aParent, + const nsACString& aContentType, + MutableBlobStorageCallback* aCallback); - nsresult AppendBlobImpls(const nsTArray<RefPtr<BlobImpl>>& aBlobImpls); - - nsTArray<RefPtr<BlobImpl>>& GetBlobImpls() { Flush(); return mBlobImpls; } + void TemporaryFileCreated(PRFileDesc* aFD); - already_AddRefed<Blob> GetBlobInternal(nsISupports* aParent, - const nsACString& aContentType, - ErrorResult& aRv); + void CreateBlobAndRespond(already_AddRefed<nsISupports> aParent, + const nsACString& aContentType, + already_AddRefed<MutableBlobStorageCallback> aCallback); + + void ErrorPropagated(nsresult aRv); private: + ~MutableBlobStorage(); + bool ExpandBufferSize(uint64_t aSize); - void Flush(); + bool ShouldBeTemporaryStorage(uint64_t aSize) const; + + nsresult MaybeCreateTemporaryFile(); - nsTArray<RefPtr<BlobImpl>> mBlobImpls; + static nsresult DispatchToIOThread(Runnable* aRunnable); + + // All these variables are touched on the main thread only. + void* mData; uint64_t mDataLen; uint64_t mDataBufferLen; + + enum StorageState { + eKeepInMemory, + eInMemory, + eWaitingForTemporaryFile, + eInTemporaryFile, + eClosed + }; + + StorageState mStorageState; + + PRFileDesc* mFD; + + nsresult mErrorResult; }; } // namespace dom } // namespace mozilla -#endif // mozilla_dom_BlobSet_h +#endif // mozilla_dom_MutableBlobStorage_h
--- a/dom/base/domerr.msg +++ b/dom/base/domerr.msg @@ -161,8 +161,21 @@ DOM4_MSG_DEF(InvalidStateError, "A subsc DOM_MSG_DEF(NS_ERROR_DOM_JS_EXCEPTION, "A callback threw an exception") DOM_MSG_DEF(NS_ERROR_DOM_DOMEXCEPTION, "A DOMException was thrown") /* Media errors */ DOM4_MSG_DEF(AbortError, "The fetching process for the media resource was aborted by the user agent at the user's request.", NS_ERROR_DOM_MEDIA_ABORT_ERR) DOM4_MSG_DEF(NotAllowedError, "The play method is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.", NS_ERROR_DOM_MEDIA_NOT_ALLOWED_ERR) DOM4_MSG_DEF(NotSupportedError, "The media resource indicated by the src attribute or assigned media provider object was not suitable.", NS_ERROR_DOM_MEDIA_NOT_SUPPORTED_ERR) + +DOM4_MSG_DEF(SyntaxError, "The URI is malformed.", NS_ERROR_DOM_MALFORMED_URI) +DOM4_MSG_DEF(SyntaxError, "Invalid header name.", NS_ERROR_DOM_INVALID_HEADER_NAME) + +/* XMLHttpRequest errors. */ +DOM4_MSG_DEF(InvalidStateError, "XMLHttpRequest has an invalid context.", NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT) +DOM4_MSG_DEF(InvalidStateError, "XMLHttpRequest state must be OPENED.", NS_ERROR_DOM_INVALID_STATE_XHR_MUST_BE_OPENED) +DOM4_MSG_DEF(InvalidStateError, "XMLHttpRequest must not be sending.", NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_SENDING) +DOM4_MSG_DEF(InvalidStateError, "XMLHttpRequest state must not be LOADING or DONE.", NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_LOADING_OR_DONE) +DOM4_MSG_DEF(InvalidStateError, "responseXML is only available if responseType is '' or 'document'.", NS_ERROR_DOM_INVALID_STATE_XHR_HAS_WRONG_RESPONSETYPE_FOR_RESPONSEXML) +DOM4_MSG_DEF(InvalidStateError, "responseText is only available if responseType is '', 'document', or 'moz-chunked-text'.", NS_ERROR_DOM_INVALID_STATE_XHR_HAS_WRONG_RESPONSETYPE_FOR_RESPONSETEXT) +DOM4_MSG_DEF(InvalidStateError, "synchronous XMLHttpRequests do not support 'moz-chunked-text' or 'moz-chunked-arraybuffer' responseType.", NS_ERROR_DOM_INVALID_STATE_XHR_CHUNKED_RESPONSETYPES_UNSUPPORTED_FOR_SYNC) +DOM4_MSG_DEF(InvalidAccessError, "synchronous XMLHttpRequests do not support timeout and responseType.", NS_ERROR_DOM_INVALID_ACCESS_XHR_TIMEOUT_AND_RESPONSETYPE_UNSUPPORTED_FOR_SYNC)
--- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -181,16 +181,17 @@ EXPORTS.mozilla.dom += [ 'FileReader.h', 'FormData.h', 'FragmentOrElement.h', 'FromParser.h', 'ImageEncoder.h', 'ImportManager.h', 'Link.h', 'Location.h', + 'MutableBlobStorage.h', 'NameSpaceConstants.h', 'Navigator.h', 'NodeInfo.h', 'NodeInfoInlines.h', 'NodeIterator.h', 'ProcessGlobal.h', 'ResponsiveImageSelector.h', 'SameProcessMessageQueue.h', @@ -242,16 +243,17 @@ UNIFIED_SOURCES += [ 'FileReader.cpp', 'FormData.cpp', 'FragmentOrElement.cpp', 'ImageEncoder.cpp', 'ImportManager.cpp', 'Link.cpp', 'Location.cpp', 'MultipartBlobImpl.cpp', + 'MutableBlobStorage.cpp', 'Navigator.cpp', 'NodeInfo.cpp', 'NodeIterator.cpp', 'nsAtomListUtils.cpp', 'nsAttrAndChildArray.cpp', 'nsAttrValue.cpp', 'nsAttrValueOrString.cpp', 'nsCCUncollectableMarker.cpp',
--- a/dom/base/nsCCUncollectableMarker.cpp +++ b/dom/base/nsCCUncollectableMarker.cpp @@ -23,16 +23,17 @@ #include "nsIXULWindow.h" #include "nsIAppShellService.h" #include "nsAppShellCID.h" #include "nsContentUtils.h" #include "nsGlobalWindow.h" #include "nsJSEnvironment.h" #include "nsInProcessTabChildGlobal.h" #include "nsFrameLoader.h" +#include "mozilla/CycleCollectedJSContext.h" #include "mozilla/EventListenerManager.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/ProcessGlobal.h" #include "xpcpublic.h" #include "nsObserverService.h" #include "nsFocusManager.h" #include "nsIInterfaceRequestorUtils.h" @@ -308,16 +309,18 @@ MarkWindowList(nsISimpleEnumerator* aWin MarkDocShell(rootDocShell, aCleanupJS, aPrepareForCC); nsCOMPtr<nsITabChild> tabChild = rootDocShell ? rootDocShell->GetTabChild() : nullptr; if (tabChild) { nsCOMPtr<nsIContentFrameMessageManager> mm; tabChild->GetMessageManager(getter_AddRefs(mm)); if (mm) { + // MarkForCC ends up calling UnmarkGray on message listeners, which + // TraceBlackJS can't do yet. mm->MarkForCC(); } } } } } nsresult @@ -484,29 +487,61 @@ mozilla::dom::TraceBlackJS(JSTracer* aTr } } #endif if (!nsCCUncollectableMarker::sGeneration) { return; } + if (nsFrameMessageManager::GetChildProcessManager()) { + nsIContentProcessMessageManager* pg = ProcessGlobal::Get(); + if (pg) { + mozilla::TraceScriptHolder(pg, aTrc); + } + } + // Mark globals of active windows black. nsGlobalWindow::WindowByIdTable* windowsById = nsGlobalWindow::GetWindowsTable(); if (windowsById) { for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) { nsGlobalWindow* window = iter.Data(); if (window->GetDocShell() && window->IsOuterWindow()) { window->TraceGlobalJSObject(aTrc); EventListenerManager* elm = window->GetExistingListenerManager(); if (elm) { elm->TraceListeners(aTrc); } + if (window->IsRootOuterWindow()) { + // In child process trace all the TabChildGlobals. + // Since there is one root outer window per TabChildGlobal, we need + // to look for only those windows, not all. + nsIDocShell* ds = window->GetDocShell(); + if (ds) { + nsCOMPtr<nsITabChild> tabChild = ds->GetTabChild(); + if (tabChild) { + nsCOMPtr<nsIContentFrameMessageManager> mm; + tabChild->GetMessageManager(getter_AddRefs(mm)); + nsCOMPtr<EventTarget> et = do_QueryInterface(mm); + if (et) { + nsCOMPtr<nsISupports> tabChildAsSupports = + do_QueryInterface(tabChild); + mozilla::TraceScriptHolder(tabChildAsSupports, aTrc); + EventListenerManager* elm = et->GetExistingListenerManager(); + if (elm) { + elm->TraceListeners(aTrc); + } + // As of now there isn't an easy way to trace message listeners. + } + } + } + } + #ifdef MOZ_XUL nsIDocument* doc = window->GetExtantDoc(); if (doc && doc->IsXULDocument()) { XULDocument* xulDoc = static_cast<XULDocument*>(doc); xulDoc->TraceProtos(aTrc, aGCNumber); } #endif }
--- a/dom/base/nsDeprecatedOperationList.h +++ b/dom/base/nsDeprecatedOperationList.h @@ -28,16 +28,17 @@ DEPRECATED_OPERATION(PrefixedVisibilityA DEPRECATED_OPERATION(NodeIteratorDetach) DEPRECATED_OPERATION(LenientThis) DEPRECATED_OPERATION(GetPreventDefault) DEPRECATED_OPERATION(GetSetUserData) DEPRECATED_OPERATION(MozGetAsFile) DEPRECATED_OPERATION(UseOfCaptureEvents) DEPRECATED_OPERATION(UseOfReleaseEvents) DEPRECATED_OPERATION(UseOfDOM3LoadMethod) +DEPRECATED_OPERATION(ChromeUseOfDOM3LoadMethod) DEPRECATED_OPERATION(ShowModalDialog) DEPRECATED_OPERATION(Window_Content) DEPRECATED_OPERATION(SyncXMLHttpRequest) DEPRECATED_OPERATION(DataContainerEvent) DEPRECATED_OPERATION(Window_Controllers) DEPRECATED_OPERATION(ImportXULIntoContent) DEPRECATED_OPERATION(PannerNodeDoppler) DEPRECATED_OPERATION(NavigatorGetUserMedia)
--- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -247,17 +247,17 @@ #include "mozilla/dom/FontFaceSet.h" #include "mozilla/dom/BoxObject.h" #include "gfxPrefs.h" #include "nsISupportsPrimitives.h" #include "mozilla/StyleSetHandle.h" #include "mozilla/StyleSetHandleInlines.h" #include "mozilla/StyleSheet.h" #include "mozilla/StyleSheetInlines.h" - +#include "mozilla/dom/SVGSVGElement.h" #include "mozilla/DocLoadingTimelineMarker.h" #include "nsISpeculativeConnect.h" #include "mozilla/MediaManager.h" #ifdef MOZ_WEBRTC #include "IPeerConnection.h" #endif // MOZ_WEBRTC @@ -3033,16 +3033,26 @@ nsDocument::GetAnimations(nsTArray<RefPt if (!root) { return; } AnimationFilter filter; filter.mSubtree = true; root->GetAnimations(filter, aAnimations); } +SVGSVGElement* +nsIDocument::GetSVGRootElement() const +{ + Element* root = GetRootElement(); + if (!root || !root->IsSVGElement(nsGkAtoms::svg)) { + return nullptr; + } + return static_cast<SVGSVGElement*>(root); +} + /* Return true if the document is in the focused top-level window, and is an * ancestor of the focused DOMWindow. */ NS_IMETHODIMP nsDocument::HasFocus(bool* aResult) { ErrorResult rv; *aResult = nsIDocument::HasFocus(rv); return rv.StealNSResult(); @@ -5967,40 +5977,16 @@ nsDocument::GetElementsByTagNameNS(const } // transfer ref to aReturn list.forget(aReturn); return NS_OK; } NS_IMETHODIMP -nsDocument::GetAsync(bool *aAsync) -{ - NS_ERROR("nsDocument::GetAsync() should be overriden by subclass!"); - - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsDocument::SetAsync(bool aAsync) -{ - NS_ERROR("nsDocument::SetAsync() should be overriden by subclass!"); - - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsDocument::Load(const nsAString& aUrl, bool *aReturn) -{ - NS_ERROR("nsDocument::Load() should be overriden by subclass!"); - - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP nsDocument::GetStyleSheets(nsIDOMStyleSheetList** aStyleSheets) { NS_ADDREF(*aStyleSheets = StyleSheets()); return NS_OK; } StyleSheetList* nsDocument::StyleSheets()
--- a/dom/base/nsDocument.h +++ b/dom/base/nsDocument.h @@ -14,17 +14,17 @@ #include "nsIDocument.h" #include "nsCOMPtr.h" #include "nsAutoPtr.h" #include "nsCRT.h" #include "nsWeakReference.h" #include "nsWeakPtr.h" #include "nsTArray.h" -#include "nsIDOMXMLDocument.h" +#include "nsIDOMDocument.h" #include "nsIDOMDocumentXBL.h" #include "nsStubDocumentObserver.h" #include "nsIScriptGlobalObject.h" #include "nsIContent.h" #include "nsIPrincipal.h" #include "nsIParser.h" #include "nsBindingManager.h" #include "nsInterfaceHashtable.h" @@ -480,26 +480,18 @@ protected: nsIDocument* aDisplayDocument); nsClassHashtable<nsURIHashKey, ExternalResource> mMap; nsRefPtrHashtable<nsURIHashKey, PendingLoad> mPendingLoads; bool mHaveShutDown; }; // Base class for our document implementations. -// -// Note that this class *implements* nsIDOMXMLDocument, but it's not -// really an nsIDOMXMLDocument. The reason for implementing -// nsIDOMXMLDocument on this class is to avoid having to duplicate all -// its inherited methods on document classes that *are* -// nsIDOMXMLDocument's. nsDocument's QI should *not* claim to support -// nsIDOMXMLDocument unless someone writes a real implementation of -// the interface. class nsDocument : public nsIDocument, - public nsIDOMXMLDocument, // inherits nsIDOMDocument + public nsIDOMDocument, public nsIDOMDocumentXBL, public nsSupportsWeakReference, public nsIScriptObjectPrincipal, public nsIRadioGroupContainer, public nsIApplicationCacheContainer, public nsStubMutationObserver, public nsIObserver, public nsIDOMXPathEvaluator @@ -793,19 +785,16 @@ private: public: // nsIDOMNode NS_FORWARD_NSIDOMNODE_TO_NSINODE_OVERRIDABLE // nsIDOMDocument NS_DECL_NSIDOMDOCUMENT - // nsIDOMXMLDocument - NS_DECL_NSIDOMXMLDOCUMENT - // nsIDOMDocumentXBL NS_DECL_NSIDOMDOCUMENTXBL // nsIDOMEventTarget virtual nsresult PreHandleEvent( mozilla::EventChainPreVisitor& aVisitor) override; virtual mozilla::EventListenerManager* GetOrCreateListenerManager() override;
--- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -617,17 +617,17 @@ nsPIDOMWindow<T>::nsPIDOMWindow(nsPIDOMW mMayHaveMouseEnterLeaveEventListener(false), mMayHavePointerEnterLeaveEventListener(false), mInnerObjectsFreed(false), mIsModalContentWindow(false), mIsActive(false), mIsBackground(false), mMediaSuspend(Preferences::GetBool("media.block-autoplay-until-in-foreground", true) ? nsISuspendedTypes::SUSPENDED_BLOCK : nsISuspendedTypes::NONE_SUSPENDED), mAudioMuted(false), mAudioVolume(1.0), mAudioCaptured(false), - mDesktopModeViewport(false), mInnerWindow(nullptr), + mDesktopModeViewport(false), mIsRootOuterWindow(false), mInnerWindow(nullptr), mOuterWindow(aOuterWindow), // Make sure no actual window ends up with mWindowID == 0 mWindowID(NextWindowID()), mHasNotifiedGlobalCreated(false), mMarkedCCGeneration(0), mServiceWorkersTestingEnabled(false) {} template<class T> nsPIDOMWindow<T>::~nsPIDOMWindow() {} @@ -3062,16 +3062,17 @@ nsGlobalWindow::SetDocShell(nsIDocShell* // handler and receive all events that occur anywhere inside // our window. nsCOMPtr<nsPIDOMWindowOuter> parentWindow = GetParent(); if (parentWindow.get() != AsOuter()) { mChromeEventHandler = parentWindow->GetChromeEventHandler(); } else { mChromeEventHandler = NS_NewWindowRoot(AsOuter()); + mIsRootOuterWindow = true; } } bool docShellActive; mDocShell->GetIsActive(&docShellActive); mIsBackground = !docShellActive; }
--- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -143,16 +143,17 @@ class MediaQueryList; class GlobalObject; class NodeFilter; class NodeIterator; enum class OrientationType : uint32_t; class ProcessingInstruction; class Promise; class StyleSheetList; class SVGDocument; +class SVGSVGElement; class Touch; class TouchList; class TreeWalker; class UndoManager; class XPathEvaluator; class XPathExpression; class XPathNSResolver; class XPathResult; @@ -2323,16 +2324,18 @@ public: virtual already_AddRefed<mozilla::dom::UndoManager> GetUndoManager() = 0; virtual mozilla::dom::DocumentTimeline* Timeline() = 0; virtual void GetAnimations( nsTArray<RefPtr<mozilla::dom::Animation>>& aAnimations) = 0; + mozilla::dom::SVGSVGElement* GetSVGRootElement() const; + nsresult ScheduleFrameRequestCallback(mozilla::dom::FrameRequestCallback& aCallback, int32_t *aHandle); void CancelFrameRequestCallback(int32_t aHandle); typedef nsTArray<RefPtr<mozilla::dom::FrameRequestCallback>> FrameRequestCallbackList; /** * Put this document's frame request callbacks into the provided * list, and forget about them.
--- a/dom/base/nsPIDOMWindow.h +++ b/dom/base/nsPIDOMWindow.h @@ -113,16 +113,22 @@ public: */ virtual already_AddRefed<nsPIDOMWindowOuter> GetTop() = 0; // Outer only virtual already_AddRefed<nsPIDOMWindowOuter> GetParent() = 0; virtual nsPIDOMWindowOuter* GetScriptableTop() = 0; virtual nsPIDOMWindowOuter* GetScriptableParent() = 0; virtual already_AddRefed<nsPIWindowRoot> GetTopWindowRoot() = 0; + bool IsRootOuterWindow() + { + MOZ_ASSERT(IsOuterWindow()); + return mIsRootOuterWindow; + } + /** * Behavies identically to GetScriptableParent extept that it returns null * if GetScriptableParent would return this window. */ virtual nsPIDOMWindowOuter* GetScriptableParentOrNull() = 0; // Inner windows only. virtual nsresult RegisterIdleObserver(nsIIdleObserver* aIdleObserver) = 0; @@ -661,16 +667,18 @@ protected: bool mAudioMuted; float mAudioVolume; bool mAudioCaptured; // current desktop mode flag. bool mDesktopModeViewport; + bool mIsRootOuterWindow; + // And these are the references between inner and outer windows. nsPIDOMWindowInner* MOZ_NON_OWNING_REF mInnerWindow; nsCOMPtr<nsPIDOMWindowOuter> mOuterWindow; // the element within the document that is currently focused when this // window is active nsCOMPtr<nsIContent> mFocusedNode;
--- a/dom/base/test/test_bug435425.html +++ b/dom/base/test/test_bug435425.html @@ -212,17 +212,17 @@ var tests = [ { method: "GET", withUpload: none, testAbort: false, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: XHR, type: "progress", optional: false}, {target: XHR, type: "load", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: none, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, - {target: XHR, type: "progress", optional: false}, + {target: XHR, type: "progress", optional: true}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: none, testAbort: false, testRedirectError: true, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: XHR, type: "error", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: none, testAbort: false, testRedirectError: false, testNetworkError: true, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, @@ -231,17 +231,17 @@ var tests = { method: "GET", withUpload: small, testAbort: false, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: XHR, type: "progress", optional: false}, {target: XHR, type: "load", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: small, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, - {target: XHR, type: "progress", optional: false}, + {target: XHR, type: "progress", optional: true}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: small, testAbort: false, testRedirectError: true, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: XHR, type: "error", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: small, testAbort: false, testRedirectError: false, testNetworkError: true, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, @@ -250,17 +250,17 @@ var tests = { method: "GET", withUpload: mid, testAbort: false, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: XHR, type: "progress", optional: false}, {target: XHR, type: "load", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: mid, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, - {target: XHR, type: "progress", optional: false}, + {target: XHR, type: "progress", optional: true}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: mid, testAbort: false, testRedirectError: true, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: XHR, type: "error", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: mid, testAbort: false, testRedirectError: false, testNetworkError: true, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, @@ -269,17 +269,17 @@ var tests = { method: "GET", withUpload: large, testAbort: false, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: XHR, type: "progress", optional: false}, {target: XHR, type: "load", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: large, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, - {target: XHR, type: "progress", optional: false}, + {target: XHR, type: "progress", optional: true}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: large, testAbort: false, testRedirectError: true, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: XHR, type: "error", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "GET", withUpload: large, testAbort: false, testRedirectError: false, testNetworkError: true, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, @@ -288,17 +288,17 @@ var tests = { method: "POST", withUpload: none, testAbort: false, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: XHR, type: "progress", optional: false}, {target: XHR, type: "load", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "POST", withUpload: none, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, - {target: XHR, type: "progress", optional: false}, + {target: XHR, type: "progress", optional: true}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "POST", withUpload: none, testAbort: false, testRedirectError: true, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: XHR, type: "error", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "POST", withUpload: none, testAbort: false, testRedirectError: false, testNetworkError: true, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, @@ -312,20 +312,20 @@ var tests = {target: UPLOAD, type: "load", optional: false}, {target: UPLOAD, type: "loadend", optional: false}, {target: XHR, type: "progress", optional: false}, {target: XHR, type: "load", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "POST", withUpload: small, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: UPLOAD, type: "loadstart", optional: false}, - {target: UPLOAD, type: "progress", optional: false}, + {target: UPLOAD, type: "progress", optional: true}, {target: UPLOAD, type: "abort", optional: false}, {target: UPLOAD, type: "loadend", optional: false}, - {target: XHR, type: "progress", optional: false}, + {target: XHR, type: "progress", optional: true}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "POST", withUpload: small, testAbort: false, testRedirectError: true, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: UPLOAD, type: "loadstart", optional: false}, {target: UPLOAD, type: "progress", optional: true}, {target: UPLOAD, type: "error", optional: false}, {target: UPLOAD, type: "loadend", optional: false}, @@ -346,20 +346,20 @@ var tests = {target: UPLOAD, type: "load", optional: false}, {target: UPLOAD, type: "loadend", optional: false}, {target: XHR, type: "progress", optional: false}, {target: XHR, type: "load", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "POST", withUpload: mid, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: UPLOAD, type: "loadstart", optional: false}, - {target: UPLOAD, type: "progress", optional: false}, + {target: UPLOAD, type: "progress", optional: true}, {target: UPLOAD, type: "abort", optional: false}, {target: UPLOAD, type: "loadend", optional: false}, - {target: XHR, type: "progress", optional: false}, + {target: XHR, type: "progress", optional: true}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "POST", withUpload: mid, testAbort: false, testRedirectError: true, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: UPLOAD, type: "loadstart", optional: false}, {target: UPLOAD, type: "progress", optional: true}, {target: UPLOAD, type: "error", optional: false}, {target: UPLOAD, type: "loadend", optional: false}, @@ -380,20 +380,20 @@ var tests = {target: UPLOAD, type: "load", optional: false}, {target: UPLOAD, type: "loadend", optional: false}, {target: XHR, type: "progress", optional: false}, {target: XHR, type: "load", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "POST", withUpload: large, testAbort: true, testRedirectError: false, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: UPLOAD, type: "loadstart", optional: false}, - {target: UPLOAD, type: "progress", optional: false}, + {target: UPLOAD, type: "progress", optional: true}, {target: UPLOAD, type: "abort", optional: false}, {target: UPLOAD, type: "loadend", optional: false}, - {target: XHR, type: "progress", optional: false}, + {target: XHR, type: "progress", optional: true}, {target: XHR, type: "abort", optional: false}, {target: XHR, type: "loadend", optional: false}]}, { method: "POST", withUpload: large, testAbort: false, testRedirectError: true, testNetworkError: false, expectedEvents: [{target: XHR, type: "loadstart", optional: false}, {target: UPLOAD, type: "loadstart", optional: false}, {target: UPLOAD, type: "progress", optional: true}, {target: UPLOAD, type: "error", optional: false}, {target: UPLOAD, type: "loadend", optional: false},
--- a/dom/base/test/test_bug450160.html +++ b/dom/base/test/test_bug450160.html @@ -29,18 +29,16 @@ function testHTMLDocuments(ids, isXHTML) ok(docType1, "No doctype?"); ok(docType1.ownerDocument, "docType should have ownerDocument!"); var doc1 = document.implementation.createDocument(null, null, docType1); is(docType1.ownerDocument, doc1, "docType should have ownerDocument!"); ok(!doc1.documentElement, "Document shouldn't have document element!"); is(doc1.body, null, "Shouldn't have .body!"); ok(doc1 instanceof HTMLDocument, "Document should be an HTML document!"); - ok(!(doc1 instanceof SVGDocument), - "Document shouldn't be an SVG document!"); var docType2 = document.implementation.createDocumentType(isXHTML ? "html" : "HTML", ids[i], null); var doc2 = document.implementation.createDocument( "http://www.w3.org/1999/xhtml", "html", docType2); is(docType2.ownerDocument, doc2, "docType should have ownerDocument!"); @@ -65,62 +63,57 @@ function testSVGDocument() { null); ok(docType1, "No doctype?"); ok(docType1.ownerDocument, "docType should have ownerDocument!"); var doc1 = document.implementation.createDocument(null, null, docType1); is(docType1.ownerDocument, doc1, "docType should have ownerDocument!"); ok(!doc1.documentElement, "Document shouldn't have document element!"); ok(!(doc1 instanceof HTMLDocument), "Document shouldn't be an HTML document!"); - ok(doc1 instanceof SVGDocument, - "Document should be an SVG document!"); + ok(doc1 instanceof XMLDocument, + "Document should be an XML document!"); - // SVG documents have .rootElement. - ok("rootElement" in doc1, "No .rootElement in document"); + // SVG documents have .documentElement. + ok("documentElement" in doc1, "No .documentElement in document"); var docType2 = document.implementation.createDocumentType("svg", "-//W3C//DTD SVG 1.1//EN", null); var doc2 = document.implementation.createDocument("http://www.w3.org/2000/svg", "svg", docType2); ok(doc2.documentElement, "Document should have document element!"); - ok(doc2.rootElement, "Should have .rootElement in document"); - is(doc2.rootElement.localName, "svg", "Wrong .rootElement!"); + is(doc2.documentElement.localName, "svg", "Wrong .documentElement!"); } function testFooBarDocument() { var docType1 = document.implementation.createDocumentType("FooBar", "FooBar", null); ok(docType1, "No doctype?"); ok(docType1.ownerDocument, "docType should have ownerDocument!"); var doc1 = document.implementation.createDocument(null, null, docType1); is(docType1.ownerDocument, doc1, "docType should have ownerDocument!"); ok(!doc1.documentElement, "Document shouldn't have document element!"); ok(!(doc1 instanceof HTMLDocument), "Document shouldn't be an HTML document!"); - ok(!(doc1 instanceof SVGDocument), - "Document shouldn't be an SVG document!"); var docType2 = document.implementation.createDocumentType("FooBar", "FooBar", null); var doc2 = document.implementation.createDocument("FooBarNS", "FooBar", docType2); ok(doc2.documentElement, "Document should have document element!"); is(doc2.documentElement.namespaceURI, "FooBarNS", "Wrong namespaceURI!"); is(doc2.documentElement.localName, "FooBar", "Wrong localName!"); } function testNullDocTypeDocument() { var doc1 = document.implementation.createDocument(null, null, null); ok(!doc1.documentElement, "Document shouldn't have document element!"); ok(!(doc1 instanceof HTMLDocument), "Document shouldn't be an HTML document!"); - ok(!(doc1 instanceof SVGDocument), - "Document shouldn't be an SVG document!"); var doc2 = document.implementation.createDocument("FooBarNS", "FooBar", null); ok(doc2.documentElement, "Document should have document element!"); is(doc2.documentElement.namespaceURI, "FooBarNS", "Wrong namespaceURI!"); is(doc2.documentElement.localName, "FooBar", "Wrong localName!"); }
--- a/dom/base/test/test_bug693875.html +++ b/dom/base/test/test_bug693875.html @@ -18,22 +18,17 @@ https://bugzilla.mozilla.org/show_bug.cg <script type="application/javascript"> /** Test for Bug 693875 **/ var dp = new DOMParser(); var d = dp.parseFromString("<?xml version='1.0'?><svg xmlns='http://www.w3.org/2000/svg'></svg>", "image/svg+xml"); -ok(d instanceof SVGDocument, "Should have created an SVG document."); -ok("rootElement" in d, "Should have created an SVG document, which has .rootElement."); +ok(d instanceof XMLDocument, "Should have created an XML document."); +ok("documentElement" in d, "Should have created an XML document, which has .documentElement."); is(d.documentElement.localName, "svg", "Root element should be svg."); is(d.documentElement.namespaceURI, "http://www.w3.org/2000/svg", "Root element should be in svg namespace."); - -dp = new DOMParser(); -d = dp.parseFromString("<?xml version='1.0'?><svg xmlns='http://www.w3.org/2000/svg'></svg>", - "text/xml"); -ok(!(d instanceof SVGDocument), "Should not have created an SVG document!"); </script> </pre> </body> </html>
--- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -1112,17 +1112,17 @@ QueryInterface(JSContext* cx, unsigned a return false; // Get the object. It might be a security wrapper, in which case we do a checked // unwrap. JS::Rooted<JSObject*> origObj(cx, &thisv.toObject()); JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(origObj, /* stopAtWindowProxy = */ false)); if (!obj) { - JS_ReportError(cx, "Permission denied to access object"); + JS_ReportErrorASCII(cx, "Permission denied to access object"); return false; } // Switch this to UnwrapDOMObjectToISupports once our global objects are // using new bindings. nsCOMPtr<nsISupports> native; UnwrapArg<nsISupports>(obj, getter_AddRefs(native)); if (!native) {
--- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -1850,18 +1850,16 @@ addExternalIface('MozTreeView', nativeTy headerFile='nsITreeView.h', notflattened=True) addExternalIface('MozWakeLockListener', headerFile='nsIDOMWakeLockListener.h') addExternalIface('MozXULTemplateBuilder', nativeType='nsIXULTemplateBuilder') addExternalIface('nsIBrowserDOMWindow', nativeType='nsIBrowserDOMWindow', notflattened=True) addExternalIface('nsIControllers', nativeType='nsIControllers') addExternalIface('nsIDOMCrypto', nativeType='nsIDOMCrypto', headerFile='Crypto.h') -addExternalIface('nsIInputStreamCallback', nativeType='nsIInputStreamCallback', - headerFile='nsIAsyncInputStream.h') addExternalIface('nsIFile', nativeType='nsIFile', notflattened=True) addExternalIface('nsILoadGroup', nativeType='nsILoadGroup', headerFile='nsILoadGroup.h', notflattened=True) addExternalIface('nsIMessageBroadcaster', nativeType='nsIMessageBroadcaster', headerFile='nsIMessageManager.h', notflattened=True) addExternalIface('nsISelectionListener', nativeType='nsISelectionListener') addExternalIface('nsIStreamListener', nativeType='nsIStreamListener', notflattened=True) addExternalIface('nsITransportProvider', nativeType='nsITransportProvider')
--- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -6831,26 +6831,30 @@ def needScopeObject(returnType, argument any(typeNeedsScopeObject(a.type) for a in arguments))) class CGCallGenerator(CGThing): """ A class to generate an actual call to a C++ object. Assumes that the C++ object is stored in a variable whose name is given by the |object| argument. + needsSubjectPrincipal is a boolean indicating whether the call should + receive the subject nsIPrincipal as argument. + isFallible is a boolean indicating whether the call should be fallible. resultVar: If the returnType is not void, then the result of the call is stored in a C++ variable named by resultVar. The caller is responsible for declaring the result variable. If the caller doesn't care about the result value, resultVar can be omitted. """ - def __init__(self, isFallible, arguments, argsPre, returnType, - extendedAttributes, descriptorProvider, nativeMethodName, - static, object="self", argsPost=[], resultVar=None): + def __init__(self, isFallible, needsSubjectPrincipal, arguments, argsPre, + returnType, extendedAttributes, descriptorProvider, + nativeMethodName, static, object="self", argsPost=[], + resultVar=None): CGThing.__init__(self) result, resultOutParam, resultRooter, resultArgs, resultConversion = \ getRetvalDeclarationForType(returnType, descriptorProvider) args = CGList([CGGeneric(arg) for arg in argsPre], ", ") for a, name in arguments: arg = CGGeneric(name) @@ -6897,16 +6901,19 @@ class CGCallGenerator(CGThing): needResultDecl = True resultVar = "result" if resultOutParam == "ref": args.append(CGGeneric(resultVar)) else: assert resultOutParam == "ptr" args.append(CGGeneric("&" + resultVar)) + if needsSubjectPrincipal: + args.append(CGGeneric("subjectPrincipal")) + if isFallible: args.append(CGGeneric("rv")) args.extend(CGGeneric(arg) for arg in argsPost) # Build up our actual call self.cgRoot = CGList([]) call = CGGeneric(nativeMethodName) @@ -6935,16 +6942,28 @@ class CGCallGenerator(CGThing): call = CGWrapper(call, pre=resultVar + " = ") elif result is not None: assert resultOutParam is None call = CGWrapper(call, pre=resultVar + " = ") call = CGWrapper(call, post=";\n") self.cgRoot.append(call) + if needsSubjectPrincipal: + self.cgRoot.prepend(CGGeneric(dedent( + """ + Maybe<nsIPrincipal*> subjectPrincipal; + if (NS_IsMainThread()) { + JSCompartment* compartment = js::GetContextCompartment(cx); + MOZ_ASSERT(compartment); + JSPrincipals* principals = JS_GetCompartmentPrincipals(compartment); + subjectPrincipal.emplace(nsJSPrincipals::get(principals)); + } + """))) + if isFallible: self.cgRoot.prepend(CGGeneric("binding_detail::FastErrorResult rv;\n")) self.cgRoot.append(CGGeneric(dedent( """ if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx))) { return false; } """))) @@ -7401,16 +7420,17 @@ class CGPerSignatureCall(CGThing): idlNode.identifier.name)) else: cgThings.append(CGIterableMethodGenerator(descriptor, idlNode.maplikeOrSetlikeOrIterable, idlNode.identifier.name)) else: cgThings.append(CGCallGenerator( self.isFallible(), + idlNode.getExtendedAttribute('NeedsSubjectPrincipal'), self.getArguments(), argsPre, returnType, self.extendedAttributes, descriptor, nativeMethodName, static, argsPost=argsPost, resultVar=resultVar)) if useCounterName: # Generate a telemetry call for when [UseCounter] is used. code = "SetDocumentAndPageUseCounter(cx, obj, eUseCounter_%s);\n" % useCounterName @@ -13807,16 +13827,19 @@ class CGNativeMember(ClassMethod): args.append(Argument("%s&" % CGUnionStruct.unionTypeDecl(returnType, True), "aRetVal")) elif returnType.isAny(): args.append(Argument("JS::MutableHandle<JS::Value>", "aRetVal")) elif returnType.isObject() or returnType.isSpiderMonkeyInterface(): args.append(Argument("JS::MutableHandle<JSObject*>", "aRetVal")) + # And the nsIPrincipal + if self.member.getExtendedAttribute('NeedsSubjectPrincipal'): + args.append(Argument("const Maybe<nsIPrincipal*>&", "aPrincipal")) # And the ErrorResult if 'infallible' not in self.extendedAttrs: # Use aRv so it won't conflict with local vars named "rv" args.append(Argument("ErrorResult&", "aRv")) # The legacycaller thisval if self.member.isMethod() and self.member.isLegacycaller(): # If it has an identifier, we can't deal with it yet assert self.member.isIdentifierLess() @@ -15752,17 +15775,17 @@ class CGMaplikeOrSetlikeMethodGenerator( something that would return an iterator is called via Xray, fail early. """ # TODO: Bug 1173651 - Remove check once bug 1023984 is fixed. code = CGGeneric(dedent( """ // TODO (Bug 1173651): Xrays currently cannot wrap iterators. Change // after bug 1023984 is fixed. if (xpc::WrapperFactory::IsXrayWrapper(obj)) { - JS_ReportError(cx, "Xray wrapping of iterators not supported."); + JS_ReportErrorASCII(cx, "Xray wrapping of iterators not supported."); return false; } JS::Rooted<JSObject*> result(cx); JS::Rooted<JS::Value> v(cx); """)) arguments = "&v" setResult = CGGeneric(dedent( """
--- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -4199,16 +4199,17 @@ class IDLAttribute(IDLInterfaceMember): identifier == "Throws" or identifier == "GetterThrows" or identifier == "ChromeOnly" or identifier == "Func" or identifier == "SecureContext" or identifier == "Frozen" or identifier == "NewObject" or identifier == "UnsafeInPrerendering" or + identifier == "NeedsSubjectPrincipal" or identifier == "BinaryName"): # Known attributes that we don't need to do anything with here pass else: raise WebIDLError("Unknown extended attribute %s on attribute" % identifier, [attr.location]) IDLInterfaceMember.handleExtendedAttribute(self, attr) @@ -4915,16 +4916,17 @@ class IDLMethod(IDLInterfaceMember, IDLS identifier == "NewObject" or identifier == "ChromeOnly" or identifier == "UnsafeInPrerendering" or identifier == "Pref" or identifier == "Deprecated" or identifier == "Func" or identifier == "SecureContext" or identifier == "BinaryName" or + identifier == "NeedsSubjectPrincipal" or identifier == "StaticClassOverride"): # Known attributes that we don't need to do anything with here pass else: raise WebIDLError("Unknown extended attribute %s on method" % identifier, [attr.location]) IDLInterfaceMember.handleExtendedAttribute(self, attr)
--- a/dom/bindings/test/TestExampleGen.webidl +++ b/dom/bindings/test/TestExampleGen.webidl @@ -768,16 +768,18 @@ interface TestExampleInterface { void passRenamedInterface(TestRenamedInterface arg); [PutForwards=writableByte] readonly attribute TestExampleInterface putForwardsAttr; [PutForwards=writableByte, LenientThis] readonly attribute TestExampleInterface putForwardsAttr2; [PutForwards=writableByte, ChromeOnly] readonly attribute TestExampleInterface putForwardsAttr3; [Throws] void throwingMethod(); [Throws] attribute boolean throwingAttr; [GetterThrows] attribute boolean throwingGetterAttr; [SetterThrows] attribute boolean throwingSetterAttr; + [NeedsSubjectPrincipal] void needsSubjectPrincipalMethod(); + [NeedsSubjectPrincipal] attribute boolean needsSubjectPrincipalAttr; legacycaller short(unsigned long arg1, TestInterface arg2); void passArgsWithDefaults(optional long arg1, optional TestInterface? arg2 = null, optional Dict arg3, optional double arg4 = 5.0, optional float arg5); attribute any jsonifierShouldSkipThis; attribute TestParentInterface jsonifierShouldSkipThis2; attribute TestCallbackInterface jsonifierShouldSkipThis3;
--- a/dom/canvas/TexUnpackBlob.cpp +++ b/dom/canvas/TexUnpackBlob.cpp @@ -390,25 +390,26 @@ TexUnpackBytes::TexOrSubImage(bool isSub } ////// MOZ_ASSERT(webgl->mBoundPixelUnpackBuffer); if (!isSubImage) { // Alloc first to catch OOMs. - gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0); + AssertUintParamCorrect(gl, LOCAL_GL_PIXEL_UNPACK_BUFFER, 0); *out_error = DoTexOrSubImage(false, gl, target, level, dui, xOffset, yOffset, zOffset, mWidth, mHeight, mDepth, nullptr); - gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, - webgl->mBoundPixelUnpackBuffer->mGLName); if (*out_error) return false; } + const ScopedLazyBind bindPBO(gl, LOCAL_GL_PIXEL_UNPACK_BUFFER, + webgl->mBoundPixelUnpackBuffer); + ////// // Make our sometimes-implicit values explicit. Also this keeps them constant when we // ask for height=mHeight-1 and such. gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, mRowLength); gl->fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT, mImageHeight); if (mDepth > 1) {
--- a/dom/canvas/WebGL2ContextBuffers.cpp +++ b/dom/canvas/WebGL2ContextBuffers.cpp @@ -80,16 +80,18 @@ WebGL2Context::CopyBufferSubData(GLenum (readType == WebGLBuffer::Kind::OtherData) ? "other" : "element", (writeType == WebGLBuffer::Kind::OtherData) ? "other" : "element"); return; } gl->MakeCurrent(); + const ScopedLazyBind readBind(gl, readTarget, readBuffer); + const ScopedLazyBind writeBind(gl, writeTarget, writeBuffer); gl->fCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size); } void WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset, const dom::ArrayBufferView& data) { const char funcName[] = "getBufferSubData"; @@ -138,16 +140,17 @@ WebGL2Context::GetBufferSubData(GLenum t ErrorInvalidOperation("%s: Currently bound transform feedback is active.", funcName); return; } //// gl->MakeCurrent(); + const ScopedLazyBind readBind(gl, target, buffer); const auto ptr = gl->fMapBufferRange(target, offset, data.LengthAllowShared(), LOCAL_GL_MAP_READ_BIT); // Warning: Possibly shared memory. See bug 1225033. memcpy(data.DataAllowShared(), ptr, data.LengthAllowShared()); gl->fUnmapBuffer(target); }
--- a/dom/canvas/WebGLBuffer.cpp +++ b/dom/canvas/WebGLBuffer.cpp @@ -11,16 +11,17 @@ #include "WebGLElementArrayCache.h" namespace mozilla { WebGLBuffer::WebGLBuffer(WebGLContext* webgl, GLuint buf) : WebGLContextBoundObject(webgl) , mGLName(buf) , mContent(Kind::Undefined) + , mUsage(LOCAL_GL_STATIC_DRAW) , mByteLength(0) , mNumActiveTFOs(0) , mBoundForTF(false) { mContext->mBuffers.insertBack(this); } WebGLBuffer::~WebGLBuffer() @@ -109,16 +110,17 @@ WebGLBuffer::BufferData(GLenum target, s mContext->ErrorInvalidOperation("%s: Buffer is bound to an active transform" " feedback object.", funcName); return; } const auto& gl = mContext->gl; gl->MakeCurrent(); + const ScopedLazyBind lazyBind(gl, target, this); mContext->InvalidateBufferFetching(); #ifdef XP_MACOSX // bug 790879 if (gl->WorkAroundDriverBugs() && size > INT32_MAX) { mContext->ErrorOutOfMemory("%s: Allocation size too large.", funcName); @@ -136,16 +138,17 @@ WebGLBuffer::BufferData(GLenum target, s MOZ_ASSERT(error == LOCAL_GL_OUT_OF_MEMORY); mContext->ErrorOutOfMemory("%s: Error from driver: 0x%04x", funcName, error); return; } } else { gl->fBufferData(target, size, data, usage); } + mUsage = usage; mByteLength = size; // Warning: Possibly shared memory. See bug 1225033. if (!ElementArrayCacheBufferData(data, size)) { mByteLength = 0; mContext->ErrorOutOfMemory("%s: Failed update index buffer cache.", funcName); } }
--- a/dom/canvas/WebGLBuffer.h +++ b/dom/canvas/WebGLBuffer.h @@ -40,16 +40,17 @@ public: void SetContentAfterBind(GLenum target); Kind Content() const { return mContent; } void Delete(); size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + GLenum Usage() const { return mUsage; } size_t ByteLength() const { return mByteLength; } bool ElementArrayCacheBufferData(const void* ptr, size_t bufferSizeInBytes); void ElementArrayCacheBufferSubData(size_t pos, const void* ptr, size_t updateSizeInBytes); bool Validate(GLenum type, uint32_t max_allowed, size_t first, size_t count) const; @@ -69,16 +70,17 @@ public: NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLBuffer) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLBuffer) protected: ~WebGLBuffer(); Kind mContent; + GLenum mUsage; size_t mByteLength; UniquePtr<WebGLElementArrayCache> mCache; size_t mNumActiveTFOs; bool mBoundForTF; }; } // namespace mozilla
--- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -2154,16 +2154,49 @@ ScopedFBRebinder::UnwrapImpl() mGL->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER, fnName(mWebGL->mBoundDrawFramebuffer)); mGL->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, fnName(mWebGL->mBoundReadFramebuffer)); } else { MOZ_ASSERT(mWebGL->mBoundDrawFramebuffer == mWebGL->mBoundReadFramebuffer); mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fnName(mWebGL->mBoundDrawFramebuffer)); } } +//////////////////// + +static GLenum +TargetIfLazy(GLenum target) +{ + switch (target) { + case LOCAL_GL_PIXEL_PACK_BUFFER: + case LOCAL_GL_PIXEL_UNPACK_BUFFER: + return target; + + default: + return 0; + } +} + +ScopedLazyBind::ScopedLazyBind(gl::GLContext* gl, GLenum target, const WebGLBuffer* buf) + : ScopedGLWrapper<ScopedLazyBind>(gl) + , mTarget(buf ? TargetIfLazy(target) : 0) + , mBuf(buf) +{ + if (mTarget) { + mGL->fBindBuffer(mTarget, mBuf->mGLName); + } +} + +void +ScopedLazyBind::UnwrapImpl() +{ + if (mTarget) { + mGL->fBindBuffer(mTarget, 0); + } +} + //////////////////////////////////////// void Intersect(uint32_t srcSize, int32_t dstStartInSrc, uint32_t dstSize, uint32_t* const out_intStartInSrc, uint32_t* const out_intStartInDst, uint32_t* const out_intSize) { // Only >0 if dstStartInSrc is >0:
--- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -1829,16 +1829,31 @@ public: : ScopedGLWrapper<ScopedFBRebinder>(webgl->gl) , mWebGL(webgl) { } private: void UnwrapImpl(); }; +class ScopedLazyBind final + : public gl::ScopedGLWrapper<ScopedLazyBind> +{ + friend struct gl::ScopedGLWrapper<ScopedLazyBind>; + + const GLenum mTarget; + const WebGLBuffer* const mBuf; + +public: + ScopedLazyBind(gl::GLContext* gl, GLenum target, const WebGLBuffer* buf); + +private: + void UnwrapImpl(); +}; + void ComputeLengthAndData(const dom::ArrayBufferViewOrSharedArrayBufferView& view, void** const out_data, size_t* const out_length, js::Scalar::Type* const out_type); void Intersect(uint32_t srcSize, int32_t dstStartInSrc, uint32_t dstSize, uint32_t* const out_intStartInSrc, uint32_t* const out_intStartInDst,
--- a/dom/canvas/WebGLContextBuffers.cpp +++ b/dom/canvas/WebGLContextBuffers.cpp @@ -132,16 +132,23 @@ WebGLContext::BindBuffer(GLenum target, gl->MakeCurrent(); gl->fBindBuffer(target, buffer ? buffer->mGLName : 0); *slot = buffer; if (buffer) { buffer->SetContentAfterBind(target); } + + switch (target) { + case LOCAL_GL_PIXEL_PACK_BUFFER: + case LOCAL_GL_PIXEL_UNPACK_BUFFER: + gl->fBindBuffer(target, 0); + break; + } } //////////////////////////////////////// bool WebGLContext::ValidateIndexedBufferBinding(const char* funcName, GLenum target, GLuint index, WebGLRefPtr<WebGLBuffer>** const out_genericBinding, @@ -424,16 +431,18 @@ WebGLContext::BufferSubDataT(GLenum targ ErrorInvalidValue("bufferSubData: Not enough data. Operation requires" " %d bytes, but buffer only has %d bytes.", checked_neededByteLength.value(), buffer->ByteLength()); return; } MakeContextCurrent(); + const ScopedLazyBind lazyBind(gl, target, buffer); + // Warning: Possibly shared memory. See bug 1225033. gl->fBufferSubData(target, byteOffset, data.LengthAllowShared(), data.DataAllowShared()); // Warning: Possibly shared memory. See bug 1225033. buffer->ElementArrayCacheBufferSubData(byteOffset, data.DataAllowShared(), data.LengthAllowShared()); }
--- a/dom/canvas/WebGLContextGL.cpp +++ b/dom/canvas/WebGLContextGL.cpp @@ -625,38 +625,27 @@ WebGLContext::GetBufferParameter(GLenum { if (IsContextLost()) return JS::NullValue(); const auto& buffer = ValidateBufferSelection("getBufferParameter", target); if (!buffer) return JS::NullValue(); - MakeContextCurrent(); - switch (pname) { - case LOCAL_GL_BUFFER_SIZE: - case LOCAL_GL_BUFFER_USAGE: - { - GLint i = 0; - gl->fGetBufferParameteriv(target, pname, &i); - if (pname == LOCAL_GL_BUFFER_SIZE) { - return JS::Int32Value(i); - } - - MOZ_ASSERT(pname == LOCAL_GL_BUFFER_USAGE); - return JS::NumberValue(uint32_t(i)); - } - break; - - default: - ErrorInvalidEnumInfo("getBufferParameter: parameter", pname); + case LOCAL_GL_BUFFER_SIZE: + return JS::NumberValue(buffer->ByteLength()); + + case LOCAL_GL_BUFFER_USAGE: + return JS::NumberValue(buffer->Usage()); + + default: + ErrorInvalidEnumInfo("getBufferParameter: parameter", pname); + return JS::NullValue(); } - - return JS::NullValue(); } JS::Value WebGLContext::GetFramebufferAttachmentParameter(JSContext* cx, GLenum target, GLenum attachment, GLenum pname, ErrorResult& rv) @@ -1523,16 +1512,19 @@ WebGL2Context::ReadPixels(GLint x, GLint const auto bytesAvailable = mBoundPixelPackBuffer->ByteLength(); const auto checkedBytesAfterOffset = CheckedUint32(bytesAvailable) - offset; uint32_t bytesAfterOffset = 0; if (checkedBytesAfterOffset.isValid()) { bytesAfterOffset = checkedBytesAfterOffset.value(); } + gl->MakeCurrent(); + const ScopedLazyBind lazyBind(gl, LOCAL_GL_PIXEL_PACK_BUFFER, mBoundPixelPackBuffer); + ReadPixelsImpl(x, y, width, height, format, type, (void*)offset, bytesAfterOffset); } static bool ValidateReadPixelsFormatAndType(const webgl::FormatInfo* srcFormat, const webgl::PackingInfo& pi, gl::GLContext* gl, WebGLContext* webgl) {
--- a/dom/canvas/WebGLTransformFeedback.h +++ b/dom/canvas/WebGLTransformFeedback.h @@ -28,19 +28,19 @@ public: private: // GLES 3.0.4 p267, Table 6.24 "Transform Feedback State" WebGLRefPtr<WebGLBuffer> mGenericBufferBinding; std::vector<IndexedBufferBinding> mIndexedBindings; bool mIsPaused; bool mIsActive; // Not in state tables: WebGLRefPtr<WebGLProgram> mActive_Program; - GLenum mActive_PrimMode; - size_t mActive_VertPosition; - size_t mActive_VertCapacity; + MOZ_INIT_OUTSIDE_CTOR GLenum mActive_PrimMode; + MOZ_INIT_OUTSIDE_CTOR size_t mActive_VertPosition; + MOZ_INIT_OUTSIDE_CTOR size_t mActive_VertCapacity; public: WebGLTransformFeedback(WebGLContext* webgl, GLuint tf); private: ~WebGLTransformFeedback(); public: NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTransformFeedback)
--- a/dom/events/DataTransfer.cpp +++ b/dom/events/DataTransfer.cpp @@ -444,41 +444,45 @@ DataTransfer::SetData(const nsAString& a RefPtr<nsVariantCC> variant = new nsVariantCC(); variant->SetAsAString(aData); aRv = SetDataAtInternal(aFormat, variant, 0, nsContentUtils::SubjectPrincipal()); } void -DataTransfer::ClearData(const Optional<nsAString>& aFormat, ErrorResult& aRv) +DataTransfer::ClearData(const Optional<nsAString>& aFormat, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aRv) { + MOZ_ASSERT(aSubjectPrincipal.isSome()); + if (mReadOnly) { aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); return; } if (MozItemCount() == 0) { return; } if (aFormat.WasPassed()) { - MozClearDataAtHelper(aFormat.Value(), 0, aRv); + MozClearDataAtHelper(aFormat.Value(), 0, aSubjectPrincipal, aRv); } else { - MozClearDataAtHelper(EmptyString(), 0, aRv); + MozClearDataAtHelper(EmptyString(), 0, aSubjectPrincipal, aRv); } } NS_IMETHODIMP DataTransfer::ClearData(const nsAString& aFormat) { Optional<nsAString> format; format = &aFormat; ErrorResult rv; - ClearData(format, rv); + ClearData(format, Some(nsContentUtils::SubjectPrincipal()), rv); return rv.StealNSResult(); } NS_IMETHODIMP DataTransfer::GetMozItemCount(uint32_t* aCount) { *aCount = MozItemCount(); return NS_OK; @@ -738,18 +742,21 @@ DataTransfer::MozSetDataAt(JSContext* aC if (!aRv.Failed()) { aRv = SetDataAtInternal(aFormat, data, aIndex, nsContentUtils::SubjectPrincipal()); } } void DataTransfer::MozClearDataAt(const nsAString& aFormat, uint32_t aIndex, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, ErrorResult& aRv) { + MOZ_ASSERT(aSubjectPrincipal.isSome()); + if (mReadOnly) { aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); return; } if (aIndex >= MozItemCount()) { aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); return; @@ -758,51 +765,53 @@ DataTransfer::MozClearDataAt(const nsASt // Only the first item is valid for clipboard events if (aIndex > 0 && (mEventMessage == eCut || mEventMessage == eCopy || mEventMessage == ePaste)) { aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); return; } - MozClearDataAtHelper(aFormat, aIndex, aRv); + MozClearDataAtHelper(aFormat, aIndex, aSubjectPrincipal, aRv); // If we just cleared the 0-th index, and there are still more than 1 indexes // remaining, MozClearDataAt should cause the 1st index to become the 0th // index. This should _only_ happen when the MozClearDataAt function is // explicitly called by script, as this behavior is inconsistent with spec. // (however, so is the MozClearDataAt API) if (aIndex == 0 && mItems->MozItemCount() > 1 && mItems->MozItemsAt(0)->Length() == 0) { mItems->PopIndexZero(); } } void DataTransfer::MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, ErrorResult& aRv) { MOZ_ASSERT(!mReadOnly); MOZ_ASSERT(aIndex < MozItemCount()); MOZ_ASSERT(aIndex == 0 || (mEventMessage != eCut && mEventMessage != eCopy && mEventMessage != ePaste)); + MOZ_ASSERT(aSubjectPrincipal.isSome()); nsAutoString format; GetRealFormat(aFormat, format); - mItems->MozRemoveByTypeAt(format, aIndex, aRv); + mItems->MozRemoveByTypeAt(format, aIndex, aSubjectPrincipal, aRv); } NS_IMETHODIMP DataTransfer::MozClearDataAt(const nsAString& aFormat, uint32_t aIndex) { ErrorResult rv; - MozClearDataAt(aFormat, aIndex, rv); + MozClearDataAt(aFormat, aIndex, Some(nsContentUtils::SubjectPrincipal()), rv); return rv.StealNSResult(); } void DataTransfer::SetDragImage(Element& aImage, int32_t aX, int32_t aY, ErrorResult& aRv) { if (mReadOnly) {
--- a/dom/events/DataTransfer.h +++ b/dom/events/DataTransfer.h @@ -139,16 +139,17 @@ public: already_AddRefed<DOMStringList> GetTypes(ErrorResult& rv) const; void GetData(const nsAString& aFormat, nsAString& aData, ErrorResult& aRv); void SetData(const nsAString& aFormat, const nsAString& aData, ErrorResult& aRv); void ClearData(const mozilla::dom::Optional<nsAString>& aFormat, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, mozilla::ErrorResult& aRv); already_AddRefed<FileList> GetFiles(mozilla::ErrorResult& aRv); already_AddRefed<Promise> GetFilesAndDirectories(ErrorResult& aRv); already_AddRefed<Promise> GetFiles(bool aRecursiveFlag, ErrorResult& aRv); @@ -165,16 +166,17 @@ public: aCursor.AssignLiteral("auto"); } } already_AddRefed<DOMStringList> MozTypesAt(uint32_t aIndex, mozilla::ErrorResult& aRv) const; void MozClearDataAt(const nsAString& aFormat, uint32_t aIndex, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, mozilla::ErrorResult& aRv); void MozSetDataAt(JSContext* aCx, const nsAString& aFormat, JS::Handle<JS::Value> aData, uint32_t aIndex, mozilla::ErrorResult& aRv); void MozGetDataAt(JSContext* aCx, const nsAString& aFormat, uint32_t aIndex, JS::MutableHandle<JS::Value> aRetval, @@ -302,16 +304,17 @@ protected: void FillAllExternalData(); void FillInExternalCustomTypes(uint32_t aIndex, nsIPrincipal* aPrincipal); void FillInExternalCustomTypes(nsIVariant* aData, uint32_t aIndex, nsIPrincipal* aPrincipal); void MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, mozilla::ErrorResult& aRv); nsCOMPtr<nsISupports> mParent; // the drop effect and effect allowed uint32_t mDropEffect; uint32_t mEffectAllowed;
--- a/dom/events/DataTransferItem.cpp +++ b/dom/events/DataTransferItem.cpp @@ -233,31 +233,28 @@ DataTransferItem::FillInExternalData() #ifdef DEBUG if (oldKind != Kind()) { NS_WARNING("Clipboard data provided by the OS does not match predicted kind"); } #endif } already_AddRefed<File> -DataTransferItem::GetAsFile(ErrorResult& aRv) +DataTransferItem::GetAsFile(const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aRv) { - return GetAsFileWithPrincipal(nsContentUtils::SubjectPrincipal(), aRv); -} + MOZ_ASSERT(aSubjectPrincipal.isSome()); -already_AddRefed<File> -DataTransferItem::GetAsFileWithPrincipal(nsIPrincipal* aPrincipal, ErrorResult& aRv) -{ if (mKind != KIND_FILE) { return nullptr; } // This is done even if we have an mCachedFile, as it performs the necessary // permissions checks to ensure that we are allowed to access this type. - nsCOMPtr<nsIVariant> data = Data(aPrincipal, aRv); + nsCOMPtr<nsIVariant> data = Data(aSubjectPrincipal.value(), aRv); if (NS_WARN_IF(!data || aRv.Failed())) { return nullptr; } // Generate the dom::File from the stored data, caching it so that the // same object is returned in the future. if (!mCachedFile) { nsCOMPtr<nsISupports> supports; @@ -281,26 +278,22 @@ DataTransferItem::GetAsFileWithPrincipal } } RefPtr<File> file = mCachedFile; return file.forget(); } already_AddRefed<FileSystemEntry> -DataTransferItem::GetAsEntry(ErrorResult& aRv) +DataTransferItem::GetAsEntry(const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aRv) { - return GetAsEntryWithPrincipal(nsContentUtils::SubjectPrincipal(), aRv); -} + MOZ_ASSERT(aSubjectPrincipal.isSome()); -already_AddRefed<FileSystemEntry> -DataTransferItem::GetAsEntryWithPrincipal(nsIPrincipal* aPrincipal, - ErrorResult& aRv) -{ - RefPtr<File> file = GetAsFileWithPrincipal(aPrincipal, aRv); + RefPtr<File> file = GetAsFile(aSubjectPrincipal, aRv); if (NS_WARN_IF(aRv.Failed()) || !file) { return nullptr; } nsCOMPtr<nsIGlobalObject> global; // This is annoying, but DataTransfer may have various things as parent. nsCOMPtr<EventTarget> target = do_QueryInterface(mDataTransfer->GetParentObject()); @@ -388,26 +381,29 @@ DataTransferItem::CreateFileFromInputStr } return File::CreateMemoryFile(mDataTransfer, data, available, fileName, mType, PR_Now()); } void DataTransferItem::GetAsString(FunctionStringCallback* aCallback, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, ErrorResult& aRv) { + MOZ_ASSERT(aSubjectPrincipal.isSome()); + if (!aCallback || mKind != KIND_STRING) { return; } // Theoretically this should be done inside of the runnable, as it might be an // expensive operation on some systems, however we wouldn't get access to the // NS_ERROR_DOM_SECURITY_ERROR messages which may be raised by this method. - nsCOMPtr<nsIVariant> data = Data(nsContentUtils::SubjectPrincipal(), aRv); + nsCOMPtr<nsIVariant> data = Data(aSubjectPrincipal.value(), aRv); if (NS_WARN_IF(!data || aRv.Failed())) { return; } nsAutoString stringData; nsresult rv = data->GetAsAString(stringData); if (NS_WARN_IF(NS_FAILED(rv))) { return;
--- a/dom/events/DataTransferItem.h +++ b/dom/events/DataTransferItem.h @@ -45,17 +45,19 @@ public: MOZ_ASSERT(mDataTransfer, "Must be associated with a DataTransfer"); } already_AddRefed<DataTransferItem> Clone(DataTransfer* aDataTransfer) const; virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; // NOTE: This accesses the subject principal, and should not be called from C++ - void GetAsString(FunctionStringCallback* aCallback, ErrorResult& aRv); + void GetAsString(FunctionStringCallback* aCallback, + const Maybe<nsIPrincipal*>& aPrincipal, + ErrorResult& aRv); void GetKind(nsAString& aKind) const { switch (mKind) { case KIND_FILE: aKind = NS_LITERAL_STRING("file"); return; case KIND_STRING: @@ -77,25 +79,21 @@ public: { return mKind; } void SetKind(eKind aKind) { mKind = aKind; } - // NOTE: This accesses the subject principal, and should not be called from C++ - already_AddRefed<File> GetAsFile(ErrorResult& aRv); - already_AddRefed<File> GetAsFileWithPrincipal(nsIPrincipal* aPrincipal, - ErrorResult& aRv); + already_AddRefed<File> + GetAsFile(const Maybe<nsIPrincipal*>& aSubjectPrincipal, ErrorResult& aRv); - // NOTE: This accesses the subject principal, and should not be called from C++ - already_AddRefed<FileSystemEntry> GetAsEntry(ErrorResult& aRv); - already_AddRefed<FileSystemEntry> GetAsEntryWithPrincipal(nsIPrincipal* aPrincipal, - ErrorResult& aRv); + already_AddRefed<FileSystemEntry> + GetAsEntry(const Maybe<nsIPrincipal*>& aSubjectPrincipal, ErrorResult& aRv); DataTransfer* GetParentObject() const { return mDataTransfer; } nsIPrincipal* Principal() const {
--- a/dom/events/DataTransferItemList.cpp +++ b/dom/events/DataTransferItemList.cpp @@ -76,29 +76,33 @@ DataTransferItemList::Clone(DataTransfer // Copy over the reference list->mItems[i] = list->mIndexedItems[index][subIndex]; } return list.forget(); } void -DataTransferItemList::Remove(uint32_t aIndex, ErrorResult& aRv) +DataTransferItemList::Remove(uint32_t aIndex, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aRv) { + MOZ_ASSERT(aSubjectPrincipal.isSome()); + if (mDataTransfer->IsReadOnly()) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } if (aIndex >= Length()) { aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); return; } - ClearDataHelper(mItems[aIndex], aIndex, -1, aRv); + ClearDataHelper(mItems[aIndex], aIndex, -1, aSubjectPrincipal, aRv); } DataTransferItem* DataTransferItemList::IndexedGetter(uint32_t aIndex, bool& aFound, ErrorResult& aRv) const { if (aIndex >= mItems.Length()) { aFound = false; return nullptr; @@ -117,96 +121,104 @@ DataTransferItemList::MozItemCount() con // if it is empty, scripts using the moz* APIs should see it as not existing. if (length == 1 && mIndexedItems[0].IsEmpty()) { return 0; } return length; } void -DataTransferItemList::Clear(ErrorResult& aRv) +DataTransferItemList::Clear(const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aRv) { + MOZ_ASSERT(aSubjectPrincipal.isSome()); + if (NS_WARN_IF(mDataTransfer->IsReadOnly())) { return; } uint32_t count = Length(); for (uint32_t i = 0; i < count; i++) { // We always remove the last item first, to avoid moving items around in // memory as much - Remove(Length() - 1, aRv); + Remove(Length() - 1, aSubjectPrincipal, aRv); ENSURE_SUCCESS_VOID(aRv); } MOZ_ASSERT(Length() == 0); } DataTransferItem* DataTransferItemList::Add(const nsAString& aData, const nsAString& aType, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, ErrorResult& aRv) { + MOZ_ASSERT(aSubjectPrincipal.isSome()); + if (NS_WARN_IF(mDataTransfer->IsReadOnly())) { return nullptr; } nsCOMPtr<nsIVariant> data(new storage::TextVariant(aData)); nsAutoString format; mDataTransfer->GetRealFormat(aType, format); - nsIPrincipal* subjectPrincipal = nsContentUtils::SubjectPrincipal(); - - if (!DataTransfer::PrincipalMaySetData(format, data, subjectPrincipal)) { + if (!DataTransfer::PrincipalMaySetData(format, data, + aSubjectPrincipal.value())) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return nullptr; } // We add the textual data to index 0. We set aInsertOnly to true, as we don't // want to update an existing entry if it is already present, as per the spec. RefPtr<DataTransferItem> item = - SetDataWithPrincipal(format, data, 0, subjectPrincipal, + SetDataWithPrincipal(format, data, 0, aSubjectPrincipal.value(), /* aInsertOnly = */ true, /* aHidden = */ false, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } MOZ_ASSERT(item->Kind() != DataTransferItem::KIND_FILE); return item; } DataTransferItem* -DataTransferItemList::Add(File& aData, ErrorResult& aRv) +DataTransferItemList::Add(File& aData, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aRv) { + MOZ_ASSERT(aSubjectPrincipal.isSome()); + if (mDataTransfer->IsReadOnly()) { return nullptr; } nsCOMPtr<nsISupports> supports = do_QueryObject(&aData); nsCOMPtr<nsIWritableVariant> data = new nsVariant(); data->SetAsISupports(supports); nsAutoString type; aData.GetType(type); - nsIPrincipal* subjectPrincipal = nsContentUtils::SubjectPrincipal(); - - if (!DataTransfer::PrincipalMaySetData(type, data, subjectPrincipal)) { + if (!DataTransfer::PrincipalMaySetData(type, data, + aSubjectPrincipal.value())) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return nullptr; } // We need to add this as a new item, as multiple files can't exist in the // same item in the Moz DataTransfer layout. It will be appended at the end of // the internal specced layout. uint32_t index = mIndexedItems.Length(); RefPtr<DataTransferItem> item = - SetDataWithPrincipal(type, data, index, subjectPrincipal, + SetDataWithPrincipal(type, data, index, aSubjectPrincipal.value(), /* aInsertOnly = */ true, /* aHidden = */ false, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } MOZ_ASSERT(item->Kind() == DataTransferItem::KIND_FILE); @@ -255,51 +267,54 @@ DataTransferItemList::Files(nsIPrincipal files = mFiles; return files.forget(); } void DataTransferItemList::MozRemoveByTypeAt(const nsAString& aType, uint32_t aIndex, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, ErrorResult& aRv) { + MOZ_ASSERT(aSubjectPrincipal.isSome()); + if (NS_WARN_IF(mDataTransfer->IsReadOnly() || aIndex >= mIndexedItems.Length())) { return; } bool removeAll = aType.IsEmpty(); nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[aIndex]; uint32_t count = items.Length(); // We remove the last item of the list repeatedly - that way we don't // have to worry about modifying the loop iterator if (removeAll) { for (uint32_t i = 0; i < count; ++i) { uint32_t index = items.Length() - 1; MOZ_ASSERT(index == count - i - 1); - ClearDataHelper(items[index], -1, index, aRv); + ClearDataHelper(items[index], -1, index, aSubjectPrincipal, aRv); if (NS_WARN_IF(aRv.Failed())) { return; } } // items is no longer a valid reference, as removing the last element from // it via ClearDataHelper invalidated it. so we can't MOZ_ASSERT that the // length is now 0. return; } for (uint32_t i = 0; i < count; ++i) { nsAutoString type; items[i]->GetType(type); if (type == aType) { - ClearDataHelper(items[i], -1, i, aRv); + ClearDataHelper(items[i], -1, i, aSubjectPrincipal, aRv); return; } } } DataTransferItem* DataTransferItemList::MozItemByTypeAt(const nsAString& aType, uint32_t aIndex) { @@ -464,26 +479,26 @@ DataTransferItemList::ClearAllItems() // Re-generate files (into an empty list) RegenerateFiles(); } void DataTransferItemList::ClearDataHelper(DataTransferItem* aItem, uint32_t aIndexHint, uint32_t aMozOffsetHint, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, ErrorResult& aRv) { MOZ_ASSERT(aItem); if (NS_WARN_IF(mDataTransfer->IsReadOnly())) { return; } - nsIPrincipal* principal = nsContentUtils::SubjectPrincipal(); - if (aItem->Principal() && principal && - !principal->Subsumes(aItem->Principal())) { + if (aItem->Principal() && aSubjectPrincipal.isSome() && + !aSubjectPrincipal.value()->Subsumes(aItem->Principal())) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; } // Check if the aIndexHint is actually the index, and then remove the item // from aItems ErrorResult rv; bool found; @@ -552,17 +567,17 @@ DataTransferItemList::GenerateFiles(File ErrorResult rv; bool found; RefPtr<DataTransferItem> item = IndexedGetter(i, found, rv); if (NS_WARN_IF(!found || rv.Failed())) { continue; } if (item->Kind() == DataTransferItem::KIND_FILE) { - RefPtr<File> file = item->GetAsFileWithPrincipal(aFilesPrincipal, rv); + RefPtr<File> file = item->GetAsFile(Some(aFilesPrincipal), rv); if (NS_WARN_IF(rv.Failed() || !file)) { continue; } aFiles->Append(file); } } }
--- a/dom/events/DataTransferItemList.h +++ b/dom/events/DataTransferItemList.h @@ -46,55 +46,63 @@ public: JS::Handle<JSObject*> aGivenProto) override; uint32_t Length() const { return mItems.Length(); }; DataTransferItem* Add(const nsAString& aData, const nsAString& aType, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, ErrorResult& rv); - DataTransferItem* Add(File& aData, ErrorResult& aRv); + DataTransferItem* Add(File& aData, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aRv); - void Remove(uint32_t aIndex, ErrorResult& aRv); + void Remove(uint32_t aIndex, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aRv); DataTransferItem* IndexedGetter(uint32_t aIndex, bool& aFound, ErrorResult& aRv) const; DataTransfer* GetParentObject() const { return mDataTransfer; } - void Clear(ErrorResult& aRv); + void Clear(const Maybe<nsIPrincipal*>& aSubjectPrincipal, ErrorResult& aRv); already_AddRefed<DataTransferItem> SetDataWithPrincipal(const nsAString& aType, nsIVariant* aData, uint32_t aIndex, nsIPrincipal* aPrincipal, bool aInsertOnly, bool aHidden, ErrorResult& aRv); already_AddRefed<FileList> Files(nsIPrincipal* aPrincipal); // Moz-style helper methods for interacting with the stored data void MozRemoveByTypeAt(const nsAString& aType, uint32_t aIndex, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, ErrorResult& aRv); DataTransferItem* MozItemByTypeAt(const nsAString& aType, uint32_t aIndex); const nsTArray<RefPtr<DataTransferItem>>* MozItemsAt(uint32_t aIndex); uint32_t MozItemCount() const; // Causes everything in indexes above 0 to shift down one index. void PopIndexZero(); // Delete every item in the DataTransferItemList, without checking for // permissions or read-only status (for internal use only). void ClearAllItems(); private: void ClearDataHelper(DataTransferItem* aItem, uint32_t aIndexHint, - uint32_t aMozOffsetHint, ErrorResult& aRv); + uint32_t aMozOffsetHint, + const Maybe<nsIPrincipal*>& aSubjectPrincipal, + ErrorResult& aRv); DataTransferItem* AppendNewItem(uint32_t aIndex, const nsAString& aType, nsIVariant* aData, nsIPrincipal* aPrincipal, bool aHidden); void RegenerateFiles(); void GenerateFiles(FileList* aFiles, nsIPrincipal* aFilesPrincipal); ~DataTransferItemList() {}
--- a/dom/geolocation/nsGeolocation.cpp +++ b/dom/geolocation/nsGeolocation.cpp @@ -5,17 +5,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsXULAppAPI.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/Telemetry.h" #include "nsAutoPtr.h" -#include "nsISettingsService.h" #include "nsGeolocation.h" #include "nsDOMClassInfoID.h" #include "nsComponentManagerUtils.h" #include "nsServiceManagerUtils.h" #include "nsContentUtils.h" #include "nsContentPermissionHelper.h" #include "nsIDocument.h" @@ -27,17 +26,16 @@ #include "mozilla/Hal.h" #include "mozilla/Services.h" #include "mozilla/Unused.h" #include "mozilla/Preferences.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/dom/Event.h" #include "mozilla/WeakPtr.h" #include "mozilla/dom/PermissionMessageUtils.h" -#include "mozilla/dom/SettingChangeNotificationBinding.h" #include "mozilla/dom/WakeLock.h" class nsIPrincipal; #ifdef MOZ_WIDGET_ANDROID #include "AndroidLocationProvider.h" #endif @@ -57,19 +55,16 @@ class nsIPrincipal; #include "WindowsLocationProvider.h" #include "mozilla/WindowsVersion.h" #endif // Some limit to the number of get or watch geolocation requests // that a window can make. #define MAX_GEO_REQUESTS_PER_WINDOW 1500 -// The settings key. -#define GEO_SETTINGS_ENABLED "geolocation.enabled" - using mozilla::Unused; // <snicker> using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::hal; class nsGeolocationRequest final : public nsIContentPermissionRequest , public nsIGeolocationUpdate @@ -145,63 +140,16 @@ CreatePositionOptionsCopy(const Position geoOptions->mEnableHighAccuracy = aOptions.mEnableHighAccuracy; geoOptions->mMaximumAge = aOptions.mMaximumAge; geoOptions->mTimeout = aOptions.mTimeout; return geoOptions; } -class GeolocationSettingsCallback : public nsISettingsServiceCallback -{ - virtual ~GeolocationSettingsCallback() { - MOZ_COUNT_DTOR(GeolocationSettingsCallback); - } - -public: - NS_DECL_ISUPPORTS - - GeolocationSettingsCallback() { - MOZ_COUNT_CTOR(GeolocationSettingsCallback); - } - - NS_IMETHOD Handle(const nsAString& aName, JS::Handle<JS::Value> aResult) override - { - MOZ_ASSERT(NS_IsMainThread()); - - // The geolocation is enabled by default: - bool value = true; - if (aResult.isBoolean()) { - value = aResult.toBoolean(); - } - - MozSettingValue(value); - return NS_OK; - } - - NS_IMETHOD HandleError(const nsAString& aName) override - { - NS_WARNING("Unable to get value for '" GEO_SETTINGS_ENABLED "'"); - - // Default it's enabled: - MozSettingValue(true); - return NS_OK; - } - - void MozSettingValue(const bool aValue) - { - RefPtr<nsGeolocationService> gs = nsGeolocationService::GetGeolocationService(); - if (gs) { - gs->HandleMozsettingValue(aValue); - } - } -}; - -NS_IMPL_ISUPPORTS(GeolocationSettingsCallback, nsISettingsServiceCallback) - class RequestPromptEvent : public Runnable { public: RequestPromptEvent(nsGeolocationRequest* aRequest, nsWeakPtr aWindow) : mRequest(aRequest) , mWindow(aWindow) { } @@ -377,22 +325,24 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION( NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest) NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest) NS_INTERFACE_MAP_ENTRY(nsIGeolocationUpdate) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGeolocationRequest) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGeolocationRequest) NS_IMPL_CYCLE_COLLECTION(nsGeolocationRequest, mCallback, mErrorCallback, mLocator) + void nsGeolocationRequest::Notify() { SetTimeoutTimer(); NotifyErrorAndShutdown(nsIDOMGeoPositionError::TIMEOUT); } + void nsGeolocationRequest::NotifyErrorAndShutdown(uint16_t aErrorCode) { MOZ_ASSERT(!mShutdown, "timeout after shutdown"); if (!mIsWatchPositionRequest) { Shutdown(); mLocator->RemoveRequest(this); } @@ -554,16 +504,17 @@ nsGeolocationRequest::Allow(JS::HandleVa NS_IMETHODIMP nsGeolocationRequest::GetRequester(nsIContentPermissionRequester** aRequester) { NS_ENSURE_ARG_POINTER(aRequester); nsCOMPtr<nsIContentPermissionRequester> requester = mRequester; requester.forget(aRequester); + return NS_OK; } void nsGeolocationRequest::SetTimeoutTimer() { StopTimeoutTimer(); @@ -633,32 +584,34 @@ nsGeolocationRequest::SendLocation(nsIDO nsIDOMGeoPositionCallback* callback = mCallback.GetXPCOMCallback(); MOZ_ASSERT(callback); callback->HandleEvent(aPosition); } SetTimeoutTimer(); MOZ_ASSERT(mShutdown || mIsWatchPositionRequest, "non-shutdown getCurrentPosition request after callback!"); } + nsIPrincipal* nsGeolocationRequest::GetPrincipal() { if (!mLocator) { return nullptr; } return mLocator->GetPrincipal(); } NS_IMETHODIMP nsGeolocationRequest::Update(nsIDOMGeoPosition* aPosition) { nsCOMPtr<nsIRunnable> ev = new RequestSendLocationEvent(aPosition, this); NS_DispatchToMainThread(ev); return NS_OK; } + NS_IMETHODIMP nsGeolocationRequest::NotifyError(uint16_t aErrorCode) { MOZ_ASSERT(NS_IsMainThread()); RefPtr<PositionError> positionError = new PositionError(mLocator, aErrorCode); positionError->NotifyCallback(mErrorCallback); return NS_OK; } @@ -690,16 +643,17 @@ NS_IMPL_ISUPPORTS(nsGeolocationRequest:: NS_IMETHODIMP nsGeolocationRequest::TimerCallbackHolder::Notify(nsITimer*) { if (mRequest && mRequest->mLocator) { RefPtr<nsGeolocationRequest> request(mRequest); request->Notify(); } + return NS_OK; } //////////////////////////////////////////////////// // nsGeolocationService //////////////////////////////////////////////////// NS_INTERFACE_MAP_BEGIN(nsGeolocationService) @@ -708,59 +662,38 @@ NS_INTERFACE_MAP_BEGIN(nsGeolocationServ NS_INTERFACE_MAP_ENTRY(nsIObserver) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsGeolocationService) NS_IMPL_RELEASE(nsGeolocationService) static bool sGeoEnabled = true; -static bool sGeoInitPending = true; static int32_t sProviderTimeout = 6000; // Time, in milliseconds, to wait for the location provider to spin up. nsresult nsGeolocationService::Init() { Preferences::AddIntVarCache(&sProviderTimeout, "geo.timeout", sProviderTimeout); Preferences::AddBoolVarCache(&sGeoEnabled, "geo.enabled", sGeoEnabled); if (!sGeoEnabled) { return NS_ERROR_FAILURE; } if (XRE_IsContentProcess()) { - sGeoInitPending = false; return NS_OK; } - // check if the geolocation service is enable from settings - nsCOMPtr<nsISettingsService> settings = - do_GetService("@mozilla.org/settingsService;1"); - - if (settings) { - nsCOMPtr<nsISettingsServiceLock> settingsLock; - nsresult rv = settings->CreateLock(nullptr, getter_AddRefs(settingsLock)); - NS_ENSURE_SUCCESS(rv, rv); - - RefPtr<GeolocationSettingsCallback> callback = new GeolocationSettingsCallback(); - rv = settingsLock->Get(GEO_SETTINGS_ENABLED, callback); - NS_ENSURE_SUCCESS(rv, rv); - } else { - // If we cannot obtain the settings service, we continue - // assuming that the geolocation is enabled: - sGeoInitPending = false; - } - // geolocation service can be enabled -> now register observer nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); if (!obs) { return NS_ERROR_FAILURE; } obs->AddObserver(this, "xpcom-shutdown", false); - obs->AddObserver(this, "mozsettings-changed", false); #ifdef MOZ_WIDGET_ANDROID mProvider = new AndroidLocationProvider(); #endif #ifdef MOZ_WIDGET_GONK // GonkGPSGeolocationProvider can be started at boot up time for initialization reasons. // do_getService gets hold of the already initialized component and starts @@ -811,82 +744,35 @@ nsresult nsGeolocationService::Init() return NS_OK; } nsGeolocationService::~nsGeolocationService() { } -void -nsGeolocationService::HandleMozsettingChanged(nsISupports* aSubject) -{ - // The string that we're interested in will be a JSON string that looks like: - // {"key":"gelocation.enabled","value":true} - - RootedDictionary<SettingChangeNotification> setting(RootingCx()); - if (!WrappedJSToDictionary(aSubject, setting)) { - return; - } - if (!setting.mKey.EqualsASCII(GEO_SETTINGS_ENABLED)) { - return; - } - if (!setting.mValue.isBoolean()) { - return; - } - - HandleMozsettingValue(setting.mValue.toBoolean()); -} - -void -nsGeolocationService::HandleMozsettingValue(const bool aValue) -{ - if (!aValue) { - // turn things off - StopDevice(); - Update(nullptr); - mLastPosition.position = nullptr; - sGeoEnabled = false; - } else { - sGeoEnabled = true; - } - - if (sGeoInitPending) { - sGeoInitPending = false; - for (uint32_t i = 0, length = mGeolocators.Length(); i < length; ++i) { - mGeolocators[i]->ServiceReady(); - } - } -} - NS_IMETHODIMP nsGeolocationService::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) { if (!strcmp("xpcom-shutdown", aTopic)) { nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); if (obs) { obs->RemoveObserver(this, "xpcom-shutdown"); - obs->RemoveObserver(this, "mozsettings-changed"); } for (uint32_t i = 0; i< mGeolocators.Length(); i++) { mGeolocators[i]->Shutdown(); } StopDevice(); return NS_OK; } - if (!strcmp("mozsettings-changed", aTopic)) { - HandleMozsettingChanged(aSubject); - return NS_OK; - } - if (!strcmp("timer-callback", aTopic)) { // decide if we can close down the service. for (uint32_t i = 0; i< mGeolocators.Length(); i++) if (mGeolocators[i]->HasActiveCallbacks()) { SetDisconnectTimer(); return NS_OK; } @@ -900,21 +786,24 @@ nsGeolocationService::Observe(nsISupport } NS_IMETHODIMP nsGeolocationService::Update(nsIDOMGeoPosition *aSomewhere) { if (aSomewhere) { SetCachedPosition(aSomewhere); } + for (uint32_t i = 0; i< mGeolocators.Length(); i++) { mGeolocators[i]->Update(aSomewhere); } + return NS_OK; } + NS_IMETHODIMP nsGeolocationService::NotifyError(uint16_t aErrorCode) { for (uint32_t i = 0; i < mGeolocators.Length(); i++) { mGeolocators[i]->NotifyError(aErrorCode); } return NS_OK; } @@ -930,17 +819,17 @@ CachedPositionAndAccuracy nsGeolocationService::GetCachedPosition() { return mLastPosition; } nsresult nsGeolocationService::StartDevice(nsIPrincipal *aPrincipal) { - if (!sGeoEnabled || sGeoInitPending) { + if (!sGeoEnabled) { return NS_ERROR_NOT_AVAILABLE; } // we do not want to keep the geolocation devices online // indefinitely. Close them down after a reasonable period of // inactivivity SetDisconnectTimer(); @@ -981,17 +870,16 @@ void nsGeolocationService::StopDisconnectTimer() { if (mDisconnectTimer) { mDisconnectTimer->Cancel(); mDisconnectTimer = nullptr; } } - void nsGeolocationService::SetDisconnectTimer() { if (!mDisconnectTimer) { mDisconnectTimer = do_CreateInstance("@mozilla.org/timer;1"); } else { mDisconnectTimer->Cancel(); } @@ -1004,51 +892,47 @@ nsGeolocationService::SetDisconnectTimer bool nsGeolocationService::HighAccuracyRequested() { for (uint32_t i = 0; i < mGeolocators.Length(); i++) { if (mGeolocators[i]->HighAccuracyRequested()) { return true; } } + return false; } void nsGeolocationService::UpdateAccuracy(bool aForceHigh) { bool highRequired = aForceHigh || HighAccuracyRequested(); if (XRE_IsContentProcess()) { ContentChild* cpc = ContentChild::GetSingleton(); if (cpc->IsAlive()) { cpc->SendSetGeolocationHigherAccuracy(highRequired); } + return; } - if (!mHigherAccuracy && highRequired) { - mProvider->SetHighAccuracy(true); - } - - if (mHigherAccuracy && !highRequired) { - mProvider->SetHighAccuracy(false); - } - + mProvider->SetHighAccuracy(!mHigherAccuracy && highRequired); mHigherAccuracy = highRequired; } void nsGeolocationService::StopDevice() { StopDisconnectTimer(); if (XRE_IsContentProcess()) { ContentChild* cpc = ContentChild::GetSingleton(); cpc->SendRemoveGeolocationListener(); + return; // bail early } nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); if (!obs) { return; } @@ -1067,23 +951,25 @@ nsGeolocationService::StopDevice() StaticRefPtr<nsGeolocationService> nsGeolocationService::sService; already_AddRefed<nsGeolocationService> nsGeolocationService::GetGeolocationService() { RefPtr<nsGeolocationService> result; if (nsGeolocationService::sService) { result = nsGeolocationService::sService; + return result.forget(); } result = new nsGeolocationService(); if (NS_FAILED(result->Init())) { return nullptr; } + ClearOnShutdown(&nsGeolocationService::sService); nsGeolocationService::sService = result; return result.forget(); } void nsGeolocationService::AddLocator(Geolocation* aLocator) { @@ -1178,31 +1064,31 @@ Geolocation::Init(nsPIDOMWindowInner* aC // If no aContentDom was passed into us, we are being used // by chrome/c++ and have no mOwner, no mPrincipal, and no need // to prompt. mService = nsGeolocationService::GetGeolocationService(); if (mService) { mService->AddLocator(this); } + return NS_OK; } bool Geolocation::ContainsRequest(nsGeolocationRequest* aRequest) { - if (aRequest->IsWatch()) { - if (mWatchingCallbacks.Contains(aRequest)) { + if (aRequest->IsWatch() && mWatchingCallbacks.Contains(aRequest)) { return true; - } - } else { - if (mPendingCallbacks.Contains(aRequest)) { - return true; - } } + + if (mPendingCallbacks.Contains(aRequest)) { + return true; + } + return false; } NS_IMETHODIMP Geolocation::HandleEvent(nsIDOMEvent* aEvent) { @@ -1216,33 +1102,37 @@ Geolocation::HandleEvent(nsIDOMEvent* aE MOZ_ASSERT(doc); if (doc->Hidden()) { WakeLockInformation info; GetWakeLockInfo(NS_LITERAL_STRING("gps"), &info); MOZ_ASSERT(XRE_IsContentProcess()); ContentChild* cpc = ContentChild::GetSingleton(); + if (!info.lockingProcesses().Contains(cpc->GetID())) { cpc->SendRemoveGeolocationListener(); mService->StopDisconnectTimer(); } - } else { - mService->SetDisconnectTimer(); + + return NS_OK; + } + + mService->SetDisconnectTimer(); - // We will unconditionally allow all the requests in the callbacks - // because if a request is put into either of these two callbacks, - // it means that it has been allowed before. - // That's why when we resume them, we unconditionally allow them again. - for (uint32_t i = 0, length = mWatchingCallbacks.Length(); i < length; ++i) { - mWatchingCallbacks[i]->Allow(JS::UndefinedHandleValue); - } - for (uint32_t i = 0, length = mPendingCallbacks.Length(); i < length; ++i) { - mPendingCallbacks[i]->Allow(JS::UndefinedHandleValue); - } + // We will unconditionally allow all the requests in the callbacks + // because if a request is put into either of these two callbacks, + // it means that it has been allowed before. + // That's why when we resume them, we unconditionally allow them again. + for (uint32_t i = 0, length = mWatchingCallbacks.Length(); i < length; ++i) { + mWatchingCallbacks[i]->Allow(JS::UndefinedHandleValue); + } + + for (uint32_t i = 0, length = mPendingCallbacks.Length(); i < length; ++i) { + mPendingCallbacks[i]->Allow(JS::UndefinedHandleValue); } return NS_OK; } void Geolocation::Shutdown() { @@ -1333,25 +1223,28 @@ Geolocation::Update(nsIDOMGeoPosition *a mPendingCallbacks[i-1]->Update(aSomewhere); RemoveRequest(mPendingCallbacks[i-1]); } // notify everyone that is watching for (uint32_t i = 0; i < mWatchingCallbacks.Length(); i++) { mWatchingCallbacks[i]->Update(aSomewhere); } + return NS_OK; } + NS_IMETHODIMP Geolocation::NotifyError(uint16_t aErrorCode) { if (!WindowOwnerStillExists()) { Shutdown(); return NS_OK; } + mozilla::Telemetry::Accumulate(mozilla::Telemetry::GEOLOCATION_ERROR, true); for (uint32_t i = mPendingCallbacks.Length(); i > 0; i--) { mPendingCallbacks[i-1]->NotifyErrorAndShutdown(aErrorCode); //NotifyErrorAndShutdown() removes the request from the array } // notify everyone that is watching @@ -1365,27 +1258,29 @@ Geolocation::NotifyError(uint16_t aError bool Geolocation::IsAlreadyCleared(nsGeolocationRequest* aRequest) { for (uint32_t i = 0, length = mClearedWatchIDs.Length(); i < length; ++i) { if (mClearedWatchIDs[i] == aRequest->WatchId()) { return true; } } + return false; } bool Geolocation::ClearPendingRequest(nsGeolocationRequest* aRequest) { if (aRequest->IsWatch() && this->IsAlreadyCleared(aRequest)) { this->NotifyAllowedRequest(aRequest); this->ClearWatch(aRequest->WatchId()); return true; } + return false; } void Geolocation::GetCurrentPosition(PositionCallback& aCallback, PositionErrorCallback* aErrorCallback, const PositionOptions& aOptions, ErrorResult& aRv) @@ -1438,21 +1333,16 @@ Geolocation::GetCurrentPosition(GeoPosit NS_DispatchToMainThread(ev); return NS_OK; } if (!mOwner && !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) { return NS_ERROR_FAILURE; } - if (sGeoInitPending) { - mPendingRequests.AppendElement(request); - return NS_OK; - } - return GetCurrentPositionReady(request); } nsresult Geolocation::GetCurrentPositionReady(nsGeolocationRequest* aRequest) { if (mOwner) { if (!RegisterRequestWithPrompt(aRequest)) { @@ -1530,21 +1420,16 @@ Geolocation::WatchPosition(GeoPositionCa NS_DispatchToMainThread(ev); return NS_OK; } if (!mOwner && !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) { return NS_ERROR_FAILURE; } - if (sGeoInitPending) { - mPendingRequests.AppendElement(request); - return NS_OK; - } - return WatchPositionReady(request); } nsresult Geolocation::WatchPositionReady(nsGeolocationRequest* aRequest) { if (mOwner) { if (!RegisterRequestWithPrompt(aRequest))
--- a/dom/geolocation/nsGeolocation.h +++ b/dom/geolocation/nsGeolocation.h @@ -67,19 +67,16 @@ public: NS_DECL_NSIOBSERVER nsGeolocationService() { mHigherAccuracy = false; } nsresult Init(); - void HandleMozsettingChanged(nsISupports* aSubject); - void HandleMozsettingValue(const bool aValue); - // Management of the Geolocation objects void AddLocator(mozilla::dom::Geolocation* locator); void RemoveLocator(mozilla::dom::Geolocation* locator); void SetCachedPosition(nsIDOMGeoPosition* aPosition); CachedPositionAndAccuracy GetCachedPosition(); // Find and startup a geolocation device (gps, nmea, etc.)
--- a/dom/html/HTMLImageElement.cpp +++ b/dom/html/HTMLImageElement.cpp @@ -112,16 +112,17 @@ private: nsCOMPtr<nsIDocument> mDocument; bool mAlwaysLoad; }; HTMLImageElement::HTMLImageElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo) : nsGenericHTMLElement(aNodeInfo) , mForm(nullptr) , mInDocResponsiveContent(false) + , mCurrentDensity(1.0) { // We start out broken AddStatesSilently(NS_EVENT_STATE_BROKEN); } HTMLImageElement::~HTMLImageElement() { DestroyImageLoadingContent(); @@ -946,49 +947,79 @@ HTMLImageElement::InResponsiveMode() // When we lose srcset or leave a <picture> element, the fallback to img.src // will happen from the microtask, and we should behave responsively in the // interim return mResponsiveSelector || mPendingImageLoadTask || HaveSrcsetOrInPicture(); } +bool +HTMLImageElement::SelectedSourceMatchesLast(nsIURI* aSelectedSource, double aSelectedDensity) +{ + // If there was no selected source previously, we don't want to short-circuit the load. + // Similarly for if there is no newly selected source. + if (!mLastSelectedSource || !aSelectedSource) { + return false; + } + bool equal = false; + return NS_SUCCEEDED(mLastSelectedSource->Equals(aSelectedSource, &equal)) && equal && + aSelectedDensity == mCurrentDensity; +} + nsresult HTMLImageElement::LoadSelectedImage(bool aForce, bool aNotify, bool aAlwaysLoad) { nsresult rv = NS_ERROR_FAILURE; if (aForce) { // In responsive mode we generally want to re-run the full // selection algorithm whenever starting a new load, per // spec. This also causes us to re-resolve the URI as appropriate. if (!UpdateResponsiveSource() && !aAlwaysLoad) { return NS_OK; } } + nsCOMPtr<nsIURI> selectedSource; + double currentDensity = 1.0; // default to 1.0 for the src attribute case if (mResponsiveSelector) { nsCOMPtr<nsIURI> url = mResponsiveSelector->GetSelectedImageURL(); + selectedSource = url; + currentDensity = mResponsiveSelector->GetSelectedImageDensity(); + if (!aAlwaysLoad && SelectedSourceMatchesLast(selectedSource, currentDensity)) { + return NS_OK; + } if (url) { rv = LoadImage(url, aForce, aNotify, eImageLoadType_Imageset); } } else { nsAutoString src; if (!GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) { CancelImageRequests(aNotify); rv = NS_OK; } else { + nsIDocument* doc = GetOurOwnerDoc(); + if (doc) { + StringToURI(src, doc, getter_AddRefs(selectedSource)); + if (!aAlwaysLoad && SelectedSourceMatchesLast(selectedSource, currentDensity)) { + return NS_OK; + } + } + // If we have a srcset attribute or are in a <picture> element, // we always use the Imageset load type, even if we parsed no // valid responsive sources from either, per spec. rv = LoadImage(src, aForce, aNotify, HaveSrcsetOrInPicture() ? eImageLoadType_Imageset : eImageLoadType_Normal); } } + mLastSelectedSource = selectedSource; + mCurrentDensity = currentDensity; if (NS_FAILED(rv)) { CancelImageRequests(aNotify); } return rv; } void
--- a/dom/html/HTMLImageElement.h +++ b/dom/html/HTMLImageElement.h @@ -287,16 +287,19 @@ protected: // True if we have a srcset attribute or a <picture> parent, regardless of if // any valid responsive sources were parsed from either. bool HaveSrcsetOrInPicture(); // True if we are using the newer image loading algorithm. This will be the // only mode after Bug 1076583 bool InResponsiveMode(); + // True if the given URL and density equal the last URL and density that was loaded by this element. + bool SelectedSourceMatchesLast(nsIURI* aSelectedSource, double aSelectedDensity); + // Resolve and load the current mResponsiveSelector (responsive mode) or src // attr image. nsresult LoadSelectedImage(bool aForce, bool aNotify, bool aAlwaysLoad); // True if this string represents a type we would support on <source type> static bool SupportedPictureSourceType(const nsAString& aType); // Update/create/destroy mResponsiveSelector @@ -358,14 +361,19 @@ protected: private: bool SourceElementMatches(nsIContent* aSourceNode); static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes, nsRuleData* aData); bool mInDocResponsiveContent; RefPtr<ImageLoadTask> mPendingImageLoadTask; + + // Last URL that was attempted to load by this element. + nsCOMPtr<nsIURI> mLastSelectedSource; + // Last pixel density that was selected. + double mCurrentDensity; }; } // namespace dom } // namespace mozilla #endif /* mozilla_dom_HTMLImageElement_h */
--- a/dom/html/nsHTMLDocument.cpp +++ b/dom/html/nsHTMLDocument.cpp @@ -537,17 +537,17 @@ nsHTMLDocument::StartDocumentLoad(const bool asData = !strcmp(aCommand, kLoadAsData); bool import = !strcmp(aCommand, "import"); if (!(view || viewSource || asData || import)) { MOZ_ASSERT(false, "Bad parser command"); return NS_ERROR_INVALID_ARG; } bool html = contentType.EqualsLiteral(TEXT_HTML); - bool xhtml = !html && contentType.EqualsLiteral(APPLICATION_XHTML_XML); + bool xhtml = !html && (contentType.EqualsLiteral(APPLICATION_XHTML_XML) || contentType.EqualsLiteral(APPLICATION_WAPXHTML_XML)); bool plainText = !html && !xhtml && nsContentUtils::IsPlainTextType(contentType); if (!(html || xhtml || plainText || viewSource)) { MOZ_ASSERT(false, "Channel with bad content type."); return NS_ERROR_INVALID_ARG; } bool loadAsHtml5 = true;
--- a/dom/html/test/forms/test_input_typing_sanitization.html +++ b/dom/html/test/forms/test_input_typing_sanitization.html @@ -113,17 +113,17 @@ function testSubmissions() { var valueIndex = 0; var submitMethod = submitForm; SimpleTest.waitForExplicitFinish(); function runTest() { - SimpleTest.requestLongerTimeout(2); + SimpleTest.requestLongerTimeout(4); var data = [ { type: 'number', canHaveBadInputValidityState: true, validData: [ "42", "-42", // should work for negative values
--- a/dom/icc/IccInfo.h +++ b/dom/icc/IccInfo.h @@ -74,18 +74,19 @@ protected: // we have all data fields expended here instead of having a data member of // |IccInfoData| defined in PIccTypes.h which indirectly includes "windows.h" // See 925382 for the restriction of including "windows.h" in UnifiedBindings.cpp. nsString mIccType; nsString mIccid; nsString mMcc; nsString mMnc; nsString mSpn; - bool mIsDisplayNetworkNameRequired; - bool mIsDisplaySpnRequired; + // The following booleans shall be initialized either in the constructor or in Update + MOZ_INIT_OUTSIDE_CTOR bool mIsDisplayNetworkNameRequired; + MOZ_INIT_OUTSIDE_CTOR bool mIsDisplaySpnRequired; }; class GsmIccInfo final : public IccInfo , public nsIGsmIccInfo { public: NS_DECL_ISUPPORTS_INHERITED NS_FORWARD_NSIICCINFO(IccInfo::) @@ -135,16 +136,17 @@ public: int32_t PrlVersion() const; private: ~CdmaIccInfo() {} nsString mPhoneNumber; - int32_t mPrlVersion; + // The following integer shall be initialized either in the constructor or in Update + MOZ_INIT_OUTSIDE_CTOR int32_t mPrlVersion; }; } // namespace dom } // namespace mozilla #endif // mozilla_dom_IccInfo_h
--- a/dom/interfaces/core/nsIDOMXMLDocument.idl +++ b/dom/interfaces/core/nsIDOMXMLDocument.idl @@ -1,26 +1,15 @@ /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "nsIDOMDocument.idl" +#include "nsISupports.idl" +// The only reason this interface still exists is that we have addon and Firefox +// code QIing to it and using it for instanceof via Components.interfaces, and +// the interface needs to exist in order for the shim stuff in +// xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp to work. [uuid(89ab39cb-c568-4d85-bd34-306d5cd5164d)] -interface nsIDOMXMLDocument : nsIDOMDocument +interface nsIDOMXMLDocument : nsISupports { - // DOM Level 3 Load & Save, DocumentLS - // http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS - /** - * Whether to load synchronously or asynchronously. - * The default is async==true. - */ - attribute boolean async; - - /** - * Load an XML document. - * - * @param url URL to an XML document. - * @return True if load successfull. - */ - boolean load(in DOMString url); };
--- a/dom/media/platforms/android/RemoteDataDecoder.cpp +++ b/dom/media/platforms/android/RemoteDataDecoder.cpp @@ -194,16 +194,21 @@ public: RefPtr<InitPromise> Init() override { mSurfaceTexture = AndroidSurfaceTexture::Create(); if (!mSurfaceTexture) { NS_WARNING("Failed to create SurfaceTexture for video decode\n"); return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__); } + if (!jni::IsFennec()) { + NS_WARNING("Remote decoding not supported in non-Fennec environment\n"); + return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__); + } + // Register native methods. JavaCallbacksSupport::Init(); mJavaCallbacks = CodecProxy::NativeCallbacks::New(); JavaCallbacksSupport::AttachNative(mJavaCallbacks, mozilla::MakeUnique<CallbacksSupport>(this, mCallback)); mJavaDecoder = CodecProxy::Create(mFormat, mSurfaceTexture->JavaSurface(), mJavaCallbacks);
--- a/dom/media/systemservices/CamerasChild.cpp +++ b/dom/media/systemservices/CamerasChild.cpp @@ -588,32 +588,31 @@ CamerasChild::ShutdownChild() LOG(("Shutdown called without PBackground thread")); } LOG(("Erasing sCameras & thread refs (original thread)")); CamerasSingleton::Child() = nullptr; CamerasSingleton::Thread() = nullptr; } bool -CamerasChild::RecvDeliverFrame(const int& capEngine, +CamerasChild::RecvDeliverFrame(const CaptureEngine& capEngine, const int& capId, mozilla::ipc::Shmem&& shmem, const size_t& size, const uint32_t& time_stamp, const int64_t& ntp_time, const int64_t& render_time) { MutexAutoLock lock(mCallbackMutex); - CaptureEngine capEng = static_cast<CaptureEngine>(capEngine); - if (Callback(capEng, capId)) { + if (Callback(capEngine, capId)) { unsigned char* image = shmem.get<unsigned char>(); - Callback(capEng, capId)->DeliverFrame(image, size, - time_stamp, - ntp_time, render_time, - nullptr); + Callback(capEngine, capId)->DeliverFrame(image, size, + time_stamp, + ntp_time, render_time, + nullptr); } else { LOG(("DeliverFrame called with dead callback")); } SendReleaseFrame(shmem); return true; } bool @@ -632,25 +631,24 @@ CamerasChild::SetFakeDeviceChangeEvents( // we fire a fake devicechange event in Camera IPC thread periodically RefPtr<FakeOnDeviceChangeEventRunnable> evt = new FakeOnDeviceChangeEventRunnable(0); CamerasSingleton::Thread()->Dispatch(evt.forget(), NS_DISPATCH_NORMAL); return 0; } bool -CamerasChild::RecvFrameSizeChange(const int& capEngine, +CamerasChild::RecvFrameSizeChange(const CaptureEngine& capEngine, const int& capId, const int& w, const int& h) { LOG((__PRETTY_FUNCTION__)); MutexAutoLock lock(mCallbackMutex); - CaptureEngine capEng = static_cast<CaptureEngine>(capEngine); - if (Callback(capEng, capId)) { - Callback(capEng, capId)->FrameSizeChange(w, h, 0); + if (Callback(capEngine, capId)) { + Callback(capEngine, capId)->FrameSizeChange(w, h, 0); } else { LOG(("Frame size change with dead callback")); } return true; } void CamerasChild::ActorDestroy(ActorDestroyReason aWhy)
--- a/dom/media/systemservices/CamerasChild.h +++ b/dom/media/systemservices/CamerasChild.h @@ -28,26 +28,16 @@ namespace mozilla { namespace ipc { class BackgroundChildImpl; } namespace camera { -enum CaptureEngine : int { - InvalidEngine = 0, - ScreenEngine, - BrowserEngine, - WinEngine, - AppEngine, - CameraEngine, - MaxEngine -}; - struct CapturerElement { CaptureEngine engine; int id; webrtc::ExternalRenderer* callback; }; // Forward declaration so we can work with pointers to it. class CamerasChild; @@ -148,20 +138,20 @@ class CamerasChild final : public PCamer public: // We are owned by the PBackground thread only. CamerasSingleton // takes a non-owning reference. NS_INLINE_DECL_REFCOUNTING(CamerasChild) // IPC messages recevied, received on the PBackground thread // these are the actual callbacks with data - virtual bool RecvDeliverFrame(const int&, const int&, mozilla::ipc::Shmem&&, + virtual bool RecvDeliverFrame(const CaptureEngine&, const int&, mozilla::ipc::Shmem&&, const size_t&, const uint32_t&, const int64_t&, const int64_t&) override; - virtual bool RecvFrameSizeChange(const int&, const int&, + virtual bool RecvFrameSizeChange(const CaptureEngine&, const int&, const int& w, const int& h) override; virtual bool RecvDeviceChange() override; int SetFakeDeviceChangeEvents(); // these are response messages to our outgoing requests virtual bool RecvReplyNumberOfCaptureDevices(const int&) override; virtual bool RecvReplyNumberOfCapabilities(const int&) override;
--- a/dom/media/systemservices/CamerasParent.cpp +++ b/dom/media/systemservices/CamerasParent.cpp @@ -508,17 +508,17 @@ CamerasParent::EnsureInitialized(int aEn } // Dispatch the runnable to do the camera operation on the // specific Cameras thread, preventing us from blocking, and // chain a runnable to send back the result on the IPC thread. // It would be nice to get rid of the code duplication here, // perhaps via Promises. bool -CamerasParent::RecvNumberOfCaptureDevices(const int& aCapEngine) +CamerasParent::RecvNumberOfCaptureDevices(const CaptureEngine& aCapEngine) { LOG((__PRETTY_FUNCTION__)); RefPtr<CamerasParent> self(this); RefPtr<Runnable> webrtc_runnable = media::NewRunnableFrom([self, aCapEngine]() -> nsresult { int num = -1; if (self->EnsureInitialized(aCapEngine)) { @@ -542,17 +542,17 @@ CamerasParent::RecvNumberOfCaptureDevice self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL); return NS_OK; }); DispatchToVideoCaptureThread(webrtc_runnable); return true; } bool -CamerasParent::RecvNumberOfCapabilities(const int& aCapEngine, +CamerasParent::RecvNumberOfCapabilities(const CaptureEngine& aCapEngine, const nsCString& unique_id) { LOG((__PRETTY_FUNCTION__)); LOG(("Getting caps for %s", unique_id.get())); RefPtr<CamerasParent> self(this); RefPtr<Runnable> webrtc_runnable = media::NewRunnableFrom([self, unique_id, aCapEngine]() -> nsresult { @@ -581,17 +581,17 @@ CamerasParent::RecvNumberOfCapabilities( self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL); return NS_OK; }); DispatchToVideoCaptureThread(webrtc_runnable); return true; } bool -CamerasParent::RecvGetCaptureCapability(const int &aCapEngine, +CamerasParent::RecvGetCaptureCapability(const CaptureEngine& aCapEngine, const nsCString& unique_id, const int& num) { LOG((__PRETTY_FUNCTION__)); LOG(("RecvGetCaptureCapability: %s %d", unique_id.get(), num)); RefPtr<CamerasParent> self(this); RefPtr<Runnable> webrtc_runnable = @@ -631,17 +631,17 @@ CamerasParent::RecvGetCaptureCapability( self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL); return NS_OK; }); DispatchToVideoCaptureThread(webrtc_runnable); return true; } bool -CamerasParent::RecvGetCaptureDevice(const int& aCapEngine, +CamerasParent::RecvGetCaptureDevice(const CaptureEngine& aCapEngine, const int& aListNumber) { LOG((__PRETTY_FUNCTION__)); RefPtr<CamerasParent> self(this); RefPtr<Runnable> webrtc_runnable = media::NewRunnableFrom([self, aCapEngine, aListNumber]() -> nsresult { char deviceName[MediaEngineSource::kMaxDeviceNameLength]; @@ -734,17 +734,17 @@ HasCameraPermission(const nsCString& aOr } } } } return allowed; } bool -CamerasParent::RecvAllocateCaptureDevice(const int& aCapEngine, +CamerasParent::RecvAllocateCaptureDevice(const CaptureEngine& aCapEngine, const nsCString& unique_id, const nsCString& aOrigin) { LOG(("%s: Verifying permissions for %s", __PRETTY_FUNCTION__, aOrigin.get())); RefPtr<CamerasParent> self(this); RefPtr<Runnable> mainthread_runnable = media::NewRunnableFrom([self, aCapEngine, unique_id, aOrigin]() -> nsresult { // Verify whether the claimed origin has received permission @@ -791,28 +791,28 @@ CamerasParent::RecvAllocateCaptureDevice self->DispatchToVideoCaptureThread(webrtc_runnable); return NS_OK; }); NS_DispatchToMainThread(mainthread_runnable); return true; } int -CamerasParent::ReleaseCaptureDevice(const int& aCapEngine, +CamerasParent::ReleaseCaptureDevice(const CaptureEngine& aCapEngine, const int& capnum) { int error = -1; if (EnsureInitialized(aCapEngine)) { error = mEngines[aCapEngine].mPtrViECapture->ReleaseCaptureDevice(capnum); } return error; } bool -CamerasParent::RecvReleaseCaptureDevice(const int& aCapEngine, +CamerasParent::RecvReleaseCaptureDevice(const CaptureEngine& aCapEngine, const int& numdev) { LOG((__PRETTY_FUNCTION__)); LOG(("RecvReleaseCamera device nr %d", numdev)); RefPtr<CamerasParent> self(this); RefPtr<Runnable> webrtc_runnable = media::NewRunnableFrom([self, aCapEngine, numdev]() -> nsresult { @@ -836,17 +836,17 @@ CamerasParent::RecvReleaseCaptureDevice( self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL); return NS_OK; }); DispatchToVideoCaptureThread(webrtc_runnable); return true; } bool -CamerasParent::RecvStartCapture(const int& aCapEngine, +CamerasParent::RecvStartCapture(const CaptureEngine& aCapEngine, const int& capnum, const CaptureCapability& ipcCaps) { LOG((__PRETTY_FUNCTION__)); RefPtr<CamerasParent> self(this); RefPtr<Runnable> webrtc_runnable = media::NewRunnableFrom([self, aCapEngine, capnum, ipcCaps]() -> nsresult { @@ -898,17 +898,17 @@ CamerasParent::RecvStartCapture(const in self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL); return NS_OK; }); DispatchToVideoCaptureThread(webrtc_runnable); return true; } void -CamerasParent::StopCapture(const int& aCapEngine, +CamerasParent::StopCapture(const CaptureEngine& aCapEngine, const int& capnum) { if (EnsureInitialized(aCapEngine)) { mEngines[aCapEngine].mPtrViECapture->StopCapture(capnum); mEngines[aCapEngine].mPtrViERender->StopRender(capnum); mEngines[aCapEngine].mPtrViERender->RemoveRenderer(capnum); mEngines[aCapEngine].mEngineIsRunning = false; @@ -919,17 +919,17 @@ CamerasParent::StopCapture(const int& aC mCallbacks.RemoveElementAt(i); break; } } } } bool -CamerasParent::RecvStopCapture(const int& aCapEngine, +CamerasParent::RecvStopCapture(const CaptureEngine& aCapEngine, const int& capnum) { LOG((__PRETTY_FUNCTION__)); RefPtr<CamerasParent> self(this); RefPtr<Runnable> webrtc_runnable = media::NewRunnableFrom([self, aCapEngine, capnum]() -> nsresult { self->StopCapture(aCapEngine, capnum);
--- a/dom/media/systemservices/CamerasParent.h +++ b/dom/media/systemservices/CamerasParent.h @@ -94,24 +94,29 @@ class CamerasParent : public PCamerasPa { NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIOBSERVER public: static already_AddRefed<CamerasParent> Create(); // Messages received form the child. These run on the IPC/PBackground thread. - virtual bool RecvAllocateCaptureDevice(const int&, const nsCString&, const nsCString&) override; - virtual bool RecvReleaseCaptureDevice(const int&, const int &) override; - virtual bool RecvNumberOfCaptureDevices(const int&) override; - virtual bool RecvNumberOfCapabilities(const int&, const nsCString&) override; - virtual bool RecvGetCaptureCapability(const int&, const nsCString&, const int&) override; - virtual bool RecvGetCaptureDevice(const int&, const int&) override; - virtual bool RecvStartCapture(const int&, const int&, const CaptureCapability&) override; - virtual bool RecvStopCapture(const int&, const int&) override; + virtual bool RecvAllocateCaptureDevice(const CaptureEngine&, const nsCString&, + const nsCString&) override; + virtual bool RecvReleaseCaptureDevice(const CaptureEngine&, + const int&) override; + virtual bool RecvNumberOfCaptureDevices(const CaptureEngine&) override; + virtual bool RecvNumberOfCapabilities(const CaptureEngine&, + const nsCString&) override; + virtual bool RecvGetCaptureCapability(const CaptureEngine&, const nsCString&, + const int&) override; + virtual bool RecvGetCaptureDevice(const CaptureEngine&, const int&) override; + virtual bool RecvStartCapture(const CaptureEngine&, const int&, + const CaptureCapability&) override; + virtual bool RecvStopCapture(const CaptureEngine&, const int&) override; virtual bool RecvReleaseFrame(mozilla::ipc::Shmem&&) override; virtual bool RecvAllDone() override; virtual void ActorDestroy(ActorDestroyReason aWhy) override; nsIThread* GetBackgroundThread() { return mPBackgroundThread; }; bool IsShuttingDown() { return !mChildIsAlive || mDestroyed || !mWebRTCAlive; }; @@ -129,18 +134,18 @@ public: CamerasParent(); protected: virtual ~CamerasParent(); // We use these helpers for shutdown and for the respective IPC commands. - void StopCapture(const int& aCapEngine, const int& capnum); - int ReleaseCaptureDevice(const int& aCapEngine, const int& capnum); + void StopCapture(const CaptureEngine& aCapEngine, const int& capnum); + int ReleaseCaptureDevice(const CaptureEngine& aCapEngine, const int& capnum); bool SetupEngine(CaptureEngine aCapEngine); bool EnsureInitialized(int aEngine); void CloseEngines(); void StopIPC(); void StopVideoCapture(); // Can't take already_AddRefed because it can fail in stupid ways. nsresult DispatchToVideoCaptureThread(Runnable* event);
new file mode 100644 --- /dev/null +++ b/dom/media/systemservices/CamerasTypes.h @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et ft=cpp : */ +/* 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_CamerasTypes_h +#define mozilla_CamerasTypes_h + +#include "ipc/IPCMessageUtils.h" + +namespace mozilla { + +namespace camera { + +enum CaptureEngine : int { + InvalidEngine = 0, + ScreenEngine, + BrowserEngine, + WinEngine, + AppEngine, + CameraEngine, + MaxEngine +}; + +} // namespace camera +} // namespace mozilla + +namespace IPC { +template<> +struct ParamTraits<mozilla::camera::CaptureEngine> : + public ContiguousEnumSerializer<mozilla::camera::CaptureEngine, + mozilla::camera::CaptureEngine::InvalidEngine, + mozilla::camera::CaptureEngine::MaxEngine> +{ }; +} + +#endif // mozilla_CamerasTypes_h
--- a/dom/media/systemservices/PCameras.ipdl +++ b/dom/media/systemservices/PCameras.ipdl @@ -1,15 +1,17 @@ /* 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 protocol PContent; include protocol PBackground; +using mozilla::camera::CaptureEngine from "CamerasTypes.h"; + namespace mozilla { namespace camera { struct CaptureCapability { int width; int height; int maxFPS; @@ -19,42 +21,42 @@ struct CaptureCapability bool interlaced; }; async protocol PCameras { manager PBackground; child: - async FrameSizeChange(int capEngine, int cap_id, int w, int h); + async FrameSizeChange(CaptureEngine capEngine, int cap_id, int w, int h); // transfers ownership of |buffer| from parent to child - async DeliverFrame(int capEngine, int cap_id, + async DeliverFrame(CaptureEngine capEngine, int cap_id, Shmem buffer, size_t size, uint32_t time_stamp, int64_t ntp_time, int64_t render_time); async DeviceChange(); async ReplyNumberOfCaptureDevices(int numdev); async ReplyNumberOfCapabilities(int numdev); async ReplyAllocateCaptureDevice(int numdev); async ReplyGetCaptureCapability(CaptureCapability cap); async ReplyGetCaptureDevice(nsCString device_name, nsCString device_id); async ReplyFailure(); async ReplySuccess(); async __delete__(); parent: - async NumberOfCaptureDevices(int engine); - async NumberOfCapabilities(int engine, nsCString deviceUniqueIdUTF8); + async NumberOfCaptureDevices(CaptureEngine engine); + async NumberOfCapabilities(CaptureEngine engine, nsCString deviceUniqueIdUTF8); - async GetCaptureCapability(int engine, nsCString unique_idUTF8, int capability_number); - async GetCaptureDevice(int engine, int num); + async GetCaptureCapability(CaptureEngine engine, nsCString unique_idUTF8, int capability_number); + async GetCaptureDevice(CaptureEngine engine, int num); - async AllocateCaptureDevice(int engine, nsCString unique_idUTF8, nsCString origin); - async ReleaseCaptureDevice(int engine, int numdev); - async StartCapture(int engine, int numdev, CaptureCapability capability); - async StopCapture(int engine, int numdev); + async AllocateCaptureDevice(CaptureEngine engine, nsCString unique_idUTF8, nsCString origin); + async ReleaseCaptureDevice(CaptureEngine engine, int numdev); + async StartCapture(CaptureEngine engine, int numdev, CaptureCapability capability); + async StopCapture(CaptureEngine engine, int numdev); // transfers frame back async ReleaseFrame(Shmem s); // Ask parent to delete us async AllDone(); }; } // namespace camera
--- a/dom/media/systemservices/moz.build +++ b/dom/media/systemservices/moz.build @@ -3,16 +3,17 @@ # 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/. if CONFIG['MOZ_WEBRTC']: EXPORTS += [ 'CamerasChild.h', 'CamerasParent.h', + 'CamerasTypes.h', 'LoadManager.h', 'LoadManagerFactory.h', 'LoadMonitor.h', ] UNIFIED_SOURCES += [ 'CamerasChild.cpp', 'CamerasParent.cpp', 'LoadManager.cpp',
--- a/dom/plugins/base/nsJSNPRuntime.cpp +++ b/dom/plugins/base/nsJSNPRuntime.cpp @@ -605,17 +605,17 @@ JSValToNPVariant(NPP npp, JSContext *cx, // Pass over ownership of npobj to *variant OBJECT_TO_NPVARIANT(npobj, *variant); return true; } static void -ThrowJSException(JSContext *cx, const char *message) +ThrowJSExceptionASCII(JSContext *cx, const char *message) { const char *ex = PeekException(); if (ex) { nsAutoString ucex; if (message) { AppendASCIItoUTF16(message, ucex); @@ -633,30 +633,30 @@ ThrowJSException(JSContext *cx, const ch if (str) { JS::Rooted<JS::Value> exn(cx, JS::StringValue(str)); ::JS_SetPendingException(cx, exn); } PopException(); } else { - ::JS_ReportError(cx, message); + ::JS_ReportErrorASCII(cx, message); } } static bool ReportExceptionIfPending(JSContext *cx) { const char *ex = PeekException(); if (!ex) { return true; } - ThrowJSException(cx, nullptr); + ThrowJSExceptionASCII(cx, nullptr); return false; } nsJSObjWrapper::nsJSObjWrapper(NPP npp) : mJSObj(nullptr), mNpp(npp), mDestroyPending(false) { MOZ_COUNT_CTOR(nsJSObjWrapper); @@ -731,18 +731,18 @@ nsJSObjWrapper::NP_HasMethod(NPObject *n if (NS_WARN_IF(!globalObject)) { return false; } dom::AutoEntryScript aes(globalObject, "NPAPI HasMethod"); JSContext *cx = aes.cx(); if (!npobj) { - ThrowJSException(cx, - "Null npobj in nsJSObjWrapper::NP_HasMethod!"); + ThrowJSExceptionASCII(cx, + "Null npobj in nsJSObjWrapper::NP_HasMethod!"); return false; } nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj; JSAutoCompartment ac(cx, npjsobj->mJSObj); @@ -767,17 +767,17 @@ doInvoke(NPObject *npobj, NPIdentifier m } // We're about to run script via JS_CallFunctionValue, so we need an // AutoEntryScript. NPAPI plugins are Gecko-specific and not in any spec. dom::AutoEntryScript aes(globalObject, "NPAPI doInvoke"); JSContext *cx = aes.cx(); if (!npobj || !result) { - ThrowJSException(cx, "Null npobj, or result in doInvoke!"); + ThrowJSExceptionASCII(cx, "Null npobj, or result in doInvoke!"); return false; } // Initialize *result VOID_TO_NPVARIANT(*result); nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj; @@ -859,18 +859,18 @@ nsJSObjWrapper::NP_HasProperty(NPObject if (NS_WARN_IF(!globalObject)) { return false; } dom::AutoEntryScript aes(globalObject, "NPAPI HasProperty"); JSContext *cx = aes.cx(); if (!npobj) { - ThrowJSException(cx, - "Null npobj in nsJSObjWrapper::NP_HasProperty!"); + ThrowJSExceptionASCII(cx, + "Null npobj in nsJSObjWrapper::NP_HasProperty!"); return false; } nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj; bool found, ok = false; AutoJSExceptionSuppressor suppressor(aes, npjsobj); @@ -897,18 +897,18 @@ nsJSObjWrapper::NP_GetProperty(NPObject } // We're about to run script via JS_CallFunctionValue, so we need an // AutoEntryScript. NPAPI plugins are Gecko-specific and not in any spec. dom::AutoEntryScript aes(globalObject, "NPAPI get"); JSContext *cx = aes.cx(); if (!npobj) { - ThrowJSException(cx, - "Null npobj in nsJSObjWrapper::NP_GetProperty!"); + ThrowJSExceptionASCII(cx, + "Null npobj in nsJSObjWrapper::NP_GetProperty!"); return false; } nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj; AutoJSExceptionSuppressor suppressor(aes, npjsobj); JSAutoCompartment ac(cx, npjsobj->mJSObj); @@ -931,18 +931,18 @@ nsJSObjWrapper::NP_SetProperty(NPObject } // We're about to run script via JS_CallFunctionValue, so we need an // AutoEntryScript. NPAPI plugins are Gecko-specific and not in any spec. dom::AutoEntryScript aes(globalObject, "NPAPI set"); JSContext *cx = aes.cx(); if (!npobj) { - ThrowJSException(cx, - "Null npobj in nsJSObjWrapper::NP_SetProperty!"); + ThrowJSExceptionASCII(cx, + "Null npobj in nsJSObjWrapper::NP_SetProperty!"); return false; } nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj; bool ok = false; AutoJSExceptionSuppressor suppressor(aes, npjsobj); @@ -968,18 +968,18 @@ nsJSObjWrapper::NP_RemoveProperty(NPObje if (NS_WARN_IF(!globalObject)) { return false; } dom::AutoEntryScript aes(globalObject, "NPAPI RemoveProperty"); JSContext *cx = aes.cx(); if (!npobj) { - ThrowJSException(cx, - "Null npobj in nsJSObjWrapper::NP_RemoveProperty!"); + ThrowJSExceptionASCII(cx, + "Null npobj in nsJSObjWrapper::NP_RemoveProperty!"); return false; } nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj; AutoJSExceptionSuppressor suppressor(aes, npjsobj); JS::ObjectOpResult result; @@ -1022,18 +1022,18 @@ nsJSObjWrapper::NP_Enumerate(NPObject *n dom::AutoEntryScript aes(globalObject, "NPAPI Enumerate"); JSContext *cx = aes.cx(); *idarray = 0; *count = 0; if (!npobj) { - ThrowJSException(cx, - "Null npobj in nsJSObjWrapper::NP_Enumerate!"); + ThrowJSExceptionASCII(cx, + "Null npobj in nsJSObjWrapper::NP_Enumerate!"); return false; } nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj; AutoJSExceptionSuppressor suppressor(aes, npjsobj); JS::Rooted<JSObject*> jsobj(cx, npjsobj->mJSObj); @@ -1042,17 +1042,17 @@ nsJSObjWrapper::NP_Enumerate(NPObject *n JS::Rooted<JS::IdVector> ida(cx, JS::IdVector(cx)); if (!JS_Enumerate(cx, jsobj, &ida)) { return false; } *count = ida.length(); *idarray = (NPIdentifier *)PR_Malloc(*count * sizeof(NPIdentifier)); if (!*idarray) { - ThrowJSException(cx, "Memory allocation failed for NPIdentifier!"); + ThrowJSExceptionASCII(cx, "Memory allocation failed for NPIdentifier!"); return false; } for (uint32_t i = 0; i < *count; i++) { JS::Rooted<JS::Value> v(cx); if (!JS_IdToValue(cx, ida[i], &v)) { PR_Free(*idarray); return false; @@ -1211,17 +1211,17 @@ GetNPObject(JSContext *cx, JSObject *obj // SetProperty call. static bool NPObjWrapper_AddProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::Handle<JS::Value> v) { NPObject *npobj = GetNPObject(cx, obj); if (!npobj || !npobj->_class || !npobj->_class->hasProperty || !npobj->_class->hasMethod) { - ThrowJSException(cx, "Bad NPObject as private data!"); + ThrowJSExceptionASCII(cx, "Bad NPObject as private data!"); return false; } if (NPObjectIsOutOfProcessProxy(npobj)) { return true; } @@ -1237,33 +1237,33 @@ NPObjWrapper_AddProperty(JSContext *cx, // We must permit methods here since JS_DefineUCFunction() will add // the function as a property bool hasMethod = npobj->_class->hasMethod(npobj, identifier); if (!ReportExceptionIfPending(cx)) return false; if (!hasMethod) { - ThrowJSException(cx, "Trying to add unsupported property on NPObject!"); + ThrowJSExceptionASCII(cx, "Trying to add unsupported property on NPObject!"); return false; } return true; } static bool NPObjWrapper_DelProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::ObjectOpResult &result) { NPObject *npobj = GetNPObject(cx, obj); if (!npobj || !npobj->_class || !npobj->_class->hasProperty || !npobj->_class->removeProperty) { - ThrowJSException(cx, "Bad NPObject as private data!"); + ThrowJSExceptionASCII(cx, "Bad NPObject as private data!"); return false; } PluginDestructionGuard pdg(LookupNPP(npobj)); NPIdentifier identifier = JSIdToNPIdentifier(id); @@ -1289,76 +1289,76 @@ NPObjWrapper_DelProperty(JSContext *cx, static bool NPObjWrapper_SetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp, JS::ObjectOpResult &result) { NPObject *npobj = GetNPObject(cx, obj); if (!npobj || !npobj->_class || !npobj->_class->hasProperty || !npobj->_class->setProperty) { - ThrowJSException(cx, "Bad NPObject as private data!"); + ThrowJSExceptionASCII(cx, "Bad NPObject as private data!"); return false; } // Find out what plugin (NPP) is the owner of the object we're // manipulating, and make it own any JSObject wrappers created here. NPP npp = LookupNPP(npobj); if (!npp) { - ThrowJSException(cx, "No NPP found for NPObject!"); + ThrowJSExceptionASCII(cx, "No NPP found for NPObject!"); return false; } PluginDestructionGuard pdg(npp); NPIdentifier identifier = JSIdToNPIdentifier(id); if (!NPObjectIsOutOfProcessProxy(npobj)) { bool hasProperty = npobj->_class->hasProperty(npobj, identifier); if (!ReportExceptionIfPending(cx)) return false; if (!hasProperty) { - ThrowJSException(cx, "Trying to set unsupported property on NPObject!"); + ThrowJSExceptionASCII(cx, "Trying to set unsupported property on NPObject!"); return false; } } NPVariant npv; if (!JSValToNPVariant(npp, cx, vp, &npv)) { - ThrowJSException(cx, "Error converting jsval to NPVariant!"); + ThrowJSExceptionASCII(cx, "Error converting jsval to NPVariant!"); return false; } bool ok = npobj->_class->setProperty(npobj, identifier, &npv); _releasevariantvalue(&npv); // Release the variant if (!ReportExceptionIfPending(cx)) return false; if (!ok) { - ThrowJSException(cx, "Error setting property on NPObject!"); + ThrowJSExceptionASCII(cx, "Error setting property on NPObject!"); return false; } return result.succeed(); } static bool NPObjWrapper_GetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) { NPObject *npobj = GetNPObject(cx, obj); if (!npobj || !npobj->_class || !npobj->_class->hasProperty || !npobj->_class->hasMethod || !npobj->_class->getProperty) { - ThrowJSException(cx, "Bad NPObject as private data!"); + ThrowJSExceptionASCII(cx, "Bad NPObject as private data!"); return false; } if (JSID_IS_SYMBOL(id)) { JS::RootedSymbol sym(cx, JSID_TO_SYMBOL(id)); if (JS::GetSymbolCode(sym) == JS::SymbolCode::toPrimitive) { JS::RootedObject obj(cx, JS_GetFunctionObject( @@ -1384,17 +1384,17 @@ NPObjWrapper_GetProperty(JSContext *cx, vp.setUndefined(); return true; } // Find out what plugin (NPP) is the owner of the object we're // manipulating, and make it own any JSObject wrappers created here. NPP npp = LookupNPP(npobj); if (!npp) { - ThrowJSException(cx, "No NPP found for NPObject!"); + ThrowJSExceptionASCII(cx, "No NPP found for NPObject!"); return false; } PluginDestructionGuard pdg(npp); bool hasProperty, hasMethod; @@ -1470,53 +1470,53 @@ NPObjWrapper_GetProperty(JSContext *cx, static bool CallNPMethodInternal(JSContext *cx, JS::Handle<JSObject*> obj, unsigned argc, JS::Value *argv, JS::Value *rval, bool ctorCall) { NPObject *npobj = GetNPObject(cx, obj); if (!npobj || !npobj->_class) { - ThrowJSException(cx, "Bad NPObject as private data!"); + ThrowJSExceptionASCII(cx, "Bad NPObject as private data!"); return false; } // Find out what plugin (NPP) is the owner of the object we're // manipulating, and make it own any JSObject wrappers created here. NPP npp = LookupNPP(npobj); if (!npp) { - ThrowJSException(cx, "Error finding NPP for NPObject!"); + ThrowJSExceptionASCII(cx, "Error finding NPP for NPObject!"); return false; } PluginDestructionGuard pdg(npp); NPVariant npargs_buf[8]; NPVariant *npargs = npargs_buf; if (argc > (sizeof(npargs_buf) / sizeof(NPVariant))) { // Our stack buffer isn't large enough to hold all arguments, // malloc a buffer. npargs = (NPVariant *)PR_Malloc(argc * sizeof(NPVariant)); if (!npargs) { - ThrowJSException(cx, "Out of memory!"); + ThrowJSExceptionASCII(cx, "Out of memory!"); return false; } } // Convert arguments uint32_t i; for (i = 0; i < argc; ++i) { if (!JSValToNPVariant(npp, cx, argv[i], npargs + i)) { - ThrowJSException(cx, "Error converting jsvals to NPVariants!"); + ThrowJSExceptionASCII(cx, "Error converting jsvals to NPVariants!"); if (npargs != npargs_buf) { PR_Free(npargs); } return false; } } @@ -1578,17 +1578,17 @@ CallNPMethodInternal(JSContext *cx, JS:: if (npargs != npargs_buf) { PR_Free(npargs); } if (!ok) { // ReportExceptionIfPending returns a return value, which is true // if no exception was thrown. In that case, throw our own. if (ReportExceptionIfPending(cx)) - ThrowJSException(cx, msg); + ThrowJSExceptionASCII(cx, msg); return false; } *rval = NPVariantToJSVal(npp, cx, &v); // *rval now owns the value, release our reference. _releasevariantvalue(&v); @@ -1608,35 +1608,35 @@ CallNPMethod(JSContext *cx, unsigned arg } static bool NPObjWrapper_Enumerate(JSContext *cx, JS::Handle<JSObject*> obj, JS::AutoIdVector &properties, bool enumerableOnly) { NPObject *npobj = GetNPObject(cx, obj); if (!npobj || !npobj->_class) { - ThrowJSException(cx, "Bad NPObject as private data!"); + ThrowJSExceptionASCII(cx, "Bad NPObject as private data!"); return false; } PluginDestructionGuard pdg(LookupNPP(npobj)); if (!NP_CLASS_STRUCT_VERSION_HAS_ENUM(npobj->_class) || !npobj->_class->enumerate) { return true; } NPIdentifier *identifiers; uint32_t length; if (!npobj->_class->enumerate(npobj, &identifiers, &length)) { if (ReportExceptionIfPending(cx)) { // ReportExceptionIfPending returns a return value, which is true // if no exception was thrown. In that case, throw our own. - ThrowJSException(cx, "Error enumerating properties on scriptable " - "plugin object"); + ThrowJSExceptionASCII(cx, "Error enumerating properties on scriptable " + "plugin object"); } return false; } if (!properties.reserve(length)) return false; JS::Rooted<jsid> id(cx); @@ -1657,17 +1657,17 @@ NPObjWrapper_Resolve(JSContext *cx, JS:: return true; PROFILER_LABEL_FUNC(js::ProfileEntry::Category::JS); NPObject *npobj = GetNPObject(cx, obj); if (!npobj || !npobj->_class || !npobj->_class->hasProperty || !npobj->_class->hasMethod) { - ThrowJSException(cx, "Bad NPObject as private data!"); + ThrowJSExceptionASCII(cx, "Bad NPObject as private data!"); return false; } PluginDestructionGuard pdg(LookupNPP(npobj)); NPIdentifier identifier = JSIdToNPIdentifier(id); @@ -2055,17 +2055,17 @@ LookupNPP(NPObject *npobj) static bool CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj, NPObject* npobj, JS::Handle<jsid> id, NPVariant* getPropertyResult, JS::MutableHandle<JS::Value> vp) { if (!npobj || !npobj->_class || !npobj->_class->getProperty || !npobj->_class->invoke) { - ThrowJSException(cx, "Bad NPObject"); + ThrowJSExceptionASCII(cx, "Bad NPObject"); return false; } NPObjectMemberPrivate *memberPrivate = (NPObjectMemberPrivate *)PR_Malloc(sizeof(NPObjectMemberPrivate)); if (!memberPrivate) return false; @@ -2165,40 +2165,40 @@ NPObjectMember_Call(JSContext *cx, unsig (NPObjectMemberPrivate *)::JS_GetInstancePrivate(cx, memobj, &sNPObjectMemberClass, &args); if (!memberPrivate || !memberPrivate->npobjWrapper) return false; NPObject *npobj = GetNPObject(cx, memberPrivate->npobjWrapper); if (!npobj) { - ThrowJSException(cx, "Call on invalid member object"); + ThrowJSExceptionASCII(cx, "Call on invalid member object"); return false; } NPVariant npargs_buf[8]; NPVariant *npargs = npargs_buf; if (args.length() > (sizeof(npargs_buf) / sizeof(NPVariant))) { // Our stack buffer isn't large enough to hold all arguments, // malloc a buffer. npargs = (NPVariant *)PR_Malloc(args.length() * sizeof(NPVariant)); if (!npargs) { - ThrowJSException(cx, "Out of memory!"); + ThrowJSExceptionASCII(cx, "Out of memory!"); return false; } } // Convert arguments for (uint32_t i = 0; i < args.length(); ++i) { if (!JSValToNPVariant(memberPrivate->npp, cx, args[i], npargs + i)) { - ThrowJSException(cx, "Error converting jsvals to NPVariants!"); + ThrowJSExceptionASCII(cx, "Error converting jsvals to NPVariants!"); if (npargs != npargs_buf) { PR_Free(npargs); } return false; } } @@ -2217,17 +2217,17 @@ NPObjectMember_Call(JSContext *cx, unsig if (npargs != npargs_buf) { PR_Free(npargs); } if (!ok) { // ReportExceptionIfPending returns a return value, which is true // if no exception was thrown. In that case, throw our own. if (ReportExceptionIfPending(cx)) - ThrowJSException(cx, "Error calling method on NPObject!"); + ThrowJSExceptionASCII(cx, "Error calling method on NPObject!"); return false; } args.rval().set(NPVariantToJSVal(memberPrivate->npp, cx, &npv)); // *vp now owns the value, release our reference. _releasevariantvalue(&npv); @@ -2294,18 +2294,18 @@ nsJSObjWrapper::HasOwnProperty(NPObject if (NS_WARN_IF(!globalObject)) { return false; } dom::AutoEntryScript aes(globalObject, "NPAPI HasOwnProperty"); JSContext *cx = aes.cx(); if (!npobj) { - ThrowJSException(cx, - "Null npobj in nsJSObjWrapper::NP_HasOwnProperty!"); + ThrowJSExceptionASCII(cx, + "Null npobj in nsJSObjWrapper::NP_HasOwnProperty!"); return false; } nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj; bool found, ok = false; AutoJSExceptionSuppressor suppressor(aes, npjsobj);
--- a/dom/security/test/cors/test_CrossSiteXHR.html +++ b/dom/security/test/cors/test_CrossSiteXHR.html @@ -754,30 +754,28 @@ function runTest() { is(res.didFail, true, "should have failed in test for " + test.toSource()); is(res.status, 0, "wrong status in test for " + test.toSource()); is(res.statusText, "", "wrong status text for " + test.toSource()); is(res.responseXML, null, "wrong responseXML in test for " + test.toSource()); is(res.responseText, "", "wrong responseText in test for " + test.toSource()); - var expectedProgressCount = 0; if (!res.sendThrew) { if (test.username) { - expectedProgressCount = 1; is(res.events.join(","), "opening,rs1,sending,loadstart,rs4,error,loadend", "wrong events in test for " + test.toSource()); } else { is(res.events.join(","), "opening,rs1,sending,loadstart,rs2,rs4,error,loadend", "wrong events in test for " + test.toSource()); } } - is(res.progressEvents, expectedProgressCount, + is(res.progressEvents, 0, "wrong events in test for " + test.toSource()); if (test.responseHeaders) { for (header in test.responseHeaders) { is(res.responseHeaders[header], null, "wrong response header (" + header + ") in test for " + test.toSource()); } }
--- a/dom/svg/SVGDocument.cpp +++ b/dom/svg/SVGDocument.cpp @@ -14,65 +14,31 @@ #include "nsLayoutStylesheetCache.h" #include "nsNetUtil.h" #include "nsServiceManagerUtils.h" #include "nsString.h" #include "nsLiteralString.h" #include "nsIDOMSVGElement.h" #include "mozilla/dom/Element.h" #include "nsSVGElement.h" -#include "mozilla/dom/SVGDocumentBinding.h" #include "mozilla/StyleSheet.h" #include "mozilla/StyleSheetInlines.h" using namespace mozilla::css; using namespace mozilla::dom; namespace mozilla { namespace dom { //---------------------------------------------------------------------- // Implementation //---------------------------------------------------------------------- // nsISupports methods: -void -SVGDocument::GetDomain(nsAString& aDomain, ErrorResult& aRv) -{ - SetDOMStringToNull(aDomain); - - if (mDocumentURI) { - nsAutoCString domain; - nsresult rv = mDocumentURI->GetHost(domain); - if (NS_FAILED(rv)) { - aRv.Throw(rv); - return; - } - if (domain.IsEmpty()) { - return; - } - CopyUTF8toUTF16(domain, aDomain); - } -} - -nsSVGElement* -SVGDocument::GetRootElement(ErrorResult& aRv) -{ - Element* root = nsDocument::GetRootElement(); - if (!root) { - return nullptr; - } - if (!root->IsSVGElement()) { - aRv.Throw(NS_NOINTERFACE); - return nullptr; - } - return static_cast<nsSVGElement*>(root); -} - nsresult SVGDocument::InsertChildAt(nsIContent* aKid, uint32_t aIndex, bool aNotify) { if (aKid->IsElement() && !aKid->IsSVGElement()) { // We can get here when well formed XML with a non-SVG root element is // served with the SVG MIME type, for example. In that case we need to load // the non-SVG UA sheets or else we can get bugs like bug 1016145. Note // that we have to do this _before_ the XMLDocument::InsertChildAt call, @@ -187,22 +153,16 @@ SVGDocument::EnsureNonSVGUserAgentStyleS if (nsLayoutUtils::ShouldUseNoScriptSheet(this)) { EnsureOnDemandBuiltInUASheet(cache->NoScriptSheet()); } EnsureOnDemandBuiltInUASheet(cache->UASheet()); EndUpdate(UPDATE_STYLE); } -JSObject* -SVGDocument::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) -{ - return SVGDocumentBinding::Wrap(aCx, this, aGivenProto); -} - } // namespace dom } // namespace mozilla //////////////////////////////////////////////////////////////////////// // Exported creation functions nsresult NS_NewSVGDocument(nsIDocument** aInstancePtrResult)
--- a/dom/svg/SVGDocument.h +++ b/dom/svg/SVGDocument.h @@ -28,28 +28,22 @@ public: { mType = eSVG; } virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex, bool aNotify) override; virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override; - // WebIDL API - void GetDomain(nsAString& aDomain, ErrorResult& aRv); - nsSVGElement* GetRootElement(ErrorResult& aRv); - virtual SVGDocument* AsSVGDocument() override { return this; } private: void EnsureNonSVGUserAgentStyleSheetsLoaded(); - virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override; - bool mHasLoadedNonSVGUserAgentStyleSheets; }; } // namespace dom } // namespace mozilla #endif // mozilla_dom_SVGDocument_h
--- a/dom/svg/test/test_fragments.html +++ b/dom/svg/test/test_fragments.html @@ -25,17 +25,17 @@ function Test(svgFragmentIdentifier, val this.svgFragmentIdentifier = svgFragmentIdentifier; this.valid = valid; } function runTests() { var svg = $("svg"); var doc = svg.contentWindow.document; - var rootElement = doc.rootElement; + var rootElement = doc.documentElement; var tests = [ new Test("unknown", false), new Test("svgView(viewBox(0,0,200,200))", true), new Test("svgView(preserveAspectRatio(xMaxYMin slice))", true), new Test("svgView(viewBox(1,2,3,4);preserveAspectRatio(xMinYMax))", true), new Test("svgView(viewBox(none))", true), new Test("svgView(zoomAndPan(disable))", true),
--- a/dom/tests/mochitest/bugs/test_onerror_message.html +++ b/dom/tests/mochitest/bugs/test_onerror_message.html @@ -24,17 +24,17 @@ https://bugzilla.mozilla.org/show_bug.cg var expected = [ { name: "Error", message: "foo", filename: String(location), lineNumber: 45 }, { name: "Error", message: "foo", filename: "bar", lineNumber: 123 }, { name: "", message: "uncaught exception: [object Object]" }, { name: "DuckError", message: "foo", filename: "bar", lineNumber: 123 }, { name: "", message: "uncaught exception: [object Object]" }, { name: "", message: "foo", filename: "baz", lineNumber: 123 }, { name: "", message: "uncaught exception: [object Object]" }, -{ name: "InvalidStateError", message: "An attempt was made to use an object that is not, or is no longer, usable", filename: String(location), lineNumber: 62 }, +{ name: "InvalidStateError", message: "XMLHttpRequest state must not be LOADING or DONE.", filename: String(location), lineNumber: 62 }, { name: "ReferenceError", message: "xxx is not defined", filename: String(location), lineNumber: 64 }, { name: "ReferenceError", message: "xxx is not defined", filename: String(location), lineNumber: 66 } ]; var counter = 0; var origin = location.protocol + "//" + location.host; postMessage(counter, origin); window.onmessage = function(e) {
--- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -1119,18 +1119,16 @@ var interfaceNamesInGlobalScope = "SVGClipPathElement", // IMPORTANT: Do not change this list without review from a DOM peer! "SVGComponentTransferFunctionElement", // IMPORTANT: Do not change this list without review from a DOM peer! "SVGDefsElement", // IMPORTANT: Do not change this list without review from a DOM peer! "SVGDescElement", // IMPORTANT: Do not change this list without review from a DOM peer! - "SVGDocument", -// IMPORTANT: Do not change this list without review from a DOM peer! "SVGElement", // IMPORTANT: Do not change this list without review from a DOM peer! "SVGEllipseElement", // IMPORTANT: Do not change this list without review from a DOM peer! "SVGFEBlendElement", // IMPORTANT: Do not change this list without review from a DOM peer! "SVGFEColorMatrixElement", // IMPORTANT: Do not change this list without review from a DOM peer!
deleted file mode 100644 --- a/dom/tests/mochitest/geolocation/chrome.ini +++ /dev/null @@ -1,9 +0,0 @@ -[DEFAULT] -support-files = - geolocation.html - geolocation_common.js - -[test_mozsettings.html] -skip-if = buildapp == 'b2g' || toolkit == 'android' -[test_mozsettingsWatch.html] -skip-if = buildapp == 'b2g' || toolkit == 'android'
--- a/dom/tests/mochitest/geolocation/geolocation_common.js +++ b/dom/tests/mochitest/geolocation/geolocation_common.js @@ -84,20 +84,8 @@ function check_geolocation(location) { // optional ok("speed" in coords, "Check to see if there is a speed"); ok (Math.abs(location.coords.latitude - 37.41857) < 0.001, "lat matches known value"); ok (Math.abs(location.coords.longitude + 122.08769) < 0.001, "lon matches known value"); // optional ok(location.coords.altitude == 42, "alt matches known value"); // optional ok(location.coords.altitudeAccuracy == 42, "alt acc matches known value"); } -function toggleGeolocationSetting(value, callback) { - var mozSettings = window.navigator.mozSettings; - var lock = mozSettings.createLock(); - - var geoenabled = {"geolocation.enabled": value}; - - req = lock.set(geoenabled); - req.onsuccess = function () { - ok(true, "set done"); - callback(); - } -}
deleted file mode 100644 --- a/dom/tests/mochitest/geolocation/test_mozsettings.html +++ /dev/null @@ -1,83 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=478911 ---> -<head> - <title>Test for getCurrentPosition </title> - <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="text/javascript" src="geolocation_common.js"></script> - -<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> -</head> -<body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=777594">Mozilla Bug 777594</a> -<p id="display"></p> -<div id="content" style="display: none"> - -</div> -<pre id="test"> -<script class="testbody" type="text/javascript"> - -SimpleTest.waitForExplicitFinish(); -SimpleTest.requestFlakyTimeout("untriaged"); - -var timeToWaitMs = 1000; - -resume_geolocationProvider(function() { - force_prompt(true, test2); -}); - -SpecialPowers.importInMainProcess("resource://gre/modules/SettingsRequestManager.jsm"); - -function test2() { - ok(navigator.geolocation, "get geolocation object"); - - toggleGeolocationSetting(false, function() { - ok(true, "turned off geolocation via mozSettings"); - setTimeout(function() { - navigator.geolocation.getCurrentPosition(successCallbackAfterMozsettingOff, - failureCallbackAfterMozsettingOff); - }, timeToWaitMs); // need to wait a bit for all of these async callbacks to finish - }); -} - -function successCallbackAfterMozsettingOff(position) { - ok(false, "Success callback should not have been called after setting geolocation.enabled to false."); - - toggleGeolocationSetting(true, function() { - ok(true, "turned on geolocation via mozSettings"); - setTimeout(function() { - navigator.geolocation.getCurrentPosition(successCallbackAfterMozsettingOn, - failureCallbackAfterMozsettingOn); - }, timeToWaitMs); // need to wait a bit for all of these async callbacks to finish - }); -} - -function failureCallbackAfterMozsettingOff(error) { - ok(true, "Geolocation didn't work after setting geolocation.enabled to false."); - - toggleGeolocationSetting(true, function() { - ok(true, "turned on geolocation via mozSettings"); - setTimeout(function() { - navigator.geolocation.getCurrentPosition(successCallbackAfterMozsettingOn, - failureCallbackAfterMozsettingOn); - }, timeToWaitMs); // need to wait a bit for all of these async callbacks to finish - }); -} - -function successCallbackAfterMozsettingOn(position) { - ok(true, "Geolocation worked after setting geolocation.enabled to true."); - SimpleTest.finish(); -} - -function failureCallbackAfterMozsettingOn(error) { - ok(false, "Geolocation didn't work after setting geolocation.enabled to true."); - SimpleTest.finish(); -} - -</script> -</pre> -</body> -</html> -
deleted file mode 100644 --- a/dom/tests/mochitest/geolocation/test_mozsettingsWatch.html +++ /dev/null @@ -1,88 +0,0 @@ -<!DOCTYPE HTML> -<html> -<!-- -https://bugzilla.mozilla.org/show_bug.cgi?id=478911 ---> -<head> - <title>Test for getCurrentPosition </title> - <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="text/javascript" src="geolocation_common.js"></script> - -<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> -</head> -<body> -<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=777594">Mozilla Bug 777594</a> -<p id="display"></p> -<div id="content" style="display: none"> - -</div> -<pre id="test"> -<script class="testbody" type="text/javascript"> - -SimpleTest.waitForExplicitFinish(); -SimpleTest.requestFlakyTimeout("untriaged"); - -resume_geolocationProvider(function() { - force_prompt(true, test2); -}); - -SpecialPowers.importInMainProcess("resource://gre/modules/SettingsRequestManager.jsm"); - -var watchId; -function test2() { - ok(navigator.geolocation, "get geolocation object"); - - toggleGeolocationSetting(false, function() { - ok(true, "turned off geolocation via mozSettings"); - setTimeout(function() { - watchId = navigator.geolocation.watchPosition(successCallbackAfterMozsettingOff, - failureCallbackAfterMozsettingOff); - }, 500); // need to wait a bit for all of these async callbacks to finish - }); -} - -function successCallbackAfterMozsettingOff(position) { - ok(false, "Success callback should not have been called after setting geolocation.enabled to false."); - - navigator.geolocation.clearWatch(watchId); - toggleGeolocationSetting(true, function() { - ok(true, "turned on geolocation via mozSettings"); - setTimeout(function() { - watchId = navigator.geolocation.watchPosition(successCallbackAfterMozsettingOn, - failureCallbackAfterMozsettingOn); - }, 500); // need to wait a bit for all of these async callbacks to finish - }); -} - -function failureCallbackAfterMozsettingOff(error) { - ok(true, "Geolocation didn't work after setting geolocation.enabled to false."); - - navigator.geolocation.clearWatch(watchId); - toggleGeolocationSetting(true, function() { - ok(true, "turned on geolocation via mozSettings"); - setTimeout(function() { - watchId = navigator.geolocation.watchPosition(successCallbackAfterMozsettingOn, - failureCallbackAfterMozsettingOn); - }, 500); // need to wait a bit for all of these async callbacks to finish - }); -} - -function successCallbackAfterMozsettingOn(position) { - ok(true, "Geolocation worked after setting geolocation.enabled to true."); - - navigator.geolocation.clearWatch(watchId); - SimpleTest.finish(); -} - -function failureCallbackAfterMozsettingOn(error) { - ok(false, "Geolocation didn't work after setting geolocation.enabled to true."); - - navigator.geolocation.clearWatch(watchId); - SimpleTest.finish(); -} - -</script> -</pre> -</body> -</html> -
--- a/dom/tests/moz.build +++ b/dom/tests/moz.build @@ -29,17 +29,16 @@ MOCHITEST_MANIFESTS += [ 'mochitest/webcomponents/mochitest.ini', 'mochitest/whatwg/mochitest.ini', ] MOCHITEST_CHROME_MANIFESTS += [ 'mochitest/beacon/chrome.ini', 'mochitest/chrome/chrome.ini', 'mochitest/general/chrome.ini', - 'mochitest/geolocation/chrome.ini', 'mochitest/localstorage/chrome.ini', 'mochitest/notification/chrome.ini', 'mochitest/sessionstorage/chrome.ini', 'mochitest/whatwg/chrome.ini', ] if CONFIG['MOZ_GAMEPAD']: MOCHITEST_MANIFESTS += [
--- a/dom/webidl/CSSStyleSheet.webidl +++ b/dom/webidl/CSSStyleSheet.webidl @@ -13,17 +13,17 @@ enum CSSStyleSheetParsingMode { "author", "user", "agent" }; interface CSSStyleSheet : StyleSheet { [Pure] readonly attribute CSSRule? ownerRule; - [Throws] + [Throws, NeedsSubjectPrincipal] readonly attribute CSSRuleList cssRules; [ChromeOnly, BinaryName="parsingModeDOM"] readonly attribute CSSStyleSheetParsingMode parsingMode; - [Throws] + [Throws, NeedsSubjectPrincipal] unsigned long insertRule(DOMString rule, unsigned long index); - [Throws] + [Throws, NeedsSubjectPrincipal] void deleteRule(unsigned long index); };
--- a/dom/webidl/DataTransfer.webidl +++ b/dom/webidl/DataTransfer.webidl @@ -18,17 +18,17 @@ interface DataTransfer { void setDragImage(Element image, long x, long y); [Throws] readonly attribute DOMStringList types; [Throws] DOMString getData(DOMString format); [Throws] void setData(DOMString format, DOMString data); - [Throws] + [Throws, NeedsSubjectPrincipal] void clearData(optional DOMString format); [Throws] readonly attribute FileList? files; }; partial interface DataTransfer { [Throws, Pref="dom.input.dirpicker"] Promise<sequence<(File or Directory)>> getFilesAndDirectories(); @@ -86,17 +86,17 @@ partial interface DataTransfer { * * If format is empty, then the data associated with all formats is removed. * If the format is not found, then this method has no effect. * * @param format the format to remove * @throws NS_ERROR_DOM_INDEX_SIZE_ERR if index is greater or equal than itemCount * @throws NO_MODIFICATION_ALLOWED_ERR if the item cannot be modified */ - [Throws] + [Throws, NeedsSubjectPrincipal] void mozClearDataAt(DOMString format, unsigned long index); /* * A data transfer may store multiple items, each at a given zero-based * index. setDataAt may only be called with an index argument less than * itemCount in which case an existing item is modified, or equal to * itemCount in which case a new item is added, and the itemCount is * incremented by one.
--- a/dom/webidl/DataTransferItem.webidl +++ b/dom/webidl/DataTransferItem.webidl @@ -5,20 +5,21 @@ * * The origin of this IDL file is: * https://html.spec.whatwg.org/multipage/interaction.html#the-datatransferitem-interface */ interface DataTransferItem { readonly attribute DOMString kind; readonly attribute DOMString type; - [Throws] + [Throws, NeedsSubjectPrincipal] void getAsString(FunctionStringCallback? _callback); - [Throws] + [Throws, NeedsSubjectPrincipal] File? getAsFile(); }; callback FunctionStringCallback = void (DOMString data); partial interface DataTransferItem { - [Pref="dom.webkitBlink.filesystem.enabled", BinaryName="getAsEntry", Throws] + [Pref="dom.webkitBlink.filesystem.enabled", BinaryName="getAsEntry", Throws, + NeedsSubjectPrincipal] FileSystemEntry? webkitGetAsEntry(); };
--- a/dom/webidl/DataTransferItemList.webidl +++ b/dom/webidl/DataTransferItemList.webidl @@ -6,17 +6,17 @@ * The origin of this IDL file is: * https://html.spec.whatwg.org/multipage/interaction.html#the-datatransferitemlist-interface */ interface DataTransferItemList { readonly attribute unsigned long length; [Throws] getter DataTransferItem (unsigned long index); - [Throws] + [Throws, NeedsSubjectPrincipal] DataTransferItem? add(DOMString data, DOMString type); - [Throws] + [Throws, NeedsSubjectPrincipal] DataTransferItem? add(File data); - [Throws] + [Throws, NeedsSubjectPrincipal] void remove(unsigned long index); - [Throws] + [Throws, NeedsSubjectPrincipal] void clear(); };
--- a/dom/webidl/Document.webidl +++ b/dom/webidl/Document.webidl @@ -322,16 +322,22 @@ partial interface Document { // http://w3c.github.io/web-animations/#extensions-to-the-document-interface partial interface Document { [Func="nsDocument::IsWebAnimationsEnabled"] readonly attribute DocumentTimeline timeline; [Func="nsDocument::IsWebAnimationsEnabled"] sequence<Animation> getAnimations(); }; +// https://svgwg.org/svg2-draft/struct.html#InterfaceDocumentExtensions +partial interface Document { + [BinaryName="SVGRootElement"] + readonly attribute SVGSVGElement? rootElement; +}; + // Mozilla extensions of various sorts partial interface Document { // nsIDOMDocumentXBL. Wish we could make these [ChromeOnly], but // that would likely break bindings running with the page principal. [Func="IsChromeOrXBL"] NodeList? getAnonymousNodes(Element elt); [Func="IsChromeOrXBL"] Element? getAnonymousElementByAttribute(Element elt, DOMString attrName,
--- a/dom/webidl/HTMLCanvasElement.webidl +++ b/dom/webidl/HTMLCanvasElement.webidl @@ -5,17 +5,16 @@ * * The origin of this IDL file is * http://www.whatwg.org/specs/web-apps/current-work/#the-canvas-element * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and * Opera Software ASA. You are granted a license to use, reproduce * and create derivative works of this document. */ -interface nsIInputStreamCallback; interface nsISupports; interface Variant; interface HTMLCanvasElement : HTMLElement { [Pure, SetterThrows] attribute unsigned long width; [Pure, SetterThrows] attribute unsigned long height;
--- a/dom/webidl/Location.webidl +++ b/dom/webidl/Location.webidl @@ -12,42 +12,42 @@ */ [Unforgeable, NonOrdinaryGetPrototypeOf] interface Location { // Bug 824857: no support for stringifier attributes yet. // stringifier attribute USVString href; // Bug 824857 should remove this. - [Throws] + [Throws, NeedsSubjectPrincipal] stringifier; - [Throws, CrossOriginWritable] + [Throws, CrossOriginWritable, NeedsSubjectPrincipal] attribute USVString href; - [Throws] + [Throws, NeedsSubjectPrincipal] readonly attribute USVString origin; - [Throws] + [Throws, NeedsSubjectPrincipal] attribute USVString protocol; - [Throws] + [Throws, NeedsSubjectPrincipal] attribute USVString host; - [Throws] + [Throws, NeedsSubjectPrincipal] attribute USVString hostname; - [Throws] + [Throws, NeedsSubjectPrincipal] attribute USVString port; - [Throws] + [Throws, NeedsSubjectPrincipal] attribute USVString pathname; - [Throws] + [Throws, NeedsSubjectPrincipal] attribute USVString search; - [Throws] + [Throws, NeedsSubjectPrincipal] attribute USVString hash; - [Throws, UnsafeInPrerendering] + [Throws, UnsafeInPrerendering, NeedsSubjectPrincipal] void assign(USVString url); - [Throws, CrossOriginCallable, UnsafeInPrerendering] + [Throws, CrossOriginCallable, UnsafeInPrerendering, NeedsSubjectPrincipal] void replace(USVString url); // XXXbz there is no forceget argument in the spec! See bug 1037721. - [Throws, UnsafeInPrerendering] + [Throws, UnsafeInPrerendering, NeedsSubjectPrincipal] void reload(optional boolean forceget = false); // Bug 1085214 [SameObject] readonly attribute USVString[] ancestorOrigins; };
deleted file mode 100644 --- a/dom/webidl/SVGDocument.webidl +++ /dev/null @@ -1,15 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - * - * The origin of this IDL file is: - * dom/interfaces/svg/nsIDOMSVGDocument.idl - */ - -interface SVGDocument : Document { - [Throws] - readonly attribute DOMString domain; - [Pure, Throws] - readonly attribute SVGElement? rootElement; -};
--- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -467,17 +467,16 @@ WEBIDL_FILES = [ 'SVGAnimateMotionElement.webidl', 'SVGAnimateTransformElement.webidl', 'SVGAnimationElement.webidl', 'SVGCircleElement.webidl', 'SVGClipPathElement.webidl', 'SVGComponentTransferFunctionElement.webidl', 'SVGDefsElement.webidl', 'SVGDescElement.webidl', - 'SVGDocument.webidl', 'SVGElement.webidl', 'SVGEllipseElement.webidl', 'SVGFEBlendElement.webidl', 'SVGFEColorMatrixElement.webidl', 'SVGFEComponentTransferElement.webidl', 'SVGFECompositeElement.webidl', 'SVGFEConvolveMatrixElement.webidl', 'SVGFEDiffuseLightingElement.webidl',
--- a/dom/workers/ChromeWorkerScope.cpp +++ b/dom/workers/ChromeWorkerScope.cpp @@ -23,17 +23,17 @@ namespace { char* UnicodeToNative(JSContext* aCx, const char16_t* aSource, size_t aSourceLen) { nsDependentString unicode(aSource, aSourceLen); nsAutoCString native; if (NS_FAILED(NS_CopyUnicodeToNative(unicode, native))) { - JS_ReportError(aCx, "Could not convert string to native charset!"); + JS_ReportErrorASCII(aCx, "Could not convert string to native charset!"); return nullptr; } char* result = static_cast<char*>(JS_malloc(aCx, native.Length() + 1)); if (!result) { return nullptr; }
--- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -6136,17 +6136,17 @@ WorkerPrivate::RescheduleTimeoutTimer(JS (mTimeouts[0]->mTargetTime - TimeStamp::Now()).ToMilliseconds(); uint32_t delay = delta > 0 ? std::min(delta, double(UINT32_MAX)) : 0; LOG(TimeoutsLog(), ("Worker %p scheduled timer for %d ms, %d pending timeouts\n", this, delay, mTimeouts.Length())); nsresult rv = mTimer->InitWithCallback(mTimerRunnable, delay, nsITimer::TYPE_ONE_SHOT); if (NS_FAILED(rv)) { - JS_ReportError(aCx, "Failed to start timer!"); + JS_ReportErrorASCII(aCx, "Failed to start timer!"); return false; } return true; } void WorkerPrivate::UpdateContextOptionsInternal(
--- a/dom/xhr/XMLHttpRequestMainThread.cpp +++ b/dom/xhr/XMLHttpRequestMainThread.cpp @@ -11,16 +11,17 @@ #include <unistd.h> #endif #include "mozilla/ArrayUtils.h" #include "mozilla/CheckedInt.h" #include "mozilla/dom/BlobSet.h" #include "mozilla/dom/File.h" #include "mozilla/dom/FetchUtil.h" #include "mozilla/dom/FormData.h" +#include "mozilla/dom/MutableBlobStorage.h" #include "mozilla/dom/XMLDocument.h" #include "mozilla/dom/URLSearchParams.h" #include "mozilla/EventDispatcher.h" #include "mozilla/EventListenerManager.h" #include "mozilla/LoadInfo.h" #include "mozilla/LoadContext.h" #include "mozilla/MemoryReporting.h" #include "nsIDOMDocument.h" @@ -66,16 +67,17 @@ #include "nsIFileChannel.h" #include "mozilla/Telemetry.h" #include "jsfriendapi.h" #include "GeckoProfiler.h" #include "mozilla/dom/EncodingUtils.h" #include "nsIUnicodeDecoder.h" #include "mozilla/dom/XMLHttpRequestBinding.h" #include "mozilla/Attributes.h" +#include "MultipartBlobImpl.h" #include "nsIPermissionManager.h" #include "nsMimeTypes.h" #include "nsIHttpChannelInternal.h" #include "nsIClassOfService.h" #include "nsCharSeparatedTokenizer.h" #include "nsStreamListenerWrapper.h" #include "xpcjsid.h" #include "nsITimedChannel.h" @@ -286,16 +288,17 @@ XMLHttpRequestMainThread::InitParameters void XMLHttpRequestMainThread::ResetResponse() { mResponseXML = nullptr; mResponseBody.Truncate(); TruncateResponseText(); mResponseBlob = nullptr; mDOMBlob = nullptr; + mBlobStorage = nullptr; mBlobSet = nullptr; mResultArrayBuffer = nullptr; mArrayBufferBuilder.reset(); mResultJSON.setUndefined(); mDataAvailable = 0; mLoadTransferred = 0; mResponseBodyDecodedPos = 0; } @@ -468,17 +471,17 @@ XMLHttpRequestMainThread::GetResponseXML return CallQueryInterface(responseXML, aResponseXML); } nsIDocument* XMLHttpRequestMainThread::GetResponseXML(ErrorResult& aRv) { if (mResponseType != XMLHttpRequestResponseType::_empty && mResponseType != XMLHttpRequestResponseType::Document) { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_HAS_WRONG_RESPONSETYPE_FOR_RESPONSEXML); return nullptr; } if (mWarnAboutSyncHtml) { mWarnAboutSyncHtml = false; LogMessage("HTMLSyncXHRWarning", GetOwner()); } if (mState != State::done) { return nullptr; @@ -590,17 +593,17 @@ void XMLHttpRequestMainThread::GetResponseText(XMLHttpRequestStringSnapshot& aSnapshot, ErrorResult& aRv) { aSnapshot.Reset(); if (mResponseType != XMLHttpRequestResponseType::_empty && mResponseType != XMLHttpRequestResponseType::Text && mResponseType != XMLHttpRequestResponseType::Moz_chunked_text) { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_HAS_WRONG_RESPONSETYPE_FOR_RESPONSETEXT); return; } if (mResponseType == XMLHttpRequestResponseType::Moz_chunked_text && !mInLoadProgressEvent) { aSnapshot.SetVoid(); return; } @@ -682,17 +685,26 @@ XMLHttpRequestMainThread::CreatePartialB return; } nsAutoCString contentType; if (mLoadTotal == mLoadTransferred) { mChannel->GetContentType(contentType); } - mResponseBlob = mBlobSet->GetBlobInternal(GetOwner(), contentType, aRv); + nsTArray<RefPtr<BlobImpl>> subImpls(mBlobSet->GetBlobImpls()); + RefPtr<BlobImpl> blobImpl = + MultipartBlobImpl::Create(Move(subImpls), + NS_ConvertASCIItoUTF16(contentType), + aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + mResponseBlob = Blob::Create(GetOwner(), blobImpl); } NS_IMETHODIMP XMLHttpRequestMainThread::GetResponseType(nsAString& aResponseType) { MOZ_ASSERT(mResponseType < XMLHttpRequestResponseType::EndGuard_); const EnumEntry& entry = XMLHttpRequestResponseTypeValues::strings[static_cast<uint32_t>(mResponseType)]; aResponseType.AssignASCII(entry.value, entry.length); @@ -713,34 +725,32 @@ NS_IMETHODIMP XMLHttpRequestMainThread:: return NS_OK; } void XMLHttpRequestMainThread::SetResponseType(XMLHttpRequestResponseType aResponseType, ErrorResult& aRv) { - // If the state is LOADING or DONE raise an INVALID_STATE_ERR exception - // and terminate these steps. if (mState == State::loading || mState == State::done) { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_LOADING_OR_DONE); return; } // sync request is not allowed setting responseType in window context if (HasOrHasHadOwner() && mState != State::unsent && mFlagSynchronous) { LogMessage("ResponseTypeSyncXHRWarning", GetOwner()); - aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); + aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_XHR_TIMEOUT_AND_RESPONSETYPE_UNSUPPORTED_FOR_SYNC); return; } if (mFlagSynchronous && (aResponseType == XMLHttpRequestResponseType::Moz_chunked_text || aResponseType == XMLHttpRequestResponseType::Moz_chunked_arraybuffer)) { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_CHUNKED_RESPONSETYPES_UNSUPPORTED_FOR_SYNC); return; } // Set the responseType attribute's value to the given value. mResponseType = aResponseType; } NS_IMETHODIMP @@ -1033,20 +1043,18 @@ XMLHttpRequestMainThread::CloseRequestWi if (mState != State::unsent && !(mState == State::opened && !mFlagSend) && mState != State::done) { ChangeState(State::done, true); if (!mFlagSyncLooping) { if (mUpload && !mUploadComplete) { mUploadComplete = true; - DispatchProgressEvent(mUpload, ProgressEventType::progress, 0, 0); DispatchProgressEvent(mUpload, aType, 0, 0); } - DispatchProgressEvent(this, ProgressEventType::progress, 0, 0); DispatchProgressEvent(this, aType, 0, 0); } } // The ChangeState call above calls onreadystatechange handlers which // if they load a new url will cause XMLHttpRequestMainThread::Open to clear // the abort state bit. If this occurs we're not uninitialized (bug 361773). if (mFlagAborted) { @@ -1436,17 +1444,17 @@ XMLHttpRequestMainThread::Open(const nsA // Step 1 nsCOMPtr<nsIDocument> responsibleDocument = GetDocumentIfCurrent(); if (!responsibleDocument) { // This could be because we're no longer current or because we're in some // non-window context... nsresult rv = CheckInnerWindowCorrectness(); if (NS_WARN_IF(NS_FAILED(rv))) { - return NS_ERROR_DOM_INVALID_STATE_ERR; + return NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT; } } NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED); // Steps 2-4 nsAutoCString method; nsresult rv = FetchUtil::GetValidRequestMethod(aMethod, method); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -1459,22 +1467,22 @@ XMLHttpRequestMainThread::Open(const nsA baseURI = mBaseURI; } else if (responsibleDocument) { baseURI = responsibleDocument->GetBaseURI(); } nsCOMPtr<nsIURI> parsedURL; rv = NS_NewURI(getter_AddRefs(parsedURL), aUrl, nullptr, baseURI); if (NS_FAILED(rv)) { if (rv == NS_ERROR_MALFORMED_URI) { - return NS_ERROR_DOM_SYNTAX_ERR; + return NS_ERROR_DOM_MALFORMED_URI; } return rv; } if (NS_WARN_IF(NS_FAILED(CheckInnerWindowCorrectness()))) { - return NS_ERROR_DOM_INVALID_STATE_ERR; + return NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT; } // Step 7 // This is already handled by the other Open() method, which passes // username and password in as NullStrings. // Step 8 nsAutoCString host; @@ -1495,17 +1503,17 @@ XMLHttpRequestMainThread::Open(const nsA if (!aAsync && HasOrHasHadOwner() && (mTimeoutMilliseconds || mResponseType != XMLHttpRequestResponseType::_empty)) { if (mTimeoutMilliseconds) { LogMessage("TimeoutSyncXHRWarning", GetOwner()); } if (mResponseType != XMLHttpRequestResponseType::_empty) { LogMessage("ResponseTypeSyncXHRWarning", GetOwner()); } - return NS_ERROR_DOM_INVALID_ACCESS_ERR; + return NS_ERROR_DOM_INVALID_ACCESS_XHR_TIMEOUT_AND_RESPONSETYPE_UNSUPPORTED_FOR_SYNC; } // Step 10 CloseRequest(); // Step 11 // timeouts are handled without a flag mFlagSend = false; @@ -1576,28 +1584,30 @@ XMLHttpRequestMainThread::StreamReaderFu XMLHttpRequestMainThread* xmlHttpRequest = static_cast<XMLHttpRequestMainThread*>(closure); if (!xmlHttpRequest || !writeCount) { NS_WARNING("XMLHttpRequest cannot read from stream: no closure or writeCount"); return NS_ERROR_FAILURE; } nsresult rv = NS_OK; - if (xmlHttpRequest->mResponseType == XMLHttpRequestResponseType::Blob || - xmlHttpRequest->mResponseType == XMLHttpRequestResponseType::Moz_blob) { + if (xmlHttpRequest->mResponseType == XMLHttpRequestResponseType::Blob) { + if (!xmlHttpRequest->mDOMBlob) { + xmlHttpRequest->MaybeCreateBlobStorage(); + rv = xmlHttpRequest->mBlobStorage->Append(fromRawSegment, count); + } + } else if (xmlHttpRequest->mResponseType == XMLHttpRequestResponseType::Moz_blob) { if (!xmlHttpRequest->mDOMBlob) { if (!xmlHttpRequest->mBlobSet) { xmlHttpRequest->mBlobSet = new BlobSet(); } rv = xmlHttpRequest->mBlobSet->AppendVoidPtr(fromRawSegment, count); } // Clear the cache so that the blob size is updated. - if (xmlHttpRequest->mResponseType == XMLHttpRequestResponseType::Moz_blob) { - xmlHttpRequest->mResponseBlob = nullptr; - } + xmlHttpRequest->mResponseBlob = nullptr; } else if ((xmlHttpRequest->mResponseType == XMLHttpRequestResponseType::Arraybuffer && !xmlHttpRequest->mIsMappedArrayBuffer) || xmlHttpRequest->mResponseType == XMLHttpRequestResponseType::Moz_chunked_arraybuffer) { // get the initial capacity to something reasonable to avoid a bunch of reallocs right // at the start if (xmlHttpRequest->mArrayBufferBuilder.capacity() == 0) xmlHttpRequest->mArrayBufferBuilder.setCapacity(std::max(count, XML_HTTP_REQUEST_ARRAYBUFFER_MIN_SIZE)); @@ -1663,16 +1673,17 @@ bool XMLHttpRequestMainThread::CreateDOM return false; nsAutoCString contentType; mChannel->GetContentType(contentType); mDOMBlob = File::CreateFromFile(GetOwner(), file, EmptyString(), NS_ConvertASCIItoUTF16(contentType)); + mBlobStorage = nullptr; mBlobSet = nullptr; NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty"); return true; } NS_IMETHODIMP XMLHttpRequestMainThread::OnDataAvailable(nsIRequest *request, nsISupports *ctxt, @@ -1903,17 +1914,17 @@ XMLHttpRequestMainThread::OnStartRequest nsCOMPtr<nsIURI> chromeXHRDocURI, chromeXHRDocBaseURI; if (doc) { chromeXHRDocURI = doc->GetDocumentURI(); chromeXHRDocBaseURI = doc->GetBaseURI(); } else { // If we're no longer current, just kill the load, though it really should // have been killed already. if (NS_WARN_IF(NS_FAILED(CheckInnerWindowCorrectness()))) { - return NS_ERROR_DOM_INVALID_STATE_ERR; + return NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT; } } // Create an empty document from it. const nsAString& emptyStr = EmptyString(); nsCOMPtr<nsIDOMDocument> responseDoc; nsIGlobalObject* global = DOMEventTargetHelper::GetParentObject(); @@ -2018,54 +2029,76 @@ XMLHttpRequestMainThread::OnStopRequest( // Is this good enough here? if (mXMLParserStreamListener && mFlagParseBody) { mXMLParserStreamListener->OnStopRequest(request, ctxt, status); } mXMLParserStreamListener = nullptr; mContext = nullptr; + bool waitingForBlobCreation = false; + if (NS_SUCCEEDED(status) && (mResponseType == XMLHttpRequestResponseType::_empty || mResponseType == XMLHttpRequestResponseType::Text)) { mLoadTotal = mResponseBody.Length(); } else if (NS_SUCCEEDED(status) && (mResponseType == XMLHttpRequestResponseType::Blob || mResponseType == XMLHttpRequestResponseType::Moz_blob)) { ErrorResult rv; if (!mDOMBlob) { CreateDOMBlob(request); } if (mDOMBlob) { mResponseBlob = mDOMBlob; mDOMBlob = nullptr; + + mLoadTotal = mResponseBlob->GetSize(rv); + if (NS_WARN_IF(rv.Failed())) { + status = rv.StealNSResult(); + } } else { - // mBlobSet can be null if the channel is non-file non-cacheable - // and if the response length is zero. - if (!mBlobSet) { - mBlobSet = new BlobSet(); - } // Smaller files may be written in cache map instead of separate files. // Also, no-store response cannot be written in persistent cache. nsAutoCString contentType; mChannel->GetContentType(contentType); - mResponseBlob = mBlobSet->GetBlobInternal(GetOwner(), contentType, rv); - mBlobSet = nullptr; - - if (NS_WARN_IF(rv.Failed())) { - return rv.StealNSResult(); + if (mResponseType == XMLHttpRequestResponseType::Blob) { + // mBlobStorage can be null if the channel is non-file non-cacheable + // and if the response length is zero. + MaybeCreateBlobStorage(); + mLoadTotal = + mBlobStorage->GetBlobWhenReady(GetOwner(), contentType, this); + waitingForBlobCreation = true; + } else { + // mBlobSet can be null if the channel is non-file non-cacheable + // and if the response length is zero. + if (!mBlobSet) { + mBlobSet = new BlobSet(); + } + + nsTArray<RefPtr<BlobImpl>> subImpls(mBlobSet->GetBlobImpls()); + RefPtr<BlobImpl> blobImpl = + MultipartBlobImpl::Create(Move(subImpls), + NS_ConvertASCIItoUTF16(contentType), + rv); + mBlobSet = nullptr; + + if (NS_WARN_IF(rv.Failed())) { + return rv.StealNSResult(); + } + + mResponseBlob = Blob::Create(GetOwner(), blobImpl); + mLoadTotal = mResponseBlob->GetSize(rv); + if (NS_WARN_IF(rv.Failed())) { + status = rv.StealNSResult(); + } } } - mLoadTotal = mResponseBlob->GetSize(rv); - if (NS_WARN_IF(rv.Failed())) { - status = rv.StealNSResult(); - } - NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty"); NS_ASSERTION(mResponseText.IsEmpty(), "mResponseText should be empty"); } else if (NS_SUCCEEDED(status) && ((mResponseType == XMLHttpRequestResponseType::Arraybuffer && !mIsMappedArrayBuffer) || mResponseType == XMLHttpRequestResponseType::Moz_chunked_arraybuffer)) { // set the capacity down to the actual length, to realloc back // down to the actual size @@ -2102,17 +2135,22 @@ XMLHttpRequestMainThread::OnStopRequest( // earlier and listeners have already been notified. Also we do // not want to do this if we already completed. if (mState == State::unsent || mState == State::done) { return NS_OK; } if (!mResponseXML) { mFlagParseBody = false; - ChangeStateToDone(); + + //We postpone the 'done' until the creation of the Blob is completed. + if (!waitingForBlobCreation) { + ChangeStateToDone(); + } + return NS_OK; } if (mIsHtml) { NS_ASSERTION(!mFlagSyncLooping, "We weren't supposed to support HTML parsing with XHR!"); nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(mResponseXML); EventListenerManager* manager = @@ -2179,20 +2217,19 @@ XMLHttpRequestMainThread::ChangeStateToD DispatchProgressEvent(this, ProgressEventType::progress, mLoadTransferred, mLoadTotal); mProgressSinceLastProgressEvent = false; } // Per spec, fire readystatechange=4/done before final error events. ChangeState(State::done, true); - // Per spec, if we failed in the upload phase, fire a final progress, error, - // and loadend event for the upload after readystatechange=4/done. + // Per spec, if we failed in the upload phase, fire a final error + // and loadend events for the upload after readystatechange=4/done. if (!mFlagSynchronous && mUpload && !mUploadComplete) { - DispatchProgressEvent(mUpload, ProgressEventType::progress, 0, 0); DispatchProgressEvent(mUpload, ProgressEventType::error, 0, 0); } // Per spec, fire download's load/error and loadend events after // readystatechange=4/done (and of course all upload events). DispatchProgressEvent(this, mErrorLoad ? ProgressEventType::error : ProgressEventType::load, @@ -2752,24 +2789,29 @@ XMLHttpRequestMainThread::Send(nsIVarian return SendInternal(&body); } nsresult XMLHttpRequestMainThread::SendInternal(const RequestBodyBase* aBody) { NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED); - // Steps 1 and 2 - if (mState != State::opened || mFlagSend) { - return NS_ERROR_DOM_INVALID_STATE_ERR; + // Step 1 + if (mState != State::opened) { + return NS_ERROR_DOM_INVALID_STATE_XHR_MUST_BE_OPENED; + } + + // Step 2 + if (mFlagSend) { + return NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_SENDING; } nsresult rv = CheckInnerWindowCorrectness(); if (NS_FAILED(rv)) { - return NS_ERROR_DOM_INVALID_STATE_ERR; + return NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT; } // If open() failed to create the channel, then throw a network error // as per spec. We really should create the channel here in send(), but // we have internal code relying on the channel being created in open(). if (!mChannel) { return NS_ERROR_DOM_NETWORK_ERR; } @@ -2947,29 +2989,34 @@ XMLHttpRequestMainThread::SendInternal(c return rv; } // http://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-setrequestheader NS_IMETHODIMP XMLHttpRequestMainThread::SetRequestHeader(const nsACString& aName, const nsACString& aValue) { - // Steps 1 and 2 - if (mState != State::opened || mFlagSend) { - return NS_ERROR_DOM_INVALID_STATE_ERR; + // Step 1 + if (mState != State::opened) { + return NS_ERROR_DOM_INVALID_STATE_XHR_MUST_BE_OPENED; + } + + // Step 2 + if (mFlagSend) { + return NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_SENDING; } // Step 3 nsAutoCString value(aValue); static const char kHTTPWhitespace[] = "\n\t\r "; value.Trim(kHTTPWhitespace); // Step 4 if (!NS_IsValidHTTPToken(aName) || !NS_IsReasonableHTTPHeaderValue(value)) { - return NS_ERROR_DOM_SYNTAX_ERR; + return NS_ERROR_DOM_INVALID_HEADER_NAME; } // Step 5 bool isPrivilegedCaller = IsSystemXHR(); bool isForbiddenHeader = nsContentUtils::IsForbiddenRequestHeader(aName); if (!isPrivilegedCaller && isForbiddenHeader) { const char16_t* params[] = { NS_ConvertUTF8toUTF16(aName).get() }; LogMessage("ForbiddenHeaderWarning", GetOwner(), params, ArrayLength(params)); @@ -3009,17 +3056,17 @@ XMLHttpRequestMainThread::SetTimeout(uin void XMLHttpRequestMainThread::SetTimeout(uint32_t aTimeout, ErrorResult& aRv) { if (mFlagSynchronous && mState != State::unsent && HasOrHasHadOwner()) { /* Timeout is not supported for synchronous requests with an owning window, per XHR2 spec. */ LogMessage("TimeoutSyncXHRWarning", GetOwner()); - aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); + aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_XHR_TIMEOUT_AND_RESPONSETYPE_UNSUPPORTED_FOR_SYNC); return; } mTimeoutMilliseconds = aTimeout; if (mRequestSentTime) { StartTimeoutTimer(); } } @@ -3081,17 +3128,17 @@ XMLHttpRequestMainThread::ReadyState() c } return 0; } void XMLHttpRequestMainThread::OverrideMimeType(const nsAString& aMimeType, ErrorResult& aRv) { if (mState == State::loading || mState == State::done) { ResetResponse(); - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_LOADING_OR_DONE); return; } mOverrideMimeType = aMimeType; } NS_IMETHODIMP XMLHttpRequestMainThread::SlowOverrideMimeType(const nsAString& aMimeType) @@ -3118,17 +3165,17 @@ NS_IMETHODIMP XMLHttpRequestMainThread::SetMozBackgroundRequest(bool aMozBackgroundRequest) { if (!IsSystemXHR()) { return NS_ERROR_DOM_SECURITY_ERR; } if (mState != State::unsent) { // Can't change this while we're in the middle of something. - return NS_ERROR_IN_PROGRESS; + return NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_SENDING; } mFlagBackgroundRequest = aMozBackgroundRequest; return NS_OK; } void @@ -3161,19 +3208,20 @@ XMLHttpRequestMainThread::SetWithCredent } void XMLHttpRequestMainThread::SetWithCredentials(bool aWithCredentials, ErrorResult& aRv) { // Return error if we're already processing a request. Note that we can't use // ReadyState() here, because it can't differentiate between "opened" and // "sent", so we use mState directly. + if ((mState != State::unsent && mState != State::opened) || mFlagSend || mIsAnon) { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_SENDING); return; } mFlagACwithCredentials = aWithCredentials; } nsresult XMLHttpRequestMainThread::ChangeState(State aState, bool aBroadcast) @@ -3578,16 +3626,56 @@ nsHeaderVisitor::VisitHeader(const nsACS mHeaders.Append(header); mHeaders.AppendLiteral(": "); mHeaders.Append(value); mHeaders.AppendLiteral("\r\n"); } return NS_OK; } +void +XMLHttpRequestMainThread::MaybeCreateBlobStorage() +{ + MOZ_ASSERT(mResponseType == XMLHttpRequestResponseType::Blob); + + if (mBlobStorage) { + return; + } + + MutableBlobStorage::MutableBlobStorageType storageType = + BasePrincipal::Cast(mPrincipal)->PrivateBrowsingId() == 0 + ? MutableBlobStorage::eCouldBeInTemporaryFile + : MutableBlobStorage::eOnlyInMemory; + + mBlobStorage = new MutableBlobStorage(storageType); +} + +void +XMLHttpRequestMainThread::BlobStoreCompleted(MutableBlobStorage* aBlobStorage, + Blob* aBlob, nsresult aRv) +{ + // Ok, the state is changed... + if (mBlobStorage != aBlobStorage || NS_FAILED(aRv)) { + return; + } + + MOZ_ASSERT(mState != State::done); + + mResponseBlob = aBlob; + mBlobStorage = nullptr; + + ErrorResult rv; + mLoadTotal = mResponseBlob->GetSize(rv); + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + } + + ChangeStateToDone(); +} + // nsXMLHttpRequestXPCOMifier implementation NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXMLHttpRequestXPCOMifier) NS_INTERFACE_MAP_ENTRY(nsIStreamListener) NS_INTERFACE_MAP_ENTRY(nsIRequestObserver) NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink) NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback) NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink) NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
--- a/dom/xhr/XMLHttpRequestMainThread.h +++ b/dom/xhr/XMLHttpRequestMainThread.h @@ -29,16 +29,17 @@ #include "nsISizeOfEventTarget.h" #include "nsIXPConnect.h" #include "nsIInputStream.h" #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/DOMEventTargetHelper.h" #include "mozilla/MemoryReporting.h" #include "mozilla/NotNull.h" +#include "mozilla/dom/MutableBlobStorage.h" #include "mozilla/dom/TypedArray.h" #include "mozilla/dom/XMLHttpRequest.h" #include "mozilla/dom/XMLHttpRequestBinding.h" #include "mozilla/dom/XMLHttpRequestEventTarget.h" #include "mozilla/dom/XMLHttpRequestString.h" #ifdef Status /* Xlib headers insist on this for some reason... Nuke it because @@ -157,17 +158,18 @@ class XMLHttpRequestMainThread final : p public nsIXMLHttpRequest, public nsIJSXMLHttpRequest, public nsIStreamListener, public nsIChannelEventSink, public nsIProgressEventSink, public nsIInterfaceRequestor, public nsSupportsWeakReference, public nsITimerCallback, - public nsISizeOfEventTarget + public nsISizeOfEventTarget, + public MutableBlobStorageCallback { friend class nsXHRParseEndListener; friend class nsXMLHttpRequestXPCOMifier; public: enum class ProgressEventType : uint8_t { loadstart, progress, @@ -531,16 +533,20 @@ public: static bool DontWarnAboutSyncXHR() { return sDontWarnAboutSyncXHR; } virtual void SetOriginAttributes(const mozilla::dom::OriginAttributesDictionary& aAttrs) override; + void BlobStoreCompleted(MutableBlobStorage* aBlobStorage, + Blob* aBlob, + nsresult aResult) override; + protected: // XHR states are meant to mirror the XHR2 spec: // https://xhr.spec.whatwg.org/#states enum class State : uint8_t { unsent, // object has been constructed. opened, // open() has been successfully invoked. headers_received, // redirects followed and response headers received. loading, // response body is being received. @@ -573,16 +579,18 @@ protected: bool InUploadPhase() const; void OnBodyParseEnd(); void ChangeStateToDone(); void StartProgressEventTimer(); void StopProgressEventTimer(); + void MaybeCreateBlobStorage(); + nsresult OnRedirectVerifyCallback(nsresult result); already_AddRefed<nsXMLHttpRequestXPCOMifier> EnsureXPCOMifier(); nsCOMPtr<nsISupports> mContext; nsCOMPtr<nsIPrincipal> mPrincipal; nsCOMPtr<nsIChannel> mChannel; nsCString mRequestMethod; @@ -639,18 +647,21 @@ protected: XMLHttpRequestResponseType mResponseType; // It is either a cached blob-response from the last call to GetResponse, // but is also explicitly set in OnStopRequest. RefPtr<Blob> mResponseBlob; // Non-null only when we are able to get a os-file representation of the // response, i.e. when loading from a file. RefPtr<Blob> mDOMBlob; - // We stream data to mBlobSet when response type is "blob" or "moz-blob" - // and mDOMBlob is null. + // We stream data to mBlobStorage when response type is "blob" and mDOMBlob is + // null. + RefPtr<MutableBlobStorage> mBlobStorage; + // We stream data to mBlobStorage when response type is "moz-blob" and + // mDOMBlob is null. nsAutoPtr<BlobSet> mBlobSet; nsString mOverrideMimeType; /** * The notification callbacks the channel had when Send() was * called. We want to forward things here as needed. */
new file mode 100644 --- /dev/null +++ b/dom/xhr/tests/common_temporaryFileBlob.js @@ -0,0 +1,100 @@ +var data = new Array(256).join("1234567890ABCDEF"); + +function createXHR() { + var xhr = new XMLHttpRequest(); + xhr.open("POST", "temporaryFileBlob.sjs"); + xhr.responseType = 'blob'; + xhr.send({toString: function() { return data; }}); + return xhr; +} + +function test_simple() { + info("Simple test"); + + var xhr = createXHR(); + + xhr.onloadend = function() { + ok(xhr.response instanceof Blob, "We have a blob!"); + is(xhr.response.size, data.length, "Data length matches"); + + var fr = new FileReader(); + fr.readAsText(xhr.response); + fr.onload = function() { + is(fr.result, data, "Data content matches"); + next(); + } + } +} + +function test_abort() { + info("Aborting during onloading"); + + var xhr = createXHR(); + + xhr.onprogress = function() { + xhr.abort(); + } + + xhr.onloadend = function() { + ok(!xhr.response, "We should not have a Blob!"); + next(); + } +} + +function test_reuse() { + info("Reuse test"); + + var xhr = createXHR(); + + var count = 0; + xhr.onloadend = function() { + ok(xhr.response instanceof Blob, "We have a blob!"); + is(xhr.response.size, data.length, "Data length matches"); + + var fr = new FileReader(); + fr.readAsText(xhr.response); + fr.onload = function() { + is(fr.result, data, "Data content matches"); + if (++count > 2) { + next(); + return; + } + + xhr.open("POST", "temporaryFileBlob.sjs"); + xhr.responseType = 'blob'; + xhr.send({toString: function() { return data; }}); + } + } +} + +function test_worker_generic(test) { + var w = new Worker('worker_temporaryFileBlob.js'); + w.onmessage = function(e) { + if (e.data.type == 'info') { + info(e.data.msg); + } else if (e.data.type == 'check') { + ok(e.data.what, e.data.msg); + } else if (e.data.type == 'finish') { + next(); + } else { + ok(false, 'Something wrong happened'); + } + } + + w.postMessage(test); +} + +function test_worker() { + info("XHR in workers"); + test_worker_generic('simple'); +} + +function test_worker_abort() { + info("XHR in workers"); + test_worker_generic('abort'); +} + +function test_worker_reuse() { + info("XHR in workers"); + test_worker_generic('reuse'); +}
--- a/dom/xhr/tests/mochitest.ini +++ b/dom/xhr/tests/mochitest.ini @@ -1,11 +1,12 @@ [DEFAULT] support-files = echo.sjs + temporaryFileBlob.sjs file_html_in_xhr.html file_html_in_xhr.sjs file_html_in_xhr2.html file_html_in_xhr3.html file_XHRDocURI.text file_XHRDocURI.text^headers^ file_XHRDocURI.xml file_XHRDocURI.xml^headers^ @@ -51,16 +52,18 @@ support-files = xhr_implicit_cancel_worker.js relativeLoad_import.js relativeLoad_worker.js relativeLoad_worker2.js responseIdentical.sjs subdir/relativeLoad_sub_worker.js subdir/relativeLoad_sub_worker2.js subdir/relativeLoad_sub_import.js + common_temporaryFileBlob.js + worker_temporaryFileBlob.js [test_xhr_overridemimetype_throws_on_invalid_state.html] skip-if = buildapp == 'b2g' # Requires webgl support [test_html_in_xhr.html] [test_sync_xhr_timer.xhtml] skip-if = toolkit == 'android' [test_xhr_abort_after_load.html] skip-if = toolkit == 'android' @@ -96,8 +99,9 @@ skip-if = buildapp == 'b2g' [test_worker_xhr_parameters.html] skip-if = buildapp == 'b2g' [test_worker_xhr_responseURL.html] [test_worker_xhr_system.html] [test_worker_xhr_timeout.html] skip-if = (os == "win") || (os == "mac") || toolkit == 'android' #bug 798220 [test_relativeLoad.html] skip-if = buildapp == 'b2g' # b2g(Failed to load script: relativeLoad_import.js) b2g-debug(Failed to load script: relativeLoad_import.js) b2g-desktop(Failed to load script: relativeLoad_import.js) +[test_temporaryFileBlob.html]
new file mode 100644 --- /dev/null +++ b/dom/xhr/tests/temporaryFileBlob.sjs @@ -0,0 +1,33 @@ +const CC = Components.Constructor; + +const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1", + "nsIBinaryInputStream", + "setInputStream"); +const BinaryOutputStream = CC("@mozilla.org/binaryoutputstream;1", + "nsIBinaryOutputStream", + "setOutputStream"); +const Timer = CC("@mozilla.org/timer;1", + "nsITimer", + "initWithCallback"); + +function handleRequest(request, response) { + var bodyStream = new BinaryInputStream(request.bodyInputStream); + var bodyBytes = []; + while ((bodyAvail = bodyStream.available()) > 0) + Array.prototype.push.apply(bodyBytes, bodyStream.readByteArray(bodyAvail)); + + var bos = new BinaryOutputStream(response.bodyOutputStream); + + response.processAsync(); + + var part = bodyBytes.splice(0, 256); + bos.writeByteArray(part, part.length); + + response.timer1 = new Timer(function(timer) { + bos.writeByteArray(bodyBytes, bodyBytes.length); + }, 1000, Components.interfaces.nsITimer.TYPE_ONE_SHOT); + + response.timer2 = new Timer(function(timer) { + response.finish(); + }, 2000, Components.interfaces.nsITimer.TYPE_ONE_SHOT); +}
new file mode 100644 --- /dev/null +++ b/dom/xhr/tests/test_temporaryFileBlob.html @@ -0,0 +1,40 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1202006</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="common_temporaryFileBlob.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> + <script type="application/javascript"> + +var tests = [ + // from common_temporaryFileBlob.js: + test_simple, + test_reuse, + test_abort, + + test_worker, + test_worker_reuse, + test_worker_abort, +]; + +function next() { + if (!tests.length) { + SimpleTest.finish(); + return; + } + + var test = tests.shift(); + test(); +} + +SpecialPowers.pushPrefEnv({ "set" : [[ "dom.blob.memoryToTemporaryFile", 1 ]] }, + next); +SimpleTest.waitForExplicitFinish(); + + </script> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/xhr/tests/worker_temporaryFileBlob.js @@ -0,0 +1,29 @@ +importScripts('common_temporaryFileBlob.js'); + +function info(msg) { + postMessage({type: 'info', msg: msg}); +} + +function ok(a, msg) { + postMessage({type: 'check', what: !!a, msg: msg}); +} + +function is(a, b, msg) { + ok(a === b, msg); +} + +function next() { + postMessage({type: 'finish'}); +} + +onmessage = function(e) { + if (e.data == 'simple') { + test_simple(); + } else if (e.data == 'abort') { + test_abort(); + } else if (e.data == 'reuse') { + test_reuse(); + } else { + ok(false, 'Something wrong happened'); + } +}
--- a/dom/xml/XMLDocument.cpp +++ b/dom/xml/XMLDocument.cpp @@ -261,66 +261,47 @@ XMLDocument::ResetToURI(nsIURI *aURI, ns StopDocumentLoad(); mChannel->Cancel(NS_BINDING_ABORTED); mChannelIsPending = false; } nsDocument::ResetToURI(aURI, aLoadGroup, aPrincipal); } -NS_IMETHODIMP -XMLDocument::GetAsync(bool *aAsync) -{ - NS_ENSURE_ARG_POINTER(aAsync); - *aAsync = mAsync; - return NS_OK; -} - -NS_IMETHODIMP -XMLDocument::SetAsync(bool aAsync) -{ - mAsync = aAsync; - return NS_OK; -} - -NS_IMETHODIMP -XMLDocument::Load(const nsAString& aUrl, bool *aReturn) -{ - ErrorResult rv; - *aReturn = Load(aUrl, rv); - return rv.StealNSResult(); -} - bool XMLDocument::Load(const nsAString& aUrl, ErrorResult& aRv) { bool hasHadScriptObject = true; nsIScriptGlobalObject* scriptObject = GetScriptHandlingObject(hasHadScriptObject); if (!scriptObject && hasHadScriptObject) { aRv.Throw(NS_ERROR_UNEXPECTED); return false; } - WarnOnceAbout(nsIDocument::eUseOfDOM3LoadMethod); - nsCOMPtr<nsIDocument> callingDoc = GetEntryDocument(); nsCOMPtr<nsIPrincipal> principal = NodePrincipal(); // The callingDoc's Principal and doc's Principal should be the same if (callingDoc && (callingDoc->NodePrincipal() != principal)) { nsContentUtils::ReportToConsole(nsIScriptError::errorFlag, NS_LITERAL_CSTRING("DOM"), callingDoc, nsContentUtils::eDOM_PROPERTIES, "XMLDocumentLoadPrincipalMismatch"); aRv.Throw(NS_ERROR_UNEXPECTED); return false; } + if (nsContentUtils::IsCallerChrome()) { + WarnOnceAbout(nsIDocument::eChromeUseOfDOM3LoadMethod); + } else { + WarnOnceAbout(nsIDocument::eUseOfDOM3LoadMethod); + } + nsIURI *baseURI = mDocumentURI; nsAutoCString charset; if (callingDoc) { baseURI = callingDoc->GetDocBaseURI(); charset = callingDoc->GetDocumentCharacterSet(); }
--- a/dom/xml/XMLDocument.h +++ b/dom/xml/XMLDocument.h @@ -13,17 +13,18 @@ #include "nsIScriptContext.h" class nsIURI; class nsIChannel; namespace mozilla { namespace dom { -class XMLDocument : public nsDocument +class XMLDocument : public nsDocument, + public nsIDOMXMLDocument { public: explicit XMLDocument(const char* aContentType = "application/xml"); NS_DECL_ISUPPORTS_INHERITED virtual void Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) override; virtual void ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup, @@ -56,17 +57,20 @@ public: // WebIDL API bool Load(const nsAString& aUrl, mozilla::ErrorResult& aRv); bool Async() const { return mAsync; } - // The XPCOM SetAsync is ok for us + void SetAsync(bool aAsync) + { + mAsync = aAsync; + } // .location is [Unforgeable], so we have to make it clear that the // nsIDocument version applies to us (it's shadowed by the XPCOM thing on // nsDocument). using nsIDocument::GetLocation; // But then we need to also pull in the nsDocument XPCOM version // because nsXULDocument tries to forward to it. using nsDocument::GetLocation;
--- a/dom/xul/templates/nsXULTemplateBuilder.cpp +++ b/dom/xul/templates/nsXULTemplateBuilder.cpp @@ -19,17 +19,16 @@ #include "nsAutoPtr.h" #include "nsCOMPtr.h" #include "nsCRT.h" #include "nsIContent.h" #include "nsIDOMElement.h" #include "nsIDOMNode.h" #include "nsIDOMDocument.h" -#include "nsIDOMXMLDocument.h" #include "nsIDOMXULElement.h" #include "nsIDocument.h" #include "nsBindingManager.h" #include "nsIDOMNodeList.h" #include "nsIObserverService.h" #include "nsIRDFCompositeDataSource.h" #include "nsIRDFInferDataSource.h" #include "nsIRDFContainerUtils.h"
--- a/extensions/cookie/nsPermission.cpp +++ b/extensions/cookie/nsPermission.cpp @@ -22,16 +22,34 @@ nsPermission::nsPermission(nsIPrincipal* : mPrincipal(aPrincipal) , mType(aType) , mCapability(aCapability) , mExpireType(aExpireType) , mExpireTime(aExpireTime) { } +already_AddRefed<nsPermission> +nsPermission::Create(nsIPrincipal* aPrincipal, + const nsACString &aType, + uint32_t aCapability, + uint32_t aExpireType, + int64_t aExpireTime) +{ + NS_ENSURE_TRUE(aPrincipal, nullptr); + nsCOMPtr<nsIPrincipal> principal = + mozilla::BasePrincipal::Cast(aPrincipal)->CloneStrippingUserContextIdAndFirstPartyDomain(); + + NS_ENSURE_TRUE(principal, nullptr); + + RefPtr<nsPermission> permission = + new nsPermission(principal, aType, aCapability, aExpireType, aExpireTime); + return permission.forget(); +} + NS_IMETHODIMP nsPermission::GetPrincipal(nsIPrincipal** aPrincipal) { nsCOMPtr<nsIPrincipal> copy = mPrincipal; copy.forget(aPrincipal); return NS_OK; } @@ -66,38 +84,46 @@ nsPermission::GetExpireTime(int64_t *aEx NS_IMETHODIMP nsPermission::Matches(nsIPrincipal* aPrincipal, bool aExactHost, bool* aMatches) { NS_ENSURE_ARG_POINTER(aPrincipal); NS_ENSURE_ARG_POINTER(aMatches); *aMatches = false; + nsCOMPtr<nsIPrincipal> principal = + mozilla::BasePrincipal::Cast(aPrincipal)->CloneStrippingUserContextIdAndFirstPartyDomain(); + + if (!principal) { + *aMatches = false; + return NS_OK; + } + // If the principals are equal, then they match. - if (mPrincipal->Equals(aPrincipal)) { + if (mPrincipal->Equals(principal)) { *aMatches = true; return NS_OK; } // If we are matching with an exact host, we're done now - the permissions don't match // otherwise, we need to start comparing subdomains! if (aExactHost) { return NS_OK; } // Compare their OriginAttributes - const mozilla::PrincipalOriginAttributes& theirAttrs = mozilla::BasePrincipal::Cast(aPrincipal)->OriginAttributesRef(); + const mozilla::PrincipalOriginAttributes& theirAttrs = mozilla::BasePrincipal::Cast(principal)->OriginAttributesRef(); const mozilla::PrincipalOriginAttributes& ourAttrs = mozilla::BasePrincipal::Cast(mPrincipal)->OriginAttributesRef(); if (theirAttrs != ourAttrs) { return NS_OK; } nsCOMPtr<nsIURI> theirURI; - nsresult rv = aPrincipal->GetURI(getter_AddRefs(theirURI)); + nsresult rv = principal->GetURI(getter_AddRefs(theirURI)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIURI> ourURI; rv = mPrincipal->GetURI(getter_AddRefs(ourURI)); NS_ENSURE_SUCCESS(rv, rv); // Compare schemes nsAutoCString theirScheme;
--- a/extensions/cookie/nsPermission.h +++ b/extensions/cookie/nsPermission.h @@ -13,23 +13,29 @@ class nsPermission : public nsIPermission { public: // nsISupports NS_DECL_ISUPPORTS NS_DECL_NSIPERMISSION + static already_AddRefed<nsPermission> Create(nsIPrincipal* aPrincipal, + const nsACString &aType, + uint32_t aCapability, + uint32_t aExpireType, + int64_t aExpireTime); + +protected: nsPermission(nsIPrincipal* aPrincipal, const nsACString &aType, uint32_t aCapability, uint32_t aExpireType, int64_t aExpireTime); -protected: virtual ~nsPermission() {}; nsCOMPtr<nsIPrincipal> mPrincipal; nsCString mType; uint32_t mCapability; uint32_t mExpireType; int64_t mExpireTime; };
--- a/extensions/cookie/nsPermissionManager.cpp +++ b/extensions/cookie/nsPermissionManager.cpp @@ -117,45 +117,35 @@ GetOriginFromPrincipal(nsIPrincipal* aPr if (!attrs.PopulateFromSuffix(suffix)) { return NS_ERROR_FAILURE; } // mPrivateBrowsingId must be set to false because PermissionManager is not supposed to have // any knowledge of private browsing. Allowing it to be true changes the suffix being hashed. attrs.mPrivateBrowsingId = 0; - // TODO: Bug 1302047 - Ignore userContextId and firstPartyDomain when matching permissions. - - // set to default to disable user context isolation for permissions - attrs.mUserContextId = nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID; - - // set to default to disable firstParty isolation for permissions. - attrs.mFirstPartyDomain.Truncate(); + // Disable userContext and firstParty isolation for permissions. + attrs.StripUserContextIdAndFirstPartyDomain(); attrs.CreateSuffix(suffix); aOrigin.Append(suffix); return NS_OK; } nsresult GetPrincipalFromOrigin(const nsACString& aOrigin, nsIPrincipal** aPrincipal) { nsAutoCString originNoSuffix; mozilla::PrincipalOriginAttributes attrs; if (!attrs.PopulateFromOrigin(aOrigin, originNoSuffix)) { return NS_ERROR_FAILURE; } - // TODO: Bug 1302047 - Ignore userContextId and firstPartyDomain when matching permissions. - - // set to default to disable user context isolation for permissions - attrs.mUserContextId = nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID; - - // set to default to disable firstParty isolation for permissions. - attrs.mFirstPartyDomain.Truncate(); + // Disable userContext and firstParty isolation for permissions. + attrs.StripUserContextIdAndFirstPartyDomain(); nsCOMPtr<nsIURI> uri; nsresult rv = NS_NewURI(getter_AddRefs(uri), originNoSuffix); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIPrincipal> principal = mozilla::BasePrincipal::CreateCodebasePrincipal(uri, attrs); principal.forget(aPrincipal); return NS_OK; @@ -2060,21 +2050,24 @@ nsPermissionManager::GetPermissionObject return NS_OK; } nsCOMPtr<nsIPrincipal> principal; nsresult rv = GetPrincipalFromOrigin(entry->GetKey()->mOrigin, getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); PermissionEntry& perm = entry->GetPermissions()[idx]; - nsCOMPtr<nsIPermission> r = new nsPermission(principal, - mTypeArray.ElementAt(perm.mType), - perm.mPermission, - perm.mExpireType, - perm.mExpireTime); + nsCOMPtr<nsIPermission> r = nsPermission::Create(principal, + mTypeArray.ElementAt(perm.mType), + perm.mPermission, + perm.mExpireType, + perm.mExpireTime); + if (NS_WARN_IF(!r)) { + return NS_ERROR_FAILURE; + } r.forget(aResult); return NS_OK; } nsresult nsPermissionManager::CommonTestPermission(nsIPrincipal* aPrincipal, const char *aType, uint32_t *aPermission, @@ -2203,23 +2196,18 @@ nsPermissionManager::GetPermissionHashKe if (NS_FAILED(rv)) { return nullptr; } // Copy the attributes over mozilla::PrincipalOriginAttributes attrs = mozilla::BasePrincipal::Cast(aPrincipal)->OriginAttributesRef(); - // TODO: Bug 1302047 - Ignore userContextId and firstPartyDomain when matching permissions. - - // ensure that the user context isolation is disabled - attrs.mUserContextId = nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID; - - // ensure firstPartyIsolation is disabled. - attrs.mFirstPartyDomain.Truncate(); + // Disable userContext and firstParty isolation for permissions. + attrs.StripUserContextIdAndFirstPartyDomain(); nsCOMPtr<nsIPrincipal> principal = mozilla::BasePrincipal::CreateCodebasePrincipal(newURI, attrs); return GetPermissionHashKey(principal, aType, aExactHostMatch); } // No entry, really... @@ -2243,22 +2231,26 @@ NS_IMETHODIMP nsPermissionManager::GetEn nsCOMPtr<nsIPrincipal> principal; nsresult rv = GetPrincipalFromOrigin(entry->GetKey()->mOrigin, getter_AddRefs(principal)); if (NS_FAILED(rv)) { continue; } - array.AppendObject( - new nsPermission(principal, - mTypeArray.ElementAt(permEntry.mType), - permEntry.mPermission, - permEntry.mExpireType, - permEntry.mExpireTime)); + nsCOMPtr<nsIPermission> permission = + nsPermission::Create(principal, + mTypeArray.ElementAt(permEntry.mType), + permEntry.mPermission, + permEntry.mExpireType, + permEntry.mExpireTime); + if (NS_WARN_IF(!permission)) { + continue; + } + array.AppendObject(permission); } } return NS_NewArrayEnumerator(aEnum, array); } NS_IMETHODIMP nsPermissionManager::GetAllForURI(nsIURI* aURI, nsISimpleEnumerator **aEnum) { @@ -2273,22 +2265,26 @@ NS_IMETHODIMP nsPermissionManager::GetAl if (entry) { for (const auto& permEntry : entry->GetPermissions()) { // Only return custom permissions if (permEntry.mPermission == nsIPermissionManager::UNKNOWN_ACTION) { continue; } - array.AppendObject( - new nsPermission(principal, - mTypeArray.ElementAt(permEntry.mType), - permEntry.mPermission, - permEntry.mExpireType, - permEntry.mExpireTime)); + nsCOMPtr<nsIPermission> permission = + nsPermission::Create(principal, + mTypeArray.ElementAt(permEntry.mType), + permEntry.mPermission, + permEntry.mExpireType, + permEntry.mExpireTime); + if (NS_WARN_IF(!permission)) { + continue; + } + array.AppendObject(permission); } } return NS_NewArrayEnumerator(aEnum, array); } NS_IMETHODIMP nsPermissionManager::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData) { @@ -2323,22 +2319,26 @@ nsPermissionManager::RemoveAllModifiedSi nsCOMPtr<nsIPrincipal> principal; nsresult rv = GetPrincipalFromOrigin(entry->GetKey()->mOrigin, getter_AddRefs(principal)); if (NS_FAILED(rv)) { continue; } - array.AppendObject( - new nsPermission(principal, - mTypeArray.ElementAt(permEntry.mType), - permEntry.mPermission, - permEntry.mExpireType, - permEntry.mExpireTime)); + nsCOMPtr<nsIPermission> permission = + nsPermission::Create(principal, + mTypeArray.ElementAt(permEntry.mType), + permEntry.mPermission, + permEntry.mExpireType, + permEntry.mExpireTime); + if (NS_WARN_IF(!permission)) { + continue; + } + array.AppendObject(permission); } } for (int32_t i = 0; i<array.Count(); ++i) { nsCOMPtr<nsIPrincipal> principal; nsAutoCString type; nsresult rv = array[i]->GetPrincipal(getter_AddRefs(principal)); @@ -2395,22 +2395,26 @@ nsPermissionManager::RemovePermissionsWi continue; } if (!aPattern.Matches(mozilla::BasePrincipal::Cast(principal)->OriginAttributesRef())) { continue; } for (const auto& permEntry : entry->GetPermissions()) { - permissions.AppendObject( - new nsPermission(principal, - mTypeArray.ElementAt(permEntry.mType), - permEntry.mPermission, - permEntry.mExpireType, - permEntry.mExpireTime)); + nsCOMPtr<nsIPermission> permission = + nsPermission::Create(principal, + mTypeArray.ElementAt(permEntry.mType), + permEntry.mPermission, + permEntry.mExpireType, + permEntry.mExpireTime); + if (NS_WARN_IF(!permission)) { + continue; + } + permissions.AppendObject(permission); } } for (int32_t i = 0; i < permissions.Count(); ++i) { nsCOMPtr<nsIPrincipal> principal; nsAutoCString type; permissions[i]->GetPrincipal(getter_AddRefs(principal)); @@ -2531,18 +2535,18 @@ void nsPermissionManager::NotifyObserversWithPermission(nsIPrincipal* aPrincipal, const nsCString &aType, uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime, const char16_t *aData) { nsCOMPtr<nsIPermission> permission = - new nsPermission(aPrincipal, aType, aPermission, - aExpireType, aExpireTime); + nsPermission::Create(aPrincipal, aType, aPermission, + aExpireType, aExpireTime); if (permission) NotifyObservers(permission, aData); } // notify observers that the permission list changed. there are four possible // values for aData: // "deleted" means a permission was deleted. aPermission is the deleted permission. // "added" means a permission was added. aPermission is the added permission.
--- a/extensions/cookie/test/unit/test_permmanager_matches.js +++ b/extensions/cookie/test/unit/test_permmanager_matches.js @@ -72,62 +72,112 @@ function run_test() { attrs = {appId: 2000, inIsolatedMozBrowser: true}; let uri0_2000_y = secMan.createCodebasePrincipal(uri0, attrs); let uri1_2000_y = secMan.createCodebasePrincipal(uri1, attrs); let uri2_2000_y = secMan.createCodebasePrincipal(uri2, attrs); let uri3_2000_y = secMan.createCodebasePrincipal(uri3, attrs); let uri4_2000_y = secMan.createCodebasePrincipal(uri4, attrs); let uri5_2000_y = secMan.createCodebasePrincipal(uri5, attrs); + attrs = {userContextId: 1}; + let uri0_1 = secMan.createCodebasePrincipal(uri0, attrs); + let uri1_1 = secMan.createCodebasePrincipal(uri1, attrs); + let uri2_1 = secMan.createCodebasePrincipal(uri2, attrs); + let uri3_1 = secMan.createCodebasePrincipal(uri3, attrs); + let uri4_1 = secMan.createCodebasePrincipal(uri4, attrs); + let uri5_1 = secMan.createCodebasePrincipal(uri5, attrs); + + attrs = {firstPartyDomain: "cnn.com"}; + let uri0_cnn = secMan.createCodebasePrincipal(uri0, attrs); + let uri1_cnn = secMan.createCodebasePrincipal(uri1, attrs); + let uri2_cnn = secMan.createCodebasePrincipal(uri2, attrs); + let uri3_cnn = secMan.createCodebasePrincipal(uri3, attrs); + let uri4_cnn = secMan.createCodebasePrincipal(uri4, attrs); + let uri5_cnn = secMan.createCodebasePrincipal(uri5, attrs); + pm.addFromPrincipal(uri0_n_n, "test/matches", pm.ALLOW_ACTION); let perm_n_n = pm.getPermissionObject(uri0_n_n, "test/matches", true); pm.addFromPrincipal(uri0_1000_n, "test/matches", pm.ALLOW_ACTION); let perm_1000_n = pm.getPermissionObject(uri0_1000_n, "test/matches", true); pm.addFromPrincipal(uri0_1000_y, "test/matches", pm.ALLOW_ACTION); let perm_1000_y = pm.getPermissionObject(uri0_1000_y, "test/matches", true); pm.addFromPrincipal(uri0_2000_n, "test/matches", pm.ALLOW_ACTION); let perm_2000_n = pm.getPermissionObject(uri0_2000_n, "test/matches", true); pm.addFromPrincipal(uri0_2000_y, "test/matches", pm.ALLOW_ACTION); let perm_2000_y = pm.getPermissionObject(uri0_2000_y, "test/matches", true); + pm.addFromPrincipal(uri0_1, "test/matches", pm.ALLOW_ACTION); + let perm_1 = pm.getPermissionObject(uri0_n_n, "test/matches", true); + pm.addFromPrincipal(uri0_cnn, "test/matches", pm.ALLOW_ACTION); + let perm_cnn = pm.getPermissionObject(uri0_n_n, "test/matches", true); - matches_always(perm_n_n, [uri0_n_n]); - matches_weak(perm_n_n, [uri1_n_n]); + matches_always(perm_n_n, [uri0_n_n, uri0_1, uri0_cnn]); + matches_weak(perm_n_n, [uri1_n_n, uri1_1, uri1_cnn]); matches_never(perm_n_n, [uri2_n_n, uri3_n_n, uri4_n_n, uri5_n_n, uri0_1000_n, uri1_1000_n, uri2_1000_n, uri3_1000_n, uri4_1000_n, uri5_1000_n, uri0_1000_y, uri1_1000_y, uri2_1000_y, uri3_1000_y, uri4_1000_y, uri5_1000_y, uri0_2000_n, uri1_2000_n, uri2_2000_n, uri3_2000_n, uri4_2000_n, uri5_2000_n, - uri0_2000_y, uri1_2000_y, uri2_2000_y, uri3_2000_y, uri4_2000_y, uri5_2000_y]); + uri0_2000_y, uri1_2000_y, uri2_2000_y, uri3_2000_y, uri4_2000_y, uri5_2000_y, + uri2_1, uri3_1, uri4_1, uri5_1, + uri2_cnn, uri3_cnn, uri4_cnn, uri5_cnn]); matches_always(perm_1000_n, [uri0_1000_n]); matches_weak(perm_1000_n, [uri1_1000_n]); matches_never(perm_1000_n, [uri2_1000_n, uri3_1000_n, uri4_1000_n, uri5_1000_n, uri0_n_n, uri1_n_n, uri2_n_n, uri3_n_n, uri4_n_n, uri5_n_n, uri0_1000_y, uri1_1000_y, uri2_1000_y, uri3_1000_y, uri4_1000_y, uri5_1000_y, uri0_2000_n, uri1_2000_n, uri2_2000_n, uri3_2000_n, uri4_2000_n, uri5_2000_n, - uri0_2000_y, uri1_2000_y, uri2_2000_y, uri3_2000_y, uri4_2000_y, uri5_2000_y]); + uri0_2000_y, uri1_2000_y, uri2_2000_y, uri3_2000_y, uri4_2000_y, uri5_2000_y, + uri0_1, uri1_1, uri2_1, uri3_1, uri4_1, uri5_1, + uri0_cnn, uri1_cnn, uri2_cnn, uri3_cnn, uri4_cnn, uri5_cnn]); matches_always(perm_1000_y, [uri0_1000_y]); matches_weak(perm_1000_y, [uri1_1000_y]); matches_never(perm_1000_y, [uri2_1000_y, uri3_1000_y, uri4_1000_y, uri5_1000_y, uri0_n_n, uri1_n_n, uri2_n_n, uri3_n_n, uri4_n_n, uri5_n_n, uri0_1000_n, uri1_1000_n, uri2_1000_n, uri3_1000_n, uri4_1000_n, uri5_1000_n, uri0_2000_n, uri1_2000_n, uri2_2000_n, uri3_2000_n, uri4_2000_n, uri5_2000_n, - uri0_2000_y, uri1_2000_y, uri2_2000_y, uri3_2000_y, uri4_2000_y, uri5_2000_y]); + uri0_2000_y, uri1_2000_y, uri2_2000_y, uri3_2000_y, uri4_2000_y, uri5_2000_y, + uri0_1, uri1_1, uri2_1, uri3_1, uri4_1, uri5_1, + uri0_cnn, uri1_cnn, uri2_cnn, uri3_cnn, uri4_cnn, uri5_cnn]); matches_always(perm_2000_n, [uri0_2000_n]); matches_weak(perm_2000_n, [uri1_2000_n]); matches_never(perm_2000_n, [uri2_2000_n, uri3_2000_n, uri4_2000_n, uri5_2000_n, uri0_n_n, uri1_n_n, uri2_n_n, uri3_n_n, uri4_n_n, uri5_n_n, uri0_2000_y, uri1_2000_y, uri2_2000_y, uri3_2000_y, uri4_2000_y, uri5_2000_y, uri0_1000_n, uri1_1000_n, uri2_1000_n, uri3_1000_n, uri4_1000_n, uri5_1000_n, - uri0_1000_y, uri1_1000_y, uri2_1000_y, uri3_1000_y, uri4_1000_y, uri5_1000_y]); + uri0_1000_y, uri1_1000_y, uri2_1000_y, uri3_1000_y, uri4_1000_y, uri5_1000_y, + uri0_1, uri1_1, uri2_1, uri3_1, uri4_1, uri5_1, + uri0_cnn, uri1_cnn, uri2_cnn, uri3_cnn, uri4_cnn, uri5_cnn]); matches_always(perm_2000_y, [uri0_2000_y]); matches_weak(perm_2000_y, [uri1_2000_y]); matches_never(perm_2000_y, [uri2_2000_y, uri3_2000_y, uri4_2000_y, uri5_2000_y, uri0_n_n, uri1_n_n, uri2_n_n, uri3_n_n, uri4_n_n, uri5_n_n, uri0_2000_n, uri1_2000_n, uri2_2000_n, uri3_2000_n, uri4_2000_n, uri5_2000_n, uri0_1000_n, uri1_1000_n, uri2_1000_n, uri3_1000_n, uri4_1000_n, uri5_1000_n, - uri0_1000_y, uri1_1000_y, uri2_1000_y, uri3_1000_y, uri4_1000_y, uri5_1000_y]); + uri0_1000_y, uri1_1000_y, uri2_1000_y, uri3_1000_y, uri4_1000_y, uri5_1000_y, + uri0_1, uri1_1, uri2_1, uri3_1, uri4_1, uri5_1, + uri0_cnn, uri1_cnn, uri2_cnn, uri3_cnn, uri4_cnn, uri5_cnn]); + + matches_always(perm_1, [uri0_n_n, uri0_1, uri0_cnn]); + matches_weak(perm_1, [uri1_n_n, uri1_1, uri1_cnn]); + matches_never(perm_1, [uri2_n_n, uri3_n_n, uri4_n_n, uri5_n_n, + uri0_1000_n, uri1_1000_n, uri2_1000_n, uri3_1000_n, uri4_1000_n, uri5_1000_n, + uri0_1000_y, uri1_1000_y, uri2_1000_y, uri3_1000_y, uri4_1000_y, uri5_1000_y, + uri0_2000_n, uri1_2000_n, uri2_2000_n, uri3_2000_n, uri4_2000_n, uri5_2000_n, + uri0_2000_y, uri1_2000_y, uri2_2000_y, uri3_2000_y, uri4_2000_y, uri5_2000_y, + uri2_1, uri3_1, uri4_1, uri5_1, + uri2_cnn, uri3_cnn, uri4_cnn, uri5_cnn]); + + matches_always(perm_cnn, [uri0_n_n, uri0_1, uri0_cnn]); + matches_weak(perm_cnn, [uri1_n_n, uri1_1, uri1_cnn]); + matches_never(perm_cnn, [uri2_n_n, uri3_n_n, uri4_n_n, uri5_n_n, + uri0_1000_n, uri1_1000_n, uri2_1000_n, uri3_1000_n, uri4_1000_n, uri5_1000_n, + uri0_1000_y, uri1_1000_y, uri2_1000_y, uri3_1000_y, uri4_1000_y, uri5_1000_y, + uri0_2000_n, uri1_2000_n, uri2_2000_n, uri3_2000_n, uri4_2000_n, uri5_2000_n, + uri0_2000_y, uri1_2000_y, uri2_2000_y, uri3_2000_y, uri4_2000_y, uri5_2000_y, + uri2_1, uri3_1, uri4_1, uri5_1, + uri2_cnn, uri3_cnn, uri4_cnn, uri5_cnn]); // Clean up! pm.removeAll(); }
--- a/gfx/2d/DrawTargetSkia.cpp +++ b/gfx/2d/DrawTargetSkia.cpp @@ -175,38 +175,38 @@ VerifyRGBXCorners(uint8_t* aData, const } int height = aSize.height; int width = aSize.width; const int pixelSize = 4; const int strideDiff = aStride - (width * pixelSize); MOZ_ASSERT(width * pixelSize <= aStride); - const int topLeft = kARGBAlphaOffset; - const int topRight = width * pixelSize + kARGBAlphaOffset - pixelSize; - const int bottomRight = aStride * height - strideDiff + kARGBAlphaOffset - pixelSize; - const int bottomLeft = aStride * height - aStride + kARGBAlphaOffset; + const int topLeft = 0; + const int topRight = width * pixelSize - pixelSize; + const int bottomRight = aStride * height - strideDiff - pixelSize; + const int bottomLeft = aStride * height - aStride; // Lastly the center pixel int middleRowHeight = height / 2; int middleRowWidth = (width / 2) * pixelSize; - const int middle = aStride * middleRowHeight + middleRowWidth + kARGBAlphaOffset; + const int middle = aStride * middleRowHeight + middleRowWidth; const int offsets[] = { topLeft, topRight, bottomRight, bottomLeft, middle }; for (size_t i = 0; i < MOZ_ARRAY_LENGTH(offsets); i++) { int offset = offsets[i]; - if (aData[offset] != 0xFF) { + if (aData[offset + kARGBAlphaOffset] != 0xFF) { int row = offset / aStride; int column = (offset % aStride) / pixelSize; gfxCriticalError() << "RGBX corner pixel at (" << column << "," << row << ") in " << width << "x" << height << " surface is not opaque: " - << int(aData[column]) << "," - << int(aData[column+1]) << "," - << int(aData[column+2]) << "," - << int(aData[column+3]); + << int(aData[offset]) << "," + << int(aData[offset+1]) << "," + << int(aData[offset+2]) << "," + << int(aData[offset+3]); } } return true; } #endif static SkBitmap
--- a/gfx/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp +++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp @@ -2549,16 +2549,20 @@ void Renderer11::releaseDeviceResources( SafeRelease(mSyncQuery); } // set notify to true to broadcast a message to all contexts of the device loss bool Renderer11::testDeviceLost() { bool isLost = false; + if (!mDevice) { + return true; + } + // GetRemovedReason is used to test if the device is removed HRESULT result = mDevice->GetDeviceRemovedReason(); isLost = d3d11::isDeviceLostError(result); if (isLost) { ERR("The D3D11 device was removed: 0x%08X", result); }
--- a/gfx/ots/README.mozilla +++ b/gfx/ots/README.mozilla @@ -1,11 +1,11 @@ This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/. Our reference repository is https://github.com/khaledhosny/ots/. -Current revision: 8d70cffebbfa58f67a5c3ed0e9bc84dccdbc5bc0 +Current revision: ba8417620956a920ed1f05a2f666fb6317fb10cb Upstream files included: LICENSE, src/, include/ Additional files: README.mozilla, src/moz.build Additional patch: ots-visibility.patch (bug 711079).
--- a/gfx/ots/include/opentype-sanitiser.h +++ b/gfx/ots/include/opentype-sanitiser.h @@ -39,16 +39,18 @@ typedef unsigned __int64 uint64_t; #define ntohs(x) _byteswap_ushort (x) #define htonl(x) _byteswap_ulong (x) #define htons(x) _byteswap_ushort (x) #else #include <arpa/inet.h> #include <stdint.h> #endif +#include <sys/types.h> + #include <algorithm> #include <cassert> #include <cstddef> #include <cstring> #define OTS_TAG(c1,c2,c3,c4) ((uint32_t)((((uint8_t)(c1))<<24)|(((uint8_t)(c2))<<16)|(((uint8_t)(c3))<<8)|((uint8_t)(c4)))) #define OTS_UNTAG(tag) ((uint8_t)((tag)>>24)), ((uint8_t)((tag)>>16)), ((uint8_t)((tag)>>8)), ((uint8_t)(tag))
--- a/gfx/ots/src/ots.cc +++ b/gfx/ots/src/ots.cc @@ -473,27 +473,28 @@ bool ProcessWOFF2(ots::OpenTypeFile *hea if (decompressed_size == 0) { return OTS_FAILURE_MSG_HDR("Size of decompressed WOFF 2.0 is set to 0"); } // decompressed font must be <= 30MB if (decompressed_size > 30 * 1024 * 1024) { return OTS_FAILURE_MSG_HDR("Size of decompressed WOFF 2.0 font exceeds 30MB"); } - std::vector<uint8_t> decompressed_buffer(decompressed_size); - if (!woff2::ConvertWOFF2ToTTF(&decompressed_buffer[0], decompressed_size, - data, length)) { + std::string buf(decompressed_size, 0); + woff2::WOFF2StringOut out(&buf); + if (!woff2::ConvertWOFF2ToTTF(data, length, &out)) { return OTS_FAILURE_MSG_HDR("Failed to convert WOFF 2.0 font to SFNT"); } + const uint8_t *decompressed = reinterpret_cast<const uint8_t*>(buf.data()); if (data[4] == 't' && data[5] == 't' && data[6] == 'c' && data[7] == 'f') { - return ProcessTTC(header, output, &decompressed_buffer[0], decompressed_size, index); + return ProcessTTC(header, output, decompressed, out.Size(), index); } else { ots::Font font(header); - return ProcessTTF(header, &font, output, &decompressed_buffer[0], decompressed_size); + return ProcessTTF(header, &font, output, decompressed, out.Size()); } } ots::TableAction GetTableAction(ots::OpenTypeFile *header, uint32_t tag) { ots::TableAction action = header->context->GetTableAction(tag); if (action == ots::TABLE_ACTION_DEFAULT) { action = ots::TABLE_ACTION_DROP;
--- a/gfx/skia/generate_mozbuild.py +++ b/gfx/skia/generate_mozbuild.py @@ -424,20 +424,22 @@ def write_mozbuild(sources): f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':\n") # Windows-specific files don't get unification because of nasty headers. # Luckily there are not many files in this. write_list(f, "SOURCES", sources['win'], 4) f.write("if CONFIG['INTEL_ARCHITECTURE']:\n") write_sources(f, sources['intel'], 4) - f.write("elif CONFIG['CPU_ARCH'] == 'arm' and CONFIG['GNU_CC']:\n") + f.write("elif CONFIG['CPU_ARCH'] in ('arm', 'aarch64') and CONFIG['GNU_CC']:\n") write_sources(f, sources['arm'], 4) - f.write(" if CONFIG['BUILD_ARM_NEON']:\n") + f.write(" if CONFIG['CPU_ARCH'] == 'aarch64':\n") + write_sources(f, sources['neon'], 8) + f.write(" elif CONFIG['BUILD_ARM_NEON']:\n") write_list(f, 'SOURCES', sources['neon'], 8) write_cflags(f, sources['neon'], 'neon', "CONFIG['NEON_FLAGS']", 8) f.write("else:\n") write_sources(f, sources['none'], 4) f.write(footer)
--- a/gfx/skia/moz.build +++ b/gfx/skia/moz.build @@ -514,26 +514,34 @@ if CONFIG['INTEL_ARCHITECTURE']: 'skia/src/opts/SkBitmapFilter_opts_SSE2.cpp', 'skia/src/opts/SkBitmapProcState_opts_SSE2.cpp', 'skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp', 'skia/src/opts/SkBlitRow_opts_SSE2.cpp', 'skia/src/opts/SkOpts_sse2.cpp', 'skia/src/opts/SkOpts_sse41.cpp', 'skia/src/opts/SkOpts_ssse3.cpp', ] -elif CONFIG['CPU_ARCH'] == 'arm' and CONFIG['GNU_CC']: +elif CONFIG['CPU_ARCH'] in ('arm', 'aarch64') and CONFIG['GNU_CC']: UNIFIED_SOURCES += [ 'skia/src/core/SkUtilsArm.cpp', 'skia/src/opts/SkBitmapProcState_opts_arm.cpp', 'skia/src/opts/SkBlitMask_opts_arm.cpp', ] SOURCES += [ 'skia/src/opts/SkBlitRow_opts_arm.cpp', ] - if CONFIG['BUILD_ARM_NEON']: + if CONFIG['CPU_ARCH'] == 'aarch64': + SOURCES += [ + 'skia/src/opts/SkBitmapProcState_arm_neon.cpp', + 'skia/src/opts/SkBitmapProcState_matrixProcs_neon.cpp', + 'skia/src/opts/SkBlitMask_opts_arm_neon.cpp', + 'skia/src/opts/SkBlitRow_opts_arm_neon.cpp', + 'skia/src/opts/SkOpts_neon.cpp', + ] + elif CONFIG['BUILD_ARM_NEON']: SOURCES += [ 'skia/src/opts/SkBitmapProcState_arm_neon.cpp', 'skia/src/opts/SkBitmapProcState_matrixProcs_neon.cpp', 'skia/src/opts/SkBlitMask_opts_arm_neon.cpp', 'skia/src/opts/SkBlitRow_opts_arm_neon.cpp', 'skia/src/opts/SkOpts_neon.cpp', ] SOURCES['skia/src/opts/SkBitmapProcState_arm_neon.cpp'].flags += CONFIG['NEON_FLAGS']
--- a/gfx/tests/mochitest/mochitest.ini +++ b/gfx/tests/mochitest/mochitest.ini @@ -1,11 +1,12 @@ [DEFAULT] skip-if = buildapp == 'mulet' || buildapp == 'b2g' [test_acceleration.html] subsuite = gpu fail-if = (os == "win" && os_version == "5.1" && e10s) # Bug 1253862 [test_bug509244.html] [test_bug513439.html] +[test_font_whitelist.html] [test_overdraw.html] # Disable test until bug 1064136 is fixed skip-if = true
new file mode 100644 --- /dev/null +++ b/gfx/tests/mochitest/test_font_whitelist.html @@ -0,0 +1,85 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1121643 +--> +<head> + <title>Test for Bug 1121643</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="/tests/SimpleTest/SpawnTask.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1121643">Mozilla Bug 1121643</a> +<span id="mono" style="font-family: monospace; font-size: 64px;">M</span> +<span id="sans" style="font-family: sans-serif; font-size: 64px;">M</span> +<span id="serif" style="font-family: serif; font-size: 64px;">M</span> +<div id="content" style="display: none"> + +</div> +<script class="testbody" type="application/javascript;version=1.7"> + +/** Test for Bug 1121643 **/ + +const DOMUtils = SpecialPowers.Cc["@mozilla.org/inspector/dom-utils;1"] + .getService(SpecialPowers.Ci.inIDOMUtils); + +// Given an element id, returns the first font face name encountered. +let fontUsed = id => { + let element = document.getElementById(id), + range = document.createRange(); + range.selectNode(element); + return DOMUtils.getUsedFontFaces(range).item(0).CSSFamilyName; +} + +// A map of the default mono, sans and serif fonts, obtained when +// whitelisting is disabled. +const fonts = { mono : fontUsed("mono"), + sans : fontUsed("sans"), + serif : fontUsed("serif") }; + +// Set the font whitelist to contain none, some, or all of the +// default mono, sans, and serif fonts. Check that the rendering +// of our three test elements uses only fonts present in the +// whitelist. +let testFontWhitelist = function* (useMono, useSans, useSerif) { + let whitelist = []; + if (useMono) { + whitelist.push(fonts.mono); + } + if (useSans) { + whitelist.push(fonts.sans); + } + if (useSerif) { + whitelist.push(fonts.serif); + } + yield SpecialPowers.pushPrefEnv({"set": [["font.system.whitelist", + whitelist.join(", ")]]}); + // If whitelist is empty, then whitelisting is considered disabled + // and all fonts are allowed. + info("font whitelist: " + JSON.stringify(whitelist)); + let whitelistEmpty = whitelist.length === 0; + is(useMono || whitelistEmpty, fontUsed("mono") === fonts.mono, + "Correct mono whitelisting state; got " + fontUsed("mono") + ", requested " + fonts.mono); + is(useSans || whitelistEmpty, fontUsed("sans") === fonts.sans, + "Correct sans whitelisting state; got " + fontUsed("sans") + ", requested " + fonts.sans); + is(useSerif || whitelistEmpty, fontUsed("serif") === fonts.serif, + "Correct serif whitelisting state; got " + fontUsed("serif") + ", requested " + fonts.serif); +} + +// Run tests to confirm that only whitelisting fonts are present in a +// rendered page. Try turning mono, sans, and serif off and on in +// every combination. +add_task(function* () { + for (let useMono of [false, true]) { + for (let useSans of [false, true]) { + for (let useSerif of [false, true]) { + yield testFontWhitelist(useMono, useSans, useSerif); + } + } + } +}); + +</script> +</body> +</html>
--- a/gfx/thebes/gfxDWriteFontList.cpp +++ b/gfx/thebes/gfxDWriteFontList.cpp @@ -734,17 +734,17 @@ gfxDWriteFontList::gfxDWriteFontList() { } // bug 602792 - CJK systems default to large CJK fonts which cause excessive // I/O strain during cold startup due to dwrite caching bugs. Default to // Arial to avoid this. gfxFontFamily * -gfxDWriteFontList::GetDefaultFont(const gfxFontStyle *aStyle) +gfxDWriteFontList::GetDefaultFontForPlatform(const gfxFontStyle *aStyle) { nsAutoString resolvedName; // try Arial first gfxFontFamily *ff; if ((ff = FindFamily(NS_LITERAL_STRING("Arial")))) { return ff; } @@ -850,17 +850,17 @@ gfxDWriteFontList::MakePlatformFont(cons enum DWriteInitError { errGDIInterop = 1, errSystemFontCollection = 2, errNoFonts = 3 }; nsresult -gfxDWriteFontList::InitFontList() +gfxDWriteFontList::InitFontListForPlatform() { LARGE_INTEGER frequency; // ticks per second LARGE_INTEGER t1, t2, t3, t4, t5; // ticks double elapsedTime, upTime; char nowTime[256], nowDate[256]; if (LOG_FONTINIT_ENABLED()) { GetTimeFormatA(LOCALE_INVARIANT, TIME_FORCE24HOURFORMAT, @@ -871,18 +871,16 @@ gfxDWriteFontList::InitFontList() QueryPerformanceFrequency(&frequency); QueryPerformanceCounter(&t1); // start HRESULT hr; mGDIFontTableAccess = Preferences::GetBool("gfx.font_rendering.directwrite.use_gdi_table_loading", false); - gfxPlatformFontList::InitFontList(); - mFontSubstitutes.Clear(); mNonExistingFonts.Clear(); hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()-> GetGdiInterop(getter_AddRefs(mGDIInterop)); if (FAILED(hr)) { Telemetry::Accumulate(Telemetry::DWRITEFONT_INIT_PROBLEM, uint32_t(errGDIInterop)); @@ -1404,17 +1402,18 @@ IFACEMETHODIMP DWriteFontFallbackRendere gfxFontEntry* gfxDWriteFontList::GlobalFontFallback(const uint32_t aCh, Script aRunScript, const gfxFontStyle* aMatchStyle, uint32_t& aCmapCount, gfxFontFamily** aMatchedFamily) { - bool useCmaps = gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback(); + bool useCmaps = IsFontFamilyWhitelistActive() || + gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback(); if (useCmaps) { return gfxPlatformFontList::GlobalFontFallback(aCh, aRunScript, aMatchStyle, aCmapCount, aMatchedFamily); }
--- a/gfx/thebes/gfxDWriteFontList.h +++ b/gfx/thebes/gfxDWriteFontList.h @@ -352,19 +352,17 @@ class gfxDWriteFontList : public gfxPlat public: gfxDWriteFontList(); static gfxDWriteFontList* PlatformFontList() { return static_cast<gfxDWriteFontList*>(sPlatformFontList); } // initialize font lists - virtual nsresult InitFontList(); - - virtual gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle); + virtual nsresult InitFontListForPlatform() override; virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName, uint16_t aWeight, int16_t aStretch, uint8_t aStyle); virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName, uint16_t aWeight, @@ -386,16 +384,20 @@ public: gfxFloat GetForceGDIClassicMaxFontSize() { return mForceGDIClassicMaxFontSize; } virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, FontListSizes* aSizes) const; virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, FontListSizes* aSizes) const; +protected: + virtual gfxFontFamily* + GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override; + private: friend class gfxDWriteFontFamily; nsresult GetFontSubstitutes(); void GetDirectWriteSubstitutes(); // search fonts system-wide for a given character, null otherwise
--- a/gfx/thebes/gfxFT2FontList.cpp +++ b/gfx/thebes/gfxFT2FontList.cpp @@ -27,18 +27,20 @@ #include "cairo-ft.h" #include "gfxFT2FontList.h" #include "gfxFT2Fonts.h" #include "gfxUserFontSet.h" #include "gfxFontUtils.h" #include "nsServiceManagerUtils.h" +#include "nsIObserverService.h" #include "nsTArray.h" #include "nsUnicharUtils.h" +#include "nsCRT.h" #include "nsDirectoryServiceUtils.h" #include "nsDirectoryServiceDefs.h" #include "nsAppDirectoryServiceDefs.h" #include "nsISimpleEnumerator.h" #include "nsIMemory.h" #include "gfxFontConstants.h" @@ -605,16 +607,18 @@ FT2FontFamily::AddFacesToFontList(Infall * faces without instantiating Freetype faces for each font file (in order to * find their attributes), leading to significantly quicker startup. */ #define CACHE_KEY "font.cached-list" class FontNameCache { public: + // Creates the object but does NOT load the cached data from the startup + // cache; call Init() after creation to do that. FontNameCache() : mMap(&mOps, sizeof(FNCMapEntry), 0) , mWriteNeeded(false) { // HACK ALERT: it's weird to assign |mOps| after we passed a pointer to // it to |mMap|'s constructor. A more normal approach here would be to // have a static |sOps| member. Unfortunately, this mysteriously but // consistently makes Fennec start-up slower, so we take this @@ -625,21 +629,18 @@ public: StringHash, HashMatchEntry, MoveEntry, PLDHashTable::ClearEntryStub, nullptr }; MOZ_ASSERT(XRE_IsParentProcess(), - "StartupCacheFontNameCache should only be used in chrome " - "process"); + "FontNameCache should only be used in chrome process"); mCache = mozilla::scache::StartupCache::GetSingleton(); - - Init(); } ~FontNameCache() { if (!mWriteNeeded || !mCache) { return; } @@ -657,29 +658,34 @@ public: buf.AppendInt(entry->mTimestamp); buf.Append(';'); buf.AppendInt(entry->mFilesize); buf.Append(';'); } mCache->PutBuffer(CACHE_KEY, buf.get(), buf.Length() + 1); } + // This may be called more than once (if we re-load the font list). void Init() { if (!mCache) { return; } + uint32_t size; UniquePtr<char[]> buf; if (NS_FAILED(mCache->GetBuffer(CACHE_KEY, &buf, &size))) { return; } LOG(("got: %s from the cache", nsDependentCString(buf.get(), size).get())); + mMap.Clear(); + mWriteNeeded = false; + const char* beginning = buf.get(); const char* end = strchr(beginning, ';'); while (end) { nsCString filename(beginning, end - beginning); beginning = end + 1; if (!(end = strchr(beginning, ';'))) { break; } @@ -707,33 +713,33 @@ public: mapEntry->mFileExists = false; } beginning = end + 1; end = strchr(beginning, ';'); } } - virtual void + void GetInfoForFile(const nsCString& aFileName, nsCString& aFaceList, uint32_t *aTimestamp, uint32_t *aFilesize) { auto entry = static_cast<FNCMapEntry*>(mMap.Search(aFileName.get())); if (entry) { *aTimestamp = entry->mTimestamp; *aFilesize = entry->mFilesize; aFaceList.Assign(entry->mFaces); // this entry does correspond to an existing file // (although it might not be up-to-date, in which case // it will get overwritten via CacheFileInfo) entry->mFileExists = true; } } - virtual void + void CacheFileInfo(const nsCString& aFileName, const nsCString& aFaceList, uint32_t aTimestamp, uint32_t aFilesize) { auto entry = static_cast<FNCMapEntry*>(mMap.Add(aFileName.get(), fallible)); if (entry) { entry->mFilename.Assign(aFileName); entry->mTimestamp = aTimestamp; @@ -789,18 +795,69 @@ private: * * gfxFT2FontList * */ // For Mobile, we use gfxFT2Fonts, and we build the font list by directly // scanning the system's Fonts directory for OpenType and TrueType files. +#define JAR_LAST_MODIFED_TIME "jar-last-modified-time" + +class WillShutdownObserver : public nsIObserver +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + + explicit WillShutdownObserver(gfxFT2FontList* aFontList) + : mFontList(aFontList) + { } + +protected: + virtual ~WillShutdownObserver() + { } + + gfxFT2FontList *mFontList; +}; + +NS_IMPL_ISUPPORTS(WillShutdownObserver, nsIObserver) + +NS_IMETHODIMP +WillShutdownObserver::Observe(nsISupports *aSubject, + const char *aTopic, + const char16_t *aData) +{ + if (!nsCRT::strcmp(aTopic, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID)) { + mFontList->WillShutdown(); + } else { + NS_NOTREACHED("unexpected notification topic"); + } + return NS_OK; +} + gfxFT2FontList::gfxFT2FontList() + : mJarModifiedTime(0) { + nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); + if (obs) { + mObserver = new WillShutdownObserver(this); + obs->AddObserver(mObserver, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, false); + } +} + +gfxFT2FontList::~gfxFT2FontList() +{ + if (mObserver) { + nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); + if (obs) { + obs->RemoveObserver(mObserver, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID); + } + mObserver = nullptr; + } } void gfxFT2FontList::AppendFacesFromCachedFaceList( const nsCString& aFileName, const nsCString& aFaceList, StandardFile aStdFile, FT2FontFamily::Visibility aVisibility) @@ -934,37 +991,34 @@ gfxFT2FontList::AppendFacesFromFontFile( } FT_Done_Face(dummy); if (aCache && 0 == statRetval && !newFaceList.IsEmpty()) { aCache->CacheFileInfo(aFileName, newFaceList, timestamp, filesize); } } } -#define JAR_LAST_MODIFED_TIME "jar-last-modified-time" - void gfxFT2FontList::FindFontsInOmnijar(FontNameCache *aCache) { bool jarChanged = false; mozilla::scache::StartupCache* cache = mozilla::scache::StartupCache::GetSingleton(); UniquePtr<char[]> cachedModifiedTimeBuf; uint32_t longSize; - int64_t jarModifiedTime; if (cache && NS_SUCCEEDED(cache->GetBuffer(JAR_LAST_MODIFED_TIME, &cachedModifiedTimeBuf, &longSize)) && longSize == sizeof(int64_t)) { nsCOMPtr<nsIFile> jarFile = Omnijar::GetPath(Omnijar::Type::GRE); - jarFile->GetLastModifiedTime(&jarModifiedTime); - if (jarModifiedTime > *(int64_t*)cachedModifiedTimeBuf.get()) { + jarFile->GetLastModifiedTime(&mJarModifiedTime); + if (mJarModifiedTime > *(int64_t*)cachedModifiedTimeBuf.get()) { jarChanged = true; } } static const char* sJarSearchPaths[] = { "res/fonts/*.ttf$", }; RefPtr<nsZipArchive> reader = Omnijar::GetReader(Omnijar::Type::GRE); @@ -976,21 +1030,16 @@ gfxFT2FontList::FindFontsInOmnijar(FontN while (NS_SUCCEEDED(find->FindNext(&path, &len))) { nsCString entryName(path, len); AppendFacesFromOmnijarEntry(reader, entryName, aCache, jarChanged); } delete find; } } - - if (cache) { - cache->PutBuffer(JAR_LAST_MODIFED_TIME, (char*)&jarModifiedTime, - sizeof(jarModifiedTime)); - } } // Given the freetype face corresponding to an entryName and face index, // add the face to the available font list and to the faceList string void gfxFT2FontList::AddFaceToList(const nsCString& aEntryName, uint32_t aIndex, StandardFile aStdFile, FT2FontFamily::Visibility aVisibility, @@ -999,27 +1048,27 @@ gfxFT2FontList::AddFaceToList(const nsCS { if (FT_Err_Ok != FT_Select_Charmap(aFace, FT_ENCODING_UNICODE)) { // ignore faces that don't support a Unicode charmap return; } // build the font entry name and create an FT2FontEntry, // but do -not- keep a reference to the FT_Face - FT2FontEntry* fe = + RefPtr<FT2FontEntry> fe = CreateNamedFontEntry(aFace, aEntryName.get(), aIndex); auto& fontFamilies = (aVisibility == FT2FontFamily::kHidden) ? mHiddenFontFamilies : mFontFamilies; if (fe) { NS_ConvertUTF8toUTF16 name(aFace->family_name); BuildKeyNameFromFontName(name); - gfxFontFamily *family = fontFamilies.GetWeak(name); + RefPtr<gfxFontFamily> family = fontFamilies.GetWeak(name); if (!family) { family = new FT2FontFamily(name); fontFamilies.Put(name, family); if (mSkipSpaceLookupCheckFamilies.Contains(name)) { family->SetSkipSpaceFeatureCheck(true); } if (mBadUnderlineFamilyNames.Contains(name)) { family->SetBadUnderlineFamily(); @@ -1157,80 +1206,85 @@ gfxFT2FontList::FindFonts() LOG(("got font list from chrome process: %d faces in %d families " "and %d in hidden families", fonts.Length(), mFontFamilies.Count(), mHiddenFontFamilies.Count())); return; } // Chrome process: get the cached list (if any) - FontNameCache fnc; + if (!mFontNameCache) { + mFontNameCache = MakeUnique<FontNameCache>(); + } + mFontNameCache->Init(); // ANDROID_ROOT is the root of the android system, typically /system; // font files are in /$ANDROID_ROOT/fonts/ nsCString root; char *androidRoot = PR_GetEnv("ANDROID_ROOT"); if (androidRoot) { root = androidRoot; } else { root = NS_LITERAL_CSTRING("/system"); } root.AppendLiteral("/fonts"); - FindFontsInDir(root, &fnc, FT2FontFamily::kVisible); + FindFontsInDir(root, mFontNameCache.get(), FT2FontFamily::kVisible); if (mFontFamilies.Count() == 0) { // if we can't find/read the font directory, we are doomed! NS_RUNTIMEABORT("Could not read the system fonts directory"); } #ifdef MOZ_WIDGET_GONK // Look for fonts in /system/fonts/hidden and preload them to the // user-font cache as data: URIs root.AppendLiteral("/hidden"); - FindFontsInDir(root, &fnc, FT2FontFamily::kHidden); + FindFontsInDir(root, mFontNameCache.get(), FT2FontFamily::kHidden); #endif // Look for fonts stored in omnijar, unless we're on a low-memory // device where we don't want to spend the RAM to decompress them. // (Prefs may disable this, or force-enable it even with low memory.) bool lowmem; nsCOMPtr<nsIMemory> mem = nsMemory::GetGlobalMemoryService(); if ((NS_SUCCEEDED(mem->IsLowMemoryPlatform(&lowmem)) && !lowmem && Preferences::GetBool("gfx.bundled_fonts.enabled")) || Preferences::GetBool("gfx.bundled_fonts.force-enabled")) { - FindFontsInOmnijar(&fnc); + FindFontsInOmnijar(mFontNameCache.get()); } // Look for downloaded fonts in a profile-agnostic "fonts" directory. nsCOMPtr<nsIProperties> dirSvc = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); if (dirSvc) { nsCOMPtr<nsIFile> appDir; nsresult rv = dirSvc->Get(NS_XPCOM_CURRENT_PROCESS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(appDir)); if (NS_SUCCEEDED(rv)) { appDir->AppendNative(NS_LITERAL_CSTRING("fonts")); nsCString localPath; if (NS_SUCCEEDED(appDir->GetNativePath(localPath))) { - FindFontsInDir(localPath, &fnc, FT2FontFamily::kVisible); + FindFontsInDir(localPath, mFontNameCache.get(), + FT2FontFamily::kVisible); } } } // look for locally-added fonts in a "fonts" subdir of the profile nsCOMPtr<nsIFile> localDir; nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR, getter_AddRefs(localDir)); if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(localDir->Append(NS_LITERAL_STRING("fonts")))) { nsCString localPath; rv = localDir->GetNativePath(localPath); if (NS_SUCCEEDED(rv)) { - FindFontsInDir(localPath, &fnc, FT2FontFamily::kVisible); + FindFontsInDir(localPath, mFontNameCache.get(), + FT2FontFamily::kVisible); } } // Finalize the families by sorting faces into standard order // and marking "simple" families. // Passing non-null userData here says that we want faces to be sorted. for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) { nsStringHashKey::KeyType key = iter.Key(); @@ -1309,17 +1363,17 @@ gfxFT2FontList::AppendFaceFromFontListEn StandardFile aStdFile) { FT2FontEntry* fe = FT2FontEntry::CreateFontEntry(aFLE); if (fe) { auto& fontFamilies = aFLE.isHidden() ? mHiddenFontFamilies : mFontFamilies; fe->mStandardFace = (aStdFile == kStandard); nsAutoString name(aFLE.familyName()); - gfxFontFamily *family = fontFamilies.GetWeak(name); + RefPtr<gfxFontFamily> family = fontFamilies.GetWeak(name); if (!family) { family = new FT2FontFamily(name); fontFamilies.Put(name, family); if (mSkipSpaceLookupCheckFamilies.Contains(name)) { family->SetSkipSpaceFeatureCheck(true); } if (mBadUnderlineFamilyNames.Contains(name)) { family->SetBadUnderlineFamily(); @@ -1411,20 +1465,19 @@ PreloadAsUserFontFaces(nsStringHashKey:: // Stash it persistently in the user-font cache. gfxUserFontSet::UserFontCache::CacheFont( fe, gfxUserFontSet::UserFontCache::kPersistent); } } nsresult -gfxFT2FontList::InitFontList() +gfxFT2FontList::InitFontListForPlatform() { - // reset font lists - gfxPlatformFontList::InitFontList(); + // reset hidden font list mHiddenFontFamilies.Clear(); LoadSkipSpaceLookupCheck(mSkipSpaceLookupCheckFamilies); FindFonts(); for (auto iter = mHiddenFontFamilies.Iter(); !iter.Done(); iter.Next()) { nsStringHashKey::KeyType key = iter.Key(); @@ -1503,17 +1556,17 @@ searchDone: fe->mStretch = aStretch; fe->mIsLocalUserFont = true; } return fe; } gfxFontFamily* -gfxFT2FontList::GetDefaultFont(const gfxFontStyle* aStyle) +gfxFT2FontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle) { gfxFontFamily *ff = nullptr; #ifdef MOZ_WIDGET_GONK ff = FindFamily(NS_LITERAL_STRING("Fira Sans")); #elif defined(MOZ_WIDGET_ANDROID) ff = FindFamily(NS_LITERAL_STRING("Roboto")); if (!ff) { ff = FindFamily(NS_LITERAL_STRING("Droid Sans")); @@ -1545,8 +1598,20 @@ gfxFT2FontList::GetFontFamilyList(nsTArr RefPtr<gfxFontFamily>& family = iter.Data(); aFamilyArray.AppendElement(family); } for (auto iter = mHiddenFontFamilies.Iter(); !iter.Done(); iter.Next()) { RefPtr<gfxFontFamily>& family = iter.Data(); aFamilyArray.AppendElement(family); } } + +void +gfxFT2FontList::WillShutdown() +{ + mozilla::scache::StartupCache* cache = + mozilla::scache::StartupCache::GetSingleton(); + if (cache && mJarModifiedTime > 0) { + cache->PutBuffer(JAR_LAST_MODIFED_TIME, + (char*)&mJarModifiedTime, sizeof(mJarModifiedTime)); + } + mFontNameCache = nullptr; +}
--- a/gfx/thebes/gfxFT2FontList.h +++ b/gfx/thebes/gfxFT2FontList.h @@ -114,18 +114,17 @@ public: void AddFacesToFontList(InfallibleTArray<FontListEntry>* aFontList, Visibility aVisibility); }; class gfxFT2FontList : public gfxPlatformFontList { public: gfxFT2FontList(); - - virtual gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle); + virtual ~gfxFT2FontList(); virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName, uint16_t aWeight, int16_t aStretch, uint8_t aStyle); virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName, uint16_t aWeight, @@ -137,23 +136,26 @@ public: void GetSystemFontList(InfallibleTArray<FontListEntry>* retValue); static gfxFT2FontList* PlatformFontList() { return static_cast<gfxFT2FontList*>(gfxPlatformFontList::PlatformFontList()); } virtual void GetFontFamilyList(nsTArray<RefPtr<gfxFontFamily> >& aFamilyArray); + void WillShutdown(); + protected: typedef enum { kUnknown, kStandard } StandardFile; - virtual nsresult InitFontList(); + // initialize font lists + virtual nsresult InitFontListForPlatform() override; void AppendFaceFromFontListEntry(const FontListEntry& aFLE, StandardFile aStdFile); void AppendFacesFromFontFile(const nsCString& aFileName, FontNameCache *aCache, StandardFile aStdFile, FT2FontFamily::Visibility aVisibility); @@ -177,15 +179,22 @@ protected: void FindFonts(); void FindFontsInOmnijar(FontNameCache *aCache); void FindFontsInDir(const nsCString& aDir, FontNameCache* aFNC, FT2FontFamily::Visibility aVisibility); + virtual gfxFontFamily* + GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override; + nsTHashtable<nsStringHashKey> mSkipSpaceLookupCheckFamilies; private: FontFamilyTable mHiddenFontFamilies; + + mozilla::UniquePtr<FontNameCache> mFontNameCache; + int64_t mJarModifiedTime; + nsCOMPtr<nsIObserver> mObserver; }; #endif /* GFX_FT2FONTLIST_H */
--- a/gfx/thebes/gfxFcPlatformFontList.cpp +++ b/gfx/thebes/gfxFcPlatformFontList.cpp @@ -980,17 +980,17 @@ gfxFcPlatformFontList::AddFontSetFamilie // Chrome Skia/Webkit code does also. if (!aFontSet) { NS_WARNING("AddFontSetFamilies called with a null font set."); return; } FcChar8* lastFamilyName = (FcChar8*)""; - gfxFontconfigFontFamily* fontFamily = nullptr; + RefPtr<gfxFontconfigFontFamily> fontFamily; nsAutoString familyName; for (int f = 0; f < aFontSet->nfont; f++) { FcPattern* font = aFontSet->fonts[f]; // not scalable? skip... FcBool scalable; if (FcPatternGetBool(font, FC_SCALABLE, 0, &scalable) != FcResultMatch || !scalable) { @@ -1056,23 +1056,20 @@ gfxFcPlatformFontList::AddFontSetFamilie if (!fullname.IsEmpty()) { ToLowerCase(fullname); mLocalNames.Put(fullname, font); } } } nsresult -gfxFcPlatformFontList::InitFontList() +gfxFcPlatformFontList::InitFontListForPlatform() { mLastConfig = FcConfigGetCurrent(); - // reset font lists - gfxPlatformFontList::InitFontList(); - mLocalNames.Clear(); mFcSubstituteCache.Clear(); // iterate over available fonts FcFontSet* systemFonts = FcConfigGetFonts(nullptr, FcSetSystem); AddFontSetFamilies(systemFonts, /* aAppFonts = */ false); mAlwaysUseFontconfigGenerics = PrefFontListsUseOnlyGenerics(); @@ -1177,17 +1174,17 @@ gfxFcPlatformFontList::GetFontList(nsIAt aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("monospace")); if (sansSerif) aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("sans-serif")); if (serif) aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("serif")); } gfxFontFamily* -gfxFcPlatformFontList::GetDefaultFont(const gfxFontStyle* aStyle) +gfxFcPlatformFontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle) { // Get the default font by using a fake name to retrieve the first // scalable font that fontconfig suggests for the given language. PrefFontList* prefFonts = FindGenericFamilies(NS_LITERAL_STRING("-moz-default"), aStyle->language); NS_ASSERTION(prefFonts, "null list of generic fonts"); if (prefFonts && !prefFonts->IsEmpty()) { return (*prefFonts)[0];
--- a/gfx/thebes/gfxFcPlatformFontList.h +++ b/gfx/thebes/gfxFcPlatformFontList.h @@ -213,26 +213,23 @@ class gfxFcPlatformFontList : public gfx public: gfxFcPlatformFontList(); static gfxFcPlatformFontList* PlatformFontList() { return static_cast<gfxFcPlatformFontList*>(sPlatformFontList); } // initialize font lists - nsresult InitFontList() override; + virtual nsresult InitFontListForPlatform() override; void GetFontList(nsIAtom *aLangGroup, const nsACString& aGenericFamily, nsTArray<nsString>& aListOfFonts) override; - gfxFontFamily* - GetDefaultFont(const gfxFontStyle* aStyle) override; - gfxFontEntry* LookupLocalFont(const nsAString& aFontName, uint16_t aWeight, int16_t aStretch, uint8_t aStyle) override; gfxFontEntry* MakePlatformFont(const nsAString& aFontName, uint16_t aWeight, int16_t aStretch, uint8_t aStyle, @@ -275,16 +272,19 @@ protected: PrefFontList* FindGenericFamilies(const nsAString& aGeneric, nsIAtom* aLanguage); // are all pref font settings set to use fontconfig generics? bool PrefFontListsUseOnlyGenerics(); static void CheckFontUpdates(nsITimer *aTimer, void *aThis); + virtual gfxFontFamily* + GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override; + #ifdef MOZ_BUNDLED_FONTS void ActivateBundledFonts(); nsCString mBundledFontsPath; bool mBundledFontsInitialized; #endif // to avoid enumerating all fonts, maintain a mapping of local font // names to family
--- a/gfx/thebes/gfxGDIFontList.cpp +++ b/gfx/thebes/gfxGDIFontList.cpp @@ -647,23 +647,20 @@ gfxGDIFontList::GetFontSubstitutes() if (ff) { mFontSubstitutes.Put(substituteName, ff); } } return NS_OK; } nsresult -gfxGDIFontList::InitFontList() +gfxGDIFontList::InitFontListForPlatform() { Telemetry::AutoTimer<Telemetry::GDI_INITFONTLIST_TOTAL> timer; - // reset font lists - gfxPlatformFontList::InitFontList(); - mFontSubstitutes.Clear(); mNonExistingFonts.Clear(); // iterate over available families LOGFONTW logfont; memset(&logfont, 0, sizeof(logfont)); logfont.lfCharSet = DEFAULT_CHARSET; @@ -915,17 +912,17 @@ gfxGDIFontList::FindAndAddFamilies(const return false; } return gfxPlatformFontList::FindAndAddFamilies(aFamily, aOutput, aStyle, aDevToCssSize); } gfxFontFamily* -gfxGDIFontList::GetDefaultFont(const gfxFontStyle* aStyle) +gfxGDIFontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle) { gfxFontFamily *ff = nullptr; // this really shouldn't fail to find a font.... NONCLIENTMETRICSW ncm; ncm.cbSize = sizeof(ncm); BOOL status = ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
--- a/gfx/thebes/gfxGDIFontList.h +++ b/gfx/thebes/gfxGDIFontList.h @@ -296,19 +296,17 @@ private: class gfxGDIFontList : public gfxPlatformFontList { public: static gfxGDIFontList* PlatformFontList() { return static_cast<gfxGDIFontList*>(sPlatformFontList); } // initialize font lists - virtual nsresult InitFontList(); - - virtual gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle); + virtual nsresult InitFontListForPlatform() override; bool FindAndAddFamilies(const nsAString& aFamily, nsTArray<gfxFontFamily*>* aOutput, gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) override; virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName, uint16_t aWeight, @@ -322,16 +320,20 @@ public: const uint8_t* aFontData, uint32_t aLength); virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, FontListSizes* aSizes) const; virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, FontListSizes* aSizes) const; +protected: + virtual gfxFontFamily* + GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override; + private: friend class gfxWindowsPlatform; gfxGDIFontList(); nsresult GetFontSubstitutes(); static int CALLBACK EnumFontFamExProc(ENUMLOGFONTEXW *lpelfe,
--- a/gfx/thebes/gfxMacPlatformFontList.h +++ b/gfx/thebes/gfxMacPlatformFontList.h @@ -77,18 +77,16 @@ protected: class gfxMacPlatformFontList : public gfxPlatformFontList { public: static gfxMacPlatformFontList* PlatformFontList() { return static_cast<gfxMacPlatformFontList*>(sPlatformFontList); } static int32_t AppleWeightToCSSWeight(int32_t aAppleWeight); - gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle) override; - bool GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) override; gfxFontEntry* LookupLocalFont(const nsAString& aFontName, uint16_t aWeight, int16_t aStretch, uint8_t aStyle) override; gfxFontEntry* MakePlatformFont(const nsAString& aFontName, @@ -105,24 +103,28 @@ public: // lookup the system font for a particular system font type and set // the name and style characteristics void LookupSystemFont(mozilla::LookAndFeel::FontID aSystemFontID, nsAString& aSystemFontName, gfxFontStyle &aFontStyle, float aDevPixPerCSSPixel); +protected: + virtual gfxFontFamily* + GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override; + private: friend class gfxPlatformMac; gfxMacPlatformFontList(); virtual ~gfxMacPlatformFontList(); // initialize font lists - nsresult InitFontList() override; + virtual nsresult InitFontListForPlatform() override; // special case font faces treated as font families (set via prefs) void InitSingleFaceList(); // initialize system fonts void InitSystemFontNames(); // helper function to lookup in both hidden system fonts and normal fonts
--- a/gfx/thebes/gfxMacPlatformFontList.mm +++ b/gfx/thebes/gfxMacPlatformFontList.mm @@ -698,34 +698,33 @@ gfxMacPlatformFontList::AddFamily(CFStri if (hiddenSystemFont && mUseSizeSensitiveSystemFont && mSystemDisplayFontFamilyName.Equals(familyName)) { sizeHint = 128.0; } nsAutoString key; ToLowerCase(familyName, key); - gfxFontFamily* familyEntry = new gfxMacFontFamily(familyName, sizeHint); + RefPtr<gfxFontFamily> familyEntry = new gfxMacFontFamily(familyName, sizeHint); table.Put(key, familyEntry); // check the bad underline blacklist if (mBadUnderlineFamilyNames.Contains(key)) { familyEntry->SetBadUnderlineFamily(); } } nsresult -gfxMacPlatformFontList::InitFontList() +gfxMacPlatformFontList::InitFontListForPlatform() { nsAutoreleasePool localPool; Telemetry::AutoTimer<Telemetry::MAC_INITFONTLIST_TOTAL> timer; - // reset font lists - gfxPlatformFontList::InitFontList(); + // reset system font list mSystemFontFamilies.Clear(); // iterate over available families InitSystemFontNames(); CFArrayRef familyNames = CTFontManagerCopyAvailableFontFamilyNames(); @@ -775,17 +774,17 @@ gfxMacPlatformFontList::InitSingleFaceLi nsAutoString key; GenerateFontListKey(familyName, key); LOG_FONTLIST(("(fontlist-singleface) family name: %s, key: %s\n", NS_ConvertUTF16toUTF8(familyName).get(), NS_ConvertUTF16toUTF8(key).get())); // add only if doesn't exist already if (!mFontFamilies.GetWeak(key)) { - gfxFontFamily *familyEntry = + RefPtr<gfxFontFamily> familyEntry = new gfxSingleFaceMacFontFamily(familyName); // LookupLocalFont sets this, need to clear fontEntry->mIsLocalUserFont = false; familyEntry->AddFontEntry(fontEntry); familyEntry->SetHasStyles(true); mFontFamilies.Put(key, familyEntry); LOG_FONTLIST(("(fontlist-singleface) added new family\n", NS_ConvertUTF16toUTF8(familyName).get(), @@ -922,17 +921,18 @@ gfxMacPlatformFontList::RegisteredFontsC gfxFontEntry* gfxMacPlatformFontList::GlobalFontFallback(const uint32_t aCh, Script aRunScript, const gfxFontStyle* aMatchStyle, uint32_t& aCmapCount, gfxFontFamily** aMatchedFamily) { - bool useCmaps = gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback(); + bool useCmaps = IsFontFamilyWhitelistActive() || + gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback(); if (useCmaps) { return gfxPlatformFontList::GlobalFontFallback(aCh, aRunScript, aMatchStyle, aCmapCount, aMatchedFamily); } @@ -1012,17 +1012,17 @@ gfxMacPlatformFontList::GlobalFontFallba } ::CFRelease(str); return fontEntry; } gfxFontFamily* -gfxMacPlatformFontList::GetDefaultFont(const gfxFontStyle* aStyle) +gfxMacPlatformFontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle) { nsAutoreleasePool localPool; NSString *defaultFamily = [[NSFont userFontOfSize:aStyle->size] familyName]; nsAutoString familyName; GetStringForNSString(defaultFamily, familyName); return FindFamily(familyName);
--- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp @@ -95,16 +95,18 @@ const gfxFontEntry::ScriptRange gfxPlatf static const char* kObservedPrefs[] = { "font.", "font.name-list.", "intl.accept_languages", // hmmmm... nullptr }; +static const char kFontSystemWhitelistPref[] = "font.system.whitelist"; + // xxx - this can probably be eliminated by reworking pref font handling code static const char *gPrefLangNames[] = { #define FONT_PREF_LANG(enum_id_, str_, atom_id_) str_ #include "gfxFontPrefLangList.h" #undef FONT_PREF_LANG }; static_assert(MOZ_ARRAY_LENGTH(gPrefLangNames) == uint32_t(eFontPrefLang_Count), @@ -168,17 +170,18 @@ gfxPlatformFontList::MemoryReporter::Col } return NS_OK; } gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames) : mFontFamilies(64), mOtherFamilyNames(16), mBadUnderlineFamilyNames(8), mSharedCmaps(8), - mStartIndex(0), mIncrement(1), mNumFamilies(0), mFontlistInitCount(0) + mStartIndex(0), mIncrement(1), mNumFamilies(0), mFontlistInitCount(0), + mFontFamilyWhitelistActive(false) { mOtherFamilyNamesInitialized = false; if (aNeedFullnamePostscriptNames) { mExtraNames = MakeUnique<ExtraNames>(); } mFaceNameListsInitialized = false; @@ -186,31 +189,65 @@ gfxPlatformFontList::gfxPlatformFontList // pref changes notification setup NS_ASSERTION(!gFontListPrefObserver, "There has been font list pref observer already"); gFontListPrefObserver = new gfxFontListPrefObserver(); NS_ADDREF(gFontListPrefObserver); Preferences::AddStrongObservers(gFontListPrefObserver, kObservedPrefs); + Preferences::RegisterCallback(FontWhitelistPrefChanged, + kFontSystemWhitelistPref); + RegisterStrongMemoryReporter(new MemoryReporter()); } gfxPlatformFontList::~gfxPlatformFontList() { mSharedCmaps.Clear(); ClearLangGroupPrefFonts(); NS_ASSERTION(gFontListPrefObserver, "There is no font list pref observer"); Preferences::RemoveObservers(gFontListPrefObserver, kObservedPrefs); + Preferences::UnregisterCallback(FontWhitelistPrefChanged, + kFontSystemWhitelistPref); NS_RELEASE(gFontListPrefObserver); } // number of CSS generic font families const uint32_t kNumGenerics = 5; +void +gfxPlatformFontList::ApplyWhitelist() +{ + nsTArray<nsString> list; + gfxFontUtils::GetPrefsFontList(kFontSystemWhitelistPref, list); + uint32_t numFonts = list.Length(); + mFontFamilyWhitelistActive = (numFonts > 0); + if (!mFontFamilyWhitelistActive) { + return; + } + nsTHashtable<nsStringHashKey> familyNamesWhitelist; + for (uint32_t i = 0; i < numFonts; i++) { + nsString key; + ToLowerCase(list[i], key); + familyNamesWhitelist.PutEntry(key); + } + for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) { + // Don't continue if we only have one font left. + if (mFontFamilies.Count() == 1) { + break; + } + nsString fontFamilyName(iter.Key()); + ToLowerCase(fontFamilyName); + if (!familyNamesWhitelist.Contains(fontFamilyName)) { + iter.Remove(); + } + } +} + nsresult gfxPlatformFontList::InitFontList() { mFontlistInitCount++; if (LOG_FONTINIT_ENABLED()) { LOG_FONTINIT(("(fontinit) system fontlist initialization\n")); } @@ -238,16 +275,22 @@ gfxPlatformFontList::InitFontList() // initialize ranges of characters for which system-wide font search should be skipped mCodepointsWithNoFonts.reset(); mCodepointsWithNoFonts.SetRange(0,0x1f); // C0 controls mCodepointsWithNoFonts.SetRange(0x7f,0x9f); // C1 controls sPlatformFontList = this; + nsresult rv = InitFontListForPlatform(); + if (NS_FAILED(rv)) { + return rv; + } + + ApplyWhitelist(); return NS_OK; } void gfxPlatformFontList::GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult) { aResult = aKeyName; ToLowerCase(aResult); @@ -1142,16 +1185,31 @@ gfxPlatformFontList::GetDefaultGeneric(e } if (uint32_t(aLang) < ArrayLength(gPrefLangNames)) { return mDefaultGenericsLangGroup[uint32_t(aLang)]; } return eFamily_serif; } + +gfxFontFamily* +gfxPlatformFontList::GetDefaultFont(const gfxFontStyle* aStyle) +{ + gfxFontFamily* family = GetDefaultFontForPlatform(aStyle); + if (family) { + return family; + } + // Something has gone wrong and we were unable to retrieve a default font + // from the platform. (Likely the whitelist has blocked all potential + // default fonts.) As a last resort, we return the first font listed in + // mFontFamilies. + return mFontFamilies.Iter().Data(); +} + void gfxPlatformFontList::GetFontFamilyNames(nsTArray<nsString>& aFontFamilyNames) { for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) { RefPtr<gfxFontFamily>& family = iter.Data(); aFontFamilyNames.AppendElement(family->Name()); } } @@ -1593,10 +1651,16 @@ gfxPlatformFontList::AddSizeOfExcludingT void gfxPlatformFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, FontListSizes* aSizes) const { aSizes->mFontListSize += aMallocSizeOf(this); AddSizeOfExcludingThis(aMallocSizeOf, aSizes); } +bool +gfxPlatformFontList::IsFontFamilyWhitelistActive() +{ + return mFontFamilyWhitelistActive; +} + #undef LOG #undef LOG_ENABLED
--- a/gfx/thebes/gfxPlatformFontList.h +++ b/gfx/thebes/gfxPlatformFontList.h @@ -109,17 +109,17 @@ public: static void Shutdown() { delete sPlatformFontList; sPlatformFontList = nullptr; } virtual ~gfxPlatformFontList(); // initialize font lists - virtual nsresult InitFontList(); + nsresult InitFontList(); virtual void GetFontList(nsIAtom *aLangGroup, const nsACString& aGenericFamily, nsTArray<nsString>& aListOfFonts); void UpdateFontList(); virtual void ClearLangGroupPrefFonts(); @@ -150,17 +150,17 @@ public: void AddPostscriptName(gfxFontEntry *aFontEntry, nsAString& aPostscriptName); bool NeedFullnamePostscriptNames() { return mExtraNames != nullptr; } // pure virtual functions, to be provided by concrete subclasses // get the system default font family - virtual gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle) = 0; + gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle); // look up a font by name on the host platform virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName, uint16_t aWeight, int16_t aStretch, uint8_t aStyle) = 0; // create a new platform font from downloaded data (@font-face) @@ -243,16 +243,23 @@ public: // default serif/sans-serif choice based on font.default.xxx prefs mozilla::FontFamilyType GetDefaultGeneric(eFontPrefLang aLang); // map lang group ==> lang string void GetSampleLangForGroup(nsIAtom* aLanguage, nsACString& aLangStr, bool aCheckEnvironment = true); + // Returns true if the font family whitelist is not empty. + bool IsFontFamilyWhitelistActive(); + + static void FontWhitelistPrefChanged(const char *aPref, void *aClosure) { + gfxPlatformFontList::PlatformFontList()->UpdateFontList(); + } + protected: class MemoryReporter final : public nsIMemoryReporter { ~MemoryReporter() {} public: NS_DECL_ISUPPORTS NS_DECL_NSIMEMORYREPORTER }; @@ -356,27 +363,35 @@ protected: void RebuildLocalFonts(); void ResolveGenericFontNames(mozilla::FontFamilyType aGenericType, eFontPrefLang aPrefLang, nsTArray<RefPtr<gfxFontFamily>>* aGenericFamilies); + virtual nsresult InitFontListForPlatform() = 0; + + void ApplyWhitelist(); + typedef nsRefPtrHashtable<nsStringHashKey, gfxFontFamily> FontFamilyTable; typedef nsRefPtrHashtable<nsStringHashKey, gfxFontEntry> FontEntryTable; // used by memory reporter to accumulate sizes of family names in the table static size_t SizeOfFontFamilyTableExcludingThis(const FontFamilyTable& aTable, mozilla::MallocSizeOf aMallocSizeOf); static size_t SizeOfFontEntryTableExcludingThis(const FontEntryTable& aTable, mozilla::MallocSizeOf aMallocSizeOf); + // Platform-specific helper for GetDefaultFont(...). + virtual gfxFontFamily* + GetDefaultFontForPlatform(const gfxFontStyle* aStyle) = 0; + // canonical family name ==> family entry (unique, one name per family entry) FontFamilyTable mFontFamilies; // other family name ==> family entry (not unique, can have multiple names per // family entry, only names *other* than the canonical names are stored here) FontFamilyTable mOtherFamilyNames; // flag set after InitOtherFamilyNames is called upon first name lookup miss @@ -432,11 +447,13 @@ protected: // see bugs 636957, 1070983, 1189129 uint32_t mFontlistInitCount; // num times InitFontList called nsTHashtable<nsPtrHashKey<gfxUserFontSet> > mUserFontSetList; nsCOMPtr<nsILanguageAtomService> mLangService; nsTArray<uint32_t> mCJKPrefLangs; nsTArray<mozilla::FontFamilyType> mDefaultGenericsLangGroup; + + bool mFontFamilyWhitelistActive; }; #endif /* GFXPLATFORMFONTLIST_H_ */
--- a/gfx/thebes/gfxUserFontSet.cpp +++ b/gfx/thebes/gfxUserFontSet.cpp @@ -417,17 +417,20 @@ gfxUserFontEntry::LoadNextSrc() // load each src entry in turn, until a local face is found // or a download begins successfully while (mSrcIndex < numSrc) { gfxFontFaceSrc& currSrc = mSrcList[mSrcIndex]; // src local ==> lookup and load immediately if (currSrc.mSourceType == gfxFontFaceSrc::eSourceType_Local) { - gfxFontEntry* fe = + // Don't look up local fonts if the font whitelist is being used. + gfxFontEntry* fe = gfxPlatformFontList::PlatformFontList()-> + IsFontFamilyWhitelistActive() ? + nullptr : gfxPlatform::GetPlatform()->LookupLocalFont(currSrc.mLocalName, mWeight, mStretch, mStyle); nsTArray<gfxUserFontSet*> fontSets; GetUserFontSets(fontSets); for (gfxUserFontSet* fontSet : fontSets) { // We need to note on each gfxUserFontSet that contains the user
--- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -360,29 +360,29 @@ gfxWindowsPlatform::InitAcceleration() mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_0); mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_1); mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0); mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_9_3); DeviceManagerDx::Init(); DeviceManagerD3D9::Init(); - // CanUseHardwareVideoDecoding depends on DeviceManagerDx state, - // so update the cached value now. - UpdateCanUseHardwareVideoDecoding(); - InitializeConfig(); InitializeDevices(); UpdateANGLEConfig(); UpdateRenderMode(); // If we have Skia and we didn't init dwrite already, do it now. if (!mDWriteFactory && GetDefaultContentBackend() == BackendType::SKIA) { InitDWriteSupport(); } + + // CanUseHardwareVideoDecoding depends on DeviceManagerDx state, + // so update the cached value now. + UpdateCanUseHardwareVideoDecoding(); } bool gfxWindowsPlatform::CanUseHardwareVideoDecoding() { DeviceManagerDx* dm = DeviceManagerDx::Get(); if (!dm) { return false;
--- a/intl/unicharutil/tools/genUnicodePropertyData.pl +++ b/intl/unicharutil/tools/genUnicodePropertyData.pl @@ -768,17 +768,18 @@ sub sprintFullWidthInverse } &genTables("", "", "FullWidthInverse", "", "uint16_t", 10, 6, \&sprintFullWidthInverse, 0, 2, 1); sub sprintCasemap { my $usv = shift; return sprintf("0x%08x,", $casemap[$usv]); } -&genTables("", "", "CaseMap", "", "uint32_t", 11, 5, \&sprintCasemap, 1, 4, 1); +&genTables("#if !ENABLE_INTL_API", "#endif", + "CaseMap", "", "uint32_t", 11, 5, \&sprintCasemap, 1, 4, 1); print STDERR "Total data = $totalData\n"; printf DATA_TABLES "const uint32_t kTitleToUpper = 0x%08x;\n", $kTitleToUpper; printf DATA_TABLES "const uint32_t kUpperToLower = 0x%08x;\n", $kUpperToLower; printf DATA_TABLES "const uint32_t kLowerToTitle = 0x%08x;\n", $kLowerToTitle; printf DATA_TABLES "const uint32_t kLowerToUpper = 0x%08x;\n", $kLowerToUpper; printf DATA_TABLES "const uint32_t kCaseMapCharMask = 0x%08x;\n\n", $kCaseMapCharMask;
--- a/intl/unicharutil/util/nsUnicodeProperties.cpp +++ b/intl/unicharutil/util/nsUnicodeProperties.cpp @@ -5,21 +5,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsUnicodeProperties.h" #include "nsUnicodePropertyData.cpp" #include "mozilla/ArrayUtils.h" #include "nsCharTraits.h" -#if ENABLE_INTL_API -#include "unicode/uchar.h" -#include "unicode/uscript.h" -#endif - #define UNICODE_BMP_LIMIT 0x10000 #define UNICODE_LIMIT 0x110000 #ifndef ENABLE_INTL_API static const nsCharProps1& GetCharProps1(uint32_t aCh) { if (aCh < UNICODE_BMP_LIMIT) { @@ -168,128 +163,78 @@ const hb_unicode_general_category_t sICU HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL, // U_CURRENCY_SYMBOL = 25, HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL, // U_MODIFIER_SYMBOL = 26, HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL, // U_OTHER_SYMBOL = 27, HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION, // U_INITIAL_PUNCTUATION = 28, HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION, // U_FINAL_PUNCTUATION = 29, }; #endif +#if !ENABLE_INTL_API uint8_t GetGeneralCategory(uint32_t aCh) { -#if ENABLE_INTL_API - return sICUtoHBcategory[u_charType(aCh)]; -#else return GetCharProps2(aCh).mCategory; -#endif } nsCharType GetBidiCat(uint32_t aCh) { -#if ENABLE_INTL_API - return nsCharType(u_charDirection(aCh)); -#else return nsCharType(GetCharProps2(aCh).mBidiCategory); -#endif } int8_t GetNumericValue(uint32_t aCh) { -#if ENABLE_INTL_API - UNumericType type = - UNumericType(u_getIntPropertyValue(aCh, UCHAR_NUMERIC_TYPE)); - return type == U_NT_DECIMAL || type == U_NT_DIGIT - ? int8_t(u_getNumericValue(aCh)) - : -1; -#else return GetCharProps2(aCh).mNumericValue; -#endif } uint32_t GetMirroredChar(uint32_t aCh) { -#if ENABLE_INTL_API - return u_charMirror(aCh); -#else return aCh + sMirrorOffsets[GetCharProps1(aCh).mMirrorOffsetIndex]; -#endif } bool HasMirroredChar(uint32_t aCh) { -#if ENABLE_INTL_API - return u_isMirrored(aCh); -#else return GetCharProps1(aCh).mMirrorOffsetIndex != 0; -#endif } uint8_t GetCombiningClass(uint32_t aCh) { -#if ENABLE_INTL_API - return u_getCombiningClass(aCh); -#else return GetCharProps1(aCh).mCombiningClass; -#endif } uint8_t GetLineBreakClass(uint32_t aCh) { -#if ENABLE_INTL_API - return u_getIntPropertyValue(aCh, UCHAR_LINE_BREAK); -#else return GetCharProps2(aCh).mLineBreak; -#endif } Script GetScriptCode(uint32_t aCh) { -#if ENABLE_INTL_API - UErrorCode err = U_ZERO_ERROR; - return Script(uscript_getScript(aCh, &err)); -#else return Script(GetCharProps2(aCh).mScriptCode); -#endif } uint32_t GetScriptTagForCode(Script aScriptCode) { -#if ENABLE_INTL_API - const char* tag = uscript_getShortName(UScriptCode(aScriptCode)); - return HB_TAG(tag[0], tag[1], tag[2], tag[3]); -#else // this will safely return 0 for negative script codes, too :) if (static_cast<uint32_t>(aScriptCode) > ArrayLength(sScriptCodeToTag)) { return 0; } return sScriptCodeToTag[static_cast<uint32_t>(aScriptCode)]; -#endif } PairedBracketType GetPairedBracketType(uint32_t aCh) { -#if ENABLE_INTL_API - return PairedBracketType - (u_getIntPropertyValue(aCh, UCHAR_BIDI_PAIRED_BRACKET_TYPE)); -#else return PairedBracketType(GetCharProps2(aCh).mPairedBracketType); -#endif } uint32_t GetPairedBracket(uint32_t aCh) { -#if ENABLE_INTL_API - return u_getBidiPairedBracket(aCh); -#else return GetPairedBracketType(aCh) != PAIRED_BRACKET_TYPE_NONE ? GetMirroredChar(aCh) : aCh; -#endif } static inline uint32_t GetCaseMapValue(uint32_t aCh) { if (aCh < UNICODE_BMP_LIMIT) { return sCaseMapValues[sCaseMapPages[0][aCh >> kCaseMapCharBits]] [aCh & ((1 << kCaseMapCharBits) - 1)]; @@ -345,36 +290,16 @@ GetTitlecaseForAll(uint32_t aCh) if (mapValue & (kLowerToTitle | kLowerToUpper)) { return aCh ^ (mapValue & kCaseMapCharMask); } if (mapValue & kUpperToLower) { return GetTitlecaseForLower(aCh ^ (mapValue & kCaseMapCharMask)); } return aCh; } - -#if 0 // currently unused - bug 857481 -HanVariantType -GetHanVariant(uint32_t aCh) -{ - // In the sHanVariantValues array, data for 4 successive characters - // (2 bits each) is packed in to each uint8_t entry, with the value - // for the lowest character stored in the least significant bits. - uint8_t v = 0; - if (aCh < UNICODE_BMP_LIMIT) { - v = sHanVariantValues[sHanVariantPages[0][aCh >> kHanVariantCharBits]] - [(aCh & ((1 << kHanVariantCharBits) - 1)) >> 2]; - } else if (aCh < (kHanVariantMaxPlane + 1) * 0x10000) { - v = sHanVariantValues[sHanVariantPages[sHanVariantPlanes[(aCh >> 16) - 1]] - [(aCh & 0xffff) >> kHanVariantCharBits]] - [(aCh & ((1 << kHanVariantCharBits) - 1)) >> 2]; - } - // extract the appropriate 2-bit field from the value - return HanVariantType((v >> ((aCh & 3) * 2)) & 3); -} #endif #define DEFINE_BMP_1PLANE_MAPPING_GET_FUNC(prefix_) \ uint32_t Get##prefix_(uint32_t aCh) \ { \ if (aCh >= UNICODE_BMP_LIMIT) { \ return aCh; \ } \
--- a/intl/unicharutil/util/nsUnicodeProperties.h +++ b/intl/unicharutil/util/nsUnicodeProperties.h @@ -5,130 +5,226 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef NS_UNICODEPROPERTIES_H #define NS_UNICODEPROPERTIES_H #include "nsBidiUtils.h" #include "nsIUGenCategory.h" #include "nsUnicodeScriptCodes.h" +#include "harfbuzz/hb.h" + +#if ENABLE_INTL_API +#include "unicode/uchar.h" +#include "unicode/uscript.h" +#endif const nsCharProps2& GetCharProps2(uint32_t aCh); namespace mozilla { namespace unicode { extern const nsIUGenCategory::nsUGenCategory sDetailedToGeneralCategory[]; -// Return whether the char has a mirrored-pair counterpart. -uint32_t GetMirroredChar(uint32_t aCh); - -bool HasMirroredChar(uint32_t aChr); - -uint8_t GetCombiningClass(uint32_t aCh); - -// returns the detailed General Category in terms of HB_UNICODE_* values -uint8_t GetGeneralCategory(uint32_t aCh); - -// returns the simplified Gen Category as defined in nsIUGenCategory -inline nsIUGenCategory::nsUGenCategory GetGenCategory(uint32_t aCh) { - return sDetailedToGeneralCategory[GetGeneralCategory(aCh)]; -} - -nsCharType GetBidiCat(uint32_t aCh); - -uint8_t GetLineBreakClass(uint32_t aCh); - -Script GetScriptCode(uint32_t aCh); - -uint32_t GetScriptTagForCode(Script aScriptCode); - /* This MUST match the values assigned by genUnicodePropertyData.pl! */ enum VerticalOrientation { VERTICAL_ORIENTATION_U = 0, VERTICAL_ORIENTATION_R = 1, VERTICAL_ORIENTATION_Tu = 2, VERTICAL_ORIENTATION_Tr = 3 }; -inline VerticalOrientation GetVerticalOrientation(uint32_t aCh) { - return VerticalOrientation(GetCharProps2(aCh).mVertOrient); -} - /* This MUST match the values assigned by genUnicodePropertyData.pl! */ enum PairedBracketType { PAIRED_BRACKET_TYPE_NONE = 0, PAIRED_BRACKET_TYPE_OPEN = 1, PAIRED_BRACKET_TYPE_CLOSE = 2 }; -PairedBracketType GetPairedBracketType(uint32_t aCh); -uint32_t GetPairedBracket(uint32_t aCh); - enum XidmodType { XIDMOD_RECOMMENDED, XIDMOD_INCLUSION, XIDMOD_UNCOMMON_USE, XIDMOD_TECHNICAL, XIDMOD_OBSOLETE, XIDMOD_ASPIRATIONAL, XIDMOD_LIMITED_USE, XIDMOD_EXCLUSION, XIDMOD_NOT_XID, XIDMOD_NOT_NFKC, XIDMOD_DEFAULT_IGNORABLE, XIDMOD_DEPRECATED, XIDMOD_NOT_CHARS }; -inline XidmodType GetIdentifierModification(uint32_t aCh) { - return XidmodType(GetCharProps2(aCh).mXidmod); +#if ENABLE_INTL_API // ICU is available, so simply forward to its API + +extern const hb_unicode_general_category_t sICUtoHBcategory[]; + +inline uint32_t +GetMirroredChar(uint32_t aCh) +{ + return u_charMirror(aCh); +} + +inline bool +HasMirroredChar(uint32_t aCh) +{ + return u_isMirrored(aCh); +} + +inline uint8_t +GetCombiningClass(uint32_t aCh) +{ + return u_getCombiningClass(aCh); +} + +inline uint8_t +GetGeneralCategory(uint32_t aCh) +{ + return sICUtoHBcategory[u_charType(aCh)]; +} + +inline nsCharType +GetBidiCat(uint32_t aCh) +{ + return nsCharType(u_charDirection(aCh)); +} + +inline int8_t +GetNumericValue(uint32_t aCh) +{ + UNumericType type = + UNumericType(u_getIntPropertyValue(aCh, UCHAR_NUMERIC_TYPE)); + return type == U_NT_DECIMAL || type == U_NT_DIGIT + ? int8_t(u_getNumericValue(aCh)) : -1; +} + +inline uint8_t +GetLineBreakClass(uint32_t aCh) +{ + return u_getIntPropertyValue(aCh, UCHAR_LINE_BREAK); +} + +inline Script +GetScriptCode(uint32_t aCh) +{ + UErrorCode err = U_ZERO_ERROR; + return Script(uscript_getScript(aCh, &err)); } +inline uint32_t +GetScriptTagForCode(Script aScriptCode) +{ + const char* tag = uscript_getShortName(UScriptCode(aScriptCode)); + return HB_TAG(tag[0], tag[1], tag[2], tag[3]); +} + +inline PairedBracketType +GetPairedBracketType(uint32_t aCh) +{ + return PairedBracketType + (u_getIntPropertyValue(aCh, UCHAR_BIDI_PAIRED_BRACKET_TYPE)); +} + +inline uint32_t +GetPairedBracket(uint32_t aCh) +{ + return u_getBidiPairedBracket(aCh); +} + +inline uint32_t +GetUppercase(uint32_t aCh) +{ + return u_toupper(aCh); +} + +inline uint32_t +GetLowercase(uint32_t aCh) +{ + return u_tolower(aCh); +} + +inline uint32_t +GetTitlecaseForLower(uint32_t aCh) // maps LC to titlecase, UC unchanged +{ + return u_isULowercase(aCh) ? u_totitle(aCh) : aCh; +} + +inline uint32_t +GetTitlecaseForAll(uint32_t aCh) // maps both UC and LC to titlecase +{ + return u_totitle(aCh); +} + +#else // not ENABLE_INTL_API + +// Return whether the char has a mirrored-pair counterpart. +uint32_t GetMirroredChar(uint32_t aCh); + +bool HasMirroredChar(uint32_t aChr); + +uint8_t GetCombiningClass(uint32_t aCh); + +// returns the detailed General Category in terms of HB_UNICODE_* values +uint8_t GetGeneralCategory(uint32_t aCh); + +nsCharType GetBidiCat(uint32_t aCh); + +uint8_t GetLineBreakClass(uint32_t aCh); + +Script GetScriptCode(uint32_t aCh); + +uint32_t GetScriptTagForCode(Script aScriptCode); + +PairedBracketType GetPairedBracketType(uint32_t aCh); +uint32_t GetPairedBracket(uint32_t aCh); + /** * Return the numeric value of the character. The value returned is the value * of the Numeric_Value in field 7 of the UCD, or -1 if field 7 is empty. * To restrict to decimal digits, the caller should also check whether * GetGeneralCategory returns HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER */ int8_t GetNumericValue(uint32_t aCh); -#if 0 // currently unused - bug 857481 -enum HanVariantType { - HVT_NotHan = 0x0, - HVT_SimplifiedOnly = 0x1, - HVT_TraditionalOnly = 0x2, - HVT_AnyHan = 0x3 -}; +uint32_t GetUppercase(uint32_t aCh); +uint32_t GetLowercase(uint32_t aCh); +uint32_t GetTitlecaseForLower(uint32_t aCh); // maps LC to titlecase, UC unchanged +uint32_t GetTitlecaseForAll(uint32_t aCh); // maps both UC and LC to titlecase + +#endif // !ENABLE_INTL_API -HanVariantType GetHanVariant(uint32_t aCh); -#endif +// returns the simplified Gen Category as defined in nsIUGenCategory +inline nsIUGenCategory::nsUGenCategory GetGenCategory(uint32_t aCh) { + return sDetailedToGeneralCategory[GetGeneralCategory(aCh)]; +} + +inline VerticalOrientation GetVerticalOrientation(uint32_t aCh) { + return VerticalOrientation(GetCharProps2(aCh).mVertOrient); +} + +inline XidmodType GetIdentifierModification(uint32_t aCh) { + return XidmodType(GetCharProps2(aCh).mXidmod); +} uint32_t GetFullWidth(uint32_t aCh); // This is the reverse function of GetFullWidth which guarantees that // for every codepoint c, GetFullWidthInverse(GetFullWidth(c)) == c. // Note that, this function does not guarantee to convert all wide // form characters to their possible narrow form. uint32_t GetFullWidthInverse(uint32_t aCh); bool IsClusterExtender(uint32_t aCh, uint8_t aCategory); inline bool IsClusterExtender(uint32_t aCh) { return IsClusterExtender(aCh, GetGeneralCategory(aCh)); } -// Case mappings for the full Unicode range; -// note that it may be worth testing for ASCII chars and taking -// a separate fast-path before calling these, in perf-critical places -uint32_t GetUppercase(uint32_t aCh); -uint32_t GetLowercase(uint32_t aCh); -uint32_t GetTitlecaseForLower(uint32_t aCh); // maps LC to titlecase, UC unchanged -uint32_t GetTitlecaseForAll(uint32_t aCh); // maps both UC and LC to titlecase - // A simple iterator for a string of char16_t codepoints that advances // by Unicode grapheme clusters class ClusterIterator { public: ClusterIterator(const char16_t* aText, uint32_t aLength) : mPos(aText), mLimit(aText + aLength) #ifdef DEBUG
--- a/intl/unicharutil/util/nsUnicodePropertyData.cpp +++ b/intl/unicharutil/util/nsUnicodePropertyData.cpp @@ -6,17 +6,17 @@ /* * Derived from the Unicode Character Database by genUnicodePropertyData.pl * * For Unicode terms of use, see http://www.unicode.org/terms_of_use.html */ /* - * Created on Tue Apr 26 07:40:35 2016 from UCD data files with version info: + * Created on Tue Sep 27 12:56:07 2016 from UCD data files with version info: * # Date: 2015-06-16, 20:24:00 GMT [KW] # # Unicode Character Database # Copyright (c) 1991-2015 Unicode, Inc. # For terms of use, see http://www.unicode.org/terms_of_use.html # @@ -1737,17 +1737,17 @@ static const uint16_t sFullWidthInverseV {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xffa1,0xffa2,0xffa3,0xffa4,0xffa5,0xffa6,0xffa7,0xffa8,0xffa9,0xffaa,0xffab,0xffac,0xffad,0xffae,0xffaf}, {0xffb0,0xffb1,0xffb2,0xffb3,0xffb4,0xffb5,0xffb6,0xffb7,0xffb8,0xffb9,0xffba,0xffbb,0xffbc,0xffbd,0xffbe,0xffc2,0xffc3,0xffc4,0xffc5,0xffc6,0xffc7,0xffca,0xffcb,0xffcc,0xffcd,0xffce,0xffcf,0xffd2,0xffd3,0xffd4,0xffd5,0xffd6,0xffd7,0xffda,0xffdb,0xffdc,0xffa0,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}, {0x0000,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f,0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f,0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f}, {0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x2985,0x2986,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}, {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x00a2,0x00a3,0x00ac,0x00af,0x00a6,0x00a5,0x20a9,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000} }; - +#if !ENABLE_INTL_API #define kCaseMapMaxPlane 1 #define kCaseMapIndexBits 11 #define kCaseMapCharBits 5 static const uint8_t sCaseMapPlanes[1] = {1}; static const uint8_t sCaseMapPages[2][2048] = { {0,0,1,2,0,3,4,5,6,7,8,9,10,11,12,13,6,14,15,16,17,0,0,0,0,0,18,19,20,21,22,23,24,25,26,6,27,6,28,6,6,29,30,31,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35,36,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,38,0,0,0,0,6,6,6,6,39,6,6,6,40,41,42,43,41,44,45,46,0,0,0,0,0,0,0,0,0,47,48,49,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,51,52,53,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,54,55,56,57,6,6,6,58,59,60,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,61,62,0,0,0,0,63,6,64,65,66,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67,68,69,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,72,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,73,74,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,76,77,78,79,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,81,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} @@ -1832,17 +1832,17 @@ static const uint32_t sCaseMapValues[82] {0x10000058,0x10000058,0x10000058,0x10000058,0x10000058,0x10000058,0x10000058,0x10000058,0x10000068,0x10000068,0x10000068,0x10000068,0x10000068,0x10000068,0x10000068,0x10000068,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000}, {0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040}, {0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x40000040,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000}, {0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040}, {0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x10000040,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000}, {0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060,0x40000060}, {0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060,0x10000060} }; - +#endif const uint32_t kTitleToUpper = 0x80000000; const uint32_t kUpperToLower = 0x40000000; const uint32_t kLowerToTitle = 0x20000000; const uint32_t kLowerToUpper = 0x10000000; const uint32_t kCaseMapCharMask = 0x001fffff; /* * * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * *
--- a/intl/unicharutil/util/nsUnicodeScriptCodes.h +++ b/intl/unicharutil/util/nsUnicodeScriptCodes.h @@ -6,17 +6,17 @@ /* * Derived from the Unicode Character Database by genUnicodePropertyData.pl * * For Unicode terms of use, see http://www.unicode.org/terms_of_use.html */ /* - * Created on Tue Apr 26 07:40:35 2016 from UCD data files with version info: + * Created on Tue Sep 27 12:56:07 2016 from UCD data files with version info: * # Date: 2015-06-16, 20:24:00 GMT [KW] # # Unicode Character Database # Copyright (c) 1991-2015 Unicode, Inc. # For terms of use, see http://www.unicode.org/terms_of_use.html #
--- a/ipc/ril/Ril.cpp +++ b/ipc/ril/Ril.cpp @@ -149,17 +149,17 @@ RilConsumer::Unregister() } bool RilConsumer::PostRILMessage(JSContext* aCx, unsigned aArgc, Value* aVp) { CallArgs args = CallArgsFromVp(aArgc, aVp); if (args.length() != 2) { - JS_ReportError(aCx, "Expecting two arguments with the RIL message"); + JS_ReportErrorASCII(aCx, "Expecting two arguments with the RIL message"); return false; } int clientId = args[0].toInt32(); if ((ssize_t)sRilConsumers.Length() <= clientId || !sRilConsumers[clientId]) { // Probably shutting down. return true; @@ -192,49 +192,49 @@ RilConsumer::Send(JSContext* aCx, const if (!abs.encodeUtf8(aCx, str)) { return NS_ERROR_FAILURE; } raw = MakeUnique<UnixSocketRawData>(abs.ptr(), abs.length()); } else if (!v.isPrimitive()) { JSObject* obj = v.toObjectOrNull(); if (!JS_IsTypedArrayObject(obj)) { - JS_ReportError(aCx, "Object passed in wasn't a typed array"); + JS_ReportErrorASCII(aCx, "Object passed in wasn't a typed array"); return NS_ERROR_FAILURE; } uint32_t type = JS_GetArrayBufferViewType(obj); if (type != js::Scalar::Int8 && type != js::Scalar::Uint8 && type != js::Scalar::Uint8Clamped) { - JS_ReportError(aCx, "Typed array data is not octets"); + JS_ReportErrorASCII(aCx, "Typed array data is not octets"); return NS_ERROR_FAILURE; } size_t size = JS_GetTypedArrayByteLength(obj); bool isShared; void* data; { AutoCheckCannotGC nogc; data = JS_GetArrayBufferViewData(obj, &isShared, nogc); } if (isShared) { - JS_ReportError( + JS_ReportErrorASCII( aCx, "Incorrect argument. Shared memory not supported"); return NS_ERROR_FAILURE; } raw = MakeUnique<UnixSocketRawData>(data, size); } else { - JS_ReportError( + JS_ReportErrorASCII( aCx, "Incorrect argument. Expecting a string or a typed array"); return NS_ERROR_FAILURE; } if (!raw) { - JS_ReportError(aCx, "Unable to post to RIL"); + JS_ReportErrorASCII(aCx, "Unable to post to RIL"); return NS_ERROR_FAILURE; } mSocket->SendSocketData(raw.release()); return NS_OK; }
--- a/ipc/testshell/XPCShellEnvironment.cpp +++ b/ipc/testshell/XPCShellEnvironment.cpp @@ -132,17 +132,17 @@ Load(JSContext *cx, { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); JS::Rooted<JSObject*> obj(cx, JS_THIS_OBJECT(cx, vp)); if (!obj) return false; if (!JS_IsGlobalObject(obj)) { - JS_ReportError(cx, "Trying to load() into a non-global object"); + JS_ReportErrorASCII(cx, "Trying to load() into a non-global object"); return false; } for (unsigned i = 0; i < args.length(); i++) { JS::Rooted<JSString*> str(cx, JS::ToString(cx, args[i])); if (!str) return false; JSAutoByteString filename(cx, str);
--- a/js/ipc/JavaScriptParent.cpp +++ b/js/ipc/JavaScriptParent.cpp @@ -105,29 +105,29 @@ JavaScriptParent::allowMessage(JSContext JSObject* jsGlobal = global ? global->GetGlobalJSObject() : nullptr; if (jsGlobal) { JSAutoCompartment ac(cx, jsGlobal); JSAddonId* addonId = JS::AddonIdOfObject(jsGlobal); if (!xpc::CompartmentPrivate::Get(jsGlobal)->allowCPOWs) { if (!addonId && ForbidUnsafeBrowserCPOWs() && !isSafe) { Telemetry::Accumulate(Telemetry::BROWSER_SHIM_USAGE_BLOCKED, 1); - JS_ReportError(cx, "unsafe CPOW usage forbidden"); + JS_ReportErrorASCII(cx, "unsafe CPOW usage forbidden"); return false; } if (addonId) { JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(JS::StringOfAddonId(addonId)); nsString addonIdString; AssignJSFlatString(addonIdString, flat); NS_ConvertUTF16toUTF8 addonIdCString(addonIdString); Telemetry::Accumulate(Telemetry::ADDON_FORBIDDEN_CPOW_USAGE, addonIdCString); if (ForbidCPOWsInCompatibleAddon(addonIdCString)) { - JS_ReportError(cx, "CPOW usage forbidden in this add-on"); + JS_ReportErrorASCII(cx, "CPOW usage forbidden in this add-on"); return false; } warn = true; } } }
--- a/js/ipc/JavaScriptShared.cpp +++ b/js/ipc/JavaScriptShared.cpp @@ -411,17 +411,17 @@ JavaScriptShared::toSymbolVariant(JSCont if (code == SymbolCode::InSymbolRegistry) { nsAutoJSString autoStr; if (!autoStr.init(cx, GetSymbolDescription(sym))) return false; *symVarp = RegisteredSymbol(autoStr); return true; } - JS_ReportError(cx, "unique symbol can't be used with CPOW"); + JS_ReportErrorASCII(cx, "unique symbol can't be used with CPOW"); return false; } JS::Symbol* JavaScriptShared::fromSymbolVariant(JSContext* cx, SymbolVariant symVar) { switch (symVar.type()) { case SymbolVariant::TWellKnownSymbol: { @@ -477,17 +477,17 @@ JavaScriptShared::ConvertID(const JSIID& to->m3[7] = from.m3_7(); } JSObject* JavaScriptShared::findObjectById(JSContext* cx, const ObjectId& objId) { RootedObject obj(cx, objects_.find(objId)); if (!obj) { - JS_ReportError(cx, "operation not possible on dead CPOW"); + JS_ReportErrorASCII(cx, "operation not possible on dead CPOW"); return nullptr; } // Each process has a dedicated compartment for CPOW targets. All CPOWs // from the other process point to objects in this scope. From there, they // can access objects in other compartments using cross-compartment // wrappers. JSAutoCompartment ac(cx, scopeForTargetObjects()); @@ -546,25 +546,25 @@ JavaScriptShared::fromDescriptor(JSConte } return true; } bool UnknownPropertyStub(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp) { - JS_ReportError(cx, "getter could not be wrapped via CPOWs"); + JS_ReportErrorASCII(cx, "getter could not be wrapped via CPOWs"); return false; } bool UnknownStrictPropertyStub(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp, ObjectOpResult& result) { - JS_ReportError(cx, "setter could not be wrapped via CPOWs"); + JS_ReportErrorASCII(cx, "setter could not be wrapped via CPOWs"); return false; } bool JavaScriptShared::toDescriptor(JSContext* cx, const PPropertyDescriptor& in, MutableHandle<PropertyDescriptor> out) { out.setAttributes(in.attrs());
--- a/js/ipc/WrapperOwner.cpp +++ b/js/ipc/WrapperOwner.cpp @@ -144,17 +144,17 @@ class CPOWProxyHandler : public BaseProx const char CPOWProxyHandler::family = 0; const CPOWProxyHandler CPOWProxyHandler::singleton; #define FORWARD(call, args) \ PROFILER_LABEL_FUNC(js::ProfileEntry::Category::JS); \ WrapperOwner* owner = OwnerOf(proxy); \ if (!owner->active()) { \ - JS_ReportError(cx, "cannot use a CPOW whose process is gone"); \ + JS_ReportErrorASCII(cx, "cannot use a CPOW whose process is gone"); \ return false; \ } \ if (!owner->allowMessage(cx)) { \ return false; \ } \ { \ CPOWTimer timer(cx); \ return owner->call args; \ @@ -354,17 +354,17 @@ CPOWProxyHandler::get(JSContext* cx, Han FORWARD(get, (cx, proxy, receiver, id, vp)); } static bool CPOWDOMQI(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); if (!args.thisv().isObject() || !IsCPOW(&args.thisv().toObject())) { - JS_ReportError(cx, "bad this object passed to special QI"); + JS_ReportErrorASCII(cx, "bad this object passed to special QI"); return false; } RootedObject proxy(cx, &args.thisv().toObject()); FORWARD(DOMQI, (cx, proxy, args)); } static bool @@ -372,17 +372,17 @@ CPOWToString(JSContext* cx, unsigned arg { CallArgs args = CallArgsFromVp(argc, vp); RootedObject callee(cx, &args.callee()); RootedValue cpowValue(cx); if (!JS_GetProperty(cx, callee, "__cpow__", &cpowValue)) return false; if (!cpowValue.isObject() || !IsCPOW(&cpowValue.toObject())) { - JS_ReportError(cx, "CPOWToString called on an incompatible object"); + JS_ReportErrorASCII(cx, "CPOWToString called on an incompatible object"); return false; } RootedObject proxy(cx, &cpowValue.toObject()); FORWARD(toString, (cx, proxy, args)); } bool @@ -644,17 +644,17 @@ WrapperOwner::callOrConstruct(JSContext* if (v.isObject()) { RootedObject obj(cx, &v.toObject()); if (xpc::IsOutObject(cx, obj)) { // Make sure it is not an in-out object. bool found; if (!JS_HasProperty(cx, obj, "value", &found)) return false; if (found) { - JS_ReportError(cx, "in-out objects cannot be sent via CPOWs yet"); + JS_ReportErrorASCII(cx, "in-out objects cannot be sent via CPOWs yet"); return false; } vals.AppendElement(JSParam(void_t())); if (!outobjects.append(ObjectValue(*obj))) return false; continue; } @@ -1057,31 +1057,31 @@ WrapperOwner::ActorDestroy(ActorDestroyR objects_.clear(); unwaivedObjectIds_.clear(); waivedObjectIds_.clear(); } bool WrapperOwner::ipcfail(JSContext* cx) { - JS_ReportError(cx, "cross-process JS call failed"); + JS_ReportErrorASCII(cx, "cross-process JS call failed"); return false; } bool WrapperOwner::ok(JSContext* cx, const ReturnStatus& status) { if (status.type() == ReturnStatus::TReturnSuccess) return true; if (status.type() == ReturnStatus::TReturnStopIteration) return JS_ThrowStopIteration(cx); if (status.type() == ReturnStatus::TReturnDeadCPOW) { - JS_ReportError(cx, "operation not possible on dead CPOW"); + JS_ReportErrorASCII(cx, "operation not possible on dead CPOW"); return false; } RootedValue exn(cx); if (!fromVariant(cx, status.get_ReturnException().exn(), &exn)) return false; JS_SetPendingException(cx, exn);
--- a/js/src/asmjs/AsmJS.cpp +++ b/js/src/asmjs/AsmJS.cpp @@ -8013,17 +8013,17 @@ HandleInstantiationFailure(JSContext* cx ScriptSource* source = metadata.scriptSource.get(); // Source discarding is allowed to affect JS semantics because it is never // enabled for normal JS content. bool haveSource = source->hasSourceData(); if (!haveSource && !JSScript::loadSource(cx, source, &haveSource)) return false; if (!haveSource) { - JS_ReportError(cx, "asm.js link failure with source discarding enabled"); + JS_ReportErrorASCII(cx, "asm.js link failure with source discarding enabled"); return false; } uint32_t begin = metadata.srcBodyStart; // starts right after 'use asm' uint32_t end = metadata.srcEndBeforeCurly(); Rooted<JSFlatString*> src(cx, source->substringDontDeflate(cx, begin, end)); if (!src) return false;
--- a/js/src/asmjs/WasmJS.cpp +++ b/js/src/asmjs/WasmJS.cpp @@ -145,17 +145,17 @@ wasm::CreateI64Object(JSContext* cx, int return result; } bool wasm::ReadI64Object(JSContext* cx, HandleValue v, int64_t* i64) { if (!v.isObject()) { - JS_ReportError(cx, "i64 JS value must be an object"); + JS_ReportErrorASCII(cx, "i64 JS value must be an object"); return false; } RootedObject obj(cx, &v.toObject()); int32_t* i32 = (int32_t*)i64; RootedValue val(cx); @@ -1506,17 +1506,17 @@ struct CompileTask : PromiseTask : Reject(cx, compileArgs, Move(error), promise); } }; static bool WebAssembly_compile(JSContext* cx, unsigned argc, Value* vp) { if (!cx->startAsyncTaskCallback || !cx->finishAsyncTaskCallback) { - JS_ReportError(cx, "WebAssembly.compile not supported in this runtime."); + JS_ReportErrorASCII(cx, "WebAssembly.compile not supported in this runtime."); return false; } CallArgs callArgs = CallArgsFromVp(argc, vp); RootedFunction nopFun(cx, NewNativeFunction(cx, Nop, 0, nullptr)); if (!nopFun) return false;
--- a/js/src/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -890,17 +890,17 @@ ModuleObject::noteFunctionDeclaration(Ex /* static */ bool ModuleObject::instantiateFunctionDeclarations(JSContext* cx, HandleModuleObject self) { MOZ_ASSERT(IsFrozen(cx, self)); FunctionDeclarationVector* funDecls = self->functionDeclarations(); if (!funDecls) { - JS_ReportError(cx, "Module function declarations have already been instantiated"); + JS_ReportErrorASCII(cx, "Module function declarations have already been instantiated"); return false; } RootedModuleEnvironmentObject env(cx, &self->initialEnvironment()); RootedFunction fun(cx); RootedValue value(cx); for (const auto& funDecl : *funDecls) { @@ -931,17 +931,17 @@ ModuleObject::setState(int32_t newState) /* static */ bool ModuleObject::evaluate(JSContext* cx, HandleModuleObject self, MutableHandleValue rval) { MOZ_ASSERT(IsFrozen(cx, self)); RootedScript script(cx, self->script()); RootedModuleEnvironmentObject scope(cx, self->environment()); if (!scope) { - JS_ReportError(cx, "Module declarations have not yet been instantiated"); + JS_ReportErrorASCII(cx, "Module declarations have not yet been instantiated"); return false; } return Execute(cx, script, *scope, rval.address()); } /* static */ ModuleNamespaceObject* ModuleObject::createNamespace(JSContext* cx, HandleModuleObject self, HandleObject exports)
--- a/js/src/builtin/Profilers.cpp +++ b/js/src/builtin/Profilers.cpp @@ -191,19 +191,19 @@ JS_DumpProfile(const char* outfile, cons struct RequiredStringArg { JSContext* mCx; char* mBytes; RequiredStringArg(JSContext* cx, const CallArgs& args, size_t argi, const char* caller) : mCx(cx), mBytes(nullptr) { if (args.length() <= argi) { - JS_ReportError(cx, "%s: not enough arguments", caller); + JS_ReportErrorASCII(cx, "%s: not enough arguments", caller); } else if (!args[argi].isString()) { - JS_ReportError(cx, "%s: invalid arguments (string expected)", caller); + JS_ReportErrorASCII(cx, "%s: invalid arguments (string expected)", caller); } else { mBytes = JS_EncodeString(cx, args[argi].toString()); } } operator void*() {