From 965ee10298b467bc1ce900aa9afb7a5cd1a54a1a Mon Sep 17 00:00:00 2001 From: Mike Shal Date: Mon, 9 May 2016 17:34:13 -0400 Subject: [PATCH 001/120] Bug 1254115 - Move dependentlibs.py invocation to moz.build; r=ted MozReview-Commit-ID: D8NF03tNuTX --HG-- extra : rebase_source : b8e4f9b672e5e9555cfc841c63e1aeb9130263d3 --- toolkit/library/Makefile.in | 7 ------- toolkit/library/dependentlibs.py | 31 +++++++++++++------------------ toolkit/library/moz.build | 16 ++++++++++++++++ 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in index ba9134e0ca5b..5574ba4fdb62 100644 --- a/toolkit/library/Makefile.in +++ b/toolkit/library/Makefile.in @@ -13,13 +13,6 @@ endif include $(topsrcdir)/config/rules.mk -ifdef COMPILE_ENVIRONMENT -target:: $(FINAL_TARGET)/dependentlibs.list -endif - -$(FINAL_TARGET)/dependentlibs.list: $(topsrcdir)/toolkit/library/dependentlibs.py $(SHARED_LIBRARY) $(wildcard $(if $(wildcard $(FINAL_TARGET)/dependentlibs.list),$(addprefix $(FINAL_TARGET)/,$(shell cat $(FINAL_TARGET)/dependentlibs.list)))) - $(PYTHON) $< $(SHARED_LIBRARY) -L $(FINAL_TARGET) $(if $(TOOLCHAIN_PREFIX),$(addprefix -p ,$(TOOLCHAIN_PREFIX))) > $@ - .PHONY: gtestxul gtestxul: $(MAKE) -C $(DEPTH) toolkit/library/gtest/target LINK_GTEST=1 diff --git a/toolkit/library/dependentlibs.py b/toolkit/library/dependentlibs.py index f4e249021b12..95803fb9d1a2 100644 --- a/toolkit/library/dependentlibs.py +++ b/toolkit/library/dependentlibs.py @@ -6,12 +6,11 @@ upon that are in the same directory, followed by the library itself. ''' -from optparse import OptionParser import os import re -import fnmatch import subprocess import sys +import mozpack.path as mozpath from mozpack.executables import ( get_type, ELF, @@ -19,8 +18,6 @@ from mozpack.executables import ( ) from buildconfig import substs -TOOLCHAIN_PREFIX = '' - def dependentlibs_dumpbin(lib): '''Returns the list of dependencies declared in the given DLL''' try: @@ -54,7 +51,7 @@ def dependentlibs_mingw_objdump(lib): def dependentlibs_readelf(lib): '''Returns the list of dependencies declared in the given ELF .so''' - proc = subprocess.Popen([TOOLCHAIN_PREFIX + 'readelf', '-d', lib], stdout = subprocess.PIPE) + proc = subprocess.Popen([substs.get('TOOLCHAIN_PREFIX', '') + 'readelf', '-d', lib], stdout = subprocess.PIPE) deps = [] for line in proc.stdout: # Each line has the following format: @@ -108,20 +105,13 @@ def dependentlibs(lib, libpaths, func): # leads to startup performance problems because of its excessive # size (around 10MB). if not dep.startswith("icu"): - deps.append(dep) + deps.append(deppath) break return deps -def main(): - parser = OptionParser() - parser.add_option("-L", dest="libpaths", action="append", metavar="PATH", help="Add the given path to the library search path") - parser.add_option("-p", dest="toolchain_prefix", metavar="PREFIX", help="Use the given prefix to readelf") - (options, args) = parser.parse_args() - if options.toolchain_prefix: - global TOOLCHAIN_PREFIX - TOOLCHAIN_PREFIX = options.toolchain_prefix - lib = args[0] +def gen_list(output, lib): + libpaths = [os.path.join(substs['DIST'], 'bin')] binary_type = get_type(lib) if binary_type == ELF: func = dependentlibs_readelf @@ -131,10 +121,15 @@ def main(): ext = os.path.splitext(lib)[1] assert(ext == '.dll') func = dependentlibs_dumpbin - if not options.libpaths: - options.libpaths = [os.path.dirname(lib)] - print '\n'.join(dependentlibs(lib, options.libpaths, func) + [lib]) + deps = dependentlibs(lib, libpaths, func) + deps.append(mozpath.join(libpaths[0], lib)) + dependentlibs_output = [mozpath.basename(f) for f in deps] + output.write('\n'.join(dependentlibs_output) + '\n') + return set(deps) + +def main(): + gen_list(sys.stdout, sys.argv[1]) if __name__ == '__main__': main() diff --git a/toolkit/library/moz.build b/toolkit/library/moz.build index 2b67d500a0e5..a3d54508b14e 100644 --- a/toolkit/library/moz.build +++ b/toolkit/library/moz.build @@ -363,5 +363,21 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': 'oleaut32', ] +if CONFIG['COMPILE_ENVIRONMENT']: + if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('cocoa', 'uikit'): + full_libname = SHARED_LIBRARY_NAME + else: + full_libname = '%s%s%s' % ( + CONFIG['DLL_PREFIX'], + LIBRARY_NAME, + CONFIG['DLL_SUFFIX'] + ) + GENERATED_FILES += ['dependentlibs.list'] + GENERATED_FILES['dependentlibs.list'].script = 'dependentlibs.py:gen_list' + GENERATED_FILES['dependentlibs.list'].inputs = [ + '!%s' % full_libname, + ] + FINAL_TARGET_FILES += ['!dependentlibs.list'] + # This needs to be last USE_LIBS += ['StaticXULComponentsEnd'] From 83707bf2adb146723753c6375dda720b461dfc00 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 20 Jul 2016 16:55:05 +0200 Subject: [PATCH 002/120] Bug 1289693 - Add missing MOZ_ANDROID_CPU_ARCH call in SpiderMonkey old-configure.in; r=glandium --- js/src/old-configure.in | 1 + 1 file changed, 1 insertion(+) diff --git a/js/src/old-configure.in b/js/src/old-configure.in index f1122bded66f..c1e7bd93305d 100644 --- a/js/src/old-configure.in +++ b/js/src/old-configure.in @@ -528,6 +528,7 @@ dnl Android libstdc++, placed here so it can use MOZ_ARCH dnl computed above. dnl ======================================================== +MOZ_ANDROID_CPU_ARCH MOZ_ANDROID_STLPORT dnl ======================================================== From b13de09ea407ea3bcb7df33281493a440435129c Mon Sep 17 00:00:00 2001 From: bechen Date: Tue, 19 Jul 2016 17:01:06 +0800 Subject: [PATCH 003/120] Bug 1281418 - Add testcase for changing the src of TrackElement. r=rillian MozReview-Commit-ID: A7QB9ELEfp3 --HG-- extra : transplant_source : %FE%12%B9%98%847%E2%BF%9E%B8%7D%BDT%E3%7E%F0%90%1E%25i --- dom/media/test/mochitest.ini | 2 + dom/media/test/test_trackelementsrc.html | 55 ++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 dom/media/test/test_trackelementsrc.html diff --git a/dom/media/test/mochitest.ini b/dom/media/test/mochitest.ini index 48b2a68dec1e..1ea7eb7079b0 100644 --- a/dom/media/test/mochitest.ini +++ b/dom/media/test/mochitest.ini @@ -856,6 +856,8 @@ tags = webvtt [test_timeupdate_small_files.html] [test_trackelementevent.html] tags = webvtt +[test_trackelementsrc.html] +tags = webvtt [test_trackevent.html] tags = webvtt [test_unseekable.html] diff --git a/dom/media/test/test_trackelementsrc.html b/dom/media/test/test_trackelementsrc.html new file mode 100644 index 000000000000..6a6372a7aa5d --- /dev/null +++ b/dom/media/test/test_trackelementsrc.html @@ -0,0 +1,55 @@ + + + + + Test for Bug 1281418 - Change the src attribue for TrackElement. + + + + + +

+ +
+
+
+ + + From f37d302b585f30def8128755e22612a3bfb359f4 Mon Sep 17 00:00:00 2001 From: bechen Date: Thu, 21 Jul 2016 16:49:24 +0800 Subject: [PATCH 004/120] Bug 1281418 - Release and reload the vtt resource when the src attribute of TrackElement changed. r=rillian MozReview-Commit-ID: B8wdOxP3HId --HG-- extra : transplant_source : %85%F3R%10%D3h%C8tSN%12%09%B5%12%91%DBT%19t%14 --- dom/html/HTMLTrackElement.cpp | 41 +++++++++++++++++++++++++++++++++-- dom/html/HTMLTrackElement.h | 10 +++++---- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/dom/html/HTMLTrackElement.cpp b/dom/html/HTMLTrackElement.cpp index aa201f4cccd7..c1cc999cc0d0 100644 --- a/dom/html/HTMLTrackElement.cpp +++ b/dom/html/HTMLTrackElement.cpp @@ -76,6 +76,7 @@ static constexpr const nsAttrValue::EnumTable* kKindTableInvalidValueDefault = & /** HTMLTrackElement */ HTMLTrackElement::HTMLTrackElement(already_AddRefed& aNodeInfo) : nsGenericHTMLElement(aNodeInfo) + , mLoadResourceDispatched(false) { } @@ -182,9 +183,46 @@ HTMLTrackElement::ParseAttribute(int32_t aNamespaceID, aResult); } +void +HTMLTrackElement::SetSrc(const nsAString& aSrc, ErrorResult& aError) +{ + SetHTMLAttr(nsGkAtoms::src, aSrc, aError); + uint16_t oldReadyState = ReadyState(); + SetReadyState(TextTrackReadyState::NotLoaded); + if (!mMediaParent) { + return; + } + if (mTrack && (oldReadyState != TextTrackReadyState::NotLoaded)) { + // Remove all the cues in MediaElement. + mMediaParent->RemoveTextTrack(mTrack); + // Recreate mTrack. + CreateTextTrack(); + } + // Stop WebVTTListener. + mListener = nullptr; + if (mChannel) { + mChannel->Cancel(NS_BINDING_ABORTED); + mChannel = nullptr; + } + + DispatchLoadResource(); +} + +void +HTMLTrackElement::DispatchLoadResource() +{ + if (!mLoadResourceDispatched) { + RefPtr r = NewRunnableMethod(this, &HTMLTrackElement::LoadResource); + nsContentUtils::RunInStableState(r.forget()); + mLoadResourceDispatched = true; + } +} + void HTMLTrackElement::LoadResource() { + mLoadResourceDispatched = false; + // Find our 'src' url nsAutoString src; if (!GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) { @@ -258,8 +296,7 @@ HTMLTrackElement::BindToTree(nsIDocument* aDocument, if (!mTrack) { CreateTextTrack(); } - RefPtr r = NewRunnableMethod(this, &HTMLTrackElement::LoadResource); - nsContentUtils::RunInStableState(r.forget()); + DispatchLoadResource(); } return NS_OK; diff --git a/dom/html/HTMLTrackElement.h b/dom/html/HTMLTrackElement.h index 24b4c6345895..560cf365a204 100644 --- a/dom/html/HTMLTrackElement.h +++ b/dom/html/HTMLTrackElement.h @@ -46,10 +46,8 @@ public: { GetHTMLURIAttr(nsGkAtoms::src, aSrc); } - void SetSrc(const nsAString& aSrc, ErrorResult& aError) - { - SetHTMLAttr(nsGkAtoms::src, aSrc, aError); - } + + void SetSrc(const nsAString& aSrc, ErrorResult& aError); void GetSrclang(DOMString& aSrclang) const { @@ -134,6 +132,10 @@ protected: RefPtr mListener; void CreateTextTrack(); + +private: + void DispatchLoadResource(); + bool mLoadResourceDispatched; }; } // namespace dom From 468fef78cc3d94430268b7d9548cd0388767163d Mon Sep 17 00:00:00 2001 From: Thomas Wisniewski Date: Wed, 27 Jul 2016 16:03:42 -0400 Subject: [PATCH 005/120] Bug 1285036 - Part 7: Change SetRequestHeader() and related header code to follow the spec more closely. r=baku --HG-- extra : rebase_source : 8d3491471156823c0f1c7c7adbcb0024494e13db --- .../test/browser_net_copy_as_curl.js | 43 +++- .../netmonitor/test/browser_net_resend.js | 2 +- dom/base/nsContentUtils.cpp | 5 +- dom/xhr/XMLHttpRequestMainThread.cpp | 186 +++++++++--------- dom/xhr/XMLHttpRequestMainThread.h | 12 +- dom/xhr/tests/test_xhr_forbidden_headers.html | 3 +- .../setrequestheader-case-insensitive.htm.ini | 5 - .../setrequestheader-header-allowed.htm.ini | 14 -- 8 files changed, 140 insertions(+), 130 deletions(-) delete mode 100644 testing/web-platform/meta/XMLHttpRequest/setrequestheader-case-insensitive.htm.ini delete mode 100644 testing/web-platform/meta/XMLHttpRequest/setrequestheader-header-allowed.htm.ini diff --git a/devtools/client/netmonitor/test/browser_net_copy_as_curl.js b/devtools/client/netmonitor/test/browser_net_copy_as_curl.js index b064e925aae2..1dfb81e4c296 100644 --- a/devtools/client/netmonitor/test/browser_net_copy_as_curl.js +++ b/devtools/client/netmonitor/test/browser_net_copy_as_curl.js @@ -17,9 +17,9 @@ function test() { "-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'", "-H 'Accept-Language: " + navigator.language + "'", "--compressed", - "-H 'X-Custom-Header-1: Custom value'", - "-H 'X-Custom-Header-2: 8.8.8.8'", - "-H 'X-Custom-Header-3: Mon, 3 Mar 2014 11:11:11 GMT'", + "-H 'x-custom-header-1: Custom value'", + "-H 'x-custom-header-2: 8.8.8.8'", + "-H 'x-custom-header-3: Mon, 3 Mar 2014 11:11:11 GMT'", "-H 'Referer: " + CURL_URL + "'", "-H 'Connection: keep-alive'", "-H 'Pragma: no-cache'", @@ -34,9 +34,9 @@ function test() { '-H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"', '-H "Accept-Language: ' + navigator.language + '"', "--compressed", - '-H "X-Custom-Header-1: Custom value"', - '-H "X-Custom-Header-2: 8.8.8.8"', - '-H "X-Custom-Header-3: Mon, 3 Mar 2014 11:11:11 GMT"', + '-H "x-custom-header-1: Custom value"', + '-H "x-custom-header-2: 8.8.8.8"', + '-H "x-custom-header-3: Mon, 3 Mar 2014 11:11:11 GMT"', '-H "Referer: ' + CURL_URL + '"', '-H "Connection: keep-alive"', '-H "Pragma: no-cache"', @@ -56,7 +56,36 @@ function test() { let requestItem = RequestsMenu.getItemAtIndex(0); RequestsMenu.selectedItem = requestItem; - waitForClipboard(EXPECTED_RESULT, function setup() { + waitForClipboard(function validate(aResult) { + if (typeof aResult !== "string") { + return false; + } + + // Different setups may produce the same command, but with the + // parameters in a different order in the commandline (which is fine). + // Here we confirm that the commands are the same even in that case. + var expected = EXPECTED_RESULT.toString().match(/[-A-Za-z1-9]+ '.*?'/g), + actual = aResult.match(/[-A-Za-z1-9]+ '.*?'/g); + + // Must begin with the same "curl 'URL'" segment + if (!actual || expected[0] != actual[0]) { + return false; + } + + // Must match each of the params in the middle (headers) + var expectedSet = new Set(expected); + var actualSet = new Set(actual); + if (expected.size != actual.size) { + return false; + } + for (let param of expectedSet) { + if (!actualSet.has(param)) { + return false; + } + } + + return true; + }, function setup() { RequestsMenu.copyAsCurl(); }, function onSuccess() { ok(true, "Clipboard contains a cURL command for the currently selected item's url."); diff --git a/devtools/client/netmonitor/test/browser_net_resend.js b/devtools/client/netmonitor/test/browser_net_resend.js index 29a2422a9ae9..ab2131fbc1a8 100644 --- a/devtools/client/netmonitor/test/browser_net_resend.js +++ b/devtools/client/netmonitor/test/browser_net_resend.js @@ -154,7 +154,7 @@ function testSentRequest(aData, aOrigData) { is(aData.url, aOrigData.url + "&" + ADD_QUERY, "correct url in sent request"); let hasHeader = aData.requestHeaders.headers.some((header) => { - return (header.name + ": " + header.value) == ADD_HEADER; + return (header.name.toLowerCase() + ": " + header.value) == ADD_HEADER.toLowerCase(); }); ok(hasHeader, "new header added to sent request"); diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index e59869009e24..136ee24be046 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -7071,9 +7071,8 @@ nsContentUtils::IsForbiddenSystemRequestHeader(const nsACString& aHeader) static const char *kInvalidHeaders[] = { "accept-charset", "accept-encoding", "access-control-request-headers", "access-control-request-method", "connection", "content-length", - "cookie", "cookie2", "content-transfer-encoding", "date", "dnt", - "expect", "host", "keep-alive", "origin", "referer", "te", "trailer", - "transfer-encoding", "upgrade", "via" + "cookie", "cookie2", "date", "dnt", "expect", "host", "keep-alive", + "origin", "referer", "te", "trailer", "transfer-encoding", "upgrade", "via" }; for (uint32_t i = 0; i < ArrayLength(kInvalidHeaders); ++i) { if (aHeader.LowerCaseEqualsASCII(kInvalidHeaders[i])) { diff --git a/dom/xhr/XMLHttpRequestMainThread.cpp b/dom/xhr/XMLHttpRequestMainThread.cpp index 7ee499f9ea3d..4c7b33c0d3da 100644 --- a/dom/xhr/XMLHttpRequestMainThread.cpp +++ b/dom/xhr/XMLHttpRequestMainThread.cpp @@ -1465,7 +1465,7 @@ XMLHttpRequestMainThread::Open(const nsACString& inMethod, const nsACString& url // Clear our record of previously set headers so future header set // operations will merge/override correctly. - mAlreadySetHeaders.Clear(); + mAuthorRequestHeaders.Clear(); // When we are called from JS we can find the load group for the page, // and add ourselves to it. This way any pending requests @@ -2480,6 +2480,9 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable nsCOMPtr httpChannel(do_QueryInterface(mChannel)); if (httpChannel) { + // Spec step 5 + SetAuthorRequestHeadersOnChannel(httpChannel); + httpChannel->GetRequestMethod(method); // If GET, method name will be uppercase if (!IsSystemXHR()) { @@ -2534,15 +2537,14 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable net::InScriptableRange(size_u64) ? static_cast(size_u64) : -1; if (postDataStream) { - // If no content type header was set by the client, we set it to - // application/xml. + // If author set no Content-Type, use the default from GetRequestBody(). nsAutoCString contentType; - if (NS_FAILED(httpChannel-> - GetRequestHeader(NS_LITERAL_CSTRING("Content-Type"), - contentType))) { + + GetAuthorRequestHeaderValue("content-type", contentType); + if (contentType.IsVoid()) { contentType = defaultContentType; - if (!charset.IsEmpty() && !contentType.IsVoid()) { + if (!charset.IsEmpty()) { // If we are providing the default content type, then we also need to // provide a charset declaration. contentType.Append(NS_LITERAL_CSTRING(";charset=")); @@ -2720,8 +2722,26 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable // Set up the preflight if needed if (!IsSystemXHR()) { + nsTArray CORSUnsafeHeaders; + const char *kCrossOriginSafeHeaders[] = { + "accept", "accept-language", "content-language", "content-type", + "last-event-id" + }; + for (RequestHeader& header : mAuthorRequestHeaders) { + bool safe = false; + for (uint32_t i = 0; i < ArrayLength(kCrossOriginSafeHeaders); ++i) { + if (header.name.EqualsASCII(kCrossOriginSafeHeaders[i])) { + safe = true; + break; + } + } + if (!safe) { + CORSUnsafeHeaders.AppendElement(header.name); + } + } + nsCOMPtr loadInfo = mChannel->GetLoadInfo(); - loadInfo->SetCorsPreflightInfo(mCORSUnsafeHeaders, + loadInfo->SetCorsPreflightInfo(CORSUnsafeHeaders, mFlagHadUploadListenersOnSend); } @@ -2847,99 +2867,62 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable // http://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-setrequestheader NS_IMETHODIMP -XMLHttpRequestMainThread::SetRequestHeader(const nsACString& header, - const nsACString& value) +XMLHttpRequestMainThread::SetRequestHeader(const nsACString& aName, + const nsACString& aValue) { // Steps 1 and 2 if (mState != State::opened || mFlagSend) { return NS_ERROR_DOM_INVALID_STATE_ERR; } - NS_ASSERTION(mChannel, "mChannel must be valid if we're OPENED."); // Step 3 - // Make sure we don't store an invalid header name in mCORSUnsafeHeaders - if (!NS_IsValidHTTPToken(header)) { + 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; } - if (!mChannel) // open() initializes mChannel, and open() - return NS_ERROR_FAILURE; // must be called before first setRequestHeader() - - nsCOMPtr httpChannel = do_QueryInterface(mChannel); - if (!httpChannel) { + // Step 5 + bool isPrivilegedCaller = IsSystemXHR(); + bool isForbiddenHeader = nsContentUtils::IsForbiddenRequestHeader(aName); + if (!isPrivilegedCaller && isForbiddenHeader) { + NS_WARNING("refusing to set request header"); return NS_OK; } - // We will merge XHR headers, per the spec (secion 4.6.2) unless: - // 1 - The caller is privileged and setting an invalid header, - // or - // 2 - we have not yet explicitly set that header; this allows web - // content to override default headers the first time they set them. - bool mergeHeaders = true; + // Step 6.1 + nsAutoCString lowercaseName; + nsContentUtils::ASCIIToLower(aName, lowercaseName); - if (!IsSystemXHR()) { - // Step 5: Check for dangerous headers. - // Prevent modification to certain HTTP headers (see bug 302263), unless - // the executing script is privileged. - if (nsContentUtils::IsForbiddenRequestHeader(header)) { - NS_WARNING("refusing to set request header"); - return NS_OK; - } - - // Check for dangerous cross-site headers - bool safeHeader = IsSystemXHR(); - if (!safeHeader) { - // Content-Type isn't always safe, but we'll deal with it in Send() - const char *kCrossOriginSafeHeaders[] = { - "accept", "accept-language", "content-language", "content-type", - "last-event-id" - }; - for (uint32_t i = 0; i < ArrayLength(kCrossOriginSafeHeaders); ++i) { - if (header.LowerCaseEqualsASCII(kCrossOriginSafeHeaders[i])) { - safeHeader = true; - break; - } + // Step 6.2 + bool notAlreadySet = true; + for (RequestHeader& header : mAuthorRequestHeaders) { + if (header.name.Equals(lowercaseName)) { + // Gecko-specific: invalid headers can be set by privileged + // callers, but will not merge. + if (isPrivilegedCaller && isForbiddenHeader) { + header.value.Assign(value); + } else { + header.value.AppendLiteral(", "); + header.value.Append(value); } - } - - if (!safeHeader) { - if (!mCORSUnsafeHeaders.Contains(header, nsCaseInsensitiveCStringArrayComparator())) { - mCORSUnsafeHeaders.AppendElement(header); - } - } - } else { - // Case 1 above - if (nsContentUtils::IsForbiddenSystemRequestHeader(header)) { - mergeHeaders = false; + notAlreadySet = false; + break; } } - if (!mAlreadySetHeaders.Contains(header)) { - // Case 2 above - mergeHeaders = false; - } - - nsresult rv; - if (value.IsEmpty()) { - rv = httpChannel->SetEmptyRequestHeader(header); - } else { - // Merge headers depending on what we decided above. - rv = httpChannel->SetRequestHeader(header, value, mergeHeaders); - } - if (rv == NS_ERROR_INVALID_ARG) { - return NS_ERROR_DOM_SYNTAX_ERR; - } - if (NS_SUCCEEDED(rv)) { - // Remember that we've set this header, so subsequent set operations will merge values. - mAlreadySetHeaders.PutEntry(nsCString(header)); - - // We'll want to duplicate this header for any replacement channels (eg. on redirect) - RequestHeader reqHeader = { - nsCString(header), nsCString(value) + // Step 6.3 + if (notAlreadySet) { + RequestHeader newHeader = { + nsCString(lowercaseName), nsCString(value) }; - mModifiedRequestHeaders.AppendElement(reqHeader); + mAuthorRequestHeaders.AppendElement(newHeader); } - return rv; + + return NS_OK; } NS_IMETHODIMP @@ -3179,6 +3162,32 @@ XMLHttpRequestMainThread::AsyncOnChannelRedirect(nsIChannel *aOldChannel, return NS_OK; } +void +XMLHttpRequestMainThread::GetAuthorRequestHeaderValue(const char* aName, + nsACString& outValue) +{ + for (RequestHeader& header : mAuthorRequestHeaders) { + if (header.name.Equals(aName)) { + outValue.Assign(header.value); + return; + } + } + outValue.SetIsVoid(true); +} + +void +XMLHttpRequestMainThread::SetAuthorRequestHeadersOnChannel( + nsCOMPtr aHttpChannel) +{ + for (RequestHeader& header : mAuthorRequestHeaders) { + if (header.value.IsEmpty()) { + aHttpChannel->SetEmptyRequestHeader(header.name); + } else { + aHttpChannel->SetRequestHeader(header.name, header.value, false); + } + } +} + nsresult XMLHttpRequestMainThread::OnRedirectVerifyCallback(nsresult result) { @@ -3191,15 +3200,7 @@ XMLHttpRequestMainThread::OnRedirectVerifyCallback(nsresult result) nsCOMPtr httpChannel(do_QueryInterface(mChannel)); if (httpChannel) { // Ensure all original headers are duplicated for the new channel (bug #553888) - for (RequestHeader& requestHeader : mModifiedRequestHeaders) { - if (requestHeader.value.IsEmpty()) { - httpChannel->SetEmptyRequestHeader(requestHeader.header); - } else { - httpChannel->SetRequestHeader(requestHeader.header, - requestHeader.value, - false); - } - } + SetAuthorRequestHeadersOnChannel(httpChannel); } } else { mErrorLoad = true; @@ -3515,9 +3516,8 @@ XMLHttpRequestMainThread::ShouldBlockAuthPrompt() // Verify that it's ok to prompt for credentials here, per spec // http://xhr.spec.whatwg.org/#the-send%28%29-method - for (uint32_t i = 0, len = mModifiedRequestHeaders.Length(); i < len; ++i) { - if (mModifiedRequestHeaders[i].header. - LowerCaseEqualsLiteral("authorization")) { + for (RequestHeader& requestHeader : mAuthorRequestHeaders) { + if (requestHeader.name.EqualsLiteral("authorization")) { return true; } } diff --git a/dom/xhr/XMLHttpRequestMainThread.h b/dom/xhr/XMLHttpRequestMainThread.h index 9a6138250a8e..d02c522a54d0 100644 --- a/dom/xhr/XMLHttpRequestMainThread.h +++ b/dom/xhr/XMLHttpRequestMainThread.h @@ -220,10 +220,10 @@ public: } virtual void - SetRequestHeader(const nsACString& aHeader, const nsACString& aValue, + SetRequestHeader(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv) override { - aRv = SetRequestHeader(aHeader, aValue); + aRv = SetRequestHeader(aName, aValue); } virtual uint32_t @@ -620,7 +620,6 @@ protected: nsCOMPtr mPrincipal; nsCOMPtr mChannel; nsCOMPtr mResponseXML; - nsTArray mCORSUnsafeHeaders; nsCOMPtr mXMLParserStreamListener; @@ -791,12 +790,13 @@ protected: struct RequestHeader { - nsCString header; + nsCString name; nsCString value; }; - nsTArray mModifiedRequestHeaders; + nsTArray mAuthorRequestHeaders; - nsTHashtable mAlreadySetHeaders; + void GetAuthorRequestHeaderValue(const char* aName, nsACString& outValue); + void SetAuthorRequestHeadersOnChannel(nsCOMPtr aChannel); // Helper object to manage our XPCOM scriptability bits nsXMLHttpRequestXPCOMifier* mXPCOMifier; diff --git a/dom/xhr/tests/test_xhr_forbidden_headers.html b/dom/xhr/tests/test_xhr_forbidden_headers.html index 4ec8ee03e506..fc076731ec7a 100644 --- a/dom/xhr/tests/test_xhr_forbidden_headers.html +++ b/dom/xhr/tests/test_xhr_forbidden_headers.html @@ -28,7 +28,6 @@ var headers = [ "coNtEnt-LEngth", "CoOKIe", "cOOkiE2", - "cOntEnt-tRAnsFer-enCoDiNg", "DATE", "dNT", "exPeCt", @@ -54,6 +53,7 @@ function startTest() { request.open("GET", window.location.href); for (i = 0; i < headers.length; i++) request.setRequestHeader(headers[i], "test" + i); + request.send(); // headers aren't set on the channel until send() // Read out headers var channel = SpecialPowers.wrap(request).channel.QueryInterface(SpecialPowers.Ci.nsIHttpChannel); @@ -73,6 +73,7 @@ function startTest() { request.open("GET", window.location.href); for (i = 0; i < headers.length; i++) request.setRequestHeader(headers[i], "test" + i); + request.send(); // headers aren't set on the channel until send() // Read out headers var channel = SpecialPowers.wrap(request).channel.QueryInterface(SpecialPowers.Ci.nsIHttpChannel); diff --git a/testing/web-platform/meta/XMLHttpRequest/setrequestheader-case-insensitive.htm.ini b/testing/web-platform/meta/XMLHttpRequest/setrequestheader-case-insensitive.htm.ini deleted file mode 100644 index 16277476d3ab..000000000000 --- a/testing/web-platform/meta/XMLHttpRequest/setrequestheader-case-insensitive.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[setrequestheader-case-insensitive.htm] - type: testharness - [XMLHttpRequest: setRequestHeader() - headers that differ in case] - expected: FAIL - diff --git a/testing/web-platform/meta/XMLHttpRequest/setrequestheader-header-allowed.htm.ini b/testing/web-platform/meta/XMLHttpRequest/setrequestheader-header-allowed.htm.ini deleted file mode 100644 index 0a2cae6870a4..000000000000 --- a/testing/web-platform/meta/XMLHttpRequest/setrequestheader-header-allowed.htm.ini +++ /dev/null @@ -1,14 +0,0 @@ -[setrequestheader-header-allowed.htm] - type: testharness - [XMLHttpRequest: setRequestHeader() - headers that are allowed (Authorization)] - expected: FAIL - - [XMLHttpRequest: setRequestHeader() - headers that are allowed (Content-Transfer-Encoding)] - expected: FAIL - - [XMLHttpRequest: setRequestHeader() - headers that are allowed (Content-Type)] - expected: FAIL - - [XMLHttpRequest: setRequestHeader() - headers that are allowed (User-Agent)] - expected: FAIL - From 978c16c644608508e382dccadbbd07f78fc43992 Mon Sep 17 00:00:00 2001 From: Thomas Wisniewski Date: Wed, 20 Jul 2016 13:02:36 -0400 Subject: [PATCH 006/120] Bug 1285036 - Part 8: Change XHR open() and related code to follow the spec more closely. r=baku --HG-- extra : rebase_source : a40634c94d6a259a181028021b780140a7fdbf41 --- dom/xhr/XMLHttpRequestMainThread.cpp | 336 +++++++++++++++------------ dom/xhr/XMLHttpRequestMainThread.h | 26 +-- dom/xhr/XMLHttpRequestWorker.cpp | 12 +- 3 files changed, 208 insertions(+), 166 deletions(-) diff --git a/dom/xhr/XMLHttpRequestMainThread.cpp b/dom/xhr/XMLHttpRequestMainThread.cpp index 4c7b33c0d3da..9acd4ee484fa 100644 --- a/dom/xhr/XMLHttpRequestMainThread.cpp +++ b/dom/xhr/XMLHttpRequestMainThread.cpp @@ -1350,54 +1350,131 @@ XMLHttpRequestMainThread::IsSystemXHR() const } NS_IMETHODIMP -XMLHttpRequestMainThread::Open(const nsACString& method, const nsACString& url, - bool async, const nsAString& user, - const nsAString& password, uint8_t optional_argc) +XMLHttpRequestMainThread::Open(const nsACString& aMethod, const nsACString& aUrl, + bool aAsync, const nsAString& aUsername, + const nsAString& aPassword, uint8_t optional_argc) { + Optional async; if (!optional_argc) { // No optional arguments were passed in. Default async to true. - async = true; + async.Construct() = true; + } else { + async.Construct() = aAsync; } - Optional realUser; + Optional username; if (optional_argc > 1) { - realUser = &user; + username = &aUsername; } - Optional realPassword; + Optional password; if (optional_argc > 2) { - realPassword = &password; + password = &aPassword; } - return Open(method, url, async, realUser, realPassword); + return OpenInternal(aMethod, aUrl, async, username, password); +} + +// This case is hit when the async parameter is outright omitted, which +// should set it to true (and the username and password to null). +void +XMLHttpRequestMainThread::Open(const nsACString& aMethod, const nsAString& aUrl, + ErrorResult& aRv) +{ + aRv = OpenInternal(aMethod, NS_ConvertUTF16toUTF8(aUrl), Optional(true), + Optional(), Optional()); +} + +// This case is hit when the async parameter is specified, even if the +// JS value was "undefined" (which due to legacy reasons should be +// treated as true, which is how it will already be passed in here). +void +XMLHttpRequestMainThread::Open(const nsACString& aMethod, + const nsAString& aUrl, + bool aAsync, + const Optional& aUsername, + const Optional& aPassword, + ErrorResult& aRv) +{ + aRv = OpenInternal(aMethod, NS_ConvertUTF16toUTF8(aUrl), + Optional(aAsync), aUsername, aPassword); } nsresult -XMLHttpRequestMainThread::Open(const nsACString& inMethod, const nsACString& url, - bool async, const Optional& user, - const Optional& password) +XMLHttpRequestMainThread::OpenInternal(const nsACString& aMethod, + const nsACString& aUrl, + const Optional& aAsync, + const Optional& aUsername, + const Optional& aPassword) { - if (inMethod.IsEmpty()) { - return NS_ERROR_DOM_SYNTAX_ERR; - } + bool async = aAsync.WasPassed() ? aAsync.Value() : true; + // Gecko-specific if (!async && !DontWarnAboutSyncXHR() && GetOwner() && GetOwner()->GetExtantDoc()) { GetOwner()->GetExtantDoc()->WarnOnceAbout(nsIDocument::eSyncXMLHttpRequest); } - Telemetry::Accumulate(Telemetry::XMLHTTPREQUEST_ASYNC_OR_SYNC, - async ? 0 : 1); + Telemetry::Accumulate(Telemetry::XMLHTTPREQUEST_ASYNC_OR_SYNC, async ? 0 : 1); + // Step 1 + nsCOMPtr 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; + } + } NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED); + // Steps 2-4 nsAutoCString method; - nsresult rv = FetchUtil::GetValidRequestMethod(inMethod, method); + nsresult rv = FetchUtil::GetValidRequestMethod(aMethod, method); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - // sync request is not allowed to use responseType or timeout - // in window context - if (!async && HasOrHasHadOwner() && - (mTimeoutMilliseconds || + // Steps 5-6 + nsCOMPtr baseURI; + if (mBaseURI) { + baseURI = mBaseURI; + } else if (responsibleDocument) { + baseURI = responsibleDocument->GetBaseURI(); + } + nsCOMPtr 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 rv; + } + if (NS_WARN_IF(NS_FAILED(CheckInnerWindowCorrectness()))) { + return NS_ERROR_DOM_INVALID_STATE_ERR; + } + + // Step 7 is already done above. + // Note that the username and password are already passed in as null by Open() + // if the async parameter is omitted, so there's no need check again here. + + // Step 8 + if (aAsync.WasPassed()) { + nsAutoCString host; + parsedURL->GetHost(host); + if (!host.IsEmpty()) { + nsAutoCString userpass; + if (aUsername.WasPassed()) { + CopyUTF16toUTF8(aUsername.Value(), userpass); + } + userpass.AppendLiteral(":"); + if (aPassword.WasPassed()) { + AppendUTF16toUTF8(aPassword.Value(), userpass); + } + parsedURL->SetUserPass(userpass); + } + } + + // Step 9 + if (!async && HasOrHasHadOwner() && (mTimeoutMilliseconds || mResponseType != XMLHttpRequestResponseType::_empty)) { if (mTimeoutMilliseconds) { LogMessage("TimeoutSyncXHRWarning", GetOwner()); @@ -1408,140 +1485,30 @@ XMLHttpRequestMainThread::Open(const nsACString& inMethod, const nsACString& url return NS_ERROR_DOM_INVALID_ACCESS_ERR; } - nsCOMPtr uri; - - CloseRequest(); // spec step 10 - ResetResponse(); // (part of) spec step 11 + // Step 10 + CloseRequest(); + // Step 11 + // timeouts are handled without a flag mFlagSend = false; + mRequestMethod.Assign(method); + mRequestURL = parsedURL; + mFlagSynchronous = !async; + mAuthorRequestHeaders.Clear(); + ResetResponse(); - // Unset any pre-existing aborted and timed-out flags. + // Gecko-specific + mFlagHadUploadListenersOnSend = false; mFlagAborted = false; mFlagTimedOut = false; - mFlagSynchronous = !async; - - nsCOMPtr doc = GetDocumentIfCurrent(); - if (!doc) { - // This could be because we're no longer current or because we're in some - // non-window context... - if (NS_WARN_IF(NS_FAILED(CheckInnerWindowCorrectness()))) { - return NS_ERROR_DOM_INVALID_STATE_ERR; - } - } - - nsCOMPtr baseURI; - if (mBaseURI) { - baseURI = mBaseURI; - } - else if (doc) { - baseURI = doc->GetBaseURI(); - } - - rv = NS_NewURI(getter_AddRefs(uri), url, nullptr, baseURI); - - if (NS_FAILED(rv)) { - if (rv == NS_ERROR_MALFORMED_URI) { - return NS_ERROR_DOM_SYNTAX_ERR; - } - return rv; - } - - if (NS_WARN_IF(NS_FAILED(CheckInnerWindowCorrectness()))) { - return NS_ERROR_DOM_INVALID_STATE_ERR; - } - - // XXXbz this is wrong: we should only be looking at whether - // user/password were passed, not at the values! See bug 759624. - if (user.WasPassed() && !user.Value().IsEmpty()) { - nsAutoCString userpass; - CopyUTF16toUTF8(user.Value(), userpass); - if (password.WasPassed() && !password.Value().IsEmpty()) { - userpass.Append(':'); - AppendUTF16toUTF8(password.Value(), userpass); - } - uri->SetUserPass(userpass); - } - - // Clear our record of previously set headers so future header set - // operations will merge/override correctly. - mAuthorRequestHeaders.Clear(); - - // When we are called from JS we can find the load group for the page, - // and add ourselves to it. This way any pending requests - // will be automatically aborted if the user leaves the page. - nsCOMPtr loadGroup = GetLoadGroup(); - - nsSecurityFlags secFlags; - nsLoadFlags loadFlags = nsIRequest::LOAD_BACKGROUND | - nsIChannel::LOAD_CLASSIFY_URI; - if (nsContentUtils::IsSystemPrincipal(mPrincipal)) { - // When chrome is loading we want to make sure to sandbox any potential - // result document. We also want to allow cross-origin loads. - secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL | - nsILoadInfo::SEC_SANDBOXED; - } - else if (IsSystemXHR()) { - // For pages that have appropriate permissions, we want to still allow - // cross-origin loads, but make sure that the any potential result - // documents get the same principal as the loader. - secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS | - nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL; - loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER; - } - else { - // Otherwise use CORS. Again, make sure that potential result documents - // use the same principal as the loader. - secFlags = nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS | - nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL; - } - - if (mIsAnon) { - secFlags |= nsILoadInfo::SEC_COOKIES_OMIT; - } - - // If we have the document, use it. Unfortunately, for dedicated workers - // 'doc' ends up being the parent document, which is not the document - // that we want to use. So make sure to avoid using 'doc' in that situation. - if (doc && doc->NodePrincipal() == mPrincipal) { - rv = NS_NewChannel(getter_AddRefs(mChannel), - uri, - doc, - secFlags, - nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST, - loadGroup, - nullptr, // aCallbacks - loadFlags); - } else { - //otherwise use the principal - rv = NS_NewChannel(getter_AddRefs(mChannel), - uri, - mPrincipal, - secFlags, - nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST, - loadGroup, - nullptr, // aCallbacks - loadFlags); - } - + rv = InitChannel(); NS_ENSURE_SUCCESS(rv, rv); - mFlagHadUploadListenersOnSend = false; - - nsCOMPtr httpChannel(do_QueryInterface(mChannel)); - if (httpChannel) { - rv = httpChannel->SetRequestMethod(method); - NS_ENSURE_SUCCESS(rv, rv); - - // Set the initiator type - nsCOMPtr timedChannel(do_QueryInterface(httpChannel)); - if (timedChannel) { - timedChannel->SetInitiatorType(kLiteralString_xmlhttprequest); - } - } - + // Step 12 if (mState != State::opened) { - ChangeState(State::opened); + mState = State::opened; + FireReadystatechangeEvent(); } return NS_OK; @@ -2139,6 +2106,81 @@ XMLHttpRequestMainThread::ChangeStateToDone() } } +nsresult +XMLHttpRequestMainThread::InitChannel() +{ + // When we are called from JS we can find the load group for the page, + // and add ourselves to it. This way any pending requests + // will be automatically aborted if the user leaves the page. + nsCOMPtr loadGroup = GetLoadGroup(); + + nsSecurityFlags secFlags; + nsLoadFlags loadFlags = nsIRequest::LOAD_BACKGROUND | + nsIChannel::LOAD_CLASSIFY_URI; + if (nsContentUtils::IsSystemPrincipal(mPrincipal)) { + // When chrome is loading we want to make sure to sandbox any potential + // result document. We also want to allow cross-origin loads. + secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL | + nsILoadInfo::SEC_SANDBOXED; + } else if (IsSystemXHR()) { + // For pages that have appropriate permissions, we want to still allow + // cross-origin loads, but make sure that the any potential result + // documents get the same principal as the loader. + secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS | + nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL; + loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER; + } else { + // Otherwise use CORS. Again, make sure that potential result documents + // use the same principal as the loader. + secFlags = nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS | + nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL; + } + + if (mIsAnon) { + secFlags |= nsILoadInfo::SEC_COOKIES_OMIT; + } + + // Use the responsibleDocument if we have it, except for dedicated workers + // where it will be the parent document, which is not the one we want to use. + nsresult rv; + nsCOMPtr responsibleDocument = GetDocumentIfCurrent(); + if (responsibleDocument && responsibleDocument->NodePrincipal() == mPrincipal) { + rv = NS_NewChannel(getter_AddRefs(mChannel), + mRequestURL, + responsibleDocument, + secFlags, + nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST, + loadGroup, + nullptr, // aCallbacks + loadFlags); + } else { + // Otherwise use the principal. + rv = NS_NewChannel(getter_AddRefs(mChannel), + mRequestURL, + mPrincipal, + secFlags, + nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST, + loadGroup, + nullptr, // aCallbacks + loadFlags); + } + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr httpChannel(do_QueryInterface(mChannel)); + if (httpChannel) { + rv = httpChannel->SetRequestMethod(mRequestMethod); + NS_ENSURE_SUCCESS(rv, rv); + + // Set the initiator type + nsCOMPtr timedChannel(do_QueryInterface(httpChannel)); + if (timedChannel) { + timedChannel->SetInitiatorType(NS_LITERAL_STRING("xmlhttprequest")); + } + } + + return NS_OK; +} + static nsresult GetRequestBodyInternal(nsIDOMDocument* aDoc, nsIInputStream** aResult, uint64_t* aContentLength, nsACString& aContentType, diff --git a/dom/xhr/XMLHttpRequestMainThread.h b/dom/xhr/XMLHttpRequestMainThread.h index d02c522a54d0..40d64c06e4bb 100644 --- a/dom/xhr/XMLHttpRequestMainThread.h +++ b/dom/xhr/XMLHttpRequestMainThread.h @@ -199,25 +199,17 @@ public: virtual uint16_t ReadyState() const override; // request + nsresult InitChannel(); + virtual void Open(const nsACString& aMethod, const nsAString& aUrl, - ErrorResult& aRv) override - { - Open(aMethod, aUrl, true, - Optional(), - Optional(), - aRv); - } + ErrorResult& aRv) override; virtual void Open(const nsACString& aMethod, const nsAString& aUrl, bool aAsync, const Optional& aUser, const Optional& aPassword, - ErrorResult& aRv) override - { - aRv = Open(aMethod, NS_ConvertUTF16toUTF8(aUrl), - aAsync, aUser, aPassword); - } + ErrorResult& aRv) override; virtual void SetRequestHeader(const nsACString& aName, const nsACString& aValue, @@ -610,15 +602,19 @@ protected: nsresult OnRedirectVerifyCallback(nsresult result); - nsresult Open(const nsACString& method, const nsACString& url, bool async, - const Optional& user, - const Optional& password); + nsresult OpenInternal(const nsACString& aMethod, + const nsACString& aUrl, + const Optional& aAsync, + const Optional& aUsername, + const Optional& aPassword); already_AddRefed EnsureXPCOMifier(); nsCOMPtr mContext; nsCOMPtr mPrincipal; nsCOMPtr mChannel; + nsCString mRequestMethod; + nsCOMPtr mRequestURL; nsCOMPtr mResponseXML; nsCOMPtr mXMLParserStreamListener; diff --git a/dom/xhr/XMLHttpRequestWorker.cpp b/dom/xhr/XMLHttpRequestWorker.cpp index f5ff9b3a27fb..24afa5c66727 100644 --- a/dom/xhr/XMLHttpRequestWorker.cpp +++ b/dom/xhr/XMLHttpRequestWorker.cpp @@ -1498,8 +1498,10 @@ SendRunnable::RunOnMainThread(ErrorResult& aRv) mProxy->mSyncLoopTarget.swap(mSyncLoopTarget); if (mHasUploadListeners) { - NS_ASSERTION(!mProxy->mUploadEventListenersAttached, "Huh?!"); - if (!mProxy->AddRemoveEventListeners(true, true)) { + // Send() can be called more than once before failure, + // so don't attach the upload listeners more than once. + if (!mProxy->mUploadEventListenersAttached && + !mProxy->AddRemoveEventListeners(true, true)) { MOZ_ASSERT(false, "This should never fail!"); } } @@ -1514,8 +1516,10 @@ SendRunnable::RunOnMainThread(ErrorResult& aRv) mProxy->mOutstandingSendCount++; if (!mHasUploadListeners) { - NS_ASSERTION(!mProxy->mUploadEventListenersAttached, "Huh?!"); - if (!mProxy->AddRemoveEventListeners(true, true)) { + // Send() can be called more than once before failure, + // so don't attach the upload listeners more than once. + if (!mProxy->mUploadEventListenersAttached && + !mProxy->AddRemoveEventListeners(true, true)) { MOZ_ASSERT(false, "This should never fail!"); } } From 16c863c9d6eaf89d79c26a0ee267867e2140317f Mon Sep 17 00:00:00 2001 From: Thomas Wisniewski Date: Thu, 21 Jul 2016 00:36:26 -0400 Subject: [PATCH 007/120] Bug 1285036 - Part 9: Clean up the XHR send() API endpoints, and how nsIVariants are handled. r=baku --HG-- extra : rebase_source : 6eb5919d4c4180c55089f0fd6dfcd728dbb52534 --- dom/xhr/XMLHttpRequestMainThread.cpp | 441 ++++++++++++--------------- dom/xhr/XMLHttpRequestMainThread.h | 139 +++------ 2 files changed, 230 insertions(+), 350 deletions(-) diff --git a/dom/xhr/XMLHttpRequestMainThread.cpp b/dom/xhr/XMLHttpRequestMainThread.cpp index 9acd4ee484fa..0ca27b16150c 100644 --- a/dom/xhr/XMLHttpRequestMainThread.cpp +++ b/dom/xhr/XMLHttpRequestMainThread.cpp @@ -2106,6 +2106,167 @@ XMLHttpRequestMainThread::ChangeStateToDone() } } +template<> nsresult +XMLHttpRequestMainThread::RequestBody::GetAsStream( + nsIInputStream** aResult, uint64_t* aContentLength, + nsACString& aContentType, nsACString& aCharset) const +{ + nsCOMPtr domdoc(do_QueryInterface(mBody)); + NS_ENSURE_STATE(domdoc); + aCharset.AssignLiteral("UTF-8"); + + nsresult rv; + nsCOMPtr storStream; + rv = NS_NewStorageStream(4096, UINT32_MAX, getter_AddRefs(storStream)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr output; + rv = storStream->GetOutputStream(0, getter_AddRefs(output)); + NS_ENSURE_SUCCESS(rv, rv); + + if (mBody->IsHTMLDocument()) { + aContentType.AssignLiteral("text/html"); + + nsString serialized; + if (!nsContentUtils::SerializeNodeToMarkup(mBody, true, serialized)) { + return NS_ERROR_OUT_OF_MEMORY; + } + NS_ConvertUTF16toUTF8 utf8Serialized(serialized); + + uint32_t written; + rv = output->Write(utf8Serialized.get(), utf8Serialized.Length(), &written); + NS_ENSURE_SUCCESS(rv, rv); + + MOZ_ASSERT(written == utf8Serialized.Length()); + } else { + aContentType.AssignLiteral("application/xml"); + + nsCOMPtr serializer = + do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + // Make sure to use the encoding we'll send + rv = serializer->SerializeToStream(domdoc, output, aCharset); + NS_ENSURE_SUCCESS(rv, rv); + } + + output->Close(); + + uint32_t length; + rv = storStream->GetLength(&length); + NS_ENSURE_SUCCESS(rv, rv); + *aContentLength = length; + + rv = storStream->NewInputStream(0, aResult); + NS_ENSURE_SUCCESS(rv, rv); + return NS_OK; +} + +template<> nsresult +XMLHttpRequestMainThread::RequestBody::GetAsStream( + nsIInputStream** aResult, uint64_t* aContentLength, + nsACString& aContentType, nsACString& aCharset) const +{ + aContentType.AssignLiteral("text/plain"); + aCharset.AssignLiteral("UTF-8"); + + nsCString converted = NS_ConvertUTF16toUTF8(*mBody); + *aContentLength = converted.Length(); + nsresult rv = NS_NewCStringInputStream(aResult, converted); + NS_ENSURE_SUCCESS(rv, rv); + return NS_OK; +} + +template<> nsresult +XMLHttpRequestMainThread::RequestBody::GetAsStream( + nsIInputStream** aResult, uint64_t* aContentLength, + nsACString& aContentType, nsACString& aCharset) const +{ + aContentType.AssignLiteral("text/plain"); + aCharset.Truncate(); + + nsresult rv = mBody->Available(aContentLength); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr stream(mBody); + stream.forget(aResult); + return NS_OK; +} + +template<> nsresult +XMLHttpRequestMainThread::RequestBody::GetAsStream( + nsIInputStream** aResult, uint64_t* aContentLength, + nsACString& aContentType, nsACString& aCharset) const +{ + return mBody->GetSendInfo(aResult, aContentLength, aContentType, aCharset); +} + +template<> nsresult +XMLHttpRequestMainThread::RequestBody::GetAsStream( + nsIInputStream** aResult, uint64_t* aContentLength, + nsACString& aContentType, nsACString& aCharset) const +{ + return mBody->GetSendInfo(aResult, aContentLength, aContentType, aCharset); +} + +template<> nsresult +XMLHttpRequestMainThread::RequestBody::GetAsStream( + nsIInputStream** aResult, uint64_t* aContentLength, + nsACString& aContentType, nsACString& aCharset) const +{ + return mBody->GetSendInfo(aResult, aContentLength, aContentType, aCharset); +} + +template<> nsresult +XMLHttpRequestMainThread::RequestBody::GetAsStream( + nsIInputStream** aResult, uint64_t* aContentLength, + nsACString& aContentType, nsACString& aCharset) const +{ + return mBody->GetSendInfo(aResult, aContentLength, aContentType, aCharset); +} + +static nsresult +GetBufferDataAsStream(const uint8_t* aData, uint32_t aDataLength, + nsIInputStream** aResult, uint64_t* aContentLength, + nsACString& aContentType, nsACString& aCharset) +{ + aContentType.SetIsVoid(true); + aCharset.Truncate(); + + *aContentLength = aDataLength; + const char* data = reinterpret_cast(aData); + + nsCOMPtr stream; + nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream), data, aDataLength, + NS_ASSIGNMENT_COPY); + NS_ENSURE_SUCCESS(rv, rv); + + stream.forget(aResult); + + return NS_OK; +} + +template<> nsresult +XMLHttpRequestMainThread::RequestBody::GetAsStream( + nsIInputStream** aResult, uint64_t* aContentLength, + nsACString& aContentType, nsACString& aCharset) const +{ + mBody->ComputeLengthAndData(); + return GetBufferDataAsStream(mBody->Data(), mBody->Length(), + aResult, aContentLength, aContentType, aCharset); +} + +template<> nsresult +XMLHttpRequestMainThread::RequestBody::GetAsStream( + nsIInputStream** aResult, uint64_t* aContentLength, + nsACString& aContentType, nsACString& aCharset) const +{ + mBody->ComputeLengthAndData(); + return GetBufferDataAsStream(mBody->Data(), mBody->Length(), + aResult, aContentLength, aContentType, aCharset); +} + + nsresult XMLHttpRequestMainThread::InitChannel() { @@ -2181,154 +2342,31 @@ XMLHttpRequestMainThread::InitChannel() return NS_OK; } -static nsresult -GetRequestBodyInternal(nsIDOMDocument* aDoc, nsIInputStream** aResult, - uint64_t* aContentLength, nsACString& aContentType, - nsACString& aCharset) +NS_IMETHODIMP +XMLHttpRequestMainThread::Send(nsIVariant* aVariant) { - nsCOMPtr doc(do_QueryInterface(aDoc)); - NS_ENSURE_STATE(doc); - aCharset.AssignLiteral("UTF-8"); - - nsresult rv; - nsCOMPtr storStream; - rv = NS_NewStorageStream(4096, UINT32_MAX, getter_AddRefs(storStream)); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr output; - rv = storStream->GetOutputStream(0, getter_AddRefs(output)); - NS_ENSURE_SUCCESS(rv, rv); - - if (doc->IsHTMLDocument()) { - aContentType.AssignLiteral("text/html"); - - nsString serialized; - if (!nsContentUtils::SerializeNodeToMarkup(doc, true, serialized)) { - return NS_ERROR_OUT_OF_MEMORY; - } - NS_ConvertUTF16toUTF8 utf8Serialized(serialized); - - uint32_t written; - rv = output->Write(utf8Serialized.get(), utf8Serialized.Length(), &written); - NS_ENSURE_SUCCESS(rv, rv); - - MOZ_ASSERT(written == utf8Serialized.Length()); - } else { - aContentType.AssignLiteral("application/xml"); - - nsCOMPtr serializer = - do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - // Make sure to use the encoding we'll send - rv = serializer->SerializeToStream(aDoc, output, aCharset); - NS_ENSURE_SUCCESS(rv, rv); - + if (!aVariant) { + return SendInternal(nullptr); } - output->Close(); - - uint32_t length; - rv = storStream->GetLength(&length); - NS_ENSURE_SUCCESS(rv, rv); - *aContentLength = length; - - return storStream->NewInputStream(0, aResult); -} - -static nsresult -GetRequestBodyInternal(const nsAString& aString, nsIInputStream** aResult, - uint64_t* aContentLength, nsACString& aContentType, - nsACString& aCharset) -{ - aContentType.AssignLiteral("text/plain"); - aCharset.AssignLiteral("UTF-8"); - - nsCString converted = NS_ConvertUTF16toUTF8(aString); - *aContentLength = converted.Length(); - return NS_NewCStringInputStream(aResult, converted); -} - -static nsresult -GetRequestBodyInternal(nsIInputStream* aStream, nsIInputStream** aResult, - uint64_t* aContentLength, nsACString& aContentType, - nsACString& aCharset) -{ - aContentType.AssignLiteral("text/plain"); - aCharset.Truncate(); - - nsresult rv = aStream->Available(aContentLength); - NS_ENSURE_SUCCESS(rv, rv); - - NS_ADDREF(*aResult = aStream); - - return NS_OK; -} - -static nsresult -GetRequestBodyInternal(URLSearchParams* aURLSearchParams, - nsIInputStream** aResult, uint64_t* aContentLength, - nsACString& aContentType, nsACString& aCharset) -{ - return aURLSearchParams->GetSendInfo(aResult, aContentLength, - aContentType, aCharset); -} - -static nsresult -GetRequestBodyInternal(nsIXHRSendable* aSendable, nsIInputStream** aResult, - uint64_t* aContentLength, nsACString& aContentType, - nsACString& aCharset) -{ - return aSendable->GetSendInfo(aResult, aContentLength, aContentType, aCharset); -} - -// Used for array buffers and array buffer views -static nsresult -GetRequestBodyInternal(const uint8_t* aData, uint32_t aDataLength, - nsIInputStream** aResult, uint64_t* aContentLength, - nsACString& aContentType, nsACString& aCharset) -{ - aContentType.SetIsVoid(true); - aCharset.Truncate(); - - *aContentLength = aDataLength; - const char* data = reinterpret_cast(aData); - - nsCOMPtr stream; - nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream), data, aDataLength, - NS_ASSIGNMENT_COPY); - NS_ENSURE_SUCCESS(rv, rv); - - stream.forget(aResult); - - return NS_OK; -} - -static nsresult -GetRequestBodyInternal(nsIVariant* aBody, nsIInputStream** aResult, - uint64_t* aContentLength, nsACString& aContentType, - nsACString& aCharset) -{ - *aResult = nullptr; - uint16_t dataType; - nsresult rv = aBody->GetDataType(&dataType); + nsresult rv = aVariant->GetDataType(&dataType); NS_ENSURE_SUCCESS(rv, rv); if (dataType == nsIDataType::VTYPE_INTERFACE || dataType == nsIDataType::VTYPE_INTERFACE_IS) { nsCOMPtr supports; nsID *iid; - rv = aBody->GetAsInterface(&iid, getter_AddRefs(supports)); + rv = aVariant->GetAsInterface(&iid, getter_AddRefs(supports)); NS_ENSURE_SUCCESS(rv, rv); free(iid); // document? - nsCOMPtr doc = do_QueryInterface(supports); + nsCOMPtr doc = do_QueryInterface(supports); if (doc) { - return GetRequestBodyInternal(doc, aResult, aContentLength, aContentType, - aCharset); + RequestBody body(doc); + return SendInternal(&body); } // nsISupportsString? @@ -2336,153 +2374,56 @@ GetRequestBodyInternal(nsIVariant* aBody, nsIInputStream** aResult, if (wstr) { nsAutoString string; wstr->GetData(string); - - return GetRequestBodyInternal(string, aResult, aContentLength, - aContentType, aCharset); + RequestBody body(&string); + return SendInternal(&body); } // nsIInputStream? nsCOMPtr stream = do_QueryInterface(supports); if (stream) { - return GetRequestBodyInternal(stream, aResult, aContentLength, - aContentType, aCharset); + RequestBody body(stream); + return SendInternal(&body); } // nsIXHRSendable? nsCOMPtr sendable = do_QueryInterface(supports); if (sendable) { - return GetRequestBodyInternal(sendable, aResult, aContentLength, - aContentType, aCharset); + RequestBody body(sendable); + return SendInternal(&body); } // ArrayBuffer? JSContext* rootingCx = nsContentUtils::RootingCx(); JS::Rooted realVal(rootingCx); - nsresult rv = aBody->GetAsJSVal(&realVal); + nsresult rv = aVariant->GetAsJSVal(&realVal); if (NS_SUCCEEDED(rv) && !realVal.isPrimitive()) { JS::Rooted obj(rootingCx, realVal.toObjectOrNull()); RootedTypedArray buf(rootingCx); if (buf.Init(obj)) { - buf.ComputeLengthAndData(); - return GetRequestBodyInternal(buf.Data(), buf.Length(), aResult, - aContentLength, aContentType, aCharset); + RequestBody body(&buf); + return SendInternal(&body); } } - } - else if (dataType == nsIDataType::VTYPE_VOID || + } else if (dataType == nsIDataType::VTYPE_VOID || dataType == nsIDataType::VTYPE_EMPTY) { - // Makes us act as if !aBody, don't upload anything - aContentType.AssignLiteral("text/plain"); - aCharset.AssignLiteral("UTF-8"); - *aContentLength = 0; - - return NS_OK; + return SendInternal(nullptr); } char16_t* data = nullptr; uint32_t len = 0; - rv = aBody->GetAsWStringWithSize(&len, &data); + rv = aVariant->GetAsWStringWithSize(&len, &data); NS_ENSURE_SUCCESS(rv, rv); nsString string; string.Adopt(data, len); - return GetRequestBodyInternal(string, aResult, aContentLength, aContentType, - aCharset); -} - -/* static */ -nsresult -XMLHttpRequestMainThread::GetRequestBody(nsIVariant* aVariant, - const Nullable& aBody, - nsIInputStream** aResult, - uint64_t* aContentLength, - nsACString& aContentType, - nsACString& aCharset) -{ - // null the content type and charset by default, as per XHR spec step 4 - aContentType.SetIsVoid(true); - aCharset.SetIsVoid(true); - - if (aVariant) { - return GetRequestBodyInternal(aVariant, aResult, aContentLength, - aContentType, aCharset); - } - - const RequestBody& body = aBody.Value(); - RequestBody::Value value = body.GetValue(); - switch (body.GetType()) { - case XMLHttpRequestMainThread::RequestBody::eArrayBuffer: - { - const ArrayBuffer* buffer = value.mArrayBuffer; - buffer->ComputeLengthAndData(); - return GetRequestBodyInternal(buffer->Data(), buffer->Length(), aResult, - aContentLength, aContentType, aCharset); - } - case XMLHttpRequestMainThread::RequestBody::eArrayBufferView: - { - const ArrayBufferView* view = value.mArrayBufferView; - view->ComputeLengthAndData(); - return GetRequestBodyInternal(view->Data(), view->Length(), aResult, - aContentLength, aContentType, aCharset); - } - case XMLHttpRequestMainThread::RequestBody::eBlob: - { - nsresult rv; - nsCOMPtr blob = value.mBlob; - nsCOMPtr sendable = do_QueryInterface(blob, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - return GetRequestBodyInternal(sendable, aResult, aContentLength, - aContentType, aCharset); - } - case XMLHttpRequestMainThread::RequestBody::eDocument: - { - nsCOMPtr document = do_QueryInterface(value.mDocument); - return GetRequestBodyInternal(document, aResult, aContentLength, - aContentType, aCharset); - } - case XMLHttpRequestMainThread::RequestBody::eDOMString: - { - return GetRequestBodyInternal(*value.mString, aResult, aContentLength, - aContentType, aCharset); - } - case XMLHttpRequestMainThread::RequestBody::eFormData: - { - MOZ_ASSERT(value.mFormData); - return GetRequestBodyInternal(value.mFormData, aResult, aContentLength, - aContentType, aCharset); - } - case XMLHttpRequestMainThread::RequestBody::eURLSearchParams: - { - MOZ_ASSERT(value.mURLSearchParams); - return GetRequestBodyInternal(value.mURLSearchParams, aResult, - aContentLength, aContentType, aCharset); - } - case XMLHttpRequestMainThread::RequestBody::eInputStream: - { - return GetRequestBodyInternal(value.mStream, aResult, aContentLength, - aContentType, aCharset); - } - default: - { - return NS_ERROR_FAILURE; - } - } - - NS_NOTREACHED("Default cases exist for a reason"); - return NS_OK; -} - -NS_IMETHODIMP -XMLHttpRequestMainThread::Send(nsIVariant *aBody) -{ - return Send(aBody, Nullable()); + RequestBody body(&string); + return SendInternal(&body); } nsresult -XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable& aBody) +XMLHttpRequestMainThread::SendInternal(const RequestBodyBase* aBody) { NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED); @@ -2561,7 +2502,7 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable mErrorLoad = false; mLoadLengthComputable = false; mLoadTotal = 0; - if ((aVariant || !aBody.IsNull()) && httpChannel && + if (aBody && httpChannel && !method.LowerCaseEqualsLiteral("get") && !method.LowerCaseEqualsLiteral("head")) { @@ -2570,8 +2511,8 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable nsCOMPtr postDataStream; uint64_t size_u64; - rv = GetRequestBody(aVariant, aBody, getter_AddRefs(postDataStream), - &size_u64, defaultContentType, charset); + rv = aBody->GetAsStream(getter_AddRefs(postDataStream), + &size_u64, defaultContentType, charset); NS_ENSURE_SUCCESS(rv, rv); // make sure it fits within js MAX_SAFE_INTEGER @@ -2579,7 +2520,7 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable net::InScriptableRange(size_u64) ? static_cast(size_u64) : -1; if (postDataStream) { - // If author set no Content-Type, use the default from GetRequestBody(). + // If author set no Content-Type, use the default from GetAsStream(). nsAutoCString contentType; GetAuthorRequestHeaderValue("content-type", contentType); @@ -2833,7 +2774,6 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable mWaitingForOnStopRequest = true; - // Step 8 mFlagSend = true; // If we're synchronous, spin an event loop here and wait @@ -2892,8 +2832,7 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable if (mUpload && mUpload->HasListenersFor(nsGkAtoms::onprogress)) { StartProgressEventTimer(); } - DispatchProgressEvent(this, ProgressEventType::loadstart, false, - 0, 0); + DispatchProgressEvent(this, ProgressEventType::loadstart, false, 0, 0); if (mUpload && !mUploadComplete) { DispatchProgressEvent(mUpload, ProgressEventType::loadstart, true, 0, mUploadTotal); diff --git a/dom/xhr/XMLHttpRequestMainThread.h b/dom/xhr/XMLHttpRequestMainThread.h index 40d64c06e4bb..afc4c062ba88 100644 --- a/dom/xhr/XMLHttpRequestMainThread.h +++ b/dom/xhr/XMLHttpRequestMainThread.h @@ -238,100 +238,34 @@ public: private: virtual ~XMLHttpRequestMainThread(); - class RequestBody + class RequestBodyBase { public: - RequestBody() : mType(eUninitialized) - { - } - explicit RequestBody(const ArrayBuffer* aArrayBuffer) : mType(eArrayBuffer) - { - mValue.mArrayBuffer = aArrayBuffer; - } - explicit RequestBody(const ArrayBufferView* aArrayBufferView) : mType(eArrayBufferView) - { - mValue.mArrayBufferView = aArrayBufferView; - } - explicit RequestBody(Blob& aBlob) : mType(eBlob) - { - mValue.mBlob = &aBlob; - } - explicit RequestBody(mozilla::dom::URLSearchParams& aURLSearchParams) : - mType(eURLSearchParams) - { - mValue.mURLSearchParams = &aURLSearchParams; - } - explicit RequestBody(nsIDocument* aDocument) : mType(eDocument) - { - mValue.mDocument = aDocument; - } - explicit RequestBody(const nsAString& aString) : mType(eDOMString) - { - mValue.mString = &aString; - } - explicit RequestBody(FormData& aFormData) : mType(eFormData) - { - mValue.mFormData = &aFormData; - } - explicit RequestBody(nsIInputStream* aStream) : mType(eInputStream) - { - mValue.mStream = aStream; - } - - enum Type { - eUninitialized, - eArrayBuffer, - eArrayBufferView, - eBlob, - eDocument, - eDOMString, - eFormData, - eInputStream, - eURLSearchParams - }; - union Value { - const ArrayBuffer* mArrayBuffer; - const ArrayBufferView* mArrayBufferView; - Blob* mBlob; - nsIDocument* mDocument; - const nsAString* mString; - FormData* mFormData; - nsIInputStream* mStream; - URLSearchParams* mURLSearchParams; - }; - - Type GetType() const - { - MOZ_ASSERT(mType != eUninitialized); - return mType; - } - Value GetValue() const - { - MOZ_ASSERT(mType != eUninitialized); - return mValue; - } - - private: - Type mType; - Value mValue; - }; - - static nsresult GetRequestBody(nsIVariant* aVariant, - const Nullable& aBody, - nsIInputStream** aResult, + virtual nsresult GetAsStream(nsIInputStream** aResult, uint64_t* aContentLength, nsACString& aContentType, - nsACString& aCharset); + nsACString& aCharset) const + { + NS_ASSERTION(false, "RequestBodyBase should not be used directly."); + return NS_ERROR_FAILURE; + } + }; - nsresult Send(nsIVariant* aVariant, const Nullable& aBody); - nsresult Send(const Nullable& aBody) + template + class RequestBody final : public RequestBodyBase { - return Send(nullptr, aBody); - } - nsresult Send(const RequestBody& aBody) - { - return Send(Nullable(aBody)); - } + Type* mBody; + public: + explicit RequestBody(Type* aBody) : mBody(aBody) + { + } + nsresult GetAsStream(nsIInputStream** aResult, + uint64_t* aContentLength, + nsACString& aContentType, + nsACString& aCharset) const override; + }; + + nsresult SendInternal(const RequestBodyBase* aBody); bool IsCrossSiteCORSRequest() const; bool IsDeniedCrossSiteCORSRequest(); @@ -345,39 +279,44 @@ public: virtual void Send(JSContext* /*aCx*/, ErrorResult& aRv) override { - aRv = Send(Nullable()); + aRv = SendInternal(nullptr); } virtual void Send(JSContext* /*aCx*/, const ArrayBuffer& aArrayBuffer, ErrorResult& aRv) override { - aRv = Send(RequestBody(&aArrayBuffer)); + RequestBody body(&aArrayBuffer); + aRv = SendInternal(&body); } virtual void Send(JSContext* /*aCx*/, const ArrayBufferView& aArrayBufferView, ErrorResult& aRv) override { - aRv = Send(RequestBody(&aArrayBufferView)); + RequestBody body(&aArrayBufferView); + aRv = SendInternal(&body); } virtual void Send(JSContext* /*aCx*/, Blob& aBlob, ErrorResult& aRv) override { - aRv = Send(RequestBody(aBlob)); + RequestBody body(&aBlob); + aRv = SendInternal(&body); } virtual void Send(JSContext* /*aCx*/, URLSearchParams& aURLSearchParams, ErrorResult& aRv) override { - aRv = Send(RequestBody(aURLSearchParams)); + RequestBody body(&aURLSearchParams); + aRv = SendInternal(&body); } virtual void Send(JSContext* /*aCx*/, nsIDocument& aDoc, ErrorResult& aRv) override { - aRv = Send(RequestBody(&aDoc)); + RequestBody body(&aDoc); + aRv = SendInternal(&body); } virtual void @@ -385,16 +324,17 @@ public: { if (DOMStringIsNull(aString)) { Send(aCx, aRv); - } - else { - aRv = Send(RequestBody(aString)); + } else { + RequestBody body(&aString); + aRv = SendInternal(&body); } } virtual void Send(JSContext* /*aCx*/, FormData& aFormData, ErrorResult& aRv) override { - aRv = Send(RequestBody(aFormData)); + RequestBody body(&aFormData); + aRv = SendInternal(&body); } virtual void @@ -418,7 +358,8 @@ public: } return; } - aRv = Send(RequestBody(aStream)); + RequestBody body(aStream); + aRv = SendInternal(&body); } void From db067f26be1184daa4baa054b28fcd7557cd385b Mon Sep 17 00:00:00 2001 From: Jan Horak Date: Thu, 28 Jul 2016 10:09:32 -0400 Subject: [PATCH 008/120] Bug 1277213 - Reset state after cancel. r=mayhemer --- netwerk/protocol/http/nsHttpChannelAuthProvider.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp b/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp index 9eb87925d44b..367826318e9f 100644 --- a/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp +++ b/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp @@ -1290,6 +1290,13 @@ NS_IMETHODIMP nsHttpChannelAuthProvider::OnAuthCancelled(nsISupports *aContext, // there are still some challenges to process, do so nsresult rv; + // Get rid of current continuationState to avoid reusing it in + // next challenges since it is no longer relevant. + if (mProxyAuth) { + NS_IF_RELEASE(mProxyAuthContinuationState); + } else { + NS_IF_RELEASE(mAuthContinuationState); + } nsAutoCString creds; rv = GetCredentials(mRemainingChallenges.get(), mProxyAuth, creds); if (NS_SUCCEEDED(rv)) { From 6c0d578d0e223cec29dd35340d670e3bc3c0cbca Mon Sep 17 00:00:00 2001 From: Julian Hector Date: Wed, 27 Jul 2016 15:45:02 +0200 Subject: [PATCH 009/120] Bug 1287008 - Add sys_fadvise64_64 to seccomp whitelist. r=gcp --- security/sandbox/linux/SandboxFilter.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/security/sandbox/linux/SandboxFilter.cpp b/security/sandbox/linux/SandboxFilter.cpp index fffef68826c0..ec7e586a1017 100644 --- a/security/sandbox/linux/SandboxFilter.cpp +++ b/security/sandbox/linux/SandboxFilter.cpp @@ -674,6 +674,11 @@ public: return Allow(); #endif +#ifdef __NR_fadvise64_64 + case __NR_fadvise64_64: + return Allow(); +#endif + case __NR_fallocate: return Allow(); From 91f614aa943e78e62eac768707e43c4bbcccd57b Mon Sep 17 00:00:00 2001 From: Jonathan Hao Date: Tue, 26 Jul 2016 20:35:00 -0400 Subject: [PATCH 010/120] Bug 1274265 - Move the final check of browser_broadcastchannel.js into content. r=baku --- .../test/browser/browser_broadcastchannel.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/browser/components/contextualidentity/test/browser/browser_broadcastchannel.js b/browser/components/contextualidentity/test/browser/browser_broadcastchannel.js index a9a716a94166..a821ce96b9b0 100644 --- a/browser/components/contextualidentity/test/browser/browser_broadcastchannel.js +++ b/browser/components/contextualidentity/test/browser/browser_broadcastchannel.js @@ -63,17 +63,16 @@ add_task(function* test() { }); } - // make sure we have received a message - yield ContentTask.spawn(receiver.browser, channelName, - function* (name) { - yield content.window.testPromise.then(function() {}); - } - ); - // Since sender1 sends before sender2, if the title is exactly // sender2's message, sender1's message must've been blocked - is(receiver.browser.contentDocument.title, sender2.message, - "should only receive messages from the same user context"); + yield ContentTask.spawn(receiver.browser, sender2.message, + function* (message) { + yield content.window.testPromise.then(function() { + is(content.document.title, message, + "should only receive messages from the same user context"); + }); + } + ); gBrowser.removeTab(sender1.tab); gBrowser.removeTab(sender2.tab); From b1a08048c4d0358c49cc59c720e4cef7bb997e8d Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Thu, 28 Jul 2016 09:04:42 +0200 Subject: [PATCH 011/120] Bug 1289911: Add WasmTlsReg in none/ platform; r=lth MozReview-Commit-ID: 9grnZ3dVmCm --HG-- extra : rebase_source : 0516ff6617099d2e401378c6b90ad2ea197183b8 extra : amend_source : 7e34021f7319d683133e742016920a094e3c24f3 --- js/src/jit/none/MacroAssembler-none.h | 1 + 1 file changed, 1 insertion(+) diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index b5ebacab5956..f104d8968651 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -85,6 +85,7 @@ static constexpr Register ABINonArgReturnReg1 = { Registers::invalid_reg }; static constexpr Register WasmTableCallPtrReg = { Registers::invalid_reg }; static constexpr Register WasmTableCallSigReg = { Registers::invalid_reg }; +static constexpr Register WasmTlsReg = { Registers::invalid_reg }; static constexpr uint32_t ABIStackAlignment = 4; static constexpr uint32_t CodeAlignment = 4; From 29ace485e11013abf577aef25f673033fb9bf9dc Mon Sep 17 00:00:00 2001 From: Ethan Lin Date: Tue, 26 Jul 2016 12:51:32 +0800 Subject: [PATCH 012/120] Bug 1260599 - Enable EXT_disjoint_timer_query extension on ANGLE. r=jgilbert --HG-- extra : rebase_source : debccc5664b65f568f3cb82f6434108bb9092045 --- dom/canvas/WebGLContext.cpp | 7 +++++++ dom/canvas/WebGLContext.h | 2 ++ dom/canvas/WebGLContextState.cpp | 6 +++++- dom/canvas/WebGLExtensionDisjointTimerQuery.cpp | 10 ++++------ 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index d20745fe6f0c..0b2d329e61d9 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -1626,6 +1626,13 @@ WebGLContext::DummyReadFramebufferOperation(const char* funcName) } } +bool +WebGLContext::HasTimestampBits() const +{ + // 'sync' provides glGetInteger64v either by supporting ARB_sync, GL3+, or GLES3+. + return gl->IsSupported(GLFeature::sync); +} + static bool CheckContextLost(GLContext* gl, bool* const out_isGuilty) { diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index 23cee25f01b6..8fb6dd4cf168 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -1473,6 +1473,8 @@ protected: bool mNeedsFakeNoStencil; bool mNeedsEmulatedLoneDepthStencil; + bool HasTimestampBits() const; + struct ScopedMaskWorkaround { WebGLContext& mWebGL; const bool mFakeNoAlpha; diff --git a/dom/canvas/WebGLContextState.cpp b/dom/canvas/WebGLContextState.cpp index dbd6f44a126b..e47e54a5ebe1 100644 --- a/dom/canvas/WebGLContextState.cpp +++ b/dom/canvas/WebGLContextState.cpp @@ -267,7 +267,11 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv) if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query)) { if (pname == LOCAL_GL_TIMESTAMP_EXT) { GLuint64 iv = 0; - gl->fGetInteger64v(pname, (GLint64*) &iv); + if (HasTimestampBits()) { + gl->fGetInteger64v(pname, (GLint64*)&iv); + } else { + GenerateWarning("QUERY_COUNTER_BITS_EXT for TIMESTAMP_EXT is 0."); + } // TODO: JS doesn't support 64-bit integers. Be lossy and // cast to double (53 bits) return JS::NumberValue(static_cast(iv)); diff --git a/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp b/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp index e2fcdaf53db9..42ebe3f57722 100644 --- a/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp +++ b/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp @@ -177,7 +177,9 @@ WebGLExtensionDisjointTimerQuery::GetQueryEXT(JSContext* cx, GLenum target, return; } GLint bits = 0; - mContext->GL()->fGetQueryiv(target, pname, &bits); + if (mContext->HasTimestampBits()) { + mContext->GL()->fGetQueryiv(target, pname, &bits); + } retval.set(JS::Int32Value(int32_t(bits))); break; } @@ -242,11 +244,7 @@ WebGLExtensionDisjointTimerQuery::IsSupported(const WebGLContext* webgl) gl::GLContext* gl = webgl->GL(); return gl->IsSupported(gl::GLFeature::query_objects) && gl->IsSupported(gl::GLFeature::get_query_object_i64v) && - gl->IsSupported(gl::GLFeature::query_counter) && // provides GL_TIMESTAMP - gl->IsSupported(gl::GLFeature::sync); // provides glGetInteger64v - // 'sync' provides glGetInteger64v either by supporting ARB_sync, GL3+, or GLES3+. - // Since there are no differences between support for glGetInteger64v and support for - // 'sync', we just piggy-back off of 'sync'. + gl->IsSupported(gl::GLFeature::query_counter); // provides GL_TIMESTAMP } void From 6ab3df37e7691168eeab9131424e6c18fc575a54 Mon Sep 17 00:00:00 2001 From: Ethan Lin Date: Tue, 26 Jul 2016 12:51:32 +0800 Subject: [PATCH 013/120] Bug 1260599 - Change EXT_disjoint_timer_query mochitest status. r=mtseng --HG-- extra : rebase_source : 1f2e1e83477d7baf8d35eafe342090a38c8eaef0 --- dom/canvas/test/webgl-mochitest/mochitest.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dom/canvas/test/webgl-mochitest/mochitest.ini b/dom/canvas/test/webgl-mochitest/mochitest.ini index c307d1639bb1..649cbc9cbdbc 100644 --- a/dom/canvas/test/webgl-mochitest/mochitest.ini +++ b/dom/canvas/test/webgl-mochitest/mochitest.ini @@ -15,7 +15,7 @@ fail-if = (os == 'android') [ensure-exts/test_EXT_color_buffer_half_float.html] fail-if = (os == 'android') [ensure-exts/test_EXT_disjoint_timer_query.html] -fail-if = (os == 'android') || (os == 'mac') || (os == 'win') +fail-if = (os == 'android') || (os == 'mac') [ensure-exts/test_EXT_frag_depth.html] fail-if = (os == 'android') [ensure-exts/test_EXT_sRGB.html] @@ -84,6 +84,7 @@ skip-if = android_version == '18' #Android 4.3 aws only; bug 1030942 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests [test_webgl_compressed_texture_es3.html] [test_webgl_disjoint_timer_query.html] +fail-if = (os == 'win') [test_webgl_force_enable.html] [test_webgl_request_context.html] skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests From 9bdd71041ae929ba23086056a474e656a6572eb8 Mon Sep 17 00:00:00 2001 From: Sander Mathijs van Veen Date: Thu, 28 Jul 2016 01:33:00 -0400 Subject: [PATCH 014/120] Bug 1287485 - Display comments inside dumped assembly code (-D flag). r=nbp --HG-- extra : rebase_source : d2cb2d023d3065b64d09dd8a434d48e0fbc7abe7 --- js/src/jit/CodeGenerator.cpp | 9 ++++++++- js/src/jit/MacroAssembler.cpp | 5 ++++- js/src/jit/MacroAssembler.h | 3 +++ js/src/jit/arm/Assembler-arm.h | 4 ++++ js/src/jit/arm/MacroAssembler-arm.cpp | 6 ++++++ js/src/jit/arm64/Assembler-arm64.h | 5 +++++ js/src/jit/arm64/MacroAssembler-arm64.cpp | 6 ++++++ js/src/jit/mips-shared/Assembler-mips-shared.h | 5 +++++ js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp | 6 ++++++ js/src/jit/x86-shared/BaseAssembler-x86-shared.h | 5 +++++ js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp | 6 ++++++ 11 files changed, 58 insertions(+), 2 deletions(-) diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 4a679d9afe6e..06d1a0143205 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -3080,9 +3080,11 @@ CodeGenerator::emitGetPropertyPolymorphic(LInstruction* ins, Register obj, Regis ReceiverGuard receiver = mir->receiver(i); Label next; + masm.comment("GuardReceiver"); GuardReceiver(masm, receiver, obj, scratch, &next, /* checkNullExpando = */ false); if (receiver.shape) { + masm.comment("loadTypedOrValue"); // If this is an unboxed expando access, GuardReceiver loaded the // expando object into scratch. Register target = receiver.group ? scratch : obj; @@ -3099,6 +3101,7 @@ CodeGenerator::emitGetPropertyPolymorphic(LInstruction* ins, Register obj, Regis masm.loadTypedOrValue(Address(scratch, offset), output); } } else { + masm.comment("loadUnboxedProperty"); const UnboxedLayout::Property* property = receiver.group->unboxedLayout().lookup(mir->name()); Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset); @@ -3392,6 +3395,7 @@ CodeGenerator::visitTypeBarrierO(LTypeBarrierO* lir) Label miss, ok; if (lir->mir()->type() == MIRType::ObjectOrNull) { + masm.comment("Object or Null"); Label* nullTarget = lir->mir()->resultTypeSet()->mightBeMIRType(MIRType::Null) ? &ok : &miss; masm.branchTestPtr(Assembler::Zero, obj, obj, nullTarget); } else { @@ -3399,8 +3403,10 @@ CodeGenerator::visitTypeBarrierO(LTypeBarrierO* lir) MOZ_ASSERT(lir->mir()->barrierKind() != BarrierKind::TypeTagOnly); } - if (lir->mir()->barrierKind() != BarrierKind::TypeTagOnly) + if (lir->mir()->barrierKind() != BarrierKind::TypeTagOnly) { + masm.comment("Type tag only"); masm.guardObjectType(obj, lir->mir()->resultTypeSet(), scratch, &miss); + } bailoutFrom(&miss, lir->snapshot()); masm.bind(&ok); @@ -5041,6 +5047,7 @@ CodeGenerator::emitDebugForceBailing(LInstruction* lir) if (lir->isOsiPoint()) return; + masm.comment("emitDebugForceBailing"); const void* bailAfterAddr = GetJitContext()->runtime->addressOfIonBailAfter(); AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All()); diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index 2e6f463a26a1..9d268d49d430 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -176,14 +176,17 @@ MacroAssembler::guardObjectType(Register obj, const TypeSet* types, continue; } - if (lastBranch.isInitialized()) + if (lastBranch.isInitialized()) { + comment("emit GC pointer checks"); lastBranch.emit(*this); + } JSObject* object = types->getSingletonNoBarrier(i); lastBranch = BranchGCPtr(Equal, obj, ImmGCPtr(object), &matched); } if (hasObjectGroups) { + comment("has object groups"); // We are possibly going to overwrite the obj register. So already // emit the branch, since branch depends on previous value of obj // register and there is definitely a branch following. So no need diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 97d55266f34c..4ece0819545d 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -390,6 +390,9 @@ class MacroAssembler : public MacroAssemblerSpecific // Flushes the assembly buffer, on platforms that need it. void flush() PER_SHARED_ARCH; + // Add a comment that is visible in the pretty printed assembly code. + void comment(const char* msg) PER_SHARED_ARCH; + // =============================================================== // Frame manipulation functions. diff --git a/js/src/jit/arm/Assembler-arm.h b/js/src/jit/arm/Assembler-arm.h index 13e4bf1dce5a..00aae6121451 100644 --- a/js/src/jit/arm/Assembler-arm.h +++ b/js/src/jit/arm/Assembler-arm.h @@ -1781,6 +1781,10 @@ class Assembler : public AssemblerShared return; } + void comment(const char* msg) { + spew("; %s", msg); + } + // Copy the assembly code to the given buffer, and perform any pending // relocations relying on the target address. void executableCopy(uint8_t* buffer); diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 1cf5e504422e..9764cfc95310 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -4742,6 +4742,12 @@ MacroAssembler::flush() Assembler::flush(); } +void +MacroAssembler::comment(const char* msg) +{ + Assembler::comment(msg); +} + // =============================================================== // Stack manipulation functions. diff --git a/js/src/jit/arm64/Assembler-arm64.h b/js/src/jit/arm64/Assembler-arm64.h index 91f0aa88b061..5ecb93de44e5 100644 --- a/js/src/jit/arm64/Assembler-arm64.h +++ b/js/src/jit/arm64/Assembler-arm64.h @@ -278,6 +278,11 @@ class Assembler : public vixl::Assembler armbuffer_.flushPool(); } + void comment(const char* msg) { + // This is not implemented because setPrinter() is not implemented. + // TODO spew("; %s", msg); + } + int actualIndex(int curOffset) { ARMBuffer::PoolEntry pe(curOffset); return armbuffer_.poolEntryOffset(pe); diff --git a/js/src/jit/arm64/MacroAssembler-arm64.cpp b/js/src/jit/arm64/MacroAssembler-arm64.cpp index 8afbb7f1d263..2fa91c3fe3d9 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.cpp +++ b/js/src/jit/arm64/MacroAssembler-arm64.cpp @@ -831,6 +831,12 @@ template void MacroAssembler::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const BaseIndex& dest, MIRType slotType); +void +MacroAssembler::comment(const char* msg) +{ + Assembler::comment(msg); +} + //}}} check_macroassembler_style } // namespace jit diff --git a/js/src/jit/mips-shared/Assembler-mips-shared.h b/js/src/jit/mips-shared/Assembler-mips-shared.h index 87b73c57c52c..13463a03d74b 100644 --- a/js/src/jit/mips-shared/Assembler-mips-shared.h +++ b/js/src/jit/mips-shared/Assembler-mips-shared.h @@ -1259,6 +1259,11 @@ class AssemblerMIPSShared : public AssemblerShared void flushBuffer() { } + void comment(const char* msg) { + // This is not implemented because setPrinter() is not implemented. + // TODO spew("; %s", msg); + } + static uint32_t NopSize() { return 4; } static void PatchWrite_Imm32(CodeLocationLabel label, Imm32 imm); diff --git a/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp b/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp index 448c8fdf1cfc..943bab28aee8 100644 --- a/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp +++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp @@ -1451,4 +1451,10 @@ MacroAssembler::branchPtrInNurseryRange(Condition cond, Register ptr, Register t SecondScratchReg, Imm32(nursery.nurserySize()), label); } +void +MacroAssembler::comment(const char* msg) +{ + Assembler::comment(msg); +} + //}}} check_macroassembler_style diff --git a/js/src/jit/x86-shared/BaseAssembler-x86-shared.h b/js/src/jit/x86-shared/BaseAssembler-x86-shared.h index 7200a8e89ee8..ea6ceab8ccd6 100644 --- a/js/src/jit/x86-shared/BaseAssembler-x86-shared.h +++ b/js/src/jit/x86-shared/BaseAssembler-x86-shared.h @@ -75,6 +75,11 @@ public: m_formatter.oneByteOp(OP_NOP); } + void comment(const char* msg) + { + spew("; %s", msg); + } + MOZ_MUST_USE JmpSrc twoByteNop() { diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp index fb7d7fa79ab0..6916bb3fc1b7 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp @@ -476,6 +476,12 @@ MacroAssembler::flush() { } +void +MacroAssembler::comment(const char* msg) +{ + masm.comment(msg); +} + // =============================================================== // Stack manipulation functions. From 67751356ee633cc7cdbf2b1e94f945697ea9fc07 Mon Sep 17 00:00:00 2001 From: Jessica Jong Date: Thu, 28 Jul 2016 02:44:00 -0400 Subject: [PATCH 015/120] Bug 1289272 - Simplify the computation of step values for input type=date. r=smaug --HG-- extra : rebase_source : 24bf85cff09e6ace2806778e9e5409756a598e57 --- dom/html/HTMLInputElement.cpp | 31 +++---------------- dom/html/test/forms/test_step_attribute.html | 28 ++++++++--------- dom/html/test/forms/test_stepup_stepdown.html | 25 +++++++-------- .../form-validation-reportValidity.html.ini | 3 -- 4 files changed, 31 insertions(+), 56 deletions(-) diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 755c3d5cf6c1..4c1b447605f3 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -2365,22 +2365,6 @@ HTMLInputElement::GetValueIfStepped(int32_t aStep, value += step * Decimal(aStep); } - // For date inputs, the value can hold a string that is not a day. We do not - // want to round it, as it might result in a step mismatch. Instead we want to - // clamp to the next valid value. - if (mType == NS_FORM_INPUT_DATE && - NS_floorModulo(Decimal(value - GetStepBase()), GetStepScaleFactor()) != Decimal(0)) { - MOZ_ASSERT(GetStep() > Decimal(0)); - Decimal validStep = EuclidLCM(GetStep().floor(), - GetStepScaleFactor().floor()); - if (aStep > 0) { - value -= NS_floorModulo(value - GetStepBase(), validStep); - value += validStep; - } else if (aStep < 0) { - value -= NS_floorModulo(value - GetStepBase(), validStep); - } - } - if (value < minimum) { value = minimum; deltaFromStep = NS_floorModulo(value - stepBase, step); @@ -6903,6 +6887,11 @@ HTMLInputElement::GetStep() const step = GetDefaultStep(); } + // For input type=date, we round the step value to have a rounded day. + if (mType == NS_FORM_INPUT_DATE) { + step = std::max(step.round(), Decimal(1)); + } + return step * GetStepScaleFactor(); } @@ -7506,16 +7495,6 @@ HTMLInputElement::GetValidationMessage(nsAString& aValidationMessage, Decimal step = GetStep(); MOZ_ASSERT(step != kStepAny && step > Decimal(0)); - // In case this is a date and the step is not an integer, we don't want to - // display the dates corresponding to the truncated timestamps of valueLow - // and valueHigh because they might suffer from a step mismatch as well. - // Instead we want the timestamps to correspond to a rounded day. That is, - // we want a multiple of the step scale factor (1 day) as well as of step. - if (mType == NS_FORM_INPUT_DATE) { - step = EuclidLCM(step.floor(), - GetStepScaleFactor().floor()); - } - Decimal stepBase = GetStepBase(); Decimal valueLow = value - NS_floorModulo(value - stepBase, step); diff --git a/dom/html/test/forms/test_step_attribute.html b/dom/html/test/forms/test_step_attribute.html index acbacd27c1cc..a57b865be88d 100644 --- a/dom/html/test/forms/test_step_attribute.html +++ b/dom/html/test/forms/test_step_attribute.html @@ -185,7 +185,7 @@ for (var test of data) { input.min = '2009-02-01'; input.step = '1.1'; input.value = '2009-02-02'; - checkValidity(input, false, apply, { low: "2009-02-01", high: "2009-02-12" }); + checkValidity(input, true, apply); // Without any step attribute the date is valid input.removeAttribute('step'); @@ -203,21 +203,21 @@ for (var test of data) { input.step = '0.9'; input.value = '1951-01-02'; - checkValidity(input, false, apply, { low: "1951-01-01", high: "1951-01-10" }); - - input.value = '1951-01-10' + is(input.step, '0.9', "check that step value is unchanged"); checkValidity(input, true, apply); - input.step = '0.5'; + input.step = '0.4'; input.value = '1951-01-02'; + is(input.step, '0.4', "check that step value is unchanged"); checkValidity(input, true, apply); input.step = '1.5'; - input.value = '1951-01-03'; - checkValidity(input, false, apply, { low: "1951-01-01", high: "1951-01-04" }); + input.value = '1951-01-02'; + is(input.step, '1.5', "check that step value is unchanged"); + checkValidity(input, false, apply, { low: "1951-01-01", high: "1951-01-03" }); input.value = '1951-01-08'; - checkValidity(input, false, apply, { low: "1951-01-07", high: "1951-01-10" }); + checkValidity(input, false, apply, { low: "1951-01-07", high: "1951-01-09" }); input.step = '3000'; input.min= '1968-01-01'; @@ -236,26 +236,26 @@ for (var test of data) { input.value = '1992-08-22'; checkValidity(input, true, apply); - input.step = '1.1'; + input.step = '2.1'; input.min = '1991-01-01'; input.value = '1991-01-01'; checkValidity(input, true, apply); input.value = '1991-01-02'; - checkValidity(input, false, apply, { low: "1991-01-01", high: "1991-01-12" }); + checkValidity(input, false, apply, { low: "1991-01-01", high: "1991-01-03" }); - input.value = '1991-01-12'; + input.value = '1991-01-03'; checkValidity(input, true, apply); - input.step = '1.1'; + input.step = '2.1'; input.min = '1969-12-20'; input.value = '1969-12-20'; checkValidity(input, true, apply); input.value = '1969-12-21'; - checkValidity(input, false, apply, { low: "1969-12-20", high: "1969-12-31" }); + checkValidity(input, false, apply, { low: "1969-12-20", high: "1969-12-22" }); - input.value = '1969-12-31'; + input.value = '1969-12-22'; checkValidity(input, true, apply); break; diff --git a/dom/html/test/forms/test_stepup_stepdown.html b/dom/html/test/forms/test_stepup_stepdown.html index 7c7f0d5ef88f..2a6d4c1dfc7d 100644 --- a/dom/html/test/forms/test_stepup_stepdown.html +++ b/dom/html/test/forms/test_stepup_stepdown.html @@ -271,12 +271,12 @@ function checkStepDown() [ '2012-01-03', '0.5', null, null, null, '2012-01-02', false ], [ '2012-01-02', '0.5', null, null, null, '2012-01-01', false ], [ '2012-01-01', '2', null, null, null, '2011-12-30', false ], - [ '2012-01-02', '0.25',null, null, 4, '2012-01-01', false ], - [ '2012-01-15', '1.1', '2012-01-01', null, 1, '2012-01-12', false ], - [ '2012-01-12', '1.1', '2012-01-01', null, 2, '2012-01-01', false ], - [ '2012-01-23', '1.1', '2012-01-01', null, 10, '2012-01-12', false ], - [ '2012-01-23', '1.1', '2012-01-01', null, 11, '2012-01-01', false ], - [ '1968-01-12', '1.1', '1968-01-01', null, 8, '1968-01-01', false ], + [ '2012-01-02', '0.25',null, null, 4, '2011-12-29', false ], + [ '2012-01-15', '1.1', '2012-01-01', null, 1, '2012-01-14', false ], + [ '2012-01-12', '1.1', '2012-01-01', null, 2, '2012-01-10', false ], + [ '2012-01-23', '1.1', '2012-01-01', null, 10, '2012-01-13', false ], + [ '2012-01-23', '1.1', '2012-01-01', null, 11, '2012-01-12', false ], + [ '1968-01-12', '1.1', '1968-01-01', null, 8, '1968-01-04', false ], // step = 0 isn't allowed (-> step = 1). [ '2012-01-02', '0', null, null, null, '2012-01-01', false ], // step < 0 isn't allowed (-> step = 1). @@ -588,14 +588,13 @@ function checkStepUp() [ '2012-01-01', null, null, null, 1.9, '2012-01-02', false ], // With step values. [ '2012-01-01', '0.5', null, null, null, '2012-01-02', false ], - [ '2012-01-01', '0.5', null, null, null, '2012-01-02', false ], [ '2012-01-01', '2', null, null, null, '2012-01-03', false ], - [ '2012-01-01', '0.25', null, null, 4, '2012-01-02', false ], - [ '2012-01-01', '1.1', '2012-01-01', null, 1, '2012-01-12', false ], - [ '2012-01-01', '1.1', '2012-01-01', null, 2, '2012-01-12', false ], - [ '2012-01-01', '1.1', '2012-01-01', null, 10, '2012-01-12', false ], - [ '2012-01-01', '1.1', '2012-01-01', null, 11, '2012-01-23', false ], - [ '1968-01-01', '1.1', '1968-01-01', null, 8, '1968-01-12', false ], + [ '2012-01-01', '0.25', null, null, 4, '2012-01-05', false ], + [ '2012-01-01', '1.1', '2012-01-01', null, 1, '2012-01-02', false ], + [ '2012-01-01', '1.1', '2012-01-01', null, 2, '2012-01-03', false ], + [ '2012-01-01', '1.1', '2012-01-01', null, 10, '2012-01-11', false ], + [ '2012-01-01', '1.1', '2012-01-01', null, 11, '2012-01-12', false ], + [ '1968-01-01', '1.1', '1968-01-01', null, 8, '1968-01-09', false ], // step = 0 isn't allowed (-> step = 1). [ '2012-01-01', '0', null, null, null, '2012-01-02', false ], // step < 0 isn't allowed (-> step = 1). diff --git a/testing/web-platform/meta/html/semantics/forms/constraints/form-validation-reportValidity.html.ini b/testing/web-platform/meta/html/semantics/forms/constraints/form-validation-reportValidity.html.ini index 40c1c80471f2..50968ab66547 100644 --- a/testing/web-platform/meta/html/semantics/forms/constraints/form-validation-reportValidity.html.ini +++ b/testing/web-platform/meta/html/semantics/forms/constraints/form-validation-reportValidity.html.ini @@ -1,8 +1,5 @@ [form-validation-reportValidity.html] type: testharness - expected: TIMEOUT - disabled: - if debug and (os == "mac"): https://bugzilla.mozilla.org/show_bug.cgi?id=1273105 [[INPUT in TEXT status\] suffering from being too long] expected: FAIL From 7fae1904bfe143d22b9940b7902fef7312c73fb5 Mon Sep 17 00:00:00 2001 From: Andrew Comminos Date: Wed, 27 Jul 2016 14:18:47 -0400 Subject: [PATCH 016/120] Bug 1131576 - Spin the event loop between calls to showPopup in test_windowminmaxsize.xul. r=enn MozReview-Commit-ID: CoZBzJQRHGx --- layout/xul/test/test_windowminmaxsize.xul | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/layout/xul/test/test_windowminmaxsize.xul b/layout/xul/test/test_windowminmaxsize.xul index 2d54ee39f32b..5909039cf58d 100644 --- a/layout/xul/test/test_windowminmaxsize.xul +++ b/layout/xul/test/test_windowminmaxsize.xul @@ -199,7 +199,12 @@ function nextPopupTest(panel) if ("last" in popupTests[gTestId]) document.getElementById("popupresizer").removeAttribute("flex"); - panel.openPopup(); + // Prevent event loop starvation as a result of popup events being + // synchronous. See bug 1131576. + SimpleTest.executeSoon(() => { + // Non-chrome shells require focus to open a popup. + SimpleTest.waitForFocus(() => { panel.openPopup() }); + }); } } From 2568d9b9fd57382959124e45ce5382b9c106244a Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Thu, 28 Jul 2016 17:01:14 +0200 Subject: [PATCH 017/120] Backed out changeset 30da5718207a (bug 1287485) for bustage --- js/src/jit/CodeGenerator.cpp | 9 +-------- js/src/jit/MacroAssembler.cpp | 5 +---- js/src/jit/MacroAssembler.h | 3 --- js/src/jit/arm/Assembler-arm.h | 4 ---- js/src/jit/arm/MacroAssembler-arm.cpp | 6 ------ js/src/jit/arm64/Assembler-arm64.h | 5 ----- js/src/jit/arm64/MacroAssembler-arm64.cpp | 6 ------ js/src/jit/mips-shared/Assembler-mips-shared.h | 5 ----- js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp | 6 ------ js/src/jit/x86-shared/BaseAssembler-x86-shared.h | 5 ----- js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp | 6 ------ 11 files changed, 2 insertions(+), 58 deletions(-) diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 06d1a0143205..4a679d9afe6e 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -3080,11 +3080,9 @@ CodeGenerator::emitGetPropertyPolymorphic(LInstruction* ins, Register obj, Regis ReceiverGuard receiver = mir->receiver(i); Label next; - masm.comment("GuardReceiver"); GuardReceiver(masm, receiver, obj, scratch, &next, /* checkNullExpando = */ false); if (receiver.shape) { - masm.comment("loadTypedOrValue"); // If this is an unboxed expando access, GuardReceiver loaded the // expando object into scratch. Register target = receiver.group ? scratch : obj; @@ -3101,7 +3099,6 @@ CodeGenerator::emitGetPropertyPolymorphic(LInstruction* ins, Register obj, Regis masm.loadTypedOrValue(Address(scratch, offset), output); } } else { - masm.comment("loadUnboxedProperty"); const UnboxedLayout::Property* property = receiver.group->unboxedLayout().lookup(mir->name()); Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset); @@ -3395,7 +3392,6 @@ CodeGenerator::visitTypeBarrierO(LTypeBarrierO* lir) Label miss, ok; if (lir->mir()->type() == MIRType::ObjectOrNull) { - masm.comment("Object or Null"); Label* nullTarget = lir->mir()->resultTypeSet()->mightBeMIRType(MIRType::Null) ? &ok : &miss; masm.branchTestPtr(Assembler::Zero, obj, obj, nullTarget); } else { @@ -3403,10 +3399,8 @@ CodeGenerator::visitTypeBarrierO(LTypeBarrierO* lir) MOZ_ASSERT(lir->mir()->barrierKind() != BarrierKind::TypeTagOnly); } - if (lir->mir()->barrierKind() != BarrierKind::TypeTagOnly) { - masm.comment("Type tag only"); + if (lir->mir()->barrierKind() != BarrierKind::TypeTagOnly) masm.guardObjectType(obj, lir->mir()->resultTypeSet(), scratch, &miss); - } bailoutFrom(&miss, lir->snapshot()); masm.bind(&ok); @@ -5047,7 +5041,6 @@ CodeGenerator::emitDebugForceBailing(LInstruction* lir) if (lir->isOsiPoint()) return; - masm.comment("emitDebugForceBailing"); const void* bailAfterAddr = GetJitContext()->runtime->addressOfIonBailAfter(); AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All()); diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index 9d268d49d430..2e6f463a26a1 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -176,17 +176,14 @@ MacroAssembler::guardObjectType(Register obj, const TypeSet* types, continue; } - if (lastBranch.isInitialized()) { - comment("emit GC pointer checks"); + if (lastBranch.isInitialized()) lastBranch.emit(*this); - } JSObject* object = types->getSingletonNoBarrier(i); lastBranch = BranchGCPtr(Equal, obj, ImmGCPtr(object), &matched); } if (hasObjectGroups) { - comment("has object groups"); // We are possibly going to overwrite the obj register. So already // emit the branch, since branch depends on previous value of obj // register and there is definitely a branch following. So no need diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 4ece0819545d..97d55266f34c 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -390,9 +390,6 @@ class MacroAssembler : public MacroAssemblerSpecific // Flushes the assembly buffer, on platforms that need it. void flush() PER_SHARED_ARCH; - // Add a comment that is visible in the pretty printed assembly code. - void comment(const char* msg) PER_SHARED_ARCH; - // =============================================================== // Frame manipulation functions. diff --git a/js/src/jit/arm/Assembler-arm.h b/js/src/jit/arm/Assembler-arm.h index 00aae6121451..13e4bf1dce5a 100644 --- a/js/src/jit/arm/Assembler-arm.h +++ b/js/src/jit/arm/Assembler-arm.h @@ -1781,10 +1781,6 @@ class Assembler : public AssemblerShared return; } - void comment(const char* msg) { - spew("; %s", msg); - } - // Copy the assembly code to the given buffer, and perform any pending // relocations relying on the target address. void executableCopy(uint8_t* buffer); diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 9764cfc95310..1cf5e504422e 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -4742,12 +4742,6 @@ MacroAssembler::flush() Assembler::flush(); } -void -MacroAssembler::comment(const char* msg) -{ - Assembler::comment(msg); -} - // =============================================================== // Stack manipulation functions. diff --git a/js/src/jit/arm64/Assembler-arm64.h b/js/src/jit/arm64/Assembler-arm64.h index 5ecb93de44e5..91f0aa88b061 100644 --- a/js/src/jit/arm64/Assembler-arm64.h +++ b/js/src/jit/arm64/Assembler-arm64.h @@ -278,11 +278,6 @@ class Assembler : public vixl::Assembler armbuffer_.flushPool(); } - void comment(const char* msg) { - // This is not implemented because setPrinter() is not implemented. - // TODO spew("; %s", msg); - } - int actualIndex(int curOffset) { ARMBuffer::PoolEntry pe(curOffset); return armbuffer_.poolEntryOffset(pe); diff --git a/js/src/jit/arm64/MacroAssembler-arm64.cpp b/js/src/jit/arm64/MacroAssembler-arm64.cpp index 2fa91c3fe3d9..8afbb7f1d263 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.cpp +++ b/js/src/jit/arm64/MacroAssembler-arm64.cpp @@ -831,12 +831,6 @@ template void MacroAssembler::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const BaseIndex& dest, MIRType slotType); -void -MacroAssembler::comment(const char* msg) -{ - Assembler::comment(msg); -} - //}}} check_macroassembler_style } // namespace jit diff --git a/js/src/jit/mips-shared/Assembler-mips-shared.h b/js/src/jit/mips-shared/Assembler-mips-shared.h index 13463a03d74b..87b73c57c52c 100644 --- a/js/src/jit/mips-shared/Assembler-mips-shared.h +++ b/js/src/jit/mips-shared/Assembler-mips-shared.h @@ -1259,11 +1259,6 @@ class AssemblerMIPSShared : public AssemblerShared void flushBuffer() { } - void comment(const char* msg) { - // This is not implemented because setPrinter() is not implemented. - // TODO spew("; %s", msg); - } - static uint32_t NopSize() { return 4; } static void PatchWrite_Imm32(CodeLocationLabel label, Imm32 imm); diff --git a/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp b/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp index 943bab28aee8..448c8fdf1cfc 100644 --- a/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp +++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp @@ -1451,10 +1451,4 @@ MacroAssembler::branchPtrInNurseryRange(Condition cond, Register ptr, Register t SecondScratchReg, Imm32(nursery.nurserySize()), label); } -void -MacroAssembler::comment(const char* msg) -{ - Assembler::comment(msg); -} - //}}} check_macroassembler_style diff --git a/js/src/jit/x86-shared/BaseAssembler-x86-shared.h b/js/src/jit/x86-shared/BaseAssembler-x86-shared.h index ea6ceab8ccd6..7200a8e89ee8 100644 --- a/js/src/jit/x86-shared/BaseAssembler-x86-shared.h +++ b/js/src/jit/x86-shared/BaseAssembler-x86-shared.h @@ -75,11 +75,6 @@ public: m_formatter.oneByteOp(OP_NOP); } - void comment(const char* msg) - { - spew("; %s", msg); - } - MOZ_MUST_USE JmpSrc twoByteNop() { diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp index 6916bb3fc1b7..fb7d7fa79ab0 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp @@ -476,12 +476,6 @@ MacroAssembler::flush() { } -void -MacroAssembler::comment(const char* msg) -{ - masm.comment(msg); -} - // =============================================================== // Stack manipulation functions. From c99449c15a1e3f5bd697730b2cc0d54f4ffbc403 Mon Sep 17 00:00:00 2001 From: Brad Lassey Date: Wed, 27 Jul 2016 17:45:48 -0400 Subject: [PATCH 018/120] bug 1289670 - Show plugin activation icon when navigator.mimetypes is queried r=mrbkap --- dom/base/nsMimeTypeArray.cpp | 9 +++++++- dom/base/nsMimeTypeArray.h | 1 + dom/base/nsPluginArray.cpp | 43 +++++++++++++++++++++++++++--------- dom/base/nsPluginArray.h | 3 +++ 4 files changed, 45 insertions(+), 11 deletions(-) diff --git a/dom/base/nsMimeTypeArray.cpp b/dom/base/nsMimeTypeArray.cpp index ea1463a6aee8..ec8a82557f59 100644 --- a/dom/base/nsMimeTypeArray.cpp +++ b/dom/base/nsMimeTypeArray.cpp @@ -30,7 +30,8 @@ NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsMimeTypeArray, mWindow, - mMimeTypes) + mMimeTypes, + mCTPMimeTypes) nsMimeTypeArray::nsMimeTypeArray(nsPIDOMWindowInner* aWindow) : mWindow(aWindow) @@ -57,6 +58,7 @@ void nsMimeTypeArray::Refresh() { mMimeTypes.Clear(); + mCTPMimeTypes.Clear(); } nsPIDOMWindowInner* @@ -133,6 +135,10 @@ nsMimeTypeArray::NamedGetter(const nsAString& aName, bool &aFound) aFound = true; return mimeType; } + nsMimeType* hiddenType = FindMimeType(mCTPMimeTypes, lowerName); + if (hiddenType) { + nsPluginArray::NotifyHiddenPluginTouched(hiddenType->GetEnabledPlugin()); + } return nullptr; } @@ -180,6 +186,7 @@ nsMimeTypeArray::EnsurePluginMimeTypes() } pluginArray->GetMimeTypes(mMimeTypes); + pluginArray->GetCTPMimeTypes(mCTPMimeTypes); } NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsMimeType, AddRef) diff --git a/dom/base/nsMimeTypeArray.h b/dom/base/nsMimeTypeArray.h index 9ffdfe033f18..85613641476b 100644 --- a/dom/base/nsMimeTypeArray.h +++ b/dom/base/nsMimeTypeArray.h @@ -48,6 +48,7 @@ protected: // mMimeTypes contains MIME types handled by plugins or by an OS // PreferredApplicationHandler. nsTArray > mMimeTypes; + nsTArray > mCTPMimeTypes; }; class nsMimeType final : public nsWrapperCache diff --git a/dom/base/nsPluginArray.cpp b/dom/base/nsPluginArray.cpp index 820e79cff6fa..824898b5504f 100644 --- a/dom/base/nsPluginArray.cpp +++ b/dom/base/nsPluginArray.cpp @@ -114,6 +114,24 @@ nsPluginArray::GetMimeTypes(nsTArray>& aMimeTypes) aMimeTypes.Sort(); } +void +nsPluginArray::GetCTPMimeTypes(nsTArray>& aMimeTypes) +{ + aMimeTypes.Clear(); + + if (!AllowPlugins()) { + return; + } + + EnsurePlugins(); + + GetPluginMimeTypes(mCTPPlugins, aMimeTypes); + + // Alphabetize the enumeration order of non-hidden MIME types to reduce + // fingerprintable entropy based on plugins' installation file times. + aMimeTypes.Sort(); +} + nsPluginElement* nsPluginArray::Item(uint32_t aIndex) { @@ -236,21 +254,26 @@ nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound) if (!aFound) { nsPluginElement* hiddenPlugin = FindPlugin(mCTPPlugins, aName); if (hiddenPlugin) { - HiddenPluginEventInit init; - init.mTag = hiddenPlugin->PluginTag(); - nsCOMPtr doc = hiddenPlugin->GetParentObject()->GetDoc(); - RefPtr event = - HiddenPluginEvent::Constructor(doc, NS_LITERAL_STRING("HiddenPlugin"), init); - event->SetTarget(doc); - event->SetTrusted(true); - event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true; - bool dummy; - doc->DispatchEvent(event, &dummy); + NotifyHiddenPluginTouched(hiddenPlugin); } } return plugin; } +void nsPluginArray::NotifyHiddenPluginTouched(nsPluginElement* aHiddenElement) +{ + HiddenPluginEventInit init; + init.mTag = aHiddenElement->PluginTag(); + nsCOMPtr doc = aHiddenElement->GetParentObject()->GetDoc(); + RefPtr event = + HiddenPluginEvent::Constructor(doc, NS_LITERAL_STRING("HiddenPlugin"), init); + event->SetTarget(doc); + event->SetTrusted(true); + event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true; + bool dummy; + doc->DispatchEvent(event, &dummy); +} + uint32_t nsPluginArray::Length() { diff --git a/dom/base/nsPluginArray.h b/dom/base/nsPluginArray.h index 8e02c9a711ac..6f9ce4651673 100644 --- a/dom/base/nsPluginArray.h +++ b/dom/base/nsPluginArray.h @@ -41,6 +41,9 @@ public: void Invalidate(); void GetMimeTypes(nsTArray>& aMimeTypes); + void GetCTPMimeTypes(nsTArray>& aMimeTypes); + + static void NotifyHiddenPluginTouched(nsPluginElement* aElement); // PluginArray WebIDL methods From 521fea749927c3259f93f5019aab4a3e1efbe750 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Thu, 28 Jul 2016 17:58:33 +0200 Subject: [PATCH 019/120] Bug 1290081 - Make canvas layer transactions asynchronous. r=sotaro --- gfx/layers/client/CanvasClient.cpp | 4 ++-- gfx/layers/client/ClientCanvasLayer.cpp | 7 +------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp index 0c4f03317935..61ce67505f83 100644 --- a/gfx/layers/client/CanvasClient.cpp +++ b/gfx/layers/client/CanvasClient.cpp @@ -98,8 +98,7 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) mBufferProviderTexture = nullptr; AutoRemoveTexture autoRemove(this); - if (mBackBuffer && - (mBackBuffer->IsImmutable() || mBackBuffer->GetSize() != aSize)) { + if (mBackBuffer && (mBackBuffer->IsReadLocked() || mBackBuffer->GetSize() != aSize)) { autoRemove.mTexture = mBackBuffer; mBackBuffer = nullptr; } @@ -122,6 +121,7 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) NS_WARNING("Failed to allocate the TextureClient"); return; } + mBackBuffer->EnableReadLock(); MOZ_ASSERT(mBackBuffer->CanExposeDrawTarget()); bufferCreated = true; diff --git a/gfx/layers/client/ClientCanvasLayer.cpp b/gfx/layers/client/ClientCanvasLayer.cpp index 6ded430dbee9..e9fec82c3580 100644 --- a/gfx/layers/client/ClientCanvasLayer.cpp +++ b/gfx/layers/client/ClientCanvasLayer.cpp @@ -90,16 +90,11 @@ ClientCanvasLayer::RenderLayer() RenderMaskLayers(this); if (!mCanvasClient) { - TextureFlags flags = TextureFlags::IMMEDIATE_UPLOAD; + TextureFlags flags = TextureFlags::DEFAULT; if (mOriginPos == gl::OriginPos::BottomLeft) { flags |= TextureFlags::ORIGIN_BOTTOM_LEFT; } - if (!mGLContext) { - // We don't support locking for buffer surfaces currently - flags |= TextureFlags::IMMEDIATE_UPLOAD; - } - if (!mIsAlphaPremultiplied) { flags |= TextureFlags::NON_PREMULTIPLIED; } From ea108a93f6196dd7254e91600fec5a2fbd41dd70 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Thu, 28 Jul 2016 17:58:42 +0200 Subject: [PATCH 020/120] Bug 1289816 - Simplify CopyableCanvasLayer::UpdateTarget and remove unnecessary copies. r=jnicol --- gfx/layers/CopyableCanvasLayer.cpp | 97 +++++++++++---------------- gfx/layers/CopyableCanvasLayer.h | 5 -- gfx/layers/basic/BasicCanvasLayer.cpp | 75 ++++++++++++++++++++- gfx/layers/basic/BasicCanvasLayer.h | 3 + 4 files changed, 113 insertions(+), 67 deletions(-) diff --git a/gfx/layers/CopyableCanvasLayer.cpp b/gfx/layers/CopyableCanvasLayer.cpp index 69ca999c3b34..1870fecf4d59 100644 --- a/gfx/layers/CopyableCanvasLayer.cpp +++ b/gfx/layers/CopyableCanvasLayer.cpp @@ -50,8 +50,6 @@ CopyableCanvasLayer::~CopyableCanvasLayer() void CopyableCanvasLayer::Initialize(const Data& aData) { - NS_ASSERTION(mSurface == nullptr, "BasicCanvasLayer::Initialize called twice!"); - if (aData.mGLContext) { mGLContext = aData.mGLContext; mIsAlphaPremultiplied = aData.mIsGLAlphaPremult; @@ -72,7 +70,7 @@ CopyableCanvasLayer::Initialize(const Data& aData) mAsyncRenderer = aData.mRenderer; mOriginPos = gl::OriginPos::BottomLeft; } else { - MOZ_CRASH("GFX: CanvasLayer created without mSurface, mDrawTarget or mGLContext?"); + MOZ_CRASH("GFX: CanvasLayer created without BufferProvider, DrawTarget or GLContext?"); } mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height); @@ -87,40 +85,36 @@ CopyableCanvasLayer::IsDataValid(const Data& aData) void CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) { - AutoReturnSnapshot autoReturn; - - if (mAsyncRenderer) { - mSurface = mAsyncRenderer->GetSurface(); - } else if (!mGLFrontbuffer && mBufferProvider) { - mSurface = mBufferProvider->BorrowSnapshot(); - if (aDestTarget) { - // If !aDestTarget we'll end up painting using mSurface later, - // so we can't return it to the provider (note that this will trigger a - // copy of the snapshot behind the scenes when the provider is unlocked). - autoReturn.mSnapshot = &mSurface; - } - // Either way we need to call ReturnSnapshot because ther may be an - // underlying TextureClient that has to be unlocked. - autoReturn.mBufferProvider = mBufferProvider; + MOZ_ASSERT(aDestTarget); + if (!aDestTarget) { + return; } - if (!mGLContext && aDestTarget) { - NS_ASSERTION(mSurface, "Must have surface to draw!"); - if (mSurface) { - aDestTarget->CopySurface(mSurface, + RefPtr surface; + + if (!mGLContext) { + AutoReturnSnapshot autoReturn; + + if (mAsyncRenderer) { + surface = mAsyncRenderer->GetSurface(); + } else if (mBufferProvider && !mGLContext) { + surface = mBufferProvider->BorrowSnapshot(); + autoReturn.mSnapshot = &surface; + autoReturn.mBufferProvider = mBufferProvider; + } + + NS_ASSERTION(surface, "Must have surface to draw!"); + if (surface) { + aDestTarget->CopySurface(surface, IntRect(0, 0, mBounds.width, mBounds.height), IntPoint(0, 0)); - mSurface = nullptr; } return; } - if ((!mGLFrontbuffer && mBufferProvider) || mAsyncRenderer) { - return; - } - - MOZ_ASSERT(mGLContext); + MOZ_ASSERT(!mBufferProvider); + MOZ_ASSERT(!mAsyncRenderer); SharedSurface* frontbuffer = nullptr; if (mGLFrontbuffer) { @@ -145,24 +139,22 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied; // Try to read back directly into aDestTarget's output buffer - if (aDestTarget) { - uint8_t* destData; - IntSize destSize; - int32_t destStride; - SurfaceFormat destFormat; - if (aDestTarget->LockBits(&destData, &destSize, &destStride, &destFormat)) { - if (destSize == readSize && destFormat == format) { - RefPtr data = - Factory::CreateWrappingDataSourceSurface(destData, destStride, destSize, destFormat); - mGLContext->Readback(frontbuffer, data); - if (needsPremult) { - gfxUtils::PremultiplyDataSurface(data, data); - } - aDestTarget->ReleaseBits(destData); - return; + uint8_t* destData; + IntSize destSize; + int32_t destStride; + SurfaceFormat destFormat; + if (aDestTarget->LockBits(&destData, &destSize, &destStride, &destFormat)) { + if (destSize == readSize && destFormat == format) { + RefPtr data = + Factory::CreateWrappingDataSourceSurface(destData, destStride, destSize, destFormat); + mGLContext->Readback(frontbuffer, data); + if (needsPremult) { + gfxUtils::PremultiplyDataSurface(data, data); } aDestTarget->ReleaseBits(destData); + return; } + aDestTarget->ReleaseBits(destData); } RefPtr resultSurf = GetTempSurface(readSize, format); @@ -177,17 +169,10 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) if (needsPremult) { gfxUtils::PremultiplyDataSurface(resultSurf, resultSurf); } - MOZ_ASSERT(resultSurf); - if (aDestTarget) { - aDestTarget->CopySurface(resultSurf, - IntRect(0, 0, readSize.width, readSize.height), - IntPoint(0, 0)); - } else { - // If !aDestSurface then we will end up painting using mSurface, so - // stick our surface into mSurface, so that the Paint() path is the same. - mSurface = resultSurf; - } + aDestTarget->CopySurface(resultSurf, + IntRect(0, 0, readSize.width, readSize.height), + IntPoint(0, 0)); } DataSourceSurface* @@ -206,11 +191,5 @@ CopyableCanvasLayer::GetTempSurface(const IntSize& aSize, return mCachedTempSurface; } -void -CopyableCanvasLayer::DiscardTempSurface() -{ - mCachedTempSurface = nullptr; -} - } // namespace layers } // namespace mozilla diff --git a/gfx/layers/CopyableCanvasLayer.h b/gfx/layers/CopyableCanvasLayer.h index 6cefa8150d5e..8fefece4f5df 100644 --- a/gfx/layers/CopyableCanvasLayer.h +++ b/gfx/layers/CopyableCanvasLayer.h @@ -49,11 +49,8 @@ public: protected: void UpdateTarget(gfx::DrawTarget* aDestTarget = nullptr); - RefPtr mSurface; RefPtr mGLContext; - GLuint mCanvasFrontbufferTexID; RefPtr mBufferProvider; - UniquePtr mGLFrontbuffer; bool mIsAlphaPremultiplied; @@ -64,8 +61,6 @@ protected: gfx::DataSourceSurface* GetTempSurface(const gfx::IntSize& aSize, const gfx::SurfaceFormat aFormat); - - void DiscardTempSurface(); }; } // namespace layers diff --git a/gfx/layers/basic/BasicCanvasLayer.cpp b/gfx/layers/basic/BasicCanvasLayer.cpp index 074c12cd9d6e..f615ff31448b 100644 --- a/gfx/layers/basic/BasicCanvasLayer.cpp +++ b/gfx/layers/basic/BasicCanvasLayer.cpp @@ -11,6 +11,11 @@ #include "nsCOMPtr.h" // for already_AddRefed #include "nsISupportsImpl.h" // for Layer::AddRef, etc #include "gfx2DGlue.h" +#include "GLScreenBuffer.h" +#include "GLContext.h" +#include "gfxUtils.h" +#include "mozilla/layers/PersistentBufferProvider.h" +#include "client/TextureClientSharedSurface.h" class gfxContext; @@ -20,6 +25,61 @@ using namespace mozilla::gl; namespace mozilla { namespace layers { +already_AddRefed +BasicCanvasLayer::UpdateSurface() +{ + if (mAsyncRenderer) { + return mAsyncRenderer->GetSurface(); + } + + if (mBufferProvider) { + // This is handled separately in Paint. + return nullptr; + } + + if (!mGLContext) { + return nullptr; + } + + SharedSurface* frontbuffer = nullptr; + if (mGLFrontbuffer) { + frontbuffer = mGLFrontbuffer.get(); + } else { + GLScreenBuffer* screen = mGLContext->Screen(); + const auto& front = screen->Front(); + if (front) { + frontbuffer = front->Surf(); + } + } + + if (!frontbuffer) { + NS_WARNING("Null frame received."); + return nullptr; + } + + IntSize readSize(frontbuffer->mSize); + SurfaceFormat format = (GetContentFlags() & CONTENT_OPAQUE) + ? SurfaceFormat::B8G8R8X8 + : SurfaceFormat::B8G8R8A8; + bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied; + + RefPtr resultSurf = GetTempSurface(readSize, format); + // There will already be a warning from inside of GetTempSurface, but + // it doesn't hurt to complain: + if (NS_WARN_IF(!resultSurf)) { + return nullptr; + } + + // Readback handles Flush/MarkDirty. + mGLContext->Readback(frontbuffer, resultSurf); + if (needsPremult) { + gfxUtils::PremultiplyDataSurface(resultSurf, resultSurf); + } + MOZ_ASSERT(resultSurf); + + return resultSurf.forget(); +} + void BasicCanvasLayer::Paint(DrawTarget* aDT, const Point& aDeviceOffset, @@ -28,15 +88,24 @@ BasicCanvasLayer::Paint(DrawTarget* aDT, if (IsHidden()) return; + RefPtr surface; if (IsDirty()) { Painted(); FirePreTransactionCallback(); - UpdateTarget(); + surface = UpdateSurface(); FireDidTransactionCallback(); } - if (!mSurface) { + AutoReturnSnapshot autoReturn(mBufferProvider); + + if (mBufferProvider) { + MOZ_ASSERT(!surface); + surface = mBufferProvider->BorrowSnapshot(); + autoReturn.mSnapshot = &surface; + } + + if (!surface) { return; } @@ -52,7 +121,7 @@ BasicCanvasLayer::Paint(DrawTarget* aDT, FillRectWithMask(aDT, aDeviceOffset, Rect(0, 0, mBounds.width, mBounds.height), - mSurface, mSamplingFilter, + surface, mSamplingFilter, DrawOptions(GetEffectiveOpacity(), GetEffectiveOperator(this)), aMaskLayer); diff --git a/gfx/layers/basic/BasicCanvasLayer.h b/gfx/layers/basic/BasicCanvasLayer.h index 3cd930c1ea2e..a63d2b8c02ea 100644 --- a/gfx/layers/basic/BasicCanvasLayer.h +++ b/gfx/layers/basic/BasicCanvasLayer.h @@ -36,6 +36,9 @@ public: Layer* aMaskLayer) override; protected: + + already_AddRefed UpdateSurface(); + BasicLayerManager* BasicManager() { return static_cast(mManager); From 0fe393780a8b341c4cfa3b16c747e38e2879cd8e Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Thu, 28 Jul 2016 18:00:45 +0200 Subject: [PATCH 021/120] Bug 1285271 - Reenable copy-on-write canvas. r=jnicol --- modules/libpref/init/all.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 5128faef4931..dc761a4b8541 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4595,7 +4595,7 @@ pref("layers.d3d11.disable-warp", true); #endif // Copy-on-write canvas -pref("layers.shared-buffer-provider.enabled", false); +pref("layers.shared-buffer-provider.enabled", true); // Force all possible layers to be always active layers pref("layers.force-active", false); From e6b4c7693bd7715c08a5448c31e53dcae294c38c Mon Sep 17 00:00:00 2001 From: Sebastian Hengst Date: Thu, 28 Jul 2016 18:13:13 +0200 Subject: [PATCH 022/120] Backed out changeset 6e6d55b02d19 (bug 1285036) --- dom/xhr/XMLHttpRequestMainThread.cpp | 441 +++++++++++++++------------ dom/xhr/XMLHttpRequestMainThread.h | 139 ++++++--- 2 files changed, 350 insertions(+), 230 deletions(-) diff --git a/dom/xhr/XMLHttpRequestMainThread.cpp b/dom/xhr/XMLHttpRequestMainThread.cpp index 0ca27b16150c..9acd4ee484fa 100644 --- a/dom/xhr/XMLHttpRequestMainThread.cpp +++ b/dom/xhr/XMLHttpRequestMainThread.cpp @@ -2106,167 +2106,6 @@ XMLHttpRequestMainThread::ChangeStateToDone() } } -template<> nsresult -XMLHttpRequestMainThread::RequestBody::GetAsStream( - nsIInputStream** aResult, uint64_t* aContentLength, - nsACString& aContentType, nsACString& aCharset) const -{ - nsCOMPtr domdoc(do_QueryInterface(mBody)); - NS_ENSURE_STATE(domdoc); - aCharset.AssignLiteral("UTF-8"); - - nsresult rv; - nsCOMPtr storStream; - rv = NS_NewStorageStream(4096, UINT32_MAX, getter_AddRefs(storStream)); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr output; - rv = storStream->GetOutputStream(0, getter_AddRefs(output)); - NS_ENSURE_SUCCESS(rv, rv); - - if (mBody->IsHTMLDocument()) { - aContentType.AssignLiteral("text/html"); - - nsString serialized; - if (!nsContentUtils::SerializeNodeToMarkup(mBody, true, serialized)) { - return NS_ERROR_OUT_OF_MEMORY; - } - NS_ConvertUTF16toUTF8 utf8Serialized(serialized); - - uint32_t written; - rv = output->Write(utf8Serialized.get(), utf8Serialized.Length(), &written); - NS_ENSURE_SUCCESS(rv, rv); - - MOZ_ASSERT(written == utf8Serialized.Length()); - } else { - aContentType.AssignLiteral("application/xml"); - - nsCOMPtr serializer = - do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - // Make sure to use the encoding we'll send - rv = serializer->SerializeToStream(domdoc, output, aCharset); - NS_ENSURE_SUCCESS(rv, rv); - } - - output->Close(); - - uint32_t length; - rv = storStream->GetLength(&length); - NS_ENSURE_SUCCESS(rv, rv); - *aContentLength = length; - - rv = storStream->NewInputStream(0, aResult); - NS_ENSURE_SUCCESS(rv, rv); - return NS_OK; -} - -template<> nsresult -XMLHttpRequestMainThread::RequestBody::GetAsStream( - nsIInputStream** aResult, uint64_t* aContentLength, - nsACString& aContentType, nsACString& aCharset) const -{ - aContentType.AssignLiteral("text/plain"); - aCharset.AssignLiteral("UTF-8"); - - nsCString converted = NS_ConvertUTF16toUTF8(*mBody); - *aContentLength = converted.Length(); - nsresult rv = NS_NewCStringInputStream(aResult, converted); - NS_ENSURE_SUCCESS(rv, rv); - return NS_OK; -} - -template<> nsresult -XMLHttpRequestMainThread::RequestBody::GetAsStream( - nsIInputStream** aResult, uint64_t* aContentLength, - nsACString& aContentType, nsACString& aCharset) const -{ - aContentType.AssignLiteral("text/plain"); - aCharset.Truncate(); - - nsresult rv = mBody->Available(aContentLength); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr stream(mBody); - stream.forget(aResult); - return NS_OK; -} - -template<> nsresult -XMLHttpRequestMainThread::RequestBody::GetAsStream( - nsIInputStream** aResult, uint64_t* aContentLength, - nsACString& aContentType, nsACString& aCharset) const -{ - return mBody->GetSendInfo(aResult, aContentLength, aContentType, aCharset); -} - -template<> nsresult -XMLHttpRequestMainThread::RequestBody::GetAsStream( - nsIInputStream** aResult, uint64_t* aContentLength, - nsACString& aContentType, nsACString& aCharset) const -{ - return mBody->GetSendInfo(aResult, aContentLength, aContentType, aCharset); -} - -template<> nsresult -XMLHttpRequestMainThread::RequestBody::GetAsStream( - nsIInputStream** aResult, uint64_t* aContentLength, - nsACString& aContentType, nsACString& aCharset) const -{ - return mBody->GetSendInfo(aResult, aContentLength, aContentType, aCharset); -} - -template<> nsresult -XMLHttpRequestMainThread::RequestBody::GetAsStream( - nsIInputStream** aResult, uint64_t* aContentLength, - nsACString& aContentType, nsACString& aCharset) const -{ - return mBody->GetSendInfo(aResult, aContentLength, aContentType, aCharset); -} - -static nsresult -GetBufferDataAsStream(const uint8_t* aData, uint32_t aDataLength, - nsIInputStream** aResult, uint64_t* aContentLength, - nsACString& aContentType, nsACString& aCharset) -{ - aContentType.SetIsVoid(true); - aCharset.Truncate(); - - *aContentLength = aDataLength; - const char* data = reinterpret_cast(aData); - - nsCOMPtr stream; - nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream), data, aDataLength, - NS_ASSIGNMENT_COPY); - NS_ENSURE_SUCCESS(rv, rv); - - stream.forget(aResult); - - return NS_OK; -} - -template<> nsresult -XMLHttpRequestMainThread::RequestBody::GetAsStream( - nsIInputStream** aResult, uint64_t* aContentLength, - nsACString& aContentType, nsACString& aCharset) const -{ - mBody->ComputeLengthAndData(); - return GetBufferDataAsStream(mBody->Data(), mBody->Length(), - aResult, aContentLength, aContentType, aCharset); -} - -template<> nsresult -XMLHttpRequestMainThread::RequestBody::GetAsStream( - nsIInputStream** aResult, uint64_t* aContentLength, - nsACString& aContentType, nsACString& aCharset) const -{ - mBody->ComputeLengthAndData(); - return GetBufferDataAsStream(mBody->Data(), mBody->Length(), - aResult, aContentLength, aContentType, aCharset); -} - - nsresult XMLHttpRequestMainThread::InitChannel() { @@ -2342,31 +2181,154 @@ XMLHttpRequestMainThread::InitChannel() return NS_OK; } -NS_IMETHODIMP -XMLHttpRequestMainThread::Send(nsIVariant* aVariant) +static nsresult +GetRequestBodyInternal(nsIDOMDocument* aDoc, nsIInputStream** aResult, + uint64_t* aContentLength, nsACString& aContentType, + nsACString& aCharset) { - if (!aVariant) { - return SendInternal(nullptr); + nsCOMPtr doc(do_QueryInterface(aDoc)); + NS_ENSURE_STATE(doc); + aCharset.AssignLiteral("UTF-8"); + + nsresult rv; + nsCOMPtr storStream; + rv = NS_NewStorageStream(4096, UINT32_MAX, getter_AddRefs(storStream)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr output; + rv = storStream->GetOutputStream(0, getter_AddRefs(output)); + NS_ENSURE_SUCCESS(rv, rv); + + if (doc->IsHTMLDocument()) { + aContentType.AssignLiteral("text/html"); + + nsString serialized; + if (!nsContentUtils::SerializeNodeToMarkup(doc, true, serialized)) { + return NS_ERROR_OUT_OF_MEMORY; + } + NS_ConvertUTF16toUTF8 utf8Serialized(serialized); + + uint32_t written; + rv = output->Write(utf8Serialized.get(), utf8Serialized.Length(), &written); + NS_ENSURE_SUCCESS(rv, rv); + + MOZ_ASSERT(written == utf8Serialized.Length()); + } else { + aContentType.AssignLiteral("application/xml"); + + nsCOMPtr serializer = + do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + // Make sure to use the encoding we'll send + rv = serializer->SerializeToStream(aDoc, output, aCharset); + NS_ENSURE_SUCCESS(rv, rv); + } + output->Close(); + + uint32_t length; + rv = storStream->GetLength(&length); + NS_ENSURE_SUCCESS(rv, rv); + *aContentLength = length; + + return storStream->NewInputStream(0, aResult); +} + +static nsresult +GetRequestBodyInternal(const nsAString& aString, nsIInputStream** aResult, + uint64_t* aContentLength, nsACString& aContentType, + nsACString& aCharset) +{ + aContentType.AssignLiteral("text/plain"); + aCharset.AssignLiteral("UTF-8"); + + nsCString converted = NS_ConvertUTF16toUTF8(aString); + *aContentLength = converted.Length(); + return NS_NewCStringInputStream(aResult, converted); +} + +static nsresult +GetRequestBodyInternal(nsIInputStream* aStream, nsIInputStream** aResult, + uint64_t* aContentLength, nsACString& aContentType, + nsACString& aCharset) +{ + aContentType.AssignLiteral("text/plain"); + aCharset.Truncate(); + + nsresult rv = aStream->Available(aContentLength); + NS_ENSURE_SUCCESS(rv, rv); + + NS_ADDREF(*aResult = aStream); + + return NS_OK; +} + +static nsresult +GetRequestBodyInternal(URLSearchParams* aURLSearchParams, + nsIInputStream** aResult, uint64_t* aContentLength, + nsACString& aContentType, nsACString& aCharset) +{ + return aURLSearchParams->GetSendInfo(aResult, aContentLength, + aContentType, aCharset); +} + +static nsresult +GetRequestBodyInternal(nsIXHRSendable* aSendable, nsIInputStream** aResult, + uint64_t* aContentLength, nsACString& aContentType, + nsACString& aCharset) +{ + return aSendable->GetSendInfo(aResult, aContentLength, aContentType, aCharset); +} + +// Used for array buffers and array buffer views +static nsresult +GetRequestBodyInternal(const uint8_t* aData, uint32_t aDataLength, + nsIInputStream** aResult, uint64_t* aContentLength, + nsACString& aContentType, nsACString& aCharset) +{ + aContentType.SetIsVoid(true); + aCharset.Truncate(); + + *aContentLength = aDataLength; + const char* data = reinterpret_cast(aData); + + nsCOMPtr stream; + nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream), data, aDataLength, + NS_ASSIGNMENT_COPY); + NS_ENSURE_SUCCESS(rv, rv); + + stream.forget(aResult); + + return NS_OK; +} + +static nsresult +GetRequestBodyInternal(nsIVariant* aBody, nsIInputStream** aResult, + uint64_t* aContentLength, nsACString& aContentType, + nsACString& aCharset) +{ + *aResult = nullptr; + uint16_t dataType; - nsresult rv = aVariant->GetDataType(&dataType); + nsresult rv = aBody->GetDataType(&dataType); NS_ENSURE_SUCCESS(rv, rv); if (dataType == nsIDataType::VTYPE_INTERFACE || dataType == nsIDataType::VTYPE_INTERFACE_IS) { nsCOMPtr supports; nsID *iid; - rv = aVariant->GetAsInterface(&iid, getter_AddRefs(supports)); + rv = aBody->GetAsInterface(&iid, getter_AddRefs(supports)); NS_ENSURE_SUCCESS(rv, rv); free(iid); // document? - nsCOMPtr doc = do_QueryInterface(supports); + nsCOMPtr doc = do_QueryInterface(supports); if (doc) { - RequestBody body(doc); - return SendInternal(&body); + return GetRequestBodyInternal(doc, aResult, aContentLength, aContentType, + aCharset); } // nsISupportsString? @@ -2374,56 +2336,153 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant) if (wstr) { nsAutoString string; wstr->GetData(string); - RequestBody body(&string); - return SendInternal(&body); + + return GetRequestBodyInternal(string, aResult, aContentLength, + aContentType, aCharset); } // nsIInputStream? nsCOMPtr stream = do_QueryInterface(supports); if (stream) { - RequestBody body(stream); - return SendInternal(&body); + return GetRequestBodyInternal(stream, aResult, aContentLength, + aContentType, aCharset); } // nsIXHRSendable? nsCOMPtr sendable = do_QueryInterface(supports); if (sendable) { - RequestBody body(sendable); - return SendInternal(&body); + return GetRequestBodyInternal(sendable, aResult, aContentLength, + aContentType, aCharset); } // ArrayBuffer? JSContext* rootingCx = nsContentUtils::RootingCx(); JS::Rooted realVal(rootingCx); - nsresult rv = aVariant->GetAsJSVal(&realVal); + nsresult rv = aBody->GetAsJSVal(&realVal); if (NS_SUCCEEDED(rv) && !realVal.isPrimitive()) { JS::Rooted obj(rootingCx, realVal.toObjectOrNull()); RootedTypedArray buf(rootingCx); if (buf.Init(obj)) { - RequestBody body(&buf); - return SendInternal(&body); + buf.ComputeLengthAndData(); + return GetRequestBodyInternal(buf.Data(), buf.Length(), aResult, + aContentLength, aContentType, aCharset); } } - } else if (dataType == nsIDataType::VTYPE_VOID || + } + else if (dataType == nsIDataType::VTYPE_VOID || dataType == nsIDataType::VTYPE_EMPTY) { - return SendInternal(nullptr); + // Makes us act as if !aBody, don't upload anything + aContentType.AssignLiteral("text/plain"); + aCharset.AssignLiteral("UTF-8"); + *aContentLength = 0; + + return NS_OK; } char16_t* data = nullptr; uint32_t len = 0; - rv = aVariant->GetAsWStringWithSize(&len, &data); + rv = aBody->GetAsWStringWithSize(&len, &data); NS_ENSURE_SUCCESS(rv, rv); nsString string; string.Adopt(data, len); - RequestBody body(&string); - return SendInternal(&body); + return GetRequestBodyInternal(string, aResult, aContentLength, aContentType, + aCharset); +} + +/* static */ +nsresult +XMLHttpRequestMainThread::GetRequestBody(nsIVariant* aVariant, + const Nullable& aBody, + nsIInputStream** aResult, + uint64_t* aContentLength, + nsACString& aContentType, + nsACString& aCharset) +{ + // null the content type and charset by default, as per XHR spec step 4 + aContentType.SetIsVoid(true); + aCharset.SetIsVoid(true); + + if (aVariant) { + return GetRequestBodyInternal(aVariant, aResult, aContentLength, + aContentType, aCharset); + } + + const RequestBody& body = aBody.Value(); + RequestBody::Value value = body.GetValue(); + switch (body.GetType()) { + case XMLHttpRequestMainThread::RequestBody::eArrayBuffer: + { + const ArrayBuffer* buffer = value.mArrayBuffer; + buffer->ComputeLengthAndData(); + return GetRequestBodyInternal(buffer->Data(), buffer->Length(), aResult, + aContentLength, aContentType, aCharset); + } + case XMLHttpRequestMainThread::RequestBody::eArrayBufferView: + { + const ArrayBufferView* view = value.mArrayBufferView; + view->ComputeLengthAndData(); + return GetRequestBodyInternal(view->Data(), view->Length(), aResult, + aContentLength, aContentType, aCharset); + } + case XMLHttpRequestMainThread::RequestBody::eBlob: + { + nsresult rv; + nsCOMPtr blob = value.mBlob; + nsCOMPtr sendable = do_QueryInterface(blob, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + return GetRequestBodyInternal(sendable, aResult, aContentLength, + aContentType, aCharset); + } + case XMLHttpRequestMainThread::RequestBody::eDocument: + { + nsCOMPtr document = do_QueryInterface(value.mDocument); + return GetRequestBodyInternal(document, aResult, aContentLength, + aContentType, aCharset); + } + case XMLHttpRequestMainThread::RequestBody::eDOMString: + { + return GetRequestBodyInternal(*value.mString, aResult, aContentLength, + aContentType, aCharset); + } + case XMLHttpRequestMainThread::RequestBody::eFormData: + { + MOZ_ASSERT(value.mFormData); + return GetRequestBodyInternal(value.mFormData, aResult, aContentLength, + aContentType, aCharset); + } + case XMLHttpRequestMainThread::RequestBody::eURLSearchParams: + { + MOZ_ASSERT(value.mURLSearchParams); + return GetRequestBodyInternal(value.mURLSearchParams, aResult, + aContentLength, aContentType, aCharset); + } + case XMLHttpRequestMainThread::RequestBody::eInputStream: + { + return GetRequestBodyInternal(value.mStream, aResult, aContentLength, + aContentType, aCharset); + } + default: + { + return NS_ERROR_FAILURE; + } + } + + NS_NOTREACHED("Default cases exist for a reason"); + return NS_OK; +} + +NS_IMETHODIMP +XMLHttpRequestMainThread::Send(nsIVariant *aBody) +{ + return Send(aBody, Nullable()); } nsresult -XMLHttpRequestMainThread::SendInternal(const RequestBodyBase* aBody) +XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable& aBody) { NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED); @@ -2502,7 +2561,7 @@ XMLHttpRequestMainThread::SendInternal(const RequestBodyBase* aBody) mErrorLoad = false; mLoadLengthComputable = false; mLoadTotal = 0; - if (aBody && httpChannel && + if ((aVariant || !aBody.IsNull()) && httpChannel && !method.LowerCaseEqualsLiteral("get") && !method.LowerCaseEqualsLiteral("head")) { @@ -2511,8 +2570,8 @@ XMLHttpRequestMainThread::SendInternal(const RequestBodyBase* aBody) nsCOMPtr postDataStream; uint64_t size_u64; - rv = aBody->GetAsStream(getter_AddRefs(postDataStream), - &size_u64, defaultContentType, charset); + rv = GetRequestBody(aVariant, aBody, getter_AddRefs(postDataStream), + &size_u64, defaultContentType, charset); NS_ENSURE_SUCCESS(rv, rv); // make sure it fits within js MAX_SAFE_INTEGER @@ -2520,7 +2579,7 @@ XMLHttpRequestMainThread::SendInternal(const RequestBodyBase* aBody) net::InScriptableRange(size_u64) ? static_cast(size_u64) : -1; if (postDataStream) { - // If author set no Content-Type, use the default from GetAsStream(). + // If author set no Content-Type, use the default from GetRequestBody(). nsAutoCString contentType; GetAuthorRequestHeaderValue("content-type", contentType); @@ -2774,6 +2833,7 @@ XMLHttpRequestMainThread::SendInternal(const RequestBodyBase* aBody) mWaitingForOnStopRequest = true; + // Step 8 mFlagSend = true; // If we're synchronous, spin an event loop here and wait @@ -2832,7 +2892,8 @@ XMLHttpRequestMainThread::SendInternal(const RequestBodyBase* aBody) if (mUpload && mUpload->HasListenersFor(nsGkAtoms::onprogress)) { StartProgressEventTimer(); } - DispatchProgressEvent(this, ProgressEventType::loadstart, false, 0, 0); + DispatchProgressEvent(this, ProgressEventType::loadstart, false, + 0, 0); if (mUpload && !mUploadComplete) { DispatchProgressEvent(mUpload, ProgressEventType::loadstart, true, 0, mUploadTotal); diff --git a/dom/xhr/XMLHttpRequestMainThread.h b/dom/xhr/XMLHttpRequestMainThread.h index afc4c062ba88..40d64c06e4bb 100644 --- a/dom/xhr/XMLHttpRequestMainThread.h +++ b/dom/xhr/XMLHttpRequestMainThread.h @@ -238,34 +238,100 @@ public: private: virtual ~XMLHttpRequestMainThread(); - class RequestBodyBase + class RequestBody { public: - virtual nsresult GetAsStream(nsIInputStream** aResult, + RequestBody() : mType(eUninitialized) + { + } + explicit RequestBody(const ArrayBuffer* aArrayBuffer) : mType(eArrayBuffer) + { + mValue.mArrayBuffer = aArrayBuffer; + } + explicit RequestBody(const ArrayBufferView* aArrayBufferView) : mType(eArrayBufferView) + { + mValue.mArrayBufferView = aArrayBufferView; + } + explicit RequestBody(Blob& aBlob) : mType(eBlob) + { + mValue.mBlob = &aBlob; + } + explicit RequestBody(mozilla::dom::URLSearchParams& aURLSearchParams) : + mType(eURLSearchParams) + { + mValue.mURLSearchParams = &aURLSearchParams; + } + explicit RequestBody(nsIDocument* aDocument) : mType(eDocument) + { + mValue.mDocument = aDocument; + } + explicit RequestBody(const nsAString& aString) : mType(eDOMString) + { + mValue.mString = &aString; + } + explicit RequestBody(FormData& aFormData) : mType(eFormData) + { + mValue.mFormData = &aFormData; + } + explicit RequestBody(nsIInputStream* aStream) : mType(eInputStream) + { + mValue.mStream = aStream; + } + + enum Type { + eUninitialized, + eArrayBuffer, + eArrayBufferView, + eBlob, + eDocument, + eDOMString, + eFormData, + eInputStream, + eURLSearchParams + }; + union Value { + const ArrayBuffer* mArrayBuffer; + const ArrayBufferView* mArrayBufferView; + Blob* mBlob; + nsIDocument* mDocument; + const nsAString* mString; + FormData* mFormData; + nsIInputStream* mStream; + URLSearchParams* mURLSearchParams; + }; + + Type GetType() const + { + MOZ_ASSERT(mType != eUninitialized); + return mType; + } + Value GetValue() const + { + MOZ_ASSERT(mType != eUninitialized); + return mValue; + } + + private: + Type mType; + Value mValue; + }; + + static nsresult GetRequestBody(nsIVariant* aVariant, + const Nullable& aBody, + nsIInputStream** aResult, uint64_t* aContentLength, nsACString& aContentType, - nsACString& aCharset) const - { - NS_ASSERTION(false, "RequestBodyBase should not be used directly."); - return NS_ERROR_FAILURE; - } - }; + nsACString& aCharset); - template - class RequestBody final : public RequestBodyBase + nsresult Send(nsIVariant* aVariant, const Nullable& aBody); + nsresult Send(const Nullable& aBody) { - Type* mBody; - public: - explicit RequestBody(Type* aBody) : mBody(aBody) - { - } - nsresult GetAsStream(nsIInputStream** aResult, - uint64_t* aContentLength, - nsACString& aContentType, - nsACString& aCharset) const override; - }; - - nsresult SendInternal(const RequestBodyBase* aBody); + return Send(nullptr, aBody); + } + nsresult Send(const RequestBody& aBody) + { + return Send(Nullable(aBody)); + } bool IsCrossSiteCORSRequest() const; bool IsDeniedCrossSiteCORSRequest(); @@ -279,44 +345,39 @@ public: virtual void Send(JSContext* /*aCx*/, ErrorResult& aRv) override { - aRv = SendInternal(nullptr); + aRv = Send(Nullable()); } virtual void Send(JSContext* /*aCx*/, const ArrayBuffer& aArrayBuffer, ErrorResult& aRv) override { - RequestBody body(&aArrayBuffer); - aRv = SendInternal(&body); + aRv = Send(RequestBody(&aArrayBuffer)); } virtual void Send(JSContext* /*aCx*/, const ArrayBufferView& aArrayBufferView, ErrorResult& aRv) override { - RequestBody body(&aArrayBufferView); - aRv = SendInternal(&body); + aRv = Send(RequestBody(&aArrayBufferView)); } virtual void Send(JSContext* /*aCx*/, Blob& aBlob, ErrorResult& aRv) override { - RequestBody body(&aBlob); - aRv = SendInternal(&body); + aRv = Send(RequestBody(aBlob)); } virtual void Send(JSContext* /*aCx*/, URLSearchParams& aURLSearchParams, ErrorResult& aRv) override { - RequestBody body(&aURLSearchParams); - aRv = SendInternal(&body); + aRv = Send(RequestBody(aURLSearchParams)); } virtual void Send(JSContext* /*aCx*/, nsIDocument& aDoc, ErrorResult& aRv) override { - RequestBody body(&aDoc); - aRv = SendInternal(&body); + aRv = Send(RequestBody(&aDoc)); } virtual void @@ -324,17 +385,16 @@ public: { if (DOMStringIsNull(aString)) { Send(aCx, aRv); - } else { - RequestBody body(&aString); - aRv = SendInternal(&body); + } + else { + aRv = Send(RequestBody(aString)); } } virtual void Send(JSContext* /*aCx*/, FormData& aFormData, ErrorResult& aRv) override { - RequestBody body(&aFormData); - aRv = SendInternal(&body); + aRv = Send(RequestBody(aFormData)); } virtual void @@ -358,8 +418,7 @@ public: } return; } - RequestBody body(aStream); - aRv = SendInternal(&body); + aRv = Send(RequestBody(aStream)); } void From 8c31962656b905516b2218b60c8840949d1a863a Mon Sep 17 00:00:00 2001 From: Sebastian Hengst Date: Thu, 28 Jul 2016 18:13:17 +0200 Subject: [PATCH 023/120] Backed out changeset de078c2e0991 (bug 1285036) --- dom/xhr/XMLHttpRequestMainThread.cpp | 336 ++++++++++++--------------- dom/xhr/XMLHttpRequestMainThread.h | 26 ++- dom/xhr/XMLHttpRequestWorker.cpp | 12 +- 3 files changed, 166 insertions(+), 208 deletions(-) diff --git a/dom/xhr/XMLHttpRequestMainThread.cpp b/dom/xhr/XMLHttpRequestMainThread.cpp index 9acd4ee484fa..4c7b33c0d3da 100644 --- a/dom/xhr/XMLHttpRequestMainThread.cpp +++ b/dom/xhr/XMLHttpRequestMainThread.cpp @@ -1350,131 +1350,54 @@ XMLHttpRequestMainThread::IsSystemXHR() const } NS_IMETHODIMP -XMLHttpRequestMainThread::Open(const nsACString& aMethod, const nsACString& aUrl, - bool aAsync, const nsAString& aUsername, - const nsAString& aPassword, uint8_t optional_argc) +XMLHttpRequestMainThread::Open(const nsACString& method, const nsACString& url, + bool async, const nsAString& user, + const nsAString& password, uint8_t optional_argc) { - Optional async; if (!optional_argc) { // No optional arguments were passed in. Default async to true. - async.Construct() = true; - } else { - async.Construct() = aAsync; + async = true; } - Optional username; + Optional realUser; if (optional_argc > 1) { - username = &aUsername; + realUser = &user; } - Optional password; + Optional realPassword; if (optional_argc > 2) { - password = &aPassword; + realPassword = &password; } - return OpenInternal(aMethod, aUrl, async, username, password); -} - -// This case is hit when the async parameter is outright omitted, which -// should set it to true (and the username and password to null). -void -XMLHttpRequestMainThread::Open(const nsACString& aMethod, const nsAString& aUrl, - ErrorResult& aRv) -{ - aRv = OpenInternal(aMethod, NS_ConvertUTF16toUTF8(aUrl), Optional(true), - Optional(), Optional()); -} - -// This case is hit when the async parameter is specified, even if the -// JS value was "undefined" (which due to legacy reasons should be -// treated as true, which is how it will already be passed in here). -void -XMLHttpRequestMainThread::Open(const nsACString& aMethod, - const nsAString& aUrl, - bool aAsync, - const Optional& aUsername, - const Optional& aPassword, - ErrorResult& aRv) -{ - aRv = OpenInternal(aMethod, NS_ConvertUTF16toUTF8(aUrl), - Optional(aAsync), aUsername, aPassword); + return Open(method, url, async, realUser, realPassword); } nsresult -XMLHttpRequestMainThread::OpenInternal(const nsACString& aMethod, - const nsACString& aUrl, - const Optional& aAsync, - const Optional& aUsername, - const Optional& aPassword) +XMLHttpRequestMainThread::Open(const nsACString& inMethod, const nsACString& url, + bool async, const Optional& user, + const Optional& password) { - bool async = aAsync.WasPassed() ? aAsync.Value() : true; + if (inMethod.IsEmpty()) { + return NS_ERROR_DOM_SYNTAX_ERR; + } - // Gecko-specific if (!async && !DontWarnAboutSyncXHR() && GetOwner() && GetOwner()->GetExtantDoc()) { GetOwner()->GetExtantDoc()->WarnOnceAbout(nsIDocument::eSyncXMLHttpRequest); } - Telemetry::Accumulate(Telemetry::XMLHTTPREQUEST_ASYNC_OR_SYNC, async ? 0 : 1); + Telemetry::Accumulate(Telemetry::XMLHTTPREQUEST_ASYNC_OR_SYNC, + async ? 0 : 1); - // Step 1 - nsCOMPtr 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; - } - } NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED); - // Steps 2-4 nsAutoCString method; - nsresult rv = FetchUtil::GetValidRequestMethod(aMethod, method); + nsresult rv = FetchUtil::GetValidRequestMethod(inMethod, method); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - // Steps 5-6 - nsCOMPtr baseURI; - if (mBaseURI) { - baseURI = mBaseURI; - } else if (responsibleDocument) { - baseURI = responsibleDocument->GetBaseURI(); - } - nsCOMPtr 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 rv; - } - if (NS_WARN_IF(NS_FAILED(CheckInnerWindowCorrectness()))) { - return NS_ERROR_DOM_INVALID_STATE_ERR; - } - - // Step 7 is already done above. - // Note that the username and password are already passed in as null by Open() - // if the async parameter is omitted, so there's no need check again here. - - // Step 8 - if (aAsync.WasPassed()) { - nsAutoCString host; - parsedURL->GetHost(host); - if (!host.IsEmpty()) { - nsAutoCString userpass; - if (aUsername.WasPassed()) { - CopyUTF16toUTF8(aUsername.Value(), userpass); - } - userpass.AppendLiteral(":"); - if (aPassword.WasPassed()) { - AppendUTF16toUTF8(aPassword.Value(), userpass); - } - parsedURL->SetUserPass(userpass); - } - } - - // Step 9 - if (!async && HasOrHasHadOwner() && (mTimeoutMilliseconds || + // sync request is not allowed to use responseType or timeout + // in window context + if (!async && HasOrHasHadOwner() && + (mTimeoutMilliseconds || mResponseType != XMLHttpRequestResponseType::_empty)) { if (mTimeoutMilliseconds) { LogMessage("TimeoutSyncXHRWarning", GetOwner()); @@ -1485,30 +1408,140 @@ XMLHttpRequestMainThread::OpenInternal(const nsACString& aMethod, return NS_ERROR_DOM_INVALID_ACCESS_ERR; } - // Step 10 - CloseRequest(); + nsCOMPtr uri; + + CloseRequest(); // spec step 10 + ResetResponse(); // (part of) spec step 11 - // Step 11 - // timeouts are handled without a flag mFlagSend = false; - mRequestMethod.Assign(method); - mRequestURL = parsedURL; - mFlagSynchronous = !async; - mAuthorRequestHeaders.Clear(); - ResetResponse(); - // Gecko-specific - mFlagHadUploadListenersOnSend = false; + // Unset any pre-existing aborted and timed-out flags. mFlagAborted = false; mFlagTimedOut = false; - rv = InitChannel(); + mFlagSynchronous = !async; + + nsCOMPtr doc = GetDocumentIfCurrent(); + if (!doc) { + // This could be because we're no longer current or because we're in some + // non-window context... + if (NS_WARN_IF(NS_FAILED(CheckInnerWindowCorrectness()))) { + return NS_ERROR_DOM_INVALID_STATE_ERR; + } + } + + nsCOMPtr baseURI; + if (mBaseURI) { + baseURI = mBaseURI; + } + else if (doc) { + baseURI = doc->GetBaseURI(); + } + + rv = NS_NewURI(getter_AddRefs(uri), url, nullptr, baseURI); + + if (NS_FAILED(rv)) { + if (rv == NS_ERROR_MALFORMED_URI) { + return NS_ERROR_DOM_SYNTAX_ERR; + } + return rv; + } + + if (NS_WARN_IF(NS_FAILED(CheckInnerWindowCorrectness()))) { + return NS_ERROR_DOM_INVALID_STATE_ERR; + } + + // XXXbz this is wrong: we should only be looking at whether + // user/password were passed, not at the values! See bug 759624. + if (user.WasPassed() && !user.Value().IsEmpty()) { + nsAutoCString userpass; + CopyUTF16toUTF8(user.Value(), userpass); + if (password.WasPassed() && !password.Value().IsEmpty()) { + userpass.Append(':'); + AppendUTF16toUTF8(password.Value(), userpass); + } + uri->SetUserPass(userpass); + } + + // Clear our record of previously set headers so future header set + // operations will merge/override correctly. + mAuthorRequestHeaders.Clear(); + + // When we are called from JS we can find the load group for the page, + // and add ourselves to it. This way any pending requests + // will be automatically aborted if the user leaves the page. + nsCOMPtr loadGroup = GetLoadGroup(); + + nsSecurityFlags secFlags; + nsLoadFlags loadFlags = nsIRequest::LOAD_BACKGROUND | + nsIChannel::LOAD_CLASSIFY_URI; + if (nsContentUtils::IsSystemPrincipal(mPrincipal)) { + // When chrome is loading we want to make sure to sandbox any potential + // result document. We also want to allow cross-origin loads. + secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL | + nsILoadInfo::SEC_SANDBOXED; + } + else if (IsSystemXHR()) { + // For pages that have appropriate permissions, we want to still allow + // cross-origin loads, but make sure that the any potential result + // documents get the same principal as the loader. + secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS | + nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL; + loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER; + } + else { + // Otherwise use CORS. Again, make sure that potential result documents + // use the same principal as the loader. + secFlags = nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS | + nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL; + } + + if (mIsAnon) { + secFlags |= nsILoadInfo::SEC_COOKIES_OMIT; + } + + // If we have the document, use it. Unfortunately, for dedicated workers + // 'doc' ends up being the parent document, which is not the document + // that we want to use. So make sure to avoid using 'doc' in that situation. + if (doc && doc->NodePrincipal() == mPrincipal) { + rv = NS_NewChannel(getter_AddRefs(mChannel), + uri, + doc, + secFlags, + nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST, + loadGroup, + nullptr, // aCallbacks + loadFlags); + } else { + //otherwise use the principal + rv = NS_NewChannel(getter_AddRefs(mChannel), + uri, + mPrincipal, + secFlags, + nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST, + loadGroup, + nullptr, // aCallbacks + loadFlags); + } + NS_ENSURE_SUCCESS(rv, rv); - // Step 12 + mFlagHadUploadListenersOnSend = false; + + nsCOMPtr httpChannel(do_QueryInterface(mChannel)); + if (httpChannel) { + rv = httpChannel->SetRequestMethod(method); + NS_ENSURE_SUCCESS(rv, rv); + + // Set the initiator type + nsCOMPtr timedChannel(do_QueryInterface(httpChannel)); + if (timedChannel) { + timedChannel->SetInitiatorType(kLiteralString_xmlhttprequest); + } + } + if (mState != State::opened) { - mState = State::opened; - FireReadystatechangeEvent(); + ChangeState(State::opened); } return NS_OK; @@ -2106,81 +2139,6 @@ XMLHttpRequestMainThread::ChangeStateToDone() } } -nsresult -XMLHttpRequestMainThread::InitChannel() -{ - // When we are called from JS we can find the load group for the page, - // and add ourselves to it. This way any pending requests - // will be automatically aborted if the user leaves the page. - nsCOMPtr loadGroup = GetLoadGroup(); - - nsSecurityFlags secFlags; - nsLoadFlags loadFlags = nsIRequest::LOAD_BACKGROUND | - nsIChannel::LOAD_CLASSIFY_URI; - if (nsContentUtils::IsSystemPrincipal(mPrincipal)) { - // When chrome is loading we want to make sure to sandbox any potential - // result document. We also want to allow cross-origin loads. - secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL | - nsILoadInfo::SEC_SANDBOXED; - } else if (IsSystemXHR()) { - // For pages that have appropriate permissions, we want to still allow - // cross-origin loads, but make sure that the any potential result - // documents get the same principal as the loader. - secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS | - nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL; - loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER; - } else { - // Otherwise use CORS. Again, make sure that potential result documents - // use the same principal as the loader. - secFlags = nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS | - nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL; - } - - if (mIsAnon) { - secFlags |= nsILoadInfo::SEC_COOKIES_OMIT; - } - - // Use the responsibleDocument if we have it, except for dedicated workers - // where it will be the parent document, which is not the one we want to use. - nsresult rv; - nsCOMPtr responsibleDocument = GetDocumentIfCurrent(); - if (responsibleDocument && responsibleDocument->NodePrincipal() == mPrincipal) { - rv = NS_NewChannel(getter_AddRefs(mChannel), - mRequestURL, - responsibleDocument, - secFlags, - nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST, - loadGroup, - nullptr, // aCallbacks - loadFlags); - } else { - // Otherwise use the principal. - rv = NS_NewChannel(getter_AddRefs(mChannel), - mRequestURL, - mPrincipal, - secFlags, - nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST, - loadGroup, - nullptr, // aCallbacks - loadFlags); - } - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr httpChannel(do_QueryInterface(mChannel)); - if (httpChannel) { - rv = httpChannel->SetRequestMethod(mRequestMethod); - NS_ENSURE_SUCCESS(rv, rv); - - // Set the initiator type - nsCOMPtr timedChannel(do_QueryInterface(httpChannel)); - if (timedChannel) { - timedChannel->SetInitiatorType(NS_LITERAL_STRING("xmlhttprequest")); - } - } - - return NS_OK; -} - static nsresult GetRequestBodyInternal(nsIDOMDocument* aDoc, nsIInputStream** aResult, uint64_t* aContentLength, nsACString& aContentType, diff --git a/dom/xhr/XMLHttpRequestMainThread.h b/dom/xhr/XMLHttpRequestMainThread.h index 40d64c06e4bb..d02c522a54d0 100644 --- a/dom/xhr/XMLHttpRequestMainThread.h +++ b/dom/xhr/XMLHttpRequestMainThread.h @@ -199,17 +199,25 @@ public: virtual uint16_t ReadyState() const override; // request - nsresult InitChannel(); - virtual void Open(const nsACString& aMethod, const nsAString& aUrl, - ErrorResult& aRv) override; + ErrorResult& aRv) override + { + Open(aMethod, aUrl, true, + Optional(), + Optional(), + aRv); + } virtual void Open(const nsACString& aMethod, const nsAString& aUrl, bool aAsync, const Optional& aUser, const Optional& aPassword, - ErrorResult& aRv) override; + ErrorResult& aRv) override + { + aRv = Open(aMethod, NS_ConvertUTF16toUTF8(aUrl), + aAsync, aUser, aPassword); + } virtual void SetRequestHeader(const nsACString& aName, const nsACString& aValue, @@ -602,19 +610,15 @@ protected: nsresult OnRedirectVerifyCallback(nsresult result); - nsresult OpenInternal(const nsACString& aMethod, - const nsACString& aUrl, - const Optional& aAsync, - const Optional& aUsername, - const Optional& aPassword); + nsresult Open(const nsACString& method, const nsACString& url, bool async, + const Optional& user, + const Optional& password); already_AddRefed EnsureXPCOMifier(); nsCOMPtr mContext; nsCOMPtr mPrincipal; nsCOMPtr mChannel; - nsCString mRequestMethod; - nsCOMPtr mRequestURL; nsCOMPtr mResponseXML; nsCOMPtr mXMLParserStreamListener; diff --git a/dom/xhr/XMLHttpRequestWorker.cpp b/dom/xhr/XMLHttpRequestWorker.cpp index 24afa5c66727..f5ff9b3a27fb 100644 --- a/dom/xhr/XMLHttpRequestWorker.cpp +++ b/dom/xhr/XMLHttpRequestWorker.cpp @@ -1498,10 +1498,8 @@ SendRunnable::RunOnMainThread(ErrorResult& aRv) mProxy->mSyncLoopTarget.swap(mSyncLoopTarget); if (mHasUploadListeners) { - // Send() can be called more than once before failure, - // so don't attach the upload listeners more than once. - if (!mProxy->mUploadEventListenersAttached && - !mProxy->AddRemoveEventListeners(true, true)) { + NS_ASSERTION(!mProxy->mUploadEventListenersAttached, "Huh?!"); + if (!mProxy->AddRemoveEventListeners(true, true)) { MOZ_ASSERT(false, "This should never fail!"); } } @@ -1516,10 +1514,8 @@ SendRunnable::RunOnMainThread(ErrorResult& aRv) mProxy->mOutstandingSendCount++; if (!mHasUploadListeners) { - // Send() can be called more than once before failure, - // so don't attach the upload listeners more than once. - if (!mProxy->mUploadEventListenersAttached && - !mProxy->AddRemoveEventListeners(true, true)) { + NS_ASSERTION(!mProxy->mUploadEventListenersAttached, "Huh?!"); + if (!mProxy->AddRemoveEventListeners(true, true)) { MOZ_ASSERT(false, "This should never fail!"); } } From 5e128b818f71851b8ffba72620c47f122221fa20 Mon Sep 17 00:00:00 2001 From: Sebastian Hengst Date: Thu, 28 Jul 2016 18:13:43 +0200 Subject: [PATCH 024/120] Backed out changeset 41a51d368f38 (bug 1285036) for failing test browser_net_copy_as_curl.js. r=backout --- .../test/browser_net_copy_as_curl.js | 43 +--- .../netmonitor/test/browser_net_resend.js | 2 +- dom/base/nsContentUtils.cpp | 5 +- dom/xhr/XMLHttpRequestMainThread.cpp | 186 +++++++++--------- dom/xhr/XMLHttpRequestMainThread.h | 12 +- dom/xhr/tests/test_xhr_forbidden_headers.html | 3 +- .../setrequestheader-case-insensitive.htm.ini | 5 + .../setrequestheader-header-allowed.htm.ini | 14 ++ 8 files changed, 130 insertions(+), 140 deletions(-) create mode 100644 testing/web-platform/meta/XMLHttpRequest/setrequestheader-case-insensitive.htm.ini create mode 100644 testing/web-platform/meta/XMLHttpRequest/setrequestheader-header-allowed.htm.ini diff --git a/devtools/client/netmonitor/test/browser_net_copy_as_curl.js b/devtools/client/netmonitor/test/browser_net_copy_as_curl.js index 1dfb81e4c296..b064e925aae2 100644 --- a/devtools/client/netmonitor/test/browser_net_copy_as_curl.js +++ b/devtools/client/netmonitor/test/browser_net_copy_as_curl.js @@ -17,9 +17,9 @@ function test() { "-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'", "-H 'Accept-Language: " + navigator.language + "'", "--compressed", - "-H 'x-custom-header-1: Custom value'", - "-H 'x-custom-header-2: 8.8.8.8'", - "-H 'x-custom-header-3: Mon, 3 Mar 2014 11:11:11 GMT'", + "-H 'X-Custom-Header-1: Custom value'", + "-H 'X-Custom-Header-2: 8.8.8.8'", + "-H 'X-Custom-Header-3: Mon, 3 Mar 2014 11:11:11 GMT'", "-H 'Referer: " + CURL_URL + "'", "-H 'Connection: keep-alive'", "-H 'Pragma: no-cache'", @@ -34,9 +34,9 @@ function test() { '-H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"', '-H "Accept-Language: ' + navigator.language + '"', "--compressed", - '-H "x-custom-header-1: Custom value"', - '-H "x-custom-header-2: 8.8.8.8"', - '-H "x-custom-header-3: Mon, 3 Mar 2014 11:11:11 GMT"', + '-H "X-Custom-Header-1: Custom value"', + '-H "X-Custom-Header-2: 8.8.8.8"', + '-H "X-Custom-Header-3: Mon, 3 Mar 2014 11:11:11 GMT"', '-H "Referer: ' + CURL_URL + '"', '-H "Connection: keep-alive"', '-H "Pragma: no-cache"', @@ -56,36 +56,7 @@ function test() { let requestItem = RequestsMenu.getItemAtIndex(0); RequestsMenu.selectedItem = requestItem; - waitForClipboard(function validate(aResult) { - if (typeof aResult !== "string") { - return false; - } - - // Different setups may produce the same command, but with the - // parameters in a different order in the commandline (which is fine). - // Here we confirm that the commands are the same even in that case. - var expected = EXPECTED_RESULT.toString().match(/[-A-Za-z1-9]+ '.*?'/g), - actual = aResult.match(/[-A-Za-z1-9]+ '.*?'/g); - - // Must begin with the same "curl 'URL'" segment - if (!actual || expected[0] != actual[0]) { - return false; - } - - // Must match each of the params in the middle (headers) - var expectedSet = new Set(expected); - var actualSet = new Set(actual); - if (expected.size != actual.size) { - return false; - } - for (let param of expectedSet) { - if (!actualSet.has(param)) { - return false; - } - } - - return true; - }, function setup() { + waitForClipboard(EXPECTED_RESULT, function setup() { RequestsMenu.copyAsCurl(); }, function onSuccess() { ok(true, "Clipboard contains a cURL command for the currently selected item's url."); diff --git a/devtools/client/netmonitor/test/browser_net_resend.js b/devtools/client/netmonitor/test/browser_net_resend.js index ab2131fbc1a8..29a2422a9ae9 100644 --- a/devtools/client/netmonitor/test/browser_net_resend.js +++ b/devtools/client/netmonitor/test/browser_net_resend.js @@ -154,7 +154,7 @@ function testSentRequest(aData, aOrigData) { is(aData.url, aOrigData.url + "&" + ADD_QUERY, "correct url in sent request"); let hasHeader = aData.requestHeaders.headers.some((header) => { - return (header.name.toLowerCase() + ": " + header.value) == ADD_HEADER.toLowerCase(); + return (header.name + ": " + header.value) == ADD_HEADER; }); ok(hasHeader, "new header added to sent request"); diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 136ee24be046..e59869009e24 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -7071,8 +7071,9 @@ nsContentUtils::IsForbiddenSystemRequestHeader(const nsACString& aHeader) static const char *kInvalidHeaders[] = { "accept-charset", "accept-encoding", "access-control-request-headers", "access-control-request-method", "connection", "content-length", - "cookie", "cookie2", "date", "dnt", "expect", "host", "keep-alive", - "origin", "referer", "te", "trailer", "transfer-encoding", "upgrade", "via" + "cookie", "cookie2", "content-transfer-encoding", "date", "dnt", + "expect", "host", "keep-alive", "origin", "referer", "te", "trailer", + "transfer-encoding", "upgrade", "via" }; for (uint32_t i = 0; i < ArrayLength(kInvalidHeaders); ++i) { if (aHeader.LowerCaseEqualsASCII(kInvalidHeaders[i])) { diff --git a/dom/xhr/XMLHttpRequestMainThread.cpp b/dom/xhr/XMLHttpRequestMainThread.cpp index 4c7b33c0d3da..7ee499f9ea3d 100644 --- a/dom/xhr/XMLHttpRequestMainThread.cpp +++ b/dom/xhr/XMLHttpRequestMainThread.cpp @@ -1465,7 +1465,7 @@ XMLHttpRequestMainThread::Open(const nsACString& inMethod, const nsACString& url // Clear our record of previously set headers so future header set // operations will merge/override correctly. - mAuthorRequestHeaders.Clear(); + mAlreadySetHeaders.Clear(); // When we are called from JS we can find the load group for the page, // and add ourselves to it. This way any pending requests @@ -2480,9 +2480,6 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable nsCOMPtr httpChannel(do_QueryInterface(mChannel)); if (httpChannel) { - // Spec step 5 - SetAuthorRequestHeadersOnChannel(httpChannel); - httpChannel->GetRequestMethod(method); // If GET, method name will be uppercase if (!IsSystemXHR()) { @@ -2537,14 +2534,15 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable net::InScriptableRange(size_u64) ? static_cast(size_u64) : -1; if (postDataStream) { - // If author set no Content-Type, use the default from GetRequestBody(). + // If no content type header was set by the client, we set it to + // application/xml. nsAutoCString contentType; - - GetAuthorRequestHeaderValue("content-type", contentType); - if (contentType.IsVoid()) { + if (NS_FAILED(httpChannel-> + GetRequestHeader(NS_LITERAL_CSTRING("Content-Type"), + contentType))) { contentType = defaultContentType; - if (!charset.IsEmpty()) { + if (!charset.IsEmpty() && !contentType.IsVoid()) { // If we are providing the default content type, then we also need to // provide a charset declaration. contentType.Append(NS_LITERAL_CSTRING(";charset=")); @@ -2722,26 +2720,8 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable // Set up the preflight if needed if (!IsSystemXHR()) { - nsTArray CORSUnsafeHeaders; - const char *kCrossOriginSafeHeaders[] = { - "accept", "accept-language", "content-language", "content-type", - "last-event-id" - }; - for (RequestHeader& header : mAuthorRequestHeaders) { - bool safe = false; - for (uint32_t i = 0; i < ArrayLength(kCrossOriginSafeHeaders); ++i) { - if (header.name.EqualsASCII(kCrossOriginSafeHeaders[i])) { - safe = true; - break; - } - } - if (!safe) { - CORSUnsafeHeaders.AppendElement(header.name); - } - } - nsCOMPtr loadInfo = mChannel->GetLoadInfo(); - loadInfo->SetCorsPreflightInfo(CORSUnsafeHeaders, + loadInfo->SetCorsPreflightInfo(mCORSUnsafeHeaders, mFlagHadUploadListenersOnSend); } @@ -2867,62 +2847,99 @@ XMLHttpRequestMainThread::Send(nsIVariant* aVariant, const Nullable // http://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-setrequestheader NS_IMETHODIMP -XMLHttpRequestMainThread::SetRequestHeader(const nsACString& aName, - const nsACString& aValue) +XMLHttpRequestMainThread::SetRequestHeader(const nsACString& header, + const nsACString& value) { // Steps 1 and 2 if (mState != State::opened || mFlagSend) { return NS_ERROR_DOM_INVALID_STATE_ERR; } + NS_ASSERTION(mChannel, "mChannel must be valid if we're OPENED."); // Step 3 - nsAutoCString value(aValue); - static const char kHTTPWhitespace[] = "\n\t\r "; - value.Trim(kHTTPWhitespace); - - // Step 4 - if (!NS_IsValidHTTPToken(aName) || !NS_IsReasonableHTTPHeaderValue(value)) { + // Make sure we don't store an invalid header name in mCORSUnsafeHeaders + if (!NS_IsValidHTTPToken(header)) { return NS_ERROR_DOM_SYNTAX_ERR; } - // Step 5 - bool isPrivilegedCaller = IsSystemXHR(); - bool isForbiddenHeader = nsContentUtils::IsForbiddenRequestHeader(aName); - if (!isPrivilegedCaller && isForbiddenHeader) { - NS_WARNING("refusing to set request header"); + if (!mChannel) // open() initializes mChannel, and open() + return NS_ERROR_FAILURE; // must be called before first setRequestHeader() + + nsCOMPtr httpChannel = do_QueryInterface(mChannel); + if (!httpChannel) { return NS_OK; } - // Step 6.1 - nsAutoCString lowercaseName; - nsContentUtils::ASCIIToLower(aName, lowercaseName); + // We will merge XHR headers, per the spec (secion 4.6.2) unless: + // 1 - The caller is privileged and setting an invalid header, + // or + // 2 - we have not yet explicitly set that header; this allows web + // content to override default headers the first time they set them. + bool mergeHeaders = true; - // Step 6.2 - bool notAlreadySet = true; - for (RequestHeader& header : mAuthorRequestHeaders) { - if (header.name.Equals(lowercaseName)) { - // Gecko-specific: invalid headers can be set by privileged - // callers, but will not merge. - if (isPrivilegedCaller && isForbiddenHeader) { - header.value.Assign(value); - } else { - header.value.AppendLiteral(", "); - header.value.Append(value); + if (!IsSystemXHR()) { + // Step 5: Check for dangerous headers. + // Prevent modification to certain HTTP headers (see bug 302263), unless + // the executing script is privileged. + if (nsContentUtils::IsForbiddenRequestHeader(header)) { + NS_WARNING("refusing to set request header"); + return NS_OK; + } + + // Check for dangerous cross-site headers + bool safeHeader = IsSystemXHR(); + if (!safeHeader) { + // Content-Type isn't always safe, but we'll deal with it in Send() + const char *kCrossOriginSafeHeaders[] = { + "accept", "accept-language", "content-language", "content-type", + "last-event-id" + }; + for (uint32_t i = 0; i < ArrayLength(kCrossOriginSafeHeaders); ++i) { + if (header.LowerCaseEqualsASCII(kCrossOriginSafeHeaders[i])) { + safeHeader = true; + break; + } } - notAlreadySet = false; - break; + } + + if (!safeHeader) { + if (!mCORSUnsafeHeaders.Contains(header, nsCaseInsensitiveCStringArrayComparator())) { + mCORSUnsafeHeaders.AppendElement(header); + } + } + } else { + // Case 1 above + if (nsContentUtils::IsForbiddenSystemRequestHeader(header)) { + mergeHeaders = false; } } - // Step 6.3 - if (notAlreadySet) { - RequestHeader newHeader = { - nsCString(lowercaseName), nsCString(value) - }; - mAuthorRequestHeaders.AppendElement(newHeader); + if (!mAlreadySetHeaders.Contains(header)) { + // Case 2 above + mergeHeaders = false; } - return NS_OK; + nsresult rv; + if (value.IsEmpty()) { + rv = httpChannel->SetEmptyRequestHeader(header); + } else { + // Merge headers depending on what we decided above. + rv = httpChannel->SetRequestHeader(header, value, mergeHeaders); + } + if (rv == NS_ERROR_INVALID_ARG) { + return NS_ERROR_DOM_SYNTAX_ERR; + } + if (NS_SUCCEEDED(rv)) { + // Remember that we've set this header, so subsequent set operations will merge values. + mAlreadySetHeaders.PutEntry(nsCString(header)); + + // We'll want to duplicate this header for any replacement channels (eg. on redirect) + RequestHeader reqHeader = { + nsCString(header), nsCString(value) + }; + mModifiedRequestHeaders.AppendElement(reqHeader); + } + return rv; } NS_IMETHODIMP @@ -3162,32 +3179,6 @@ XMLHttpRequestMainThread::AsyncOnChannelRedirect(nsIChannel *aOldChannel, return NS_OK; } -void -XMLHttpRequestMainThread::GetAuthorRequestHeaderValue(const char* aName, - nsACString& outValue) -{ - for (RequestHeader& header : mAuthorRequestHeaders) { - if (header.name.Equals(aName)) { - outValue.Assign(header.value); - return; - } - } - outValue.SetIsVoid(true); -} - -void -XMLHttpRequestMainThread::SetAuthorRequestHeadersOnChannel( - nsCOMPtr aHttpChannel) -{ - for (RequestHeader& header : mAuthorRequestHeaders) { - if (header.value.IsEmpty()) { - aHttpChannel->SetEmptyRequestHeader(header.name); - } else { - aHttpChannel->SetRequestHeader(header.name, header.value, false); - } - } -} - nsresult XMLHttpRequestMainThread::OnRedirectVerifyCallback(nsresult result) { @@ -3200,7 +3191,15 @@ XMLHttpRequestMainThread::OnRedirectVerifyCallback(nsresult result) nsCOMPtr httpChannel(do_QueryInterface(mChannel)); if (httpChannel) { // Ensure all original headers are duplicated for the new channel (bug #553888) - SetAuthorRequestHeadersOnChannel(httpChannel); + for (RequestHeader& requestHeader : mModifiedRequestHeaders) { + if (requestHeader.value.IsEmpty()) { + httpChannel->SetEmptyRequestHeader(requestHeader.header); + } else { + httpChannel->SetRequestHeader(requestHeader.header, + requestHeader.value, + false); + } + } } } else { mErrorLoad = true; @@ -3516,8 +3515,9 @@ XMLHttpRequestMainThread::ShouldBlockAuthPrompt() // Verify that it's ok to prompt for credentials here, per spec // http://xhr.spec.whatwg.org/#the-send%28%29-method - for (RequestHeader& requestHeader : mAuthorRequestHeaders) { - if (requestHeader.name.EqualsLiteral("authorization")) { + for (uint32_t i = 0, len = mModifiedRequestHeaders.Length(); i < len; ++i) { + if (mModifiedRequestHeaders[i].header. + LowerCaseEqualsLiteral("authorization")) { return true; } } diff --git a/dom/xhr/XMLHttpRequestMainThread.h b/dom/xhr/XMLHttpRequestMainThread.h index d02c522a54d0..9a6138250a8e 100644 --- a/dom/xhr/XMLHttpRequestMainThread.h +++ b/dom/xhr/XMLHttpRequestMainThread.h @@ -220,10 +220,10 @@ public: } virtual void - SetRequestHeader(const nsACString& aName, const nsACString& aValue, + SetRequestHeader(const nsACString& aHeader, const nsACString& aValue, ErrorResult& aRv) override { - aRv = SetRequestHeader(aName, aValue); + aRv = SetRequestHeader(aHeader, aValue); } virtual uint32_t @@ -620,6 +620,7 @@ protected: nsCOMPtr mPrincipal; nsCOMPtr mChannel; nsCOMPtr mResponseXML; + nsTArray mCORSUnsafeHeaders; nsCOMPtr mXMLParserStreamListener; @@ -790,13 +791,12 @@ protected: struct RequestHeader { - nsCString name; + nsCString header; nsCString value; }; - nsTArray mAuthorRequestHeaders; + nsTArray mModifiedRequestHeaders; - void GetAuthorRequestHeaderValue(const char* aName, nsACString& outValue); - void SetAuthorRequestHeadersOnChannel(nsCOMPtr aChannel); + nsTHashtable mAlreadySetHeaders; // Helper object to manage our XPCOM scriptability bits nsXMLHttpRequestXPCOMifier* mXPCOMifier; diff --git a/dom/xhr/tests/test_xhr_forbidden_headers.html b/dom/xhr/tests/test_xhr_forbidden_headers.html index fc076731ec7a..4ec8ee03e506 100644 --- a/dom/xhr/tests/test_xhr_forbidden_headers.html +++ b/dom/xhr/tests/test_xhr_forbidden_headers.html @@ -28,6 +28,7 @@ var headers = [ "coNtEnt-LEngth", "CoOKIe", "cOOkiE2", + "cOntEnt-tRAnsFer-enCoDiNg", "DATE", "dNT", "exPeCt", @@ -53,7 +54,6 @@ function startTest() { request.open("GET", window.location.href); for (i = 0; i < headers.length; i++) request.setRequestHeader(headers[i], "test" + i); - request.send(); // headers aren't set on the channel until send() // Read out headers var channel = SpecialPowers.wrap(request).channel.QueryInterface(SpecialPowers.Ci.nsIHttpChannel); @@ -73,7 +73,6 @@ function startTest() { request.open("GET", window.location.href); for (i = 0; i < headers.length; i++) request.setRequestHeader(headers[i], "test" + i); - request.send(); // headers aren't set on the channel until send() // Read out headers var channel = SpecialPowers.wrap(request).channel.QueryInterface(SpecialPowers.Ci.nsIHttpChannel); diff --git a/testing/web-platform/meta/XMLHttpRequest/setrequestheader-case-insensitive.htm.ini b/testing/web-platform/meta/XMLHttpRequest/setrequestheader-case-insensitive.htm.ini new file mode 100644 index 000000000000..16277476d3ab --- /dev/null +++ b/testing/web-platform/meta/XMLHttpRequest/setrequestheader-case-insensitive.htm.ini @@ -0,0 +1,5 @@ +[setrequestheader-case-insensitive.htm] + type: testharness + [XMLHttpRequest: setRequestHeader() - headers that differ in case] + expected: FAIL + diff --git a/testing/web-platform/meta/XMLHttpRequest/setrequestheader-header-allowed.htm.ini b/testing/web-platform/meta/XMLHttpRequest/setrequestheader-header-allowed.htm.ini new file mode 100644 index 000000000000..0a2cae6870a4 --- /dev/null +++ b/testing/web-platform/meta/XMLHttpRequest/setrequestheader-header-allowed.htm.ini @@ -0,0 +1,14 @@ +[setrequestheader-header-allowed.htm] + type: testharness + [XMLHttpRequest: setRequestHeader() - headers that are allowed (Authorization)] + expected: FAIL + + [XMLHttpRequest: setRequestHeader() - headers that are allowed (Content-Transfer-Encoding)] + expected: FAIL + + [XMLHttpRequest: setRequestHeader() - headers that are allowed (Content-Type)] + expected: FAIL + + [XMLHttpRequest: setRequestHeader() - headers that are allowed (User-Agent)] + expected: FAIL + From 6f429bf7de36fd70be5615267d889d1692c7bae2 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 22 Jul 2016 15:26:50 -0500 Subject: [PATCH 025/120] Bug 1288225 - Tweak ESLint update text. r=ahal MozReview-Commit-ID: 8zSAit7xXeU --- tools/lint/eslint/update | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/lint/eslint/update b/tools/lint/eslint/update index 91158525dd7f..f8b47d789642 100755 --- a/tools/lint/eslint/update +++ b/tools/lint/eslint/update @@ -12,7 +12,7 @@ case "$choice" in y|Y ) echo "" echo "1. Go to https://api.pub.build.mozilla.org/" - echo "2. Log In using your Mozilla LDAP account." + echo "2. Log in using your Mozilla LDAP account." echo "3. Click on \"Tokens.\"" echo "4. Issue a user token with the permissions tooltool.upload.public and tooltool.download.public." echo "" @@ -22,7 +22,7 @@ case "$choice" in ;; n|N ) echo "" - echo "You will need to contact somebody that has these permissions... people most likely to have these permissions are members of the releng, ateam, a sheriff or mratcliffe@mozilla.com." + echo "You will need to contact somebody that has these permissions... people most likely to have these permissions are members of the releng, ateam, a sheriff, mratcliffe, or jryans" exit 1 ;; * ) From f8c4ba227999f773784434dac9ecec5756d6be9a Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 22 Jul 2016 17:13:15 -0500 Subject: [PATCH 026/120] Bug 1288225 - Use PEP 8 style for method names. r=ahal MozReview-Commit-ID: 7ci9vAdUw0J --- tools/lint/mach_commands.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tools/lint/mach_commands.py b/tools/lint/mach_commands.py index b21960c95b46..4a075673e8dc 100644 --- a/tools/lint/mach_commands.py +++ b/tools/lint/mach_commands.py @@ -96,18 +96,18 @@ class MachCommands(MachCommandBase): module_path = self.get_eslint_module_path() # eslint requires at least node 4.2.3 - nodePath = self.getNodeOrNpmPath("node", LooseVersion("4.2.3")) + nodePath = self.get_node_or_npm_path("node", LooseVersion("4.2.3")) if not nodePath: return 1 if setup: return self.eslint_setup() - npmPath = self.getNodeOrNpmPath("npm") + npmPath = self.get_node_or_npm_path("npm") if not npmPath: return 1 - if self.eslintModuleHasIssues(): + if self.eslint_module_has_issues(): install = self._prompt_yn("\nContinuing will automatically fix " "these issues. Would you like to " "continue") @@ -178,7 +178,7 @@ class MachCommands(MachCommandBase): # we manually switch folders here instead. os.chdir(module_path) - npmPath = self.getNodeOrNpmPath("npm") + npmPath = self.get_node_or_npm_path("npm") if not npmPath: return 1 @@ -198,7 +198,7 @@ class MachCommands(MachCommandBase): print("Installing %s v%s using \"%s\"..." % (name, version, " ".join(cmd))) - success = self.callProcess(pkg, cmd) + success = self.call_process(pkg, cmd) if not success: return 1 @@ -210,7 +210,7 @@ class MachCommands(MachCommandBase): os.chdir(orig_cwd) - def callProcess(self, name, cmd, cwd=None): + def call_process(self, name, cmd, cwd=None): try: with open(os.devnull, "w") as fnull: subprocess.check_call(cmd, cwd=cwd, stdout=fnull) @@ -224,7 +224,7 @@ class MachCommands(MachCommandBase): return True - def eslintModuleHasIssues(self): + def eslint_module_has_issues(self): has_issues = False node_module_path = os.path.join(self.get_eslint_module_path(), "node_modules") @@ -247,7 +247,7 @@ class MachCommands(MachCommandBase): def node_package_installed(self, package_name="", globalInstall=False, cwd=None): try: - npmPath = self.getNodeOrNpmPath("npm") + npmPath = self.get_node_or_npm_path("npm") cmd = [npmPath, "ls", "--parseable", package_name] @@ -261,7 +261,7 @@ class MachCommands(MachCommandBase): except subprocess.CalledProcessError: return False - def getPossibleNodePathsWin(self): + def get_possible_node_paths_win(self): """ Return possible nodejs paths on Windows. """ @@ -275,7 +275,7 @@ class MachCommands(MachCommandBase): os.path.join(os.environ.get("PROGRAMFILES"), "nodejs") }) - def getNodeOrNpmPath(self, filename, minversion=None): + def get_node_or_npm_path(self, filename, minversion=None): """ Return the nodejs or npm path. """ @@ -283,7 +283,7 @@ class MachCommands(MachCommandBase): for ext in [".cmd", ".exe", ""]: try: nodeOrNpmPath = which.which(filename + ext, - path=self.getPossibleNodePathsWin()) + path=self.get_possible_node_paths_win()) if self.is_valid(nodeOrNpmPath, minversion): return nodeOrNpmPath except which.WhichError: @@ -302,7 +302,7 @@ class MachCommands(MachCommandBase): print(NPM_NOT_FOUND_MESSAGE) if platform.system() == "Windows": - appPaths = self.getPossibleNodePathsWin() + appPaths = self.get_possible_node_paths_win() for p in appPaths: print(" - %s" % p) From c9822d13cd56769b3fd6dd37e23ad72f186bac5d Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 22 Jul 2016 18:18:58 -0500 Subject: [PATCH 027/120] Bug 1288225 - Exclude eslint-plugin-mozilla from tooltool. r=ahal This removes the in-tree plugin from the tooltool archive and uses that code directly from the Gecko checkout instead. For automation, we now get ESLint and external plugins from tooltool and then symbolic link to the in-tree plugin. For local development, we install ESLint and external plugins following the shrinkwrap file created from the last change to the tooltool archive. The local plugin is then installed. This change also removes the list of module versions from mach_commands.py, so there is only one place to update module versions for the future. MozReview-Commit-ID: AhbZ8lVPmN4 --- .../ci/legacy/tasks/tests/eslint-gecko.yml | 1 + tools/lint/eslint/manifest.tt | 4 +- tools/lint/eslint/npm-shrinkwrap.json | 58 ++++---- tools/lint/eslint/package.json | 15 +- tools/lint/eslint/update | 9 +- tools/lint/mach_commands.py | 134 ++++++++++-------- 6 files changed, 121 insertions(+), 100 deletions(-) diff --git a/taskcluster/ci/legacy/tasks/tests/eslint-gecko.yml b/taskcluster/ci/legacy/tasks/tests/eslint-gecko.yml index 9dea3ede0394..fd59e2a25df6 100644 --- a/taskcluster/ci/legacy/tasks/tests/eslint-gecko.yml +++ b/taskcluster/ci/legacy/tasks/tests/eslint-gecko.yml @@ -29,6 +29,7 @@ task: /build/tooltool.py fetch -m manifest.tt && tar xvfz eslint.tar.gz && rm eslint.tar.gz && + ln -s ../eslint-plugin-mozilla node_modules && cd ../../.. && tools/lint/eslint/node_modules/.bin/eslint --quiet --plugin html --ext [.js,.jsm,.jsx,.xml,.html] -f tools/lint/eslint-formatter . diff --git a/tools/lint/eslint/manifest.tt b/tools/lint/eslint/manifest.tt index 1eabd483c5c2..6f70b55ff2e8 100644 --- a/tools/lint/eslint/manifest.tt +++ b/tools/lint/eslint/manifest.tt @@ -1,8 +1,8 @@ [ { -"size": 2349680, +"size": 2371391, "visibility": "public", -"digest": "2b02ae6dd4bc735990660f97a831f05e604c28120977e4120cf59619fb02be22cbd42be26ec2bd176f172f4566f3dfb445082e8d9651346662b8fb8fde407b8c", +"digest": "31421d2c6dbf6d8ab6ee45f29b191d1932b7f84a5f8a9cdf24d071a39be75c7013c7db07d79921cbb300678820bd0abca600edbd0b51bf907f0a7eafd3f91382", "algorithm": "sha512", "filename": "eslint.tar.gz" } diff --git a/tools/lint/eslint/npm-shrinkwrap.json b/tools/lint/eslint/npm-shrinkwrap.json index deec183be73c..bfcd08833456 100644 --- a/tools/lint/eslint/npm-shrinkwrap.json +++ b/tools/lint/eslint/npm-shrinkwrap.json @@ -1,9 +1,10 @@ { + "name": "mach-eslint", "dependencies": { "acorn": { - "version": "3.2.0", + "version": "3.3.0", "from": "acorn@>=3.1.0 <4.0.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.2.0.tgz" + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz" }, "acorn-jsx": { "version": "3.0.1", @@ -206,45 +207,35 @@ }, "escope": { "version": "3.6.0", - "from": "escope@>=3.6.0 <4.0.0", + "from": "escope@>=3.2.0 <4.0.0", "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz" }, "eslint": { "version": "2.9.0", "from": "eslint@2.9.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-2.9.0.tgz" + "resolved": "https://registry.npmjs.org/eslint/-/eslint-2.9.0.tgz", + "dependencies": { + "espree": { + "version": "3.1.4", + "from": "espree@3.1.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.1.4.tgz" + } + } }, "eslint-plugin-html": { "version": "1.4.0", "from": "eslint-plugin-html@1.4.0", "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-1.4.0.tgz" }, - "eslint-plugin-mozilla": { - "version": "0.2.0", - "from": "eslint-plugin-mozilla", - "resolved": "file:eslint-plugin-mozilla", - "dependencies": { - "espree": { - "version": "2.2.5", - "from": "espree@>=2.2.4 <3.0.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-2.2.5.tgz" - } - } - }, "eslint-plugin-react": { "version": "4.2.3", "from": "eslint-plugin-react@4.2.3", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-4.2.3.tgz" }, "espree": { - "version": "3.1.4", - "from": "espree@3.1.4", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.1.4.tgz" - }, - "esprima": { - "version": "2.7.2", - "from": "esprima@>=2.6.0 <3.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.2.tgz" + "version": "2.2.5", + "from": "espree@>=2.2.4 <3.0.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-2.2.5.tgz" }, "esrecurse": { "version": "4.1.0", @@ -260,7 +251,7 @@ }, "estraverse": { "version": "4.2.0", - "from": "estraverse@>=4.2.0 <5.0.0", + "from": "estraverse@>=4.1.1 <5.0.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz" }, "esutils": { @@ -329,9 +320,9 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz" }, "graceful-fs": { - "version": "4.1.4", + "version": "4.1.5", "from": "graceful-fs@>=4.1.2 <5.0.0", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.4.tgz" + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.5.tgz" }, "has-ansi": { "version": "2.0.0", @@ -411,7 +402,14 @@ "js-yaml": { "version": "3.6.1", "from": "js-yaml@>=3.5.1 <4.0.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.1.tgz" + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.1.tgz", + "dependencies": { + "esprima": { + "version": "2.7.2", + "from": "esprima@>=2.6.0 <3.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.2.tgz" + } + } }, "json-stable-stringify": { "version": "1.0.1", @@ -434,9 +432,9 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz" }, "lodash": { - "version": "4.13.1", + "version": "4.14.0", "from": "lodash@>=4.0.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.13.1.tgz" + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.14.0.tgz" }, "minimatch": { "version": "3.0.2", diff --git a/tools/lint/eslint/package.json b/tools/lint/eslint/package.json index 415b3418d12c..4b6bb7d195ea 100644 --- a/tools/lint/eslint/package.json +++ b/tools/lint/eslint/package.json @@ -1,12 +1,15 @@ { - "name": "", - "description": "None", + "name": "mach-eslint", + "description": "ESLint and external plugins for use with mach", "repository": {}, "license": "MPL-2.0", "dependencies": { - "eslint": "*", - "eslint-plugin-html": "*", - "eslint-plugin-mozilla": "*", - "eslint-plugin-react": "*" + "eslint": "2.9.0", + "eslint-plugin-html": "1.4.0", + "eslint-plugin-react": "4.2.3", + "escope": "^3.2.0", + "espree": "^2.2.4", + "estraverse": "^4.1.1", + "sax": "^1.1.4" } } diff --git a/tools/lint/eslint/update b/tools/lint/eslint/update index f8b47d789642..47758423644d 100755 --- a/tools/lint/eslint/update +++ b/tools/lint/eslint/update @@ -37,8 +37,13 @@ echo "Removing node_modules and npm_shrinkwrap.json..." rm -rf node_modules/ rm npm-shrinkwrap.json -echo "Installing eslint and dependencies..." -../../../mach eslint --setup +echo "Installing eslint and external plugins..." +# ESLint and all _external_ plugins are listed in this directory's package.json, +# so a regular `npm install` will install them at the specified versions. +# The in-tree eslint-plugin-mozilla is kept out of this tooltool archive on +# purpose so that it can be changed by any developer without requiring tooltool +# access to make changes. +npm install echo "Creating npm shrinkwrap..." npm shrinkwrap diff --git a/tools/lint/mach_commands.py b/tools/lint/mach_commands.py index 4a075673e8dc..d11534abd296 100644 --- a/tools/lint/mach_commands.py +++ b/tools/lint/mach_commands.py @@ -9,6 +9,7 @@ import json import logging import os import platform +import re import subprocess import sys import which @@ -29,13 +30,6 @@ from mach.decorators import ( here = os.path.abspath(os.path.dirname(__file__)) -ESLINT_PACKAGES = [ - "eslint@2.9.0", - "eslint-plugin-html@1.4.0", - "eslint-plugin-mozilla@0.2.0", - "eslint-plugin-react@4.2.3" -] - ESLINT_NOT_FOUND_MESSAGE = ''' Could not find eslint! We looked at the --binary option, at the ESLINT environment variable, and then at your local node_modules path. Please Install @@ -61,6 +55,9 @@ option in the node installation) and try again. Valid installation paths: '''.strip() +VERSION_RE = re.compile(r"^\d+\.\d+\.\d+$") +CARET_VERSION_RANGE_RE = re.compile(r"^\^((\d+)\.\d+\.\d+)$") + def setup_argument_parser(): from mozlint import cli @@ -84,7 +81,7 @@ class MachCommands(MachCommandBase): @Command('eslint', category='devenv', description='Run eslint or help configure eslint for optimal development.') @CommandArgument('-s', '--setup', default=False, action='store_true', - help='configure eslint for optimal development.') + help='Configure eslint for optimal development.') @CommandArgument('-e', '--ext', default='[.js,.jsm,.jsx,.xml,.html]', help='Filename extensions to lint, default: "[.js,.jsm,.jsx,.xml,.html]".') @CommandArgument('-b', '--binary', default=None, @@ -103,8 +100,8 @@ class MachCommands(MachCommandBase): if setup: return self.eslint_setup() - npmPath = self.get_node_or_npm_path("npm") - if not npmPath: + npm_path = self.get_node_or_npm_path("npm") + if not npm_path: return 1 if self.eslint_module_has_issues(): @@ -162,7 +159,7 @@ class MachCommands(MachCommandBase): 'Finished eslint. {msg} encountered.') return success - def eslint_setup(self, update_only=False): + def eslint_setup(self): """Ensure eslint is optimally configured. This command will inspect your eslint configuration and @@ -178,30 +175,22 @@ class MachCommands(MachCommandBase): # we manually switch folders here instead. os.chdir(module_path) - npmPath = self.get_node_or_npm_path("npm") - if not npmPath: + npm_path = self.get_node_or_npm_path("npm") + if not npm_path: return 1 - # Install eslint and necessary plugins. - for pkg in ESLINT_PACKAGES: - name, version = pkg.split("@") - success = False + # Install ESLint and external plugins + cmd = [npm_path, "install"] + print("Installing eslint for mach using \"%s\"..." % (" ".join(cmd))) + if not self.call_process("eslint", cmd): + return 1 - if self.node_package_installed(pkg, cwd=module_path): - success = True - else: - if pkg.startswith("eslint-plugin-mozilla"): - cmd = [npmPath, "install", - os.path.join(module_path, "eslint-plugin-mozilla")] - else: - cmd = [npmPath, "install", pkg] - - print("Installing %s v%s using \"%s\"..." - % (name, version, " ".join(cmd))) - success = self.call_process(pkg, cmd) - - if not success: - return 1 + # Install in-tree ESLint plugin + cmd = [npm_path, "install", + os.path.join(module_path, "eslint-plugin-mozilla")] + print("Installing eslint-plugin-mozilla using \"%s\"..." % (" ".join(cmd))) + if not self.call_process("eslint-plugin-mozilla", cmd): + return 1 eslint_path = os.path.join(module_path, "node_modules", ".bin", "eslint") @@ -224,42 +213,67 @@ class MachCommands(MachCommandBase): return True + def expected_eslint_modules(self): + # Read the expected version of ESLint and external modules + expected_modules_path = os.path.join(self.get_eslint_module_path(), "package.json") + with open(expected_modules_path, "r") as f: + expected_modules = json.load(f)["dependencies"] + + # Also read the in-tree ESLint plugin version + mozilla_json_path = os.path.join(self.get_eslint_module_path(), + "eslint-plugin-mozilla", "package.json") + with open(mozilla_json_path, "r") as f: + expected_modules["eslint-plugin-mozilla"] = json.load(f)["version"] + + return expected_modules + def eslint_module_has_issues(self): has_issues = False - node_module_path = os.path.join(self.get_eslint_module_path(), "node_modules") + node_modules_path = os.path.join(self.get_eslint_module_path(), "node_modules") - for pkg in ESLINT_PACKAGES: - name, req_version = pkg.split("@") - path = os.path.join(node_module_path, name, "package.json") + for name, version_range in self.expected_eslint_modules().iteritems(): + path = os.path.join(node_modules_path, name, "package.json") if not os.path.exists(path): - print("%s v%s needs to be installed locally." % (name, req_version)) + print("%s v%s needs to be installed locally." % (name, version_range)) has_issues = True continue data = json.load(open(path)) - if data["version"] != req_version: - print("%s v%s should be v%s." % (name, data["version"], req_version)) + if not self.version_in_range(data["version"], version_range): + print("%s v%s should be v%s." % (name, data["version"], version_range)) has_issues = True return has_issues - def node_package_installed(self, package_name="", globalInstall=False, cwd=None): - try: - npmPath = self.get_node_or_npm_path("npm") - - cmd = [npmPath, "ls", "--parseable", package_name] - - if globalInstall: - cmd.append("-g") - - with open(os.devnull, "w") as fnull: - subprocess.check_call(cmd, stdout=fnull, stderr=fnull, cwd=cwd) - + def version_in_range(self, version, version_range): + """ + Check if a module version is inside a version range. Only supports explicit versions and + caret ranges for the moment, since that's all we've used so far. + """ + if version == version_range: return True - except subprocess.CalledProcessError: - return False + + version_match = VERSION_RE.match(version) + if not version_match: + raise RuntimeError("mach eslint doesn't understand module version %s" % version) + version = LooseVersion(version) + + # Caret ranges as specified by npm allow changes that do not modify the left-most non-zero + # digit in the [major, minor, patch] tuple. The code below assumes the major digit is + # non-zero. + range_match = CARET_VERSION_RANGE_RE.match(version_range) + if range_match: + range_version = range_match.group(1) + range_major = int(range_match.group(2)) + + range_min = LooseVersion(range_version) + range_max = LooseVersion("%d.0.0" % (range_major + 1)) + + return range_min <= version < range_max + + return False def get_possible_node_paths_win(self): """ @@ -282,17 +296,17 @@ class MachCommands(MachCommandBase): if platform.system() == "Windows": for ext in [".cmd", ".exe", ""]: try: - nodeOrNpmPath = which.which(filename + ext, - path=self.get_possible_node_paths_win()) - if self.is_valid(nodeOrNpmPath, minversion): - return nodeOrNpmPath + node_or_npm_path = which.which(filename + ext, + path=self.get_possible_node_paths_win()) + if self.is_valid(node_or_npm_path, minversion): + return node_or_npm_path except which.WhichError: pass else: try: - nodeOrNpmPath = which.which(filename) - if self.is_valid(nodeOrNpmPath, minversion): - return nodeOrNpmPath + node_or_npm_path = which.which(filename) + if self.is_valid(node_or_npm_path, minversion): + return node_or_npm_path except which.WhichError: pass From c316de06c205d3909022f59563a6ed9be2bd85c9 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Thu, 28 Jul 2016 13:34:28 -0400 Subject: [PATCH 028/120] Bug 1284356 - add crashtest. r=me --- dom/canvas/crashtests/1284356-1.html | 9 +++++++++ dom/canvas/crashtests/crashtests.list | 1 + 2 files changed, 10 insertions(+) create mode 100644 dom/canvas/crashtests/1284356-1.html diff --git a/dom/canvas/crashtests/1284356-1.html b/dom/canvas/crashtests/1284356-1.html new file mode 100644 index 000000000000..bbdb135b0ed8 --- /dev/null +++ b/dom/canvas/crashtests/1284356-1.html @@ -0,0 +1,9 @@ + + \ No newline at end of file diff --git a/dom/canvas/crashtests/crashtests.list b/dom/canvas/crashtests/crashtests.list index 1bec85fb794b..b565b0c7ff44 100644 --- a/dom/canvas/crashtests/crashtests.list +++ b/dom/canvas/crashtests/crashtests.list @@ -29,6 +29,7 @@ skip-if(azureCairo) load 1229983-1.html load 1229932-1.html load 1244850-1.html load 1246775-1.html +load 1284356-1.html skip-if(d2d) load 1287515-1.html load 1288872-1.html From 99a26ab433e48ae485c975fa14955f17e56bc33d Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Thu, 28 Jul 2016 13:38:50 -0400 Subject: [PATCH 029/120] Bug 1284578 - add crashtest. r=me --- dom/canvas/crashtests/1284578-1.html | 8 ++++++++ dom/canvas/crashtests/crashtests.list | 1 + 2 files changed, 9 insertions(+) create mode 100644 dom/canvas/crashtests/1284578-1.html diff --git a/dom/canvas/crashtests/1284578-1.html b/dom/canvas/crashtests/1284578-1.html new file mode 100644 index 000000000000..ba6e5f963025 --- /dev/null +++ b/dom/canvas/crashtests/1284578-1.html @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/dom/canvas/crashtests/crashtests.list b/dom/canvas/crashtests/crashtests.list index b565b0c7ff44..cc5a5760dc41 100644 --- a/dom/canvas/crashtests/crashtests.list +++ b/dom/canvas/crashtests/crashtests.list @@ -30,6 +30,7 @@ load 1229932-1.html load 1244850-1.html load 1246775-1.html load 1284356-1.html +load 1284578-1.html skip-if(d2d) load 1287515-1.html load 1288872-1.html From 5cc2b19359bf85985552de841c915517e1bb5a61 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Thu, 28 Jul 2016 10:53:22 -0700 Subject: [PATCH 030/120] Backed out 2 changesets (bug 1260599) for winxp mochitest gl bustage Backed out changeset 4e066314768c (bug 1260599) Backed out changeset d50028181044 (bug 1260599) --- dom/canvas/WebGLContext.cpp | 7 ------- dom/canvas/WebGLContext.h | 2 -- dom/canvas/WebGLContextState.cpp | 6 +----- dom/canvas/WebGLExtensionDisjointTimerQuery.cpp | 10 ++++++---- dom/canvas/test/webgl-mochitest/mochitest.ini | 3 +-- 5 files changed, 8 insertions(+), 20 deletions(-) diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index 0b2d329e61d9..d20745fe6f0c 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -1626,13 +1626,6 @@ WebGLContext::DummyReadFramebufferOperation(const char* funcName) } } -bool -WebGLContext::HasTimestampBits() const -{ - // 'sync' provides glGetInteger64v either by supporting ARB_sync, GL3+, or GLES3+. - return gl->IsSupported(GLFeature::sync); -} - static bool CheckContextLost(GLContext* gl, bool* const out_isGuilty) { diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index 8fb6dd4cf168..23cee25f01b6 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -1473,8 +1473,6 @@ protected: bool mNeedsFakeNoStencil; bool mNeedsEmulatedLoneDepthStencil; - bool HasTimestampBits() const; - struct ScopedMaskWorkaround { WebGLContext& mWebGL; const bool mFakeNoAlpha; diff --git a/dom/canvas/WebGLContextState.cpp b/dom/canvas/WebGLContextState.cpp index e47e54a5ebe1..dbd6f44a126b 100644 --- a/dom/canvas/WebGLContextState.cpp +++ b/dom/canvas/WebGLContextState.cpp @@ -267,11 +267,7 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv) if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query)) { if (pname == LOCAL_GL_TIMESTAMP_EXT) { GLuint64 iv = 0; - if (HasTimestampBits()) { - gl->fGetInteger64v(pname, (GLint64*)&iv); - } else { - GenerateWarning("QUERY_COUNTER_BITS_EXT for TIMESTAMP_EXT is 0."); - } + gl->fGetInteger64v(pname, (GLint64*) &iv); // TODO: JS doesn't support 64-bit integers. Be lossy and // cast to double (53 bits) return JS::NumberValue(static_cast(iv)); diff --git a/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp b/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp index 42ebe3f57722..e2fcdaf53db9 100644 --- a/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp +++ b/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp @@ -177,9 +177,7 @@ WebGLExtensionDisjointTimerQuery::GetQueryEXT(JSContext* cx, GLenum target, return; } GLint bits = 0; - if (mContext->HasTimestampBits()) { - mContext->GL()->fGetQueryiv(target, pname, &bits); - } + mContext->GL()->fGetQueryiv(target, pname, &bits); retval.set(JS::Int32Value(int32_t(bits))); break; } @@ -244,7 +242,11 @@ WebGLExtensionDisjointTimerQuery::IsSupported(const WebGLContext* webgl) gl::GLContext* gl = webgl->GL(); return gl->IsSupported(gl::GLFeature::query_objects) && gl->IsSupported(gl::GLFeature::get_query_object_i64v) && - gl->IsSupported(gl::GLFeature::query_counter); // provides GL_TIMESTAMP + gl->IsSupported(gl::GLFeature::query_counter) && // provides GL_TIMESTAMP + gl->IsSupported(gl::GLFeature::sync); // provides glGetInteger64v + // 'sync' provides glGetInteger64v either by supporting ARB_sync, GL3+, or GLES3+. + // Since there are no differences between support for glGetInteger64v and support for + // 'sync', we just piggy-back off of 'sync'. } void diff --git a/dom/canvas/test/webgl-mochitest/mochitest.ini b/dom/canvas/test/webgl-mochitest/mochitest.ini index 649cbc9cbdbc..c307d1639bb1 100644 --- a/dom/canvas/test/webgl-mochitest/mochitest.ini +++ b/dom/canvas/test/webgl-mochitest/mochitest.ini @@ -15,7 +15,7 @@ fail-if = (os == 'android') [ensure-exts/test_EXT_color_buffer_half_float.html] fail-if = (os == 'android') [ensure-exts/test_EXT_disjoint_timer_query.html] -fail-if = (os == 'android') || (os == 'mac') +fail-if = (os == 'android') || (os == 'mac') || (os == 'win') [ensure-exts/test_EXT_frag_depth.html] fail-if = (os == 'android') [ensure-exts/test_EXT_sRGB.html] @@ -84,7 +84,6 @@ skip-if = android_version == '18' #Android 4.3 aws only; bug 1030942 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests [test_webgl_compressed_texture_es3.html] [test_webgl_disjoint_timer_query.html] -fail-if = (os == 'win') [test_webgl_force_enable.html] [test_webgl_request_context.html] skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests From fe2ffde0f8cccd4342f7c00951ad7cde8dc3be51 Mon Sep 17 00:00:00 2001 From: Glenn Randers-Pehrson Date: Thu, 21 Jul 2016 11:13:00 -0400 Subject: [PATCH 031/120] Bug 1283961 - Part 1: Remove limits on PNG image dimensions (libpng). r=seth --HG-- extra : rebase_source : 400ad744e14fbecd9b1aac784124df4c86078dbe --- media/libpng/pnglibconf.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/media/libpng/pnglibconf.h b/media/libpng/pnglibconf.h index 57cd675a4460..d1ef23b7f63a 100644 --- a/media/libpng/pnglibconf.h +++ b/media/libpng/pnglibconf.h @@ -5,9 +5,12 @@ #ifndef PNGLCONF_H #define PNGLCONF_H -/* limit image dimensions (bug #251381, #591822, and #967656) */ -#ifndef MOZ_PNG_MAX_DIMENSION -# define MOZ_PNG_MAX_DIMENSION 32767 +/* Limit image dimensions (bug #251381, #591822, #967656, and #1283961) */ +#ifndef MOZ_PNG_MAX_WIDTH +# define MOZ_PNG_MAX_WIDTH 0x7fffffffL /* Unlimited */ +#endif +#ifndef MOZ_PNG_MAX_HEIGHT +# define MOZ_PNG_MAX_HEIGHT 0x7fffffffL /* Unlimited */ #endif #define PNG_API_RULE 0 @@ -23,8 +26,8 @@ #define PNG_sRGB_PROFILE_CHECKS -1 #define PNG_USER_CHUNK_CACHE_MAX 128 #define PNG_USER_CHUNK_MALLOC_MAX 4000000L -#define PNG_USER_HEIGHT_MAX MOZ_PNG_MAX_DIMENSION -#define PNG_USER_WIDTH_MAX MOZ_PNG_MAX_DIMENSION +#define PNG_USER_HEIGHT_MAX MOZ_PNG_MAX_WIDTH +#define PNG_USER_WIDTH_MAX MOZ_PNG_MAX_HEIGHT #define PNG_WEIGHT_SHIFT 8 #define PNG_ZBUF_SIZE 8192 #define PNG_Z_DEFAULT_COMPRESSION (-1) From e2b623ebe9adcc038ecae967b88e820c2124991a Mon Sep 17 00:00:00 2001 From: Glenn Randers-Pehrson Date: Thu, 28 Jul 2016 07:37:00 -0400 Subject: [PATCH 032/120] Bug 1283961 - Part 2: Remove limits on PNG image dimensions (nsPNGDecoder). r=seth --HG-- extra : rebase_source : 8c138a12011233e320d4e55e95348c4c961b95b6 --- image/decoders/nsPNGDecoder.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/image/decoders/nsPNGDecoder.cpp b/image/decoders/nsPNGDecoder.cpp index e4d89d8edc28..1f1c06338da6 100644 --- a/image/decoders/nsPNGDecoder.cpp +++ b/image/decoders/nsPNGDecoder.cpp @@ -34,9 +34,12 @@ namespace image { static LazyLogModule sPNGLog("PNGDecoder"); static LazyLogModule sPNGDecoderAccountingLog("PNGDecoderAccounting"); -// Limit image dimensions (bug #251381, #591822, and #967656) -#ifndef MOZ_PNG_MAX_DIMENSION -# define MOZ_PNG_MAX_DIMENSION 32767 +// limit image dimensions (bug #251381, #591822, #967656, and #1283961) +#ifndef MOZ_PNG_MAX_WIDTH +# define MOZ_PNG_MAX_WIDTH 0x7fffffff // Unlimited +#endif +#ifndef MOZ_PNG_MAX_HEIGHT +# define MOZ_PNG_MAX_HEIGHT 0x7fffffff // Unlimited #endif nsPNGDecoder::AnimFrameInfo::AnimFrameInfo() @@ -323,6 +326,7 @@ nsPNGDecoder::InitInternal() #endif #ifdef PNG_SET_USER_LIMITS_SUPPORTED + png_set_user_limits(mPNG, MOZ_PNG_MAX_WIDTH, MOZ_PNG_MAX_HEIGHT); if (mCMSMode != eCMSMode_Off) { png_set_chunk_malloc_max(mPNG, 4000000L); } @@ -557,11 +561,6 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type); - // Are we too big? - if (width > MOZ_PNG_MAX_DIMENSION || height > MOZ_PNG_MAX_DIMENSION) { - png_longjmp(decoder->mPNG, 1); - } - const IntRect frameRect(0, 0, width, height); // Post our size to the superclass From c0b8ab7939bb89e27254641c475f1703d84d4a7f Mon Sep 17 00:00:00 2001 From: Ethan Lin Date: Wed, 20 Jul 2016 19:10:00 -0400 Subject: [PATCH 033/120] Bug 1287652 - Add crash test case. r=mchang --HG-- extra : rebase_source : de4ebae4ca2e7981c1ad21e1ce7834df2dc81d89 --- dom/canvas/crashtests/1287652-1.html | 8 ++++++++ dom/canvas/crashtests/crashtests.list | 1 + 2 files changed, 9 insertions(+) create mode 100644 dom/canvas/crashtests/1287652-1.html diff --git a/dom/canvas/crashtests/1287652-1.html b/dom/canvas/crashtests/1287652-1.html new file mode 100644 index 000000000000..7eaccd58a353 --- /dev/null +++ b/dom/canvas/crashtests/1287652-1.html @@ -0,0 +1,8 @@ + + diff --git a/dom/canvas/crashtests/crashtests.list b/dom/canvas/crashtests/crashtests.list index cc5a5760dc41..ec8516ab4511 100644 --- a/dom/canvas/crashtests/crashtests.list +++ b/dom/canvas/crashtests/crashtests.list @@ -32,5 +32,6 @@ load 1246775-1.html load 1284356-1.html load 1284578-1.html skip-if(d2d) load 1287515-1.html +load 1287652-1.html load 1288872-1.html From cf5d21b1f8a42e2d2ac2e7b9fc920b676f218ae6 Mon Sep 17 00:00:00 2001 From: Jonathan Kingston Date: Tue, 28 Jun 2016 15:24:48 +0100 Subject: [PATCH 034/120] Bug 1173199 - Create preference to disable MathML. r=huseby, r=smaug If the mathml.disabled preference is true, treat and other MathML elements as generic XML elements. This patch disables the rendering code of MathML however preserves the namespace so to reduce the breakage. Original patch by: Kathy Brade MozReview-Commit-ID: A2f2Q2b4eqR --HG-- extra : rebase_source : 63bf465fa6ff62610d7ed16002a7d479b87df393 --- dom/base/Element.cpp | 6 +- dom/base/NameSpaceConstants.h | 3 +- dom/base/NodeInfo.cpp | 3 +- dom/base/nsContentUtils.cpp | 3 +- dom/base/nsDOMAttributeMap.cpp | 3 +- dom/base/nsNameSpaceManager.cpp | 80 ++++++++++- dom/base/nsNameSpaceManager.h | 26 ++-- dom/svg/SVGAnimationElement.cpp | 9 ++ dom/svg/SVGAnimationElement.h | 4 + dom/svg/SVGGraphicsElement.cpp | 6 + dom/svg/SVGGraphicsElement.h | 2 + dom/svg/SVGSymbolElement.cpp | 10 ++ dom/svg/SVGSymbolElement.h | 3 + dom/svg/SVGTests.cpp | 4 +- dom/svg/SVGTests.h | 2 + dom/svg/nsSVGFeatures.cpp | 8 +- dom/svg/nsSVGFeatures.h | 2 +- dom/xbl/nsXBLPrototypeBinding.cpp | 2 +- dom/xml/nsXMLContentSink.cpp | 3 + layout/mathml/moz.build | 3 + layout/mathml/tests/chrome.ini | 6 + layout/mathml/tests/mathml_example_test.html | 28 ++++ layout/mathml/tests/mochitest.ini | 1 + layout/mathml/tests/test_disabled.html | 47 +++++++ layout/mathml/tests/test_disabled_chrome.html | 55 ++++++++ .../mathml/disabled-scriptlevel-1-ref.html | 129 +++++++++++++++++ .../mathml/disabled-scriptlevel-1-ref.xhtml | 133 ++++++++++++++++++ .../mathml/disabled-scriptlevel-1.html | 129 +++++++++++++++++ .../mathml/disabled-scriptlevel-1.xhtml | 133 ++++++++++++++++++ layout/reftests/mathml/reftest.list | 2 + layout/style/ServoBindings.cpp | 3 +- modules/libpref/init/all.js | 3 + .../web-platform/mozilla/meta/MANIFEST.json | 11 +- .../html/syntax/parsing/math-parse01.html.ini | 2 + .../html/syntax/parsing/math-parse01.html | 62 ++++++++ 35 files changed, 898 insertions(+), 28 deletions(-) create mode 100644 layout/mathml/tests/chrome.ini create mode 100644 layout/mathml/tests/mathml_example_test.html create mode 100644 layout/mathml/tests/test_disabled.html create mode 100644 layout/mathml/tests/test_disabled_chrome.html create mode 100644 layout/reftests/mathml/disabled-scriptlevel-1-ref.html create mode 100644 layout/reftests/mathml/disabled-scriptlevel-1-ref.xhtml create mode 100644 layout/reftests/mathml/disabled-scriptlevel-1.html create mode 100644 layout/reftests/mathml/disabled-scriptlevel-1.xhtml create mode 100644 testing/web-platform/mozilla/meta/html/syntax/parsing/math-parse01.html.ini create mode 100644 testing/web-platform/mozilla/tests/html/syntax/parsing/math-parse01.html diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index e56b5db3ff22..ec6d430dc365 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -1258,7 +1258,7 @@ Element::GetAttributeNS(const nsAString& aNamespaceURI, nsAString& aReturn) { int32_t nsid = - nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI); + nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI, OwnerDoc()); if (nsid == kNameSpaceID_Unknown) { // Unknown namespace means no attribute. @@ -1300,7 +1300,7 @@ Element::RemoveAttributeNS(const nsAString& aNamespaceURI, { nsCOMPtr name = NS_Atomize(aLocalName); int32_t nsid = - nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI); + nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI, OwnerDoc()); if (nsid == kNameSpaceID_Unknown) { // If the namespace ID is unknown, it means there can't possibly be an @@ -1377,7 +1377,7 @@ Element::HasAttributeNS(const nsAString& aNamespaceURI, const nsAString& aLocalName) const { int32_t nsid = - nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI); + nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI, OwnerDoc()); if (nsid == kNameSpaceID_Unknown) { // Unknown namespace means no attr... diff --git a/dom/base/NameSpaceConstants.h b/dom/base/NameSpaceConstants.h index e4cad72a4e3c..d6c3f079fc47 100644 --- a/dom/base/NameSpaceConstants.h +++ b/dom/base/NameSpaceConstants.h @@ -23,6 +23,7 @@ static const int32_t kNameSpaceID_None = 0; #define kNameSpaceID_RDF 8 #define kNameSpaceID_XUL 9 #define kNameSpaceID_SVG 10 -#define kNameSpaceID_LastBuiltin 10 // last 'built-in' namespace +#define kNameSpaceID_disabled_MathML 11 +#define kNameSpaceID_LastBuiltin 11 // last 'built-in' namespace #endif // mozilla_dom_NameSpaceConstants_h__ diff --git a/dom/base/NodeInfo.cpp b/dom/base/NodeInfo.cpp index 791d4881ab2e..856d06c35aaf 100644 --- a/dom/base/NodeInfo.cpp +++ b/dom/base/NodeInfo.cpp @@ -197,7 +197,8 @@ bool NodeInfo::NamespaceEquals(const nsAString& aNamespaceURI) const { int32_t nsid = - nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI); + nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI, + mOwnerManager->GetDocument()); return mozilla::dom::NodeInfo::NamespaceEquals(nsid); } diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index e59869009e24..e0b68ebafd83 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -2892,7 +2892,8 @@ nsContentUtils::SplitQName(const nsIContent* aNamespaceResolver, nameSpace); NS_ENSURE_SUCCESS(rv, rv); - *aNamespace = NameSpaceManager()->GetNameSpaceID(nameSpace); + *aNamespace = NameSpaceManager()->GetNameSpaceID(nameSpace, + aNamespaceResolver->OwnerDoc()); if (*aNamespace == kNameSpaceID_Unknown) return NS_ERROR_FAILURE; diff --git a/dom/base/nsDOMAttributeMap.cpp b/dom/base/nsDOMAttributeMap.cpp index fe7de268ba98..ca9be88cc955 100644 --- a/dom/base/nsDOMAttributeMap.cpp +++ b/dom/base/nsDOMAttributeMap.cpp @@ -446,7 +446,8 @@ nsDOMAttributeMap::GetAttrNodeInfo(const nsAString& aNamespaceURI, if (!aNamespaceURI.IsEmpty()) { nameSpaceID = - nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI); + nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI, + mContent->OwnerDoc()); if (nameSpaceID == kNameSpaceID_Unknown) { return nullptr; diff --git a/dom/base/nsNameSpaceManager.cpp b/dom/base/nsNameSpaceManager.cpp index fb37832f6dcc..f82bf02be8c1 100644 --- a/dom/base/nsNameSpaceManager.cpp +++ b/dom/base/nsNameSpaceManager.cpp @@ -15,17 +15,25 @@ #include "mozilla/dom/NodeInfo.h" #include "nsCOMArray.h" #include "nsContentCreatorFunctions.h" +#include "nsContentUtils.h" #include "nsGkAtoms.h" +#include "nsIDocument.h" #include "nsString.h" #include "mozilla/dom/NodeInfo.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/dom/XBLChildrenElement.h" #include "mozilla/dom/Element.h" +#include "mozilla/Preferences.h" using namespace mozilla; using namespace mozilla::dom; -StaticAutoPtr nsNameSpaceManager::sInstance; +static const char* kPrefMathMLDisabled = "mathml.disabled"; +static const char* kObservedPrefs[] = { + kPrefMathMLDisabled, + nullptr +}; +StaticRefPtr nsNameSpaceManager::sInstance; /* static */ nsNameSpaceManager* nsNameSpaceManager::GetInstance() { @@ -49,6 +57,14 @@ bool nsNameSpaceManager::Init() rv = AddNameSpace(dont_AddRef(uri), id); \ NS_ENSURE_SUCCESS(rv, false) +#define REGISTER_DISABLED_NAMESPACE(uri, id) \ + rv = AddDisabledNameSpace(dont_AddRef(uri), id); \ + NS_ENSURE_SUCCESS(rv, false) + + mozilla::Preferences::AddStrongObservers(this, kObservedPrefs); + mMathMLDisabled = mozilla::Preferences::GetBool(kPrefMathMLDisabled); + + // Need to be ordered according to ID. REGISTER_NAMESPACE(nsGkAtoms::nsuri_xmlns, kNameSpaceID_XMLNS); REGISTER_NAMESPACE(nsGkAtoms::nsuri_xml, kNameSpaceID_XML); @@ -60,8 +76,10 @@ bool nsNameSpaceManager::Init() REGISTER_NAMESPACE(nsGkAtoms::nsuri_rdf, kNameSpaceID_RDF); REGISTER_NAMESPACE(nsGkAtoms::nsuri_xul, kNameSpaceID_XUL); REGISTER_NAMESPACE(nsGkAtoms::nsuri_svg, kNameSpaceID_SVG); + REGISTER_DISABLED_NAMESPACE(nsGkAtoms::nsuri_mathml, kNameSpaceID_disabled_MathML); #undef REGISTER_NAMESPACE +#undef REGISTER_DISABLED_NAMESPACE return true; } @@ -110,24 +128,32 @@ nsNameSpaceManager::GetNameSpaceURI(int32_t aNameSpaceID, nsAString& aURI) } int32_t -nsNameSpaceManager::GetNameSpaceID(const nsAString& aURI) +nsNameSpaceManager::GetNameSpaceID(const nsAString& aURI, + nsIDocument* aDocument) { if (aURI.IsEmpty()) { return kNameSpaceID_None; // xmlns="", see bug 75700 for details } nsCOMPtr atom = NS_Atomize(aURI); - return GetNameSpaceID(atom); + return GetNameSpaceID(atom, aDocument); } int32_t -nsNameSpaceManager::GetNameSpaceID(nsIAtom* aURI) +nsNameSpaceManager::GetNameSpaceID(nsIAtom* aURI, + nsIDocument* aDocument) { if (aURI == nsGkAtoms::_empty) { return kNameSpaceID_None; // xmlns="", see bug 75700 for details } int32_t nameSpaceID; + if (mMathMLDisabled && + mDisabledURIToIDTable.Get(aURI, &nameSpaceID) && + !nsContentUtils::IsChromeDoc(aDocument)) { + NS_POSTCONDITION(nameSpaceID >= 0, "Bogus namespace ID"); + return nameSpaceID; + } if (mURIToIDTable.Get(aURI, &nameSpaceID)) { NS_POSTCONDITION(nameSpaceID >= 0, "Bogus namespace ID"); return nameSpaceID; @@ -153,7 +179,19 @@ NS_NewElement(Element** aResult, } #endif if (ns == kNameSpaceID_MathML) { - return NS_NewMathMLElement(aResult, ni.forget()); + // If the mathml.disabled pref. is true, convert all MathML nodes into + // disabled MathML nodes by swapping the namespace. + nsNameSpaceManager* nsmgr = nsNameSpaceManager::GetInstance(); + if ((nsmgr && !nsmgr->mMathMLDisabled) || + nsContentUtils::IsChromeDoc(ni->GetDocument())) { + return NS_NewMathMLElement(aResult, ni.forget()); + } + + RefPtr genericXMLNI = + ni->NodeInfoManager()-> + GetNodeInfo(ni->NameAtom(), ni->GetPrefixAtom(), + kNameSpaceID_disabled_MathML, ni->NodeType(), ni->GetExtraName()); + return NS_NewXMLElement(aResult, genericXMLNI.forget()); } if (ns == kNameSpaceID_SVG) { return NS_NewSVGElement(aResult, ni.forget(), aFromParser); @@ -195,3 +233,35 @@ nsresult nsNameSpaceManager::AddNameSpace(already_AddRefed aURI, return NS_OK; } + +nsresult +nsNameSpaceManager::AddDisabledNameSpace(already_AddRefed aURI, + const int32_t aNameSpaceID) +{ + nsCOMPtr uri = aURI; + if (aNameSpaceID < 0) { + // We've wrapped... Can't do anything else here; just bail. + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ASSERTION(aNameSpaceID - 1 == (int32_t) mURIArray.Length(), + "BAD! AddDisabledNameSpace not called in right order!"); + + mURIArray.AppendElement(uri.forget()); + mDisabledURIToIDTable.Put(mURIArray.LastElement(), aNameSpaceID); + + return NS_OK; +} + +// nsISupports +NS_IMPL_ISUPPORTS(nsNameSpaceManager, + nsIObserver) + +// nsIObserver +NS_IMETHODIMP +nsNameSpaceManager::Observe(nsISupports* aObject, const char* aTopic, + const char16_t* aMessage) +{ + mMathMLDisabled = mozilla::Preferences::GetBool(kPrefMathMLDisabled); + return NS_OK; +} diff --git a/dom/base/nsNameSpaceManager.h b/dom/base/nsNameSpaceManager.h index 2d12391c9f31..9bbf4e6590b1 100644 --- a/dom/base/nsNameSpaceManager.h +++ b/dom/base/nsNameSpaceManager.h @@ -10,6 +10,8 @@ #include "nsDataHashtable.h" #include "nsHashKeys.h" #include "nsIAtom.h" +#include "nsIDocument.h" +#include "nsIObserver.h" #include "nsTArray.h" #include "mozilla/StaticPtr.h" @@ -30,34 +32,42 @@ class nsAString; * */ -class nsNameSpaceManager final +class nsNameSpaceManager final : public nsIObserver { public: - ~nsNameSpaceManager() {} + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + virtual nsresult RegisterNameSpace(const nsAString& aURI, + int32_t& aNameSpaceID); - nsresult RegisterNameSpace(const nsAString& aURI, int32_t& aNameSpaceID); - - nsresult GetNameSpaceURI(int32_t aNameSpaceID, nsAString& aURI); + virtual nsresult GetNameSpaceURI(int32_t aNameSpaceID, nsAString& aURI); nsIAtom* NameSpaceURIAtom(int32_t aNameSpaceID) { MOZ_ASSERT(aNameSpaceID > 0 && (int64_t) aNameSpaceID <= (int64_t) mURIArray.Length()); return mURIArray.ElementAt(aNameSpaceID - 1); // id is index + 1 } - int32_t GetNameSpaceID(const nsAString& aURI); - int32_t GetNameSpaceID(nsIAtom* aURI); + int32_t GetNameSpaceID(const nsAString& aURI, + nsIDocument* aDocument); + int32_t GetNameSpaceID(nsIAtom* aURI, + nsIDocument* aDocument); bool HasElementCreator(int32_t aNameSpaceID); static nsNameSpaceManager* GetInstance(); + bool mMathMLDisabled; + private: bool Init(); nsresult AddNameSpace(already_AddRefed aURI, const int32_t aNameSpaceID); + nsresult AddDisabledNameSpace(already_AddRefed aURI, const int32_t aNameSpaceID); + ~nsNameSpaceManager() {}; nsDataHashtable mURIToIDTable; + nsDataHashtable mDisabledURIToIDTable; nsTArray> mURIArray; - static mozilla::StaticAutoPtr sInstance; + static mozilla::StaticRefPtr sInstance; }; #endif // nsNameSpaceManager_h___ diff --git a/dom/svg/SVGAnimationElement.cpp b/dom/svg/SVGAnimationElement.cpp index 9b8431c7e4fe..c9d1191daf4b 100644 --- a/dom/svg/SVGAnimationElement.cpp +++ b/dom/svg/SVGAnimationElement.cpp @@ -348,6 +348,15 @@ SVGAnimationElement::IsNodeOfType(uint32_t aFlags) const return !(aFlags & ~(eCONTENT | eANIMATION)); } +//---------------------------------------------------------------------- +// SVGTests methods + +bool +SVGAnimationElement::IsInChromeDoc() const +{ + return nsContentUtils::IsChromeDoc(OwnerDoc()); +} + //---------------------------------------------------------------------- // SVG utility methods diff --git a/dom/svg/SVGAnimationElement.h b/dom/svg/SVGAnimationElement.h index 8297a339fb97..9bcbdf0c2214 100644 --- a/dom/svg/SVGAnimationElement.h +++ b/dom/svg/SVGAnimationElement.h @@ -86,6 +86,10 @@ public: void EndElement(ErrorResult& rv) { EndElementAt(0.f, rv); } void EndElementAt(float offset, ErrorResult& rv); + // SVGTests + virtual bool IsInChromeDoc() const override; + + protected: // nsSVGElement overrides diff --git a/dom/svg/SVGGraphicsElement.cpp b/dom/svg/SVGGraphicsElement.cpp index d4e0fe50b37c..ba6306680317 100644 --- a/dom/svg/SVGGraphicsElement.cpp +++ b/dom/svg/SVGGraphicsElement.cpp @@ -31,5 +31,11 @@ SVGGraphicsElement::~SVGGraphicsElement() { } +bool +SVGGraphicsElement::IsInChromeDoc() const +{ + return nsContentUtils::IsChromeDoc(OwnerDoc()); +} + } // namespace dom } // namespace mozilla diff --git a/dom/svg/SVGGraphicsElement.h b/dom/svg/SVGGraphicsElement.h index 57a284fda1e8..a6437dba9ed6 100644 --- a/dom/svg/SVGGraphicsElement.h +++ b/dom/svg/SVGGraphicsElement.h @@ -25,6 +25,8 @@ protected: public: // interfaces: NS_DECL_ISUPPORTS_INHERITED + + bool IsInChromeDoc() const override; }; } // namespace dom diff --git a/dom/svg/SVGSymbolElement.cpp b/dom/svg/SVGSymbolElement.cpp index 7f77b464edb2..42de96efd182 100644 --- a/dom/svg/SVGSymbolElement.cpp +++ b/dom/svg/SVGSymbolElement.cpp @@ -80,6 +80,16 @@ SVGSymbolElement::IsAttributeMapped(const nsIAtom* name) const SVGSymbolElementBase::IsAttributeMapped(name); } +//---------------------------------------------------------------------- +// SVGTests methods + +bool +SVGSymbolElement::IsInChromeDoc() const +{ + return nsContentUtils::IsChromeDoc(OwnerDoc()); +} + + //---------------------------------------------------------------------- // nsSVGElement methods diff --git a/dom/svg/SVGSymbolElement.h b/dom/svg/SVGSymbolElement.h index dd28a2da717a..427840f3f2fe 100644 --- a/dom/svg/SVGSymbolElement.h +++ b/dom/svg/SVGSymbolElement.h @@ -44,6 +44,9 @@ public: already_AddRefed ViewBox(); already_AddRefed PreserveAspectRatio(); + // SVGTests + bool IsInChromeDoc() const override; + protected: virtual nsSVGViewBox *GetViewBox() override; virtual SVGAnimatedPreserveAspectRatio *GetPreserveAspectRatio() override; diff --git a/dom/svg/SVGTests.cpp b/dom/svg/SVGTests.cpp index ab8077dd5aef..0fa83ca9f7b0 100644 --- a/dom/svg/SVGTests.cpp +++ b/dom/svg/SVGTests.cpp @@ -57,7 +57,7 @@ SVGTests::SystemLanguage() bool SVGTests::HasExtension(const nsAString& aExtension) { - return nsSVGFeatures::HasExtension(aExtension); + return nsSVGFeatures::HasExtension(aExtension, IsInChromeDoc()); } bool @@ -139,7 +139,7 @@ SVGTests::PassesConditionalProcessingTests(const nsString *aAcceptLangs) const return false; } for (uint32_t i = 0; i < mStringListAttributes[EXTENSIONS].Length(); i++) { - if (!nsSVGFeatures::HasExtension(mStringListAttributes[EXTENSIONS][i])) { + if (!nsSVGFeatures::HasExtension(mStringListAttributes[EXTENSIONS][i], IsInChromeDoc())) { return false; } } diff --git a/dom/svg/SVGTests.h b/dom/svg/SVGTests.h index 4e65e5b9d13a..1e0de76e3f09 100644 --- a/dom/svg/SVGTests.h +++ b/dom/svg/SVGTests.h @@ -95,6 +95,8 @@ public: already_AddRefed SystemLanguage(); bool HasExtension(const nsAString& aExtension); + virtual bool IsInChromeDoc() const = 0; + protected: virtual ~SVGTests() {} diff --git a/dom/svg/nsSVGFeatures.cpp b/dom/svg/nsSVGFeatures.cpp index 3ce6d3697e31..1b028250b6d3 100644 --- a/dom/svg/nsSVGFeatures.cpp +++ b/dom/svg/nsSVGFeatures.cpp @@ -15,6 +15,7 @@ #include "nsSVGFeatures.h" #include "nsIContent.h" #include "nsIDocument.h" +#include "nsNameSpaceManager.h" #include "mozilla/Preferences.h" using namespace mozilla; @@ -42,11 +43,14 @@ nsSVGFeatures::HasFeature(nsISupports* aObject, const nsAString& aFeature) } /*static*/ bool -nsSVGFeatures::HasExtension(const nsAString& aExtension) +nsSVGFeatures::HasExtension(const nsAString& aExtension, const bool aIsInChrome) { #define SVG_SUPPORTED_EXTENSION(str) if (aExtension.EqualsLiteral(str)) return true; SVG_SUPPORTED_EXTENSION("http://www.w3.org/1999/xhtml") - SVG_SUPPORTED_EXTENSION("http://www.w3.org/1998/Math/MathML") + nsNameSpaceManager* nameSpaceManager = nsNameSpaceManager::GetInstance(); + if (aIsInChrome || !nameSpaceManager->mMathMLDisabled) { + SVG_SUPPORTED_EXTENSION("http://www.w3.org/1998/Math/MathML") + } #undef SVG_SUPPORTED_EXTENSION return false; diff --git a/dom/svg/nsSVGFeatures.h b/dom/svg/nsSVGFeatures.h index 248f36a99f10..0e8ad3eec1a6 100644 --- a/dom/svg/nsSVGFeatures.h +++ b/dom/svg/nsSVGFeatures.h @@ -30,7 +30,7 @@ public: * "http://www.w3.org/1999/xhtml" and "http://www.w3.org/1998/Math/MathML" */ static bool - HasExtension(const nsAString& aExtension); + HasExtension(const nsAString& aExtension, const bool aIsInChrome); }; #endif // __NS_SVGFEATURES_H__ diff --git a/dom/xbl/nsXBLPrototypeBinding.cpp b/dom/xbl/nsXBLPrototypeBinding.cpp index 5152360f82af..43ad448c405d 100644 --- a/dom/xbl/nsXBLPrototypeBinding.cpp +++ b/dom/xbl/nsXBLPrototypeBinding.cpp @@ -1599,7 +1599,7 @@ nsXBLPrototypeBinding::ResolveBaseBinding() mBinding->LookupNamespaceURI(prefix, nameSpace); if (!nameSpace.IsEmpty()) { int32_t nameSpaceID = - nsContentUtils::NameSpaceManager()->GetNameSpaceID(nameSpace); + nsContentUtils::NameSpaceManager()->GetNameSpaceID(nameSpace, doc); nsCOMPtr tagName = NS_Atomize(display); // Check the white list diff --git a/dom/xml/nsXMLContentSink.cpp b/dom/xml/nsXMLContentSink.cpp index d36c1fb1b4f2..aeaa302f466c 100644 --- a/dom/xml/nsXMLContentSink.cpp +++ b/dom/xml/nsXMLContentSink.cpp @@ -1049,6 +1049,9 @@ nsXMLContentSink::HandleEndElement(const char16_t *aName, bool isTemplateElement = debugTagAtom == nsGkAtoms::_template && debugNameSpaceID == kNameSpaceID_XHTML; NS_ASSERTION(content->NodeInfo()->Equals(debugTagAtom, debugNameSpaceID) || + (debugNameSpaceID == kNameSpaceID_MathML && + content->NodeInfo()->NamespaceID() == kNameSpaceID_disabled_MathML && + content->NodeInfo()->Equals(debugTagAtom)) || isTemplateElement, "Wrong element being closed"); #endif diff --git a/layout/mathml/moz.build b/layout/mathml/moz.build index c177c552b467..f40b2c2c6589 100644 --- a/layout/mathml/moz.build +++ b/layout/mathml/moz.build @@ -12,6 +12,9 @@ if CONFIG['ENABLE_TESTS']: 'imptests/mochitest.ini', 'tests/mochitest.ini', ] + MOCHITEST_CHROME_MANIFESTS += [ + 'tests/chrome.ini', +] UNIFIED_SOURCES += [ 'nsMathMLChar.cpp', diff --git a/layout/mathml/tests/chrome.ini b/layout/mathml/tests/chrome.ini new file mode 100644 index 000000000000..0885f4c6b378 --- /dev/null +++ b/layout/mathml/tests/chrome.ini @@ -0,0 +1,6 @@ +[DEFAULT] + +support-files = + mathml_example_test.html + +[test_disabled_chrome.html] diff --git a/layout/mathml/tests/mathml_example_test.html b/layout/mathml/tests/mathml_example_test.html new file mode 100644 index 000000000000..6eee75d01384 --- /dev/null +++ b/layout/mathml/tests/mathml_example_test.html @@ -0,0 +1,28 @@ + + + + O + O + + + O + O + + + O + O + O + + + O + O + O + + O + O + + + + + + diff --git a/layout/mathml/tests/mochitest.ini b/layout/mathml/tests/mochitest.ini index 3d7960c72c95..6a665150964b 100644 --- a/layout/mathml/tests/mochitest.ini +++ b/layout/mathml/tests/mochitest.ini @@ -6,6 +6,7 @@ [test_bug827713-2.html] [test_bug827713.html] [test_bug975681.html] +[test_disabled.html] [test_opentype-axis-height.html] [test_opentype-fraction.html] [test_opentype-limits.html] diff --git a/layout/mathml/tests/test_disabled.html b/layout/mathml/tests/test_disabled.html new file mode 100644 index 000000000000..9b649d0f9c45 --- /dev/null +++ b/layout/mathml/tests/test_disabled.html @@ -0,0 +1,47 @@ + + + + + + + + +Mozilla Bug 166235 +
hi there
+
+
+
+ + + diff --git a/layout/mathml/tests/test_disabled_chrome.html b/layout/mathml/tests/test_disabled_chrome.html new file mode 100644 index 000000000000..dff4011bb776 --- /dev/null +++ b/layout/mathml/tests/test_disabled_chrome.html @@ -0,0 +1,55 @@ + + + + + + + + + + +Mozilla Bug 166235 +
hi there
+
+
+
+ + + diff --git a/layout/reftests/mathml/disabled-scriptlevel-1-ref.html b/layout/reftests/mathml/disabled-scriptlevel-1-ref.html new file mode 100644 index 000000000000..76658a0b678d --- /dev/null +++ b/layout/reftests/mathml/disabled-scriptlevel-1-ref.html @@ -0,0 +1,129 @@ + + + + scriptlevel + + + + + + + + O + O + + + + + + + + + O + O + + + + + O + O + + + + + + + + + + O + O + + + O + + + + + + + + + O + O + + + O + O + + + O + O + O + + + O + O + O + + O + O + + + + + + + + + O + O + + + O + O + + + O + O + O + + + + + + diff --git a/layout/reftests/mathml/disabled-scriptlevel-1-ref.xhtml b/layout/reftests/mathml/disabled-scriptlevel-1-ref.xhtml new file mode 100644 index 000000000000..6b22791ab83f --- /dev/null +++ b/layout/reftests/mathml/disabled-scriptlevel-1-ref.xhtml @@ -0,0 +1,133 @@ + + + scriptlevel + + + + + + + + + O + O + + + + + + + + + O + O + + + + + O + O + + + + + + + + + + O + O + + + O + + + + + + + + + O + O + + + O + O + + + O + O + O + + + O + O + O + + O + O + + + + + + + + + O + O + + + O + O + + + O + O + O + + + + + + diff --git a/layout/reftests/mathml/disabled-scriptlevel-1.html b/layout/reftests/mathml/disabled-scriptlevel-1.html new file mode 100644 index 000000000000..9cd388f1c77c --- /dev/null +++ b/layout/reftests/mathml/disabled-scriptlevel-1.html @@ -0,0 +1,129 @@ + + + + scriptlevel + + + + + + + + O + O + + + + + + + + + O + O + + + + + O + O + + + + + + + + + + O + O + + + O + + + + + + + + + O + O + + + O + O + + + O + O + O + + + O + O + O + + O + O + + + + + + + + + O + O + + + O + O + + + O + O + O + + + + + + diff --git a/layout/reftests/mathml/disabled-scriptlevel-1.xhtml b/layout/reftests/mathml/disabled-scriptlevel-1.xhtml new file mode 100644 index 000000000000..5d710a787c2c --- /dev/null +++ b/layout/reftests/mathml/disabled-scriptlevel-1.xhtml @@ -0,0 +1,133 @@ + + + scriptlevel + + + + + + + + + O + O + + + + + + + + + O + O + + + + + O + O + + + + + + + + + + O + O + + + O + + + + + + + + + O + O + + + O + O + + + O + O + O + + + O + O + O + + O + O + + + + + + + + + O + O + + + O + O + + + O + O + O + + + + + + diff --git a/layout/reftests/mathml/reftest.list b/layout/reftests/mathml/reftest.list index cf0ddd9305cb..8afb1082bf89 100644 --- a/layout/reftests/mathml/reftest.list +++ b/layout/reftests/mathml/reftest.list @@ -11,6 +11,8 @@ fails == dir-9.html dir-9-ref.html # Bug 787215 == dir-10.html dir-10-ref.html random-if((B2G&&browserIsRemote)||Mulet) == dir-11.html dir-11-ref.html # Initial mulet triage: parity with B2G/B2G Desktop == css-spacing-1.html css-spacing-1-ref.html +pref(mathml.disabled,true) == disabled-scriptlevel-1.html disabled-scriptlevel-1-ref.html +pref(mathml.disabled,true) == disabled-scriptlevel-1.xhtml disabled-scriptlevel-1-ref.xhtml == displaystyle-1.html displaystyle-1-ref.html == displaystyle-2.html displaystyle-2-ref.html == displaystyle-3.html displaystyle-3-ref.html diff --git a/layout/style/ServoBindings.cpp b/layout/style/ServoBindings.cpp index 3442e28d4547..f8ce49d470b2 100644 --- a/layout/style/ServoBindings.cpp +++ b/layout/style/ServoBindings.cpp @@ -232,7 +232,8 @@ static bool DoMatch(Implementor* aElement, nsIAtom* aNS, nsIAtom* aName, MatchFn aMatch) { if (aNS) { - int32_t ns = nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNS); + int32_t ns = nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNS, + aElement->OwnerDoc()); NS_ENSURE_TRUE(ns != kNameSpaceID_Unknown, false); const nsAttrValue* value = aElement->GetParsedAttr(aName, ns); return value && aMatch(value); diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index dc761a4b8541..31351a4ee24a 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -280,6 +280,9 @@ pref("print.shrink-to-fit.scale-limit-percent", 20); // Whether we should display simplify page checkbox on print preview UI pref("print.use_simplify_page", false); +// Disable support for MathML +pref("mathml.disabled", false); + // Enable scale transform for stretchy MathML operators. See bug 414277. pref("mathml.scale_stretchy_operators.enabled", true); diff --git a/testing/web-platform/mozilla/meta/MANIFEST.json b/testing/web-platform/mozilla/meta/MANIFEST.json index 11cbfa0b451e..221d5356697c 100644 --- a/testing/web-platform/mozilla/meta/MANIFEST.json +++ b/testing/web-platform/mozilla/meta/MANIFEST.json @@ -9,7 +9,16 @@ "local_changes": { "deleted": [], "deleted_reftests": {}, - "items": {}, + "items": { + "testharness": { + "html/syntax/parsing/math-parse01.html": [ + { + "path": "html/syntax/parsing/math-parse01.html", + "url": "/html/syntax/parsing/math-parse01.html" + } + ] + } + }, "reftest_nodes": {} }, "reftest_nodes": {}, diff --git a/testing/web-platform/mozilla/meta/html/syntax/parsing/math-parse01.html.ini b/testing/web-platform/mozilla/meta/html/syntax/parsing/math-parse01.html.ini new file mode 100644 index 000000000000..73bc9da25c6d --- /dev/null +++ b/testing/web-platform/mozilla/meta/html/syntax/parsing/math-parse01.html.ini @@ -0,0 +1,2 @@ +[math-parse01.html] + prefs: ["mathml.disabled:true"] diff --git a/testing/web-platform/mozilla/tests/html/syntax/parsing/math-parse01.html b/testing/web-platform/mozilla/tests/html/syntax/parsing/math-parse01.html new file mode 100644 index 000000000000..3aff716d9f7c --- /dev/null +++ b/testing/web-platform/mozilla/tests/html/syntax/parsing/math-parse01.html @@ -0,0 +1,62 @@ + + + +math in html: parsing + + + + +

math in html: parsing

+ +
+ +
+
+
+
1a
+
⟨⟩
+
𝕂
+
a
+
a
+
+ + + From 38b1158591d2940626bd2a9f4301a74d641beb92 Mon Sep 17 00:00:00 2001 From: "Byron Campen [:bwc]" Date: Wed, 27 Jul 2016 14:21:58 -0500 Subject: [PATCH 035/120] Bug 1287874: Add missing math.h include. r=drno MozReview-Commit-ID: APRXVtWHlBX --HG-- extra : rebase_source : fe8e299f81d4623456c28e2b5aca76b1e29b4503 --- media/mtransport/third_party/nICEr/src/stun/stun_client_ctx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/media/mtransport/third_party/nICEr/src/stun/stun_client_ctx.c b/media/mtransport/third_party/nICEr/src/stun/stun_client_ctx.c index 8bdba8c7cd88..e8d91982b712 100644 --- a/media/mtransport/third_party/nICEr/src/stun/stun_client_ctx.c +++ b/media/mtransport/third_party/nICEr/src/stun/stun_client_ctx.c @@ -35,6 +35,7 @@ static char *RCSSTRING __UNUSED__="$Id: stun_client_ctx.c,v 1.2 2008/04/28 18:21 #include #include +#include #include #include "stun.h" From 6606fbb009c5df8558b58e2e37926fd5d9f4486a Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Mon, 11 Jul 2016 12:31:33 -0400 Subject: [PATCH 036/120] Bug 1286096 - Have MediaEngineDefaultVideoSource inherit from MediaEngineCameraVideoSource. r=padenot MozReview-Commit-ID: KxT4HRaGe9 --HG-- extra : rebase_source : e1cd848912be7db9cb338bba9a19e1de46a2563f --- dom/media/webrtc/MediaEngineCameraVideoSource.h | 3 +++ dom/media/webrtc/MediaEngineDefault.cpp | 2 +- dom/media/webrtc/MediaEngineDefault.h | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/dom/media/webrtc/MediaEngineCameraVideoSource.h b/dom/media/webrtc/MediaEngineCameraVideoSource.h index 810fe4419c25..175bb6cc6966 100644 --- a/dom/media/webrtc/MediaEngineCameraVideoSource.h +++ b/dom/media/webrtc/MediaEngineCameraVideoSource.h @@ -25,6 +25,7 @@ class MediaEngineCameraVideoSource : public MediaEngineVideoSource, protected MediaConstraintsHelper { public: + // Some subclasses use an index to track multiple instances. explicit MediaEngineCameraVideoSource(int aIndex, const char* aMonitorName = "Camera.Monitor") : MediaEngineVideoSource(kReleased) @@ -38,6 +39,8 @@ public: , mTrackID(0) {} + explicit MediaEngineCameraVideoSource(const char* aMonitorName = "Camera.Monitor") + : MediaEngineCameraVideoSource(0, aMonitorName) {} void GetName(nsAString& aName) const override; void GetUUID(nsACString& aUUID) const override; diff --git a/dom/media/webrtc/MediaEngineDefault.cpp b/dom/media/webrtc/MediaEngineDefault.cpp index 4f3931943f32..a6370569456f 100644 --- a/dom/media/webrtc/MediaEngineDefault.cpp +++ b/dom/media/webrtc/MediaEngineDefault.cpp @@ -43,7 +43,7 @@ NS_IMPL_ISUPPORTS(MediaEngineDefaultVideoSource, nsITimerCallback) */ MediaEngineDefaultVideoSource::MediaEngineDefaultVideoSource() - : MediaEngineVideoSource(kReleased) + : MediaEngineCameraVideoSource("FakeVideo.Monitor") , mTimer(nullptr) , mMonitor("Fake video") , mCb(16), mCr(16) diff --git a/dom/media/webrtc/MediaEngineDefault.h b/dom/media/webrtc/MediaEngineDefault.h index 3680aa56a9ff..0a83f656c787 100644 --- a/dom/media/webrtc/MediaEngineDefault.h +++ b/dom/media/webrtc/MediaEngineDefault.h @@ -18,6 +18,7 @@ #include "VideoSegment.h" #include "AudioSegment.h" #include "StreamTracks.h" +#include "MediaEngineCameraVideoSource.h" #include "MediaStreamGraph.h" #include "MediaTrackConstraints.h" @@ -33,8 +34,7 @@ class MediaEngineDefault; * The default implementation of the MediaEngine interface. */ class MediaEngineDefaultVideoSource : public nsITimerCallback, - public MediaEngineVideoSource, - private MediaConstraintsHelper + public MediaEngineCameraVideoSource { public: MediaEngineDefaultVideoSource(); From 36d85898acc59b1fcbe5d38ab7edcf0d34a6257c Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Mon, 11 Jul 2016 16:52:20 -0400 Subject: [PATCH 037/120] Bug 1286096 - Enable width/height constraints on fake device. r=padenot MozReview-Commit-ID: 1SPPbysZjqL --HG-- extra : rebase_source : aa52d5d518fc1f52c81709c22212c892b0527d46 --- dom/media/webrtc/MediaEngineDefault.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/dom/media/webrtc/MediaEngineDefault.cpp b/dom/media/webrtc/MediaEngineDefault.cpp index a6370569456f..7401f12844ef 100644 --- a/dom/media/webrtc/MediaEngineDefault.cpp +++ b/dom/media/webrtc/MediaEngineDefault.cpp @@ -96,15 +96,20 @@ MediaEngineDefaultVideoSource::Allocate(const dom::MediaTrackConstraints &aConst return NS_ERROR_FAILURE; } + FlattenedConstraints c(aConstraints); + // Mock failure for automated tests. - if (aConstraints.mDeviceId.IsString() && - aConstraints.mDeviceId.GetAsString().EqualsASCII("bad device")) { + if (c.mDeviceId.mIdeal.find(NS_LITERAL_STRING("bad device")) != + c.mDeviceId.mIdeal.end()) { return NS_ERROR_FAILURE; } + mOpts = aPrefs; - mOpts.mWidth = mOpts.mWidth ? mOpts.mWidth : MediaEngine::DEFAULT_43_VIDEO_WIDTH; - mOpts.mHeight = mOpts.mHeight ? mOpts.mHeight : MediaEngine::DEFAULT_43_VIDEO_HEIGHT; + mOpts.mWidth = c.mWidth.Get(aPrefs.mWidth ? aPrefs.mWidth : + MediaEngine::DEFAULT_43_VIDEO_WIDTH); + mOpts.mHeight = c.mHeight.Get(aPrefs.mHeight ? aPrefs.mHeight : + MediaEngine::DEFAULT_43_VIDEO_HEIGHT); mState = kAllocated; aOutHandle = nullptr; return NS_OK; From 2982c3ee8670665fd122b558d873763325f12586 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Mon, 11 Jul 2016 19:27:43 -0400 Subject: [PATCH 038/120] Bug 1286096 - Remove fakeTracks constraint. r=drno,smaug MozReview-Commit-ID: I9ZsufufRYg --HG-- extra : rebase_source : 6d3ace3a22ce34586da4899cc0f7b2727a5fc6e0 --- dom/media/MediaManager.cpp | 26 ++++------ dom/media/MediaManager.h | 4 +- .../test/test_multiple_mediastreamtracks.html | 10 ++-- dom/media/webrtc/MediaEngine.h | 6 --- dom/media/webrtc/MediaEngineDefault.cpp | 48 ------------------- dom/media/webrtc/MediaEngineDefault.h | 8 +--- dom/webidl/MediaStream.webidl | 4 -- 7 files changed, 17 insertions(+), 89 deletions(-) diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index ed9e54fcda1d..13e38b59f902 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -1618,7 +1618,7 @@ already_AddRefed MediaManager::EnumerateRawDevices(uint64_t aWindowId, MediaSourceEnum aVideoType, MediaSourceEnum aAudioType, - bool aFake, bool aFakeTracks) + bool aFake) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aVideoType != MediaSourceEnum::Other || @@ -1639,15 +1639,9 @@ MediaManager::EnumerateRawDevices(uint64_t aWindowId, } } - if (!aFake) { - // Fake tracks only make sense when we have a fake stream. - aFakeTracks = false; - } - MediaManager::PostTask(NewTaskFrom([id, aWindowId, audioLoopDev, videoLoopDev, aVideoType, - aAudioType, aFake, - aFakeTracks]() mutable { + aAudioType, aFake]() mutable { // Only enumerate what's asked for, and only fake cams and mics. bool hasVideo = aVideoType != MediaSourceEnum::Other; bool hasAudio = aAudioType != MediaSourceEnum::Other; @@ -1656,7 +1650,7 @@ MediaManager::EnumerateRawDevices(uint64_t aWindowId, RefPtr fakeBackend, realBackend; if (fakeCams || fakeMics) { - fakeBackend = new MediaEngineDefault(aFakeTracks); + fakeBackend = new MediaEngineDefault(); } if ((!fakeCams && hasVideo) || (!fakeMics && hasAudio)) { RefPtr manager = MediaManager_GetInstance(); @@ -2345,14 +2339,11 @@ MediaManager::GetUserMedia(nsPIDOMWindowInner* aWindow, bool fake = c.mFake.WasPassed()? c.mFake.Value() : Preferences::GetBool("media.navigator.streams.fake"); - bool fakeTracks = c.mFakeTracks.WasPassed()? c.mFakeTracks.Value() : false; - bool askPermission = !privileged && (!fake || Preferences::GetBool("media.navigator.permission.fake")); RefPtr p = EnumerateDevicesImpl(windowID, videoType, - audioType, fake, - fakeTracks); + audioType, fake); p->Then([this, onSuccess, onFailure, windowID, c, listener, askPermission, prefs, isHTTPS, callID, origin](SourceSet*& aDevices) mutable { @@ -2539,7 +2530,7 @@ already_AddRefed MediaManager::EnumerateDevicesImpl(uint64_t aWindowId, MediaSourceEnum aVideoType, MediaSourceEnum aAudioType, - bool aFake, bool aFakeTracks) + bool aFake) { MOZ_ASSERT(NS_IsMainThread()); nsPIDOMWindowInner* window = @@ -2568,13 +2559,12 @@ MediaManager::EnumerateDevicesImpl(uint64_t aWindowId, RefPtr> p = media::GetOriginKey(origin, privateBrowsing, persist); p->Then([id, aWindowId, aVideoType, aAudioType, - aFake, aFakeTracks](const nsCString& aOriginKey) mutable { + aFake](const nsCString& aOriginKey) mutable { MOZ_ASSERT(NS_IsMainThread()); RefPtr mgr = MediaManager_GetInstance(); - RefPtr p = mgr->EnumerateRawDevices(aWindowId, - aVideoType, aAudioType, - aFake, aFakeTracks); + RefPtr p = mgr->EnumerateRawDevices(aWindowId, aVideoType, + aAudioType, aFake); p->Then([id, aWindowId, aOriginKey](SourceSet*& aDevices) mutable { UniquePtr devices(aDevices); // secondary result diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index a5495ba7f7c2..2bee592bf976 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -273,12 +273,12 @@ private: EnumerateRawDevices(uint64_t aWindowId, dom::MediaSourceEnum aVideoType, dom::MediaSourceEnum aAudioType, - bool aFake, bool aFakeTracks); + bool aFake); already_AddRefed EnumerateDevicesImpl(uint64_t aWindowId, dom::MediaSourceEnum aVideoSrcType, dom::MediaSourceEnum aAudioSrcType, - bool aFake = false, bool aFakeTracks = false); + bool aFake = false); already_AddRefed SelectSettings( dom::MediaStreamConstraints& aConstraints, diff --git a/dom/media/test/test_multiple_mediastreamtracks.html b/dom/media/test/test_multiple_mediastreamtracks.html index 66d6866bf0a5..afc172733360 100644 --- a/dom/media/test/test_multiple_mediastreamtracks.html +++ b/dom/media/test/test_multiple_mediastreamtracks.html @@ -10,8 +10,11 @@
 
-  
-
-
-Mozilla Bug 166235
-
hi there
-
-
-
- - - diff --git a/layout/mathml/tests/test_disabled_chrome.html b/layout/mathml/tests/test_disabled_chrome.html deleted file mode 100644 index dff4011bb776..000000000000 --- a/layout/mathml/tests/test_disabled_chrome.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - -Mozilla Bug 166235 -
hi there
-
-
-
- - - diff --git a/layout/reftests/mathml/disabled-scriptlevel-1-ref.html b/layout/reftests/mathml/disabled-scriptlevel-1-ref.html deleted file mode 100644 index 76658a0b678d..000000000000 --- a/layout/reftests/mathml/disabled-scriptlevel-1-ref.html +++ /dev/null @@ -1,129 +0,0 @@ - - - - scriptlevel - - - - - - - - O - O - - - - - - - - - O - O - - - - - O - O - - - - - - - - - - O - O - - - O - - - - - - - - - O - O - - - O - O - - - O - O - O - - - O - O - O - - O - O - - - - - - - - - O - O - - - O - O - - - O - O - O - - - - - - diff --git a/layout/reftests/mathml/disabled-scriptlevel-1-ref.xhtml b/layout/reftests/mathml/disabled-scriptlevel-1-ref.xhtml deleted file mode 100644 index 6b22791ab83f..000000000000 --- a/layout/reftests/mathml/disabled-scriptlevel-1-ref.xhtml +++ /dev/null @@ -1,133 +0,0 @@ - - - scriptlevel - - - - - - - - - O - O - - - - - - - - - O - O - - - - - O - O - - - - - - - - - - O - O - - - O - - - - - - - - - O - O - - - O - O - - - O - O - O - - - O - O - O - - O - O - - - - - - - - - O - O - - - O - O - - - O - O - O - - - - - - diff --git a/layout/reftests/mathml/disabled-scriptlevel-1.html b/layout/reftests/mathml/disabled-scriptlevel-1.html deleted file mode 100644 index 9cd388f1c77c..000000000000 --- a/layout/reftests/mathml/disabled-scriptlevel-1.html +++ /dev/null @@ -1,129 +0,0 @@ - - - - scriptlevel - - - - - - - - O - O - - - - - - - - - O - O - - - - - O - O - - - - - - - - - - O - O - - - O - - - - - - - - - O - O - - - O - O - - - O - O - O - - - O - O - O - - O - O - - - - - - - - - O - O - - - O - O - - - O - O - O - - - - - - diff --git a/layout/reftests/mathml/disabled-scriptlevel-1.xhtml b/layout/reftests/mathml/disabled-scriptlevel-1.xhtml deleted file mode 100644 index 5d710a787c2c..000000000000 --- a/layout/reftests/mathml/disabled-scriptlevel-1.xhtml +++ /dev/null @@ -1,133 +0,0 @@ - - - scriptlevel - - - - - - - - - O - O - - - - - - - - - O - O - - - - - O - O - - - - - - - - - - O - O - - - O - - - - - - - - - O - O - - - O - O - - - O - O - O - - - O - O - O - - O - O - - - - - - - - - O - O - - - O - O - - - O - O - O - - - - - - diff --git a/layout/reftests/mathml/reftest.list b/layout/reftests/mathml/reftest.list index 8afb1082bf89..cf0ddd9305cb 100644 --- a/layout/reftests/mathml/reftest.list +++ b/layout/reftests/mathml/reftest.list @@ -11,8 +11,6 @@ fails == dir-9.html dir-9-ref.html # Bug 787215 == dir-10.html dir-10-ref.html random-if((B2G&&browserIsRemote)||Mulet) == dir-11.html dir-11-ref.html # Initial mulet triage: parity with B2G/B2G Desktop == css-spacing-1.html css-spacing-1-ref.html -pref(mathml.disabled,true) == disabled-scriptlevel-1.html disabled-scriptlevel-1-ref.html -pref(mathml.disabled,true) == disabled-scriptlevel-1.xhtml disabled-scriptlevel-1-ref.xhtml == displaystyle-1.html displaystyle-1-ref.html == displaystyle-2.html displaystyle-2-ref.html == displaystyle-3.html displaystyle-3-ref.html diff --git a/layout/style/ServoBindings.cpp b/layout/style/ServoBindings.cpp index f8ce49d470b2..3442e28d4547 100644 --- a/layout/style/ServoBindings.cpp +++ b/layout/style/ServoBindings.cpp @@ -232,8 +232,7 @@ static bool DoMatch(Implementor* aElement, nsIAtom* aNS, nsIAtom* aName, MatchFn aMatch) { if (aNS) { - int32_t ns = nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNS, - aElement->OwnerDoc()); + int32_t ns = nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNS); NS_ENSURE_TRUE(ns != kNameSpaceID_Unknown, false); const nsAttrValue* value = aElement->GetParsedAttr(aName, ns); return value && aMatch(value); diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 31351a4ee24a..dc761a4b8541 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -280,9 +280,6 @@ pref("print.shrink-to-fit.scale-limit-percent", 20); // Whether we should display simplify page checkbox on print preview UI pref("print.use_simplify_page", false); -// Disable support for MathML -pref("mathml.disabled", false); - // Enable scale transform for stretchy MathML operators. See bug 414277. pref("mathml.scale_stretchy_operators.enabled", true); diff --git a/testing/web-platform/mozilla/meta/MANIFEST.json b/testing/web-platform/mozilla/meta/MANIFEST.json index 221d5356697c..11cbfa0b451e 100644 --- a/testing/web-platform/mozilla/meta/MANIFEST.json +++ b/testing/web-platform/mozilla/meta/MANIFEST.json @@ -9,16 +9,7 @@ "local_changes": { "deleted": [], "deleted_reftests": {}, - "items": { - "testharness": { - "html/syntax/parsing/math-parse01.html": [ - { - "path": "html/syntax/parsing/math-parse01.html", - "url": "/html/syntax/parsing/math-parse01.html" - } - ] - } - }, + "items": {}, "reftest_nodes": {} }, "reftest_nodes": {}, diff --git a/testing/web-platform/mozilla/meta/html/syntax/parsing/math-parse01.html.ini b/testing/web-platform/mozilla/meta/html/syntax/parsing/math-parse01.html.ini deleted file mode 100644 index 73bc9da25c6d..000000000000 --- a/testing/web-platform/mozilla/meta/html/syntax/parsing/math-parse01.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[math-parse01.html] - prefs: ["mathml.disabled:true"] diff --git a/testing/web-platform/mozilla/tests/html/syntax/parsing/math-parse01.html b/testing/web-platform/mozilla/tests/html/syntax/parsing/math-parse01.html deleted file mode 100644 index 3aff716d9f7c..000000000000 --- a/testing/web-platform/mozilla/tests/html/syntax/parsing/math-parse01.html +++ /dev/null @@ -1,62 +0,0 @@ - - - -math in html: parsing - - - - -

math in html: parsing

- -
- -
-
-
-
1a
-
⟨⟩
-
𝕂
-
a
-
a
-
- - - From 38ab2d74ce661b9a19c2e240f7e41b72673515f1 Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Wed, 27 Jul 2016 16:47:50 -0700 Subject: [PATCH 046/120] Bug 1289944 - Remove now-unneeded blob URL hack for favicons. r=felipe --- browser/modules/ContentLinkHandler.jsm | 34 +++----------------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/browser/modules/ContentLinkHandler.jsm b/browser/modules/ContentLinkHandler.jsm index b2cab07503fa..a125e445d526 100644 --- a/browser/modules/ContentLinkHandler.jsm +++ b/browser/modules/ContentLinkHandler.jsm @@ -108,37 +108,9 @@ this.ContentLinkHandler = { } sizeHistogramTypes.add(sizesType); - if (uri.scheme == 'blob') { - // Blob URLs don't work cross process, work around this by sending as a data uri - let channel = NetUtil.newChannel({ - uri: uri, - contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE, - loadUsingSystemPrincipal: true - }); - let listener = { - encoded: "", - bis: null, - onStartRequest: function(aRequest, aContext) { - this.bis = Components.classes["@mozilla.org/binaryinputstream;1"] - .createInstance(Components.interfaces.nsIBinaryInputStream); - }, - onStopRequest: function(aRequest, aContext, aStatusCode) { - let spec = "data:" + channel.contentType + ";base64," + this.encoded; - chromeGlobal.sendAsyncMessage( - "Link:SetIcon", - {url: spec, loadingPrincipal: link.ownerDocument.nodePrincipal}); - }, - onDataAvailable: function(request, context, inputStream, offset, count) { - this.bis.setInputStream(inputStream); - this.encoded += btoa(this.bis.readBytes(this.bis.available())); - } - } - channel.asyncOpen2(listener); - } else { - chromeGlobal.sendAsyncMessage( - "Link:SetIcon", - {url: uri.spec, loadingPrincipal: link.ownerDocument.nodePrincipal}); - } + chromeGlobal.sendAsyncMessage( + "Link:SetIcon", + {url: uri.spec, loadingPrincipal: link.ownerDocument.nodePrincipal}); iconAdded = true; break; case "search": From 926b72001b0215c35db28401794f6d318c33ebd2 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Tue, 26 Jul 2016 13:06:52 -0400 Subject: [PATCH 047/120] Bug 1281968 - Include the flags passed through CC/CXX in ./mach compileflags; r=gps --- python/mozbuild/mozbuild/compilation/codecomplete.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/python/mozbuild/mozbuild/compilation/codecomplete.py b/python/mozbuild/mozbuild/compilation/codecomplete.py index 728cdc15c5e9..05583961a552 100644 --- a/python/mozbuild/mozbuild/compilation/codecomplete.py +++ b/python/mozbuild/mozbuild/compilation/codecomplete.py @@ -47,12 +47,17 @@ class Introspection(MachCommandBase): build_vars = util.get_build_vars(make_dir, self) if what.endswith('.c'): + cc = 'CC' name = 'COMPILE_CFLAGS' else: + cc = 'CXX' name = 'COMPILE_CXXFLAGS' if name not in build_vars: return + # Drop the first flag since that is the pathname of the compiler. + flags = (shell_split(build_vars[cc]) + shell_split(build_vars[name]))[1:] + print(' '.join(shell_quote(arg) - for arg in util.sanitize_cflags(shell_split(build_vars[name])))) + for arg in util.sanitize_cflags(flags))) From 55953792221f817b186ff62827fbe8d0de1cff52 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Sun, 24 Jul 2016 16:09:26 -0700 Subject: [PATCH 048/120] Bug 1288885: Support testing WebExtensions from xpcshell tests. r=aswan Most of the test helper code is derived from the SpecialPowers/ExtensionTestUtils code that does the same. Eventually, the two implementations should probably be unified, but I don't think it's worth the trouble for now. MozReview-Commit-ID: 7Yy9jWkGsMM --HG-- extra : source : 8da1ed0adf15e8244e57f22c581bbee072a118b9 --- .../extensions/test/xpcshell/.eslintrc | 4 + .../extensions/test/xpcshell/head.js | 61 ++-- .../xpcshell/test_ext_manifest_commands.js | 2 +- toolkit/components/extensions/Extension.jsm | 3 +- .../extensions/ExtensionXPCShellUtils.jsm | 285 ++++++++++++++++++ toolkit/components/extensions/moz.build | 4 + .../extensions/test/xpcshell/.eslintrc | 4 + .../extensions/test/xpcshell/head.js | 37 +-- ...st_ext_manifest_content_security_policy.js | 4 +- .../xpcshell/test_ext_manifest_incognito.js | 4 +- 10 files changed, 340 insertions(+), 68 deletions(-) create mode 100644 toolkit/components/extensions/ExtensionXPCShellUtils.jsm diff --git a/browser/components/extensions/test/xpcshell/.eslintrc b/browser/components/extensions/test/xpcshell/.eslintrc index 60fdab2176e8..03381914eed7 100644 --- a/browser/components/extensions/test/xpcshell/.eslintrc +++ b/browser/components/extensions/test/xpcshell/.eslintrc @@ -1,3 +1,7 @@ { "extends": "../../../../../testing/xpcshell/xpcshell.eslintrc", + + "globals": { + "browser": false, + }, } diff --git a/browser/components/extensions/test/xpcshell/head.js b/browser/components/extensions/test/xpcshell/head.js index 032d01012e7e..de4a4a3f6e98 100644 --- a/browser/components/extensions/test/xpcshell/head.js +++ b/browser/components/extensions/test/xpcshell/head.js @@ -2,12 +2,24 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +/* exported createHttpServer */ + Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "AppConstants", + "resource://gre/modules/AppConstants.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Extension", "resource://gre/modules/Extension.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "ExtensionData", "resource://gre/modules/Extension.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "ExtensionManagement", + "resource://gre/modules/ExtensionManagement.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "ExtensionTestUtils", + "resource://testing-common/ExtensionXPCShellUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", + "resource://gre/modules/FileUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "HttpServer", + "resource://testing-common/httpd.js"); XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Schemas", @@ -15,36 +27,29 @@ XPCOMUtils.defineLazyModuleGetter(this, "Schemas", XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); -/* exported normalizeManifest */ +ExtensionTestUtils.init(this); -let BASE_MANIFEST = { - "applications": {"gecko": {"id": "test@web.ext"}}, - "manifest_version": 2, +/** + * Creates a new HttpServer for testing, and begins listening on the + * specified port. Automatically shuts down the server when the test + * unit ends. + * + * @param {integer} [port] + * The port to listen on. If omitted, listen on a random + * port. The latter is the preferred behavior. + * + * @returns {HttpServer} + */ +function createHttpServer(port = -1) { + let server = new HttpServer(); + server.start(port); - "name": "name", - "version": "0", -}; + do_register_cleanup(() => { + return new Promise(resolve => { + server.stop(resolve); + }); + }); -function* normalizeManifest(manifest, baseManifest = BASE_MANIFEST) { - const {Management} = Cu.import("resource://gre/modules/Extension.jsm", {}); - yield Management.lazyInit(); - - let errors = []; - let context = { - url: null, - - logError: error => { - errors.push(error); - }, - - preprocessors: {}, - }; - - manifest = Object.assign({}, baseManifest, manifest); - - let normalized = Schemas.normalize(manifest, "manifest.WebExtensionManifest", context); - normalized.errors = errors; - - return normalized; + return server; } diff --git a/browser/components/extensions/test/xpcshell/test_ext_manifest_commands.js b/browser/components/extensions/test/xpcshell/test_ext_manifest_commands.js index 237ea953cb94..4de7afe01ab6 100644 --- a/browser/components/extensions/test/xpcshell/test_ext_manifest_commands.js +++ b/browser/components/extensions/test/xpcshell/test_ext_manifest_commands.js @@ -4,7 +4,7 @@ add_task(function* test_manifest_commands() { - let normalized = yield normalizeManifest({ + let normalized = yield ExtensionTestUtils.normalizeManifest({ "commands": { "toggle-feature": { "suggested_key": {"default": "Shifty+Y"}, diff --git a/toolkit/components/extensions/Extension.jsm b/toolkit/components/extensions/Extension.jsm index b5ba41f565ff..3f853e695fef 100644 --- a/toolkit/components/extensions/Extension.jsm +++ b/toolkit/components/extensions/Extension.jsm @@ -56,6 +56,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "MessageChannel", XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm"); +Cu.import("resource://gre/modules/ExtensionContent.jsm"); Cu.import("resource://gre/modules/ExtensionManagement.jsm"); const BASE_SCHEMA = "chrome://extensions/content/schemas/manifest.json"; @@ -326,7 +327,7 @@ class ProxyContext extends ExtensionContext { function findPathInObject(obj, path) { for (let elt of path) { - obj = obj[elt]; + obj = obj[elt] || undefined; } return obj; } diff --git a/toolkit/components/extensions/ExtensionXPCShellUtils.jsm b/toolkit/components/extensions/ExtensionXPCShellUtils.jsm new file mode 100644 index 000000000000..10a7b47f6064 --- /dev/null +++ b/toolkit/components/extensions/ExtensionXPCShellUtils.jsm @@ -0,0 +1,285 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +this.EXPORTED_SYMBOLS = ["ExtensionTestUtils"]; + +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; + +Components.utils.import("resource://gre/modules/Task.jsm"); +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); + +XPCOMUtils.defineLazyModuleGetter(this, "Extension", + "resource://gre/modules/Extension.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", + "resource://gre/modules/FileUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Schemas", + "resource://gre/modules/Schemas.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Services", + "resource://gre/modules/Services.jsm"); + +XPCOMUtils.defineLazyServiceGetter(this, "uuidGenerator", + "@mozilla.org/uuid-generator;1", "nsIUUIDGenerator"); + +/* exported ExtensionTestUtils */ + +let BASE_MANIFEST = Object.freeze({ + "applications": Object.freeze({ + "gecko": Object.freeze({ + "id": "test@web.ext", + }), + }), + + "manifest_version": 2, + + "name": "name", + "version": "0", +}); + +class ExtensionWrapper { + constructor(extension, testScope) { + this.extension = extension; + this.testScope = testScope; + + this.state = "uninitialized"; + + this.testResolve = null; + this.testDone = new Promise(resolve => { this.testResolve = resolve; }); + + this.messageHandler = new Map(); + this.messageAwaiter = new Map(); + + this.messageQueue = new Set(); + + this.testScope.do_register_cleanup(() => { + if (this.messageQueue.size) { + let names = Array.from(this.messageQueue, ([msg]) => msg); + this.testScope.equal(JSON.stringify(names), "[]", "message queue is empty"); + } + if (this.messageAwaiter.size) { + let names = Array.from(this.messageAwaiter.keys()); + this.testScope.equal(JSON.stringify(names), "[]", "no tasks awaiting on messages"); + } + }); + + /* eslint-disable mozilla/balanced-listeners */ + extension.on("test-eq", (kind, pass, msg, expected, actual) => { + this.testScope.ok(pass, `${msg} - Expected: ${expected}, Actual: ${actual}`); + }); + extension.on("test-log", (kind, pass, msg) => { + this.testScope.do_print(msg); + }); + extension.on("test-result", (kind, pass, msg) => { + this.testScope.ok(pass, msg); + }); + extension.on("test-done", (kind, pass, msg, expected, actual) => { + this.testScope.ok(pass, msg); + this.testResolve(msg); + }); + + extension.on("test-message", (kind, msg, ...args) => { + let handler = this.messageHandler.get(msg); + if (handler) { + handler(...args); + } else { + this.messageQueue.add([msg, ...args]); + this.checkMessages(); + } + }); + /* eslint-enable mozilla/balanced-listeners */ + + this.testScope.do_register_cleanup(() => { + if (this.state == "pending" || this.state == "running") { + this.testScope.equal(this.state, "unloaded", "Extension left running at test shutdown"); + return this.unload(); + } else if (extension.state == "unloading") { + this.testScope.equal(this.state, "unloaded", "Extension not fully unloaded at test shutdown"); + } + }); + + this.testScope.do_print(`Extension loaded`); + } + + startup() { + if (this.state != "uninitialized") { + throw new Error("Extension already started"); + } + this.state = "pending"; + + return this.extension.startup().then( + result => { + this.state = "running"; + + return result; + }, + error => { + this.state = "failed"; + + return Promise.reject(error); + }); + } + + unload() { + if (this.state != "running") { + throw new Error("Extension not running"); + } + this.state = "unloading"; + + this.extension.shutdown(); + this.state = "unloaded"; + + return Promise.resolve(); + } + + sendMessage(...args) { + this.extension.testMessage(...args); + } + + awaitFinish(msg) { + return this.testDone.then(actual => { + if (msg) { + this.testScope.equal(actual, msg, "test result correct"); + } + return actual; + }); + } + + checkMessages() { + for (let message of this.messageQueue) { + let [msg, ...args] = message; + + let listener = this.messageAwaiter.get(msg); + if (listener) { + this.messageQueue.delete(message); + this.messageAwaiter.delete(msg); + + listener.resolve(...args); + return; + } + } + } + + checkDuplicateListeners(msg) { + if (this.messageHandler.has(msg) || this.messageAwaiter.has(msg)) { + throw new Error("only one message handler allowed"); + } + } + + awaitMessage(msg) { + return new Promise(resolve => { + this.checkDuplicateListeners(msg); + + this.messageAwaiter.set(msg, {resolve}); + this.checkMessages(); + }); + } + + onMessage(msg, callback) { + this.checkDuplicateListeners(msg); + this.messageHandler.set(msg, callback); + } +} + +var ExtensionTestUtils = { + BASE_MANIFEST, + + normalizeManifest: Task.async(function* (manifest, baseManifest = BASE_MANIFEST) { + const {Management} = Cu.import("resource://gre/modules/Extension.jsm", {}); + + yield Management.lazyInit(); + + let errors = []; + let context = { + url: null, + + logError: error => { + errors.push(error); + }, + + preprocessors: {}, + }; + + manifest = Object.assign({}, baseManifest, manifest); + + let normalized = Schemas.normalize(manifest, "manifest.WebExtensionManifest", context); + normalized.errors = errors; + + return normalized; + }), + + currentScope: null, + + profileDir: null, + + init(scope) { + this.currentScope = scope; + + this.profileDir = scope.do_get_profile(); + + // We need to load at least one frame script into every message + // manager to ensure that the scriptable wrapper for its global gets + // created before we try to access it externally. If we don't, we + // fail sanity checks on debug builds the first time we try to + // create a wrapper, because we should never have a global without a + // cached wrapper. + Services.mm.loadFrameScript("data:text/javascript,//", true); + + + let tmpD = this.profileDir.clone(); + tmpD.append("tmp"); + tmpD.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); + + let dirProvider = { + getFile(prop, persistent) { + persistent.value = false; + if (prop == "TmpD") { + return tmpD.clone(); + } + return null; + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider]), + }; + Services.dirsvc.registerProvider(dirProvider); + + + scope.do_register_cleanup(() => { + tmpD.remove(true); + Services.dirsvc.unregisterProvider(dirProvider); + + this.currentScope = null; + }); + }, + + addonManagerStarted: false, + + startAddonManager() { + if (this.addonManagerStarted) { + return; + } + this.addonManagerStarted = true; + + let appInfo = {}; + Cu.import("resource://testing-common/AppInfo.jsm", appInfo); + + appInfo.updateAppInfo({ + ID: "xpcshell@tests.mozilla.org", + name: "XPCShell", + version: "48", + platformVersion: "48", + }); + + + let manager = Cc["@mozilla.org/addons/integration;1"].getService(Ci.nsIObserver) + .QueryInterface(Ci.nsITimerCallback); + manager.observe(null, "addons-startup", null); + }, + + loadExtension(data, id = uuidGenerator.generateUUID().number) { + let extension = Extension.generate(id, data); + + return new ExtensionWrapper(extension, this.currentScope); + }, +}; diff --git a/toolkit/components/extensions/moz.build b/toolkit/components/extensions/moz.build index f8bac0b63b70..a810f3e7c298 100644 --- a/toolkit/components/extensions/moz.build +++ b/toolkit/components/extensions/moz.build @@ -19,6 +19,10 @@ EXTRA_COMPONENTS += [ 'extensions-toolkit.manifest', ] +TESTING_JS_MODULES += [ + 'ExtensionXPCShellUtils.jsm', +] + DIRS += ['schemas'] JAR_MANIFESTS += ['jar.mn'] diff --git a/toolkit/components/extensions/test/xpcshell/.eslintrc b/toolkit/components/extensions/test/xpcshell/.eslintrc index 60fdab2176e8..03381914eed7 100644 --- a/toolkit/components/extensions/test/xpcshell/.eslintrc +++ b/toolkit/components/extensions/test/xpcshell/.eslintrc @@ -1,3 +1,7 @@ { "extends": "../../../../../testing/xpcshell/xpcshell.eslintrc", + + "globals": { + "browser": false, + }, } diff --git a/toolkit/components/extensions/test/xpcshell/head.js b/toolkit/components/extensions/test/xpcshell/head.js index 0a7d4e22603c..f427a1cec116 100644 --- a/toolkit/components/extensions/test/xpcshell/head.js +++ b/toolkit/components/extensions/test/xpcshell/head.js @@ -8,6 +8,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "Extension", "resource://gre/modules/Extension.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "ExtensionData", "resource://gre/modules/Extension.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "ExtensionTestUtils", + "resource://testing-common/ExtensionXPCShellUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Schemas", @@ -15,37 +17,4 @@ XPCOMUtils.defineLazyModuleGetter(this, "Schemas", XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); -/* exported normalizeManifest */ - -let BASE_MANIFEST = { - "applications": {"gecko": {"id": "test@web.ext"}}, - - "manifest_version": 2, - - "name": "name", - "version": "0", -}; - -function* normalizeManifest(manifest, baseManifest = BASE_MANIFEST) { - const {Management} = Cu.import("resource://gre/modules/Extension.jsm", {}); - - yield Management.lazyInit(); - - let errors = []; - let context = { - url: null, - - logError: error => { - errors.push(error); - }, - - preprocessors: {}, - }; - - manifest = Object.assign({}, baseManifest, manifest); - - let normalized = Schemas.normalize(manifest, "manifest.WebExtensionManifest", context); - normalized.errors = errors; - - return normalized; -} +ExtensionTestUtils.init(this); diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_manifest_content_security_policy.js b/toolkit/components/extensions/test/xpcshell/test_ext_manifest_content_security_policy.js index f65c4e33f4d1..2b0084980c7a 100644 --- a/toolkit/components/extensions/test/xpcshell/test_ext_manifest_content_security_policy.js +++ b/toolkit/components/extensions/test/xpcshell/test_ext_manifest_content_security_policy.js @@ -4,7 +4,7 @@ add_task(function* test_manifest_csp() { - let normalized = yield normalizeManifest({ + let normalized = yield ExtensionTestUtils.normalizeManifest({ "content_security_policy": "script-src 'self'; object-src 'none'", }); @@ -15,7 +15,7 @@ add_task(function* test_manifest_csp() { "Should have the expected poilcy string"); - normalized = yield normalizeManifest({ + normalized = yield ExtensionTestUtils.normalizeManifest({ "content_security_policy": "object-src 'none'", }); diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_manifest_incognito.js b/toolkit/components/extensions/test/xpcshell/test_ext_manifest_incognito.js index 2f48179d919c..94649692e90c 100644 --- a/toolkit/components/extensions/test/xpcshell/test_ext_manifest_incognito.js +++ b/toolkit/components/extensions/test/xpcshell/test_ext_manifest_incognito.js @@ -4,7 +4,7 @@ add_task(function* test_manifest_incognito() { - let normalized = yield normalizeManifest({ + let normalized = yield ExtensionTestUtils.normalizeManifest({ "incognito": "spanning", }); @@ -14,7 +14,7 @@ add_task(function* test_manifest_incognito() { "spanning", "Should have the expected incognito string"); - normalized = yield normalizeManifest({ + normalized = yield ExtensionTestUtils.normalizeManifest({ "incognito": "split", }); From bacba188eba72fed3b437a742786dd87e5aa1b4c Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Fri, 22 Jul 2016 16:21:42 -0700 Subject: [PATCH 049/120] Bug 1288885: Migrate alarms tests to xpcshell. r=aswan MozReview-Commit-ID: 6NPOqsAfWSb --HG-- rename : toolkit/components/extensions/test/mochitest/test_ext_alarms.html => toolkit/components/extensions/test/xpcshell/test_ext_alarms.js extra : source : 2a6b728f83134c815e3c2b0cc0aceddced403ae5 --- .../extensions/test/mochitest/mochitest.ini | 1 - .../test_ext_alarms.js} | 20 ++----------------- .../extensions/test/xpcshell/xpcshell.ini | 1 + 3 files changed, 3 insertions(+), 19 deletions(-) rename toolkit/components/extensions/test/{mochitest/test_ext_alarms.html => xpcshell/test_ext_alarms.js} (95%) diff --git a/toolkit/components/extensions/test/mochitest/mochitest.ini b/toolkit/components/extensions/test/mochitest/mochitest.ini index 2ac232f2b3f6..8d58f56bcff9 100644 --- a/toolkit/components/extensions/test/mochitest/mochitest.ini +++ b/toolkit/components/extensions/test/mochitest/mochitest.ini @@ -85,7 +85,6 @@ skip-if = os == 'android' # Android does not currently support tabs. [test_ext_cookies.html] [test_ext_bookmarks.html] skip-if = (os == 'android' || buildapp == 'b2g') # unimplemented api. Bug 1258975 on android. -[test_ext_alarms.html] [test_ext_background_window_properties.html] [test_ext_background_sub_windows.html] [test_ext_background_api_injection.html] diff --git a/toolkit/components/extensions/test/mochitest/test_ext_alarms.html b/toolkit/components/extensions/test/xpcshell/test_ext_alarms.js similarity index 95% rename from toolkit/components/extensions/test/mochitest/test_ext_alarms.html rename to toolkit/components/extensions/test/xpcshell/test_ext_alarms.js index 1bfd45370efd..002f919d73c5 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_alarms.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_alarms.js @@ -1,16 +1,5 @@ - - - - WebExtension test - - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/xpcshell/xpcshell.ini b/toolkit/components/extensions/test/xpcshell/xpcshell.ini index 43c7a2e4835b..097a58776dae 100644 --- a/toolkit/components/extensions/test/xpcshell/xpcshell.ini +++ b/toolkit/components/extensions/test/xpcshell/xpcshell.ini @@ -4,6 +4,7 @@ tail = firefox-appdir = browser skip-if = toolkit == 'gonk' || appname == "thunderbird" +[test_ext_alarms.js] [test_csp_custom_policies.js] [test_csp_validator.js] [test_locale_data.js] From d9fc463ca94de0e625d5b27682a85b95d42c6cf3 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Fri, 22 Jul 2016 16:57:58 -0700 Subject: [PATCH 050/120] Bug 1288885: Migrate simple extension mochitests to xpcshell. r=aswan MozReview-Commit-ID: BiaTf6u43XP --HG-- rename : toolkit/components/extensions/test/mochitest/test_ext_background_runtime_connect_params.html => toolkit/components/extensions/test/xpcshell/test_ext_background_runtime_connect_params.js rename : toolkit/components/extensions/test/mochitest/test_ext_extension.html => toolkit/components/extensions/test/xpcshell/test_ext_extension.js rename : toolkit/components/extensions/test/mochitest/test_ext_idle.html => toolkit/components/extensions/test/xpcshell/test_ext_idle.js rename : toolkit/components/extensions/test/mochitest/test_ext_onmessage_removelistener.html => toolkit/components/extensions/test/xpcshell/test_ext_onmessage_removelistener.js rename : toolkit/components/extensions/test/mochitest/test_ext_runtime_getPlatformInfo.html => toolkit/components/extensions/test/xpcshell/test_ext_runtime_getPlatformInfo.js rename : toolkit/components/extensions/test/mochitest/test_ext_runtime_sendMessage.html => toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage.js rename : toolkit/components/extensions/test/mochitest/test_ext_simple.html => toolkit/components/extensions/test/xpcshell/test_ext_simple.js extra : source : f9fd137c9691e75d9e01d61be14608e7f28c7815 --- .../extensions/test/mochitest/mochitest.ini | 7 ---- ..._ext_background_runtime_connect_params.js} | 23 ++---------- .../test_ext_extension.js} | 30 ++++------------ .../test_ext_idle.js} | 19 ++-------- .../test_ext_onmessage_removelistener.js} | 23 ++---------- .../test_ext_runtime_connect_no_receiver.js | 19 ++++++++++ .../test_ext_runtime_getPlatformInfo.js} | 21 ++--------- .../test_ext_runtime_sendMessage.js} | 21 ++--------- ...est_ext_runtime_sendMessage_no_receiver.js | 22 ++++++++++++ .../test_ext_simple.js} | 35 ++++--------------- .../extensions/test/xpcshell/xpcshell.ini | 15 ++++++-- 11 files changed, 81 insertions(+), 154 deletions(-) rename toolkit/components/extensions/test/{mochitest/test_ext_background_runtime_connect_params.html => xpcshell/test_ext_background_runtime_connect_params.js} (74%) rename toolkit/components/extensions/test/{mochitest/test_ext_extension.html => xpcshell/test_ext_extension.js} (67%) rename toolkit/components/extensions/test/{mochitest/test_ext_idle.html => xpcshell/test_ext_idle.js} (50%) rename toolkit/components/extensions/test/{mochitest/test_ext_onmessage_removelistener.html => xpcshell/test_ext_onmessage_removelistener.js} (54%) create mode 100644 toolkit/components/extensions/test/xpcshell/test_ext_runtime_connect_no_receiver.js rename toolkit/components/extensions/test/{mochitest/test_ext_runtime_getPlatformInfo.html => xpcshell/test_ext_runtime_getPlatformInfo.js} (54%) rename toolkit/components/extensions/test/{mochitest/test_ext_runtime_sendMessage.html => xpcshell/test_ext_runtime_sendMessage.js} (82%) create mode 100644 toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_no_receiver.js rename toolkit/components/extensions/test/{mochitest/test_ext_simple.html => xpcshell/test_ext_simple.js} (55%) diff --git a/toolkit/components/extensions/test/mochitest/mochitest.ini b/toolkit/components/extensions/test/mochitest/mochitest.ini index 8d58f56bcff9..e370f5560873 100644 --- a/toolkit/components/extensions/test/mochitest/mochitest.ini +++ b/toolkit/components/extensions/test/mochitest/mochitest.ini @@ -36,10 +36,8 @@ support-files = file_permission_xhr.html file_download.txt -[test_ext_extension.html] [test_ext_inIncognitoContext_window.html] skip-if = os == 'android' # Android does not currently support windows. -[test_ext_simple.html] [test_ext_geturl.html] [test_ext_background_canvas.html] [test_ext_content_security_policy.html] @@ -54,9 +52,7 @@ skip-if = buildapp == 'b2g' # runat != document_idle is not supported. [test_ext_exclude_include_globs.html] [test_ext_i18n_css.html] [test_ext_generate.html] -[test_ext_idle.html] [test_ext_localStorage.html] -[test_ext_onmessage_removelistener.html] [test_ext_notifications.html] [test_ext_permission_xhr.html] skip-if = buildapp == 'b2g' # JavaScript error: jar:remoteopenfile:///data/local/tmp/generated-extension.xpi!/content.js, line 46: NS_ERROR_ILLEGAL_VALUE: @@ -67,9 +63,7 @@ skip-if = (os == 'android' || buildapp == 'b2g') # port.sender.tab is undefined [test_ext_runtime_connect2.html] skip-if = (os == 'android' || buildapp == 'b2g') # port.sender.tab is undefined on b2g. Bug 1258975 on android. [test_ext_runtime_disconnect.html] -[test_ext_runtime_getPlatformInfo.html] [test_ext_runtime_id.html] -[test_ext_runtime_sendMessage.html] [test_ext_sandbox_var.html] [test_ext_sendmessage_reply.html] skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2g. Bug 1258975 on android. @@ -81,7 +75,6 @@ skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2 [test_ext_storage_content.html] [test_ext_storage_tab.html] skip-if = os == 'android' # Android does not currently support tabs. -[test_ext_background_runtime_connect_params.html] [test_ext_cookies.html] [test_ext_bookmarks.html] skip-if = (os == 'android' || buildapp == 'b2g') # unimplemented api. Bug 1258975 on android. diff --git a/toolkit/components/extensions/test/mochitest/test_ext_background_runtime_connect_params.html b/toolkit/components/extensions/test/xpcshell/test_ext_background_runtime_connect_params.js similarity index 74% rename from toolkit/components/extensions/test/mochitest/test_ext_background_runtime_connect_params.html rename to toolkit/components/extensions/test/xpcshell/test_ext_background_runtime_connect_params.js index 8296ec335ca0..008bdbbed1a9 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_background_runtime_connect_params.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_background_runtime_connect_params.js @@ -1,16 +1,5 @@ - - - - WebExtension test - - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/mochitest/test_ext_extension.html b/toolkit/components/extensions/test/xpcshell/test_ext_extension.js similarity index 67% rename from toolkit/components/extensions/test/mochitest/test_ext_extension.html rename to toolkit/components/extensions/test/xpcshell/test_ext_extension.js index a8d225573799..28e4890538ad 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_extension.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_extension.js @@ -1,16 +1,5 @@ - - - - WebExtension test - - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/mochitest/test_ext_idle.html b/toolkit/components/extensions/test/xpcshell/test_ext_idle.js similarity index 50% rename from toolkit/components/extensions/test/mochitest/test_ext_idle.html rename to toolkit/components/extensions/test/xpcshell/test_ext_idle.js index 8e2d92383801..8e128791d426 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_idle.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_idle.js @@ -1,16 +1,5 @@ - - - - WebExtension idle API test - - - - - - - - - - diff --git a/toolkit/components/extensions/test/mochitest/test_ext_onmessage_removelistener.html b/toolkit/components/extensions/test/xpcshell/test_ext_onmessage_removelistener.js similarity index 54% rename from toolkit/components/extensions/test/mochitest/test_ext_onmessage_removelistener.html rename to toolkit/components/extensions/test/xpcshell/test_ext_onmessage_removelistener.js index eadbed1411a9..6f8b553fc6b2 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_onmessage_removelistener.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_onmessage_removelistener.js @@ -1,16 +1,5 @@ - - - - WebExtension test - - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_connect_no_receiver.js b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_connect_no_receiver.js new file mode 100644 index 000000000000..7c22a8a4b0dc --- /dev/null +++ b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_connect_no_receiver.js @@ -0,0 +1,19 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +add_task(function* test_connect_without_listener() { + function background() { + let port = browser.runtime.connect(); + port.onDisconnect.addListener(() => { + browser.test.notifyPass("port.onDisconnect was called"); + }); + } + + let extension = ExtensionTestUtils.loadExtension({background}); + yield extension.startup(); + + yield extension.awaitFinish("port.onDisconnect was called"); + + yield extension.unload(); +}); diff --git a/toolkit/components/extensions/test/mochitest/test_ext_runtime_getPlatformInfo.html b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_getPlatformInfo.js similarity index 54% rename from toolkit/components/extensions/test/mochitest/test_ext_runtime_getPlatformInfo.html rename to toolkit/components/extensions/test/xpcshell/test_ext_runtime_getPlatformInfo.js index 0dc80a7cf443..3487321d86dc 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_runtime_getPlatformInfo.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_getPlatformInfo.js @@ -1,16 +1,5 @@ - - - - WebExtension test - - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/mochitest/test_ext_runtime_sendMessage.html b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage.js similarity index 82% rename from toolkit/components/extensions/test/mochitest/test_ext_runtime_sendMessage.html rename to toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage.js index d360580ea380..a85b7fb7299f 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_runtime_sendMessage.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage.js @@ -1,16 +1,5 @@ - - - - WebExtension test - - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_no_receiver.js b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_no_receiver.js new file mode 100644 index 000000000000..6640bbe8ea22 --- /dev/null +++ b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_no_receiver.js @@ -0,0 +1,22 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +add_task(function* test_sendMessage_without_listener() { + function background() { + browser.runtime.sendMessage("msg").then(reply => { + browser.test.assertEq(undefined, reply); + browser.test.notifyFail("Did not expect a reply to sendMessage"); + }, error => { + browser.test.assertEq("Could not establish connection. Receiving end does not exist.", error.message); + browser.test.notifyPass("sendMessage callback was invoked"); + }); + } + + let extension = ExtensionTestUtils.loadExtension({background}); + yield extension.startup(); + + yield extension.awaitFinish("sendMessage callback was invoked"); + + yield extension.unload(); +}); diff --git a/toolkit/components/extensions/test/mochitest/test_ext_simple.html b/toolkit/components/extensions/test/xpcshell/test_ext_simple.js similarity index 55% rename from toolkit/components/extensions/test/mochitest/test_ext_simple.html rename to toolkit/components/extensions/test/xpcshell/test_ext_simple.js index dd545d9c7e61..f91ec3c2c310 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_simple.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_simple.js @@ -1,16 +1,5 @@ - - - - Test for simple WebExtension - - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/xpcshell/xpcshell.ini b/toolkit/components/extensions/test/xpcshell/xpcshell.ini index 097a58776dae..e4f3d5f23e98 100644 --- a/toolkit/components/extensions/test/xpcshell/xpcshell.ini +++ b/toolkit/components/extensions/test/xpcshell/xpcshell.ini @@ -4,16 +4,25 @@ tail = firefox-appdir = browser skip-if = toolkit == 'gonk' || appname == "thunderbird" -[test_ext_alarms.js] [test_csp_custom_policies.js] [test_csp_validator.js] -[test_locale_data.js] -[test_locale_converter.js] +[test_ext_alarms.js] +[test_ext_background_runtime_connect_params.js] [test_ext_contexts.js] +[test_ext_extension.js] +[test_ext_idle.js] [test_ext_json_parser.js] [test_ext_manifest_content_security_policy.js] [test_ext_manifest_incognito.js] +[test_ext_onmessage_removelistener.js] +[test_ext_runtime_connect_no_receiver.js] +[test_ext_runtime_getPlatformInfo.js] +[test_ext_runtime_sendMessage.js] +[test_ext_runtime_sendMessage_no_receiver.js] [test_ext_schemas.js] +[test_ext_simple.js] [test_getAPILevelForWindow.js] +[test_locale_converter.js] +[test_locale_data.js] [test_native_messaging.js] skip-if = os == "android" From 4a132af371b5b719d184bc875858abcbaccb5a18 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Wed, 27 Jul 2016 21:47:53 -0700 Subject: [PATCH 051/120] Bug 1288885: Migrate localStorage mochitests to xpcshell. r=aswan MozReview-Commit-ID: 1sjpnsKYEv5 --HG-- rename : toolkit/components/extensions/test/mochitest/test_ext_localStorage.html => toolkit/components/extensions/test/xpcshell/test_ext_localStorage.js extra : source : 8f9b353347181aba8d2c5bbb8357251031367b27 --- .../extensions/test/mochitest/mochitest.ini | 1 - .../test_ext_localStorage.js} | 31 ++++++------------- .../extensions/test/xpcshell/xpcshell.ini | 1 + 3 files changed, 11 insertions(+), 22 deletions(-) rename toolkit/components/extensions/test/{mochitest/test_ext_localStorage.html => xpcshell/test_ext_localStorage.js} (56%) diff --git a/toolkit/components/extensions/test/mochitest/mochitest.ini b/toolkit/components/extensions/test/mochitest/mochitest.ini index e370f5560873..1f7ffb7fd045 100644 --- a/toolkit/components/extensions/test/mochitest/mochitest.ini +++ b/toolkit/components/extensions/test/mochitest/mochitest.ini @@ -52,7 +52,6 @@ skip-if = buildapp == 'b2g' # runat != document_idle is not supported. [test_ext_exclude_include_globs.html] [test_ext_i18n_css.html] [test_ext_generate.html] -[test_ext_localStorage.html] [test_ext_notifications.html] [test_ext_permission_xhr.html] skip-if = buildapp == 'b2g' # JavaScript error: jar:remoteopenfile:///data/local/tmp/generated-extension.xpi!/content.js, line 46: NS_ERROR_ILLEGAL_VALUE: diff --git a/toolkit/components/extensions/test/mochitest/test_ext_localStorage.html b/toolkit/components/extensions/test/xpcshell/test_ext_localStorage.js similarity index 56% rename from toolkit/components/extensions/test/mochitest/test_ext_localStorage.html rename to toolkit/components/extensions/test/xpcshell/test_ext_localStorage.js index 31119cb70b05..885df5990e45 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_localStorage.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_localStorage.js @@ -1,16 +1,5 @@ - - - - WebExtension test - - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/xpcshell/xpcshell.ini b/toolkit/components/extensions/test/xpcshell/xpcshell.ini index e4f3d5f23e98..4f74d42620f8 100644 --- a/toolkit/components/extensions/test/xpcshell/xpcshell.ini +++ b/toolkit/components/extensions/test/xpcshell/xpcshell.ini @@ -12,6 +12,7 @@ skip-if = toolkit == 'gonk' || appname == "thunderbird" [test_ext_extension.js] [test_ext_idle.js] [test_ext_json_parser.js] +[test_ext_localStorage.js] [test_ext_manifest_content_security_policy.js] [test_ext_manifest_incognito.js] [test_ext_onmessage_removelistener.js] From f6052f7eae0ff7435c57048fd307d284d3574c10 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Fri, 22 Jul 2016 17:29:52 -0700 Subject: [PATCH 052/120] Bug 1288885: Migrate bookmarks mochitests to xpcshell. r=aswan MozReview-Commit-ID: 9PFJcqXXxhU --HG-- rename : toolkit/components/extensions/test/mochitest/test_ext_bookmarks.html => browser/components/extensions/test/xpcshell/test_ext_bookmarks.js extra : source : 8c67ff2971ecc155ce26dc5d9905c5de7e4bfd4b --- .../test/xpcshell/test_ext_bookmarks.js | 26 ++++--------------- .../extensions/test/xpcshell/xpcshell.ini | 1 + .../extensions/test/mochitest/mochitest.ini | 2 -- .../extensions/test/xpcshell/head.js | 2 ++ 4 files changed, 8 insertions(+), 23 deletions(-) rename toolkit/components/extensions/test/mochitest/test_ext_bookmarks.html => browser/components/extensions/test/xpcshell/test_ext_bookmarks.js (96%) diff --git a/toolkit/components/extensions/test/mochitest/test_ext_bookmarks.html b/browser/components/extensions/test/xpcshell/test_ext_bookmarks.js similarity index 96% rename from toolkit/components/extensions/test/mochitest/test_ext_bookmarks.html rename to browser/components/extensions/test/xpcshell/test_ext_bookmarks.js index 6157f98e093a..fce99b761bd0 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_bookmarks.html +++ b/browser/components/extensions/test/xpcshell/test_ext_bookmarks.js @@ -1,16 +1,5 @@ - - - - WebExtension test - - - - - - - - - - - - diff --git a/browser/components/extensions/test/xpcshell/xpcshell.ini b/browser/components/extensions/test/xpcshell/xpcshell.ini index 29749bb80fd5..cd06f185970f 100644 --- a/browser/components/extensions/test/xpcshell/xpcshell.ini +++ b/browser/components/extensions/test/xpcshell/xpcshell.ini @@ -3,4 +3,5 @@ head = head.js tail = firefox-appdir = browser +[test_ext_bookmarks.js] [test_ext_manifest_commands.js] diff --git a/toolkit/components/extensions/test/mochitest/mochitest.ini b/toolkit/components/extensions/test/mochitest/mochitest.ini index 1f7ffb7fd045..299be2be6266 100644 --- a/toolkit/components/extensions/test/mochitest/mochitest.ini +++ b/toolkit/components/extensions/test/mochitest/mochitest.ini @@ -75,8 +75,6 @@ skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2 [test_ext_storage_tab.html] skip-if = os == 'android' # Android does not currently support tabs. [test_ext_cookies.html] -[test_ext_bookmarks.html] -skip-if = (os == 'android' || buildapp == 'b2g') # unimplemented api. Bug 1258975 on android. [test_ext_background_window_properties.html] [test_ext_background_sub_windows.html] [test_ext_background_api_injection.html] diff --git a/toolkit/components/extensions/test/xpcshell/head.js b/toolkit/components/extensions/test/xpcshell/head.js index f427a1cec116..e23c674e2dac 100644 --- a/toolkit/components/extensions/test/xpcshell/head.js +++ b/toolkit/components/extensions/test/xpcshell/head.js @@ -8,6 +8,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "Extension", "resource://gre/modules/Extension.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "ExtensionData", "resource://gre/modules/Extension.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "ExtensionManagement", + "resource://gre/modules/ExtensionManagement.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "ExtensionTestUtils", "resource://testing-common/ExtensionXPCShellUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", From 5f6ca9beb6dcb98dd535ce510d60d07039d83848 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Fri, 22 Jul 2016 17:32:31 -0700 Subject: [PATCH 053/120] Bug 1288885: Migrate storage mochitests to xpcshell. r=aswan MozReview-Commit-ID: 1DYgv3LNDOW --HG-- rename : toolkit/components/extensions/test/mochitest/test_ext_storage.html => toolkit/components/extensions/test/xpcshell/test_ext_storage.js extra : source : d520f1245f5c43d6ca9d4c60684db344e183b0d0 --- .../extensions/test/mochitest/mochitest.ini | 1 - .../test_ext_storage.js} | 26 +++++-------------- .../extensions/test/xpcshell/xpcshell.ini | 1 + 3 files changed, 7 insertions(+), 21 deletions(-) rename toolkit/components/extensions/test/{mochitest/test_ext_storage.html => xpcshell/test_ext_storage.js} (91%) diff --git a/toolkit/components/extensions/test/mochitest/mochitest.ini b/toolkit/components/extensions/test/mochitest/mochitest.ini index 299be2be6266..9b70a0fd3ea5 100644 --- a/toolkit/components/extensions/test/mochitest/mochitest.ini +++ b/toolkit/components/extensions/test/mochitest/mochitest.ini @@ -70,7 +70,6 @@ skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2 skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2g. Bug 1258975 on android. [test_ext_sendmessage_doublereply.html] skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2g. Bug 1258975 on android. -[test_ext_storage.html] [test_ext_storage_content.html] [test_ext_storage_tab.html] skip-if = os == 'android' # Android does not currently support tabs. diff --git a/toolkit/components/extensions/test/mochitest/test_ext_storage.html b/toolkit/components/extensions/test/xpcshell/test_ext_storage.js similarity index 91% rename from toolkit/components/extensions/test/mochitest/test_ext_storage.html rename to toolkit/components/extensions/test/xpcshell/test_ext_storage.js index bc19d8e731cb..98868f815de9 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_storage.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_storage.js @@ -1,16 +1,5 @@ - - - - WebExtension test - - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/xpcshell/xpcshell.ini b/toolkit/components/extensions/test/xpcshell/xpcshell.ini index 4f74d42620f8..cf36d4427c84 100644 --- a/toolkit/components/extensions/test/xpcshell/xpcshell.ini +++ b/toolkit/components/extensions/test/xpcshell/xpcshell.ini @@ -22,6 +22,7 @@ skip-if = toolkit == 'gonk' || appname == "thunderbird" [test_ext_runtime_sendMessage_no_receiver.js] [test_ext_schemas.js] [test_ext_simple.js] +[test_ext_storage.js] [test_getAPILevelForWindow.js] [test_locale_converter.js] [test_locale_data.js] From 6faa8711527a21b9cf1cfcbbb010c5f52ef13a15 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Fri, 22 Jul 2016 18:49:50 -0700 Subject: [PATCH 054/120] Bug 1288885: Migrate downloads mochitests to xpcshell. r=aswan MozReview-Commit-ID: Z67uTNUcqD --HG-- rename : toolkit/components/extensions/test/mochitest/file_download.html => toolkit/components/extensions/test/xpcshell/data/file_download.html rename : toolkit/components/extensions/test/mochitest/file_download.txt => toolkit/components/extensions/test/xpcshell/data/file_download.txt rename : toolkit/components/extensions/test/mochitest/test_ext_downloads.html => toolkit/components/extensions/test/xpcshell/test_ext_downloads.js rename : toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_download.html => toolkit/components/extensions/test/xpcshell/test_ext_downloads_download.js rename : toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_misc.html => toolkit/components/extensions/test/xpcshell/test_ext_downloads_misc.js rename : toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_search.html => toolkit/components/extensions/test/xpcshell/test_ext_downloads_search.js extra : source : abd51b3d2b52da0669680153e5321b9b843d6cd2 extra : histedit_source : b47606b4c1bc828ed445689f57ff600db69e1ad7 --- .../extensions/test/mochitest/chrome.ini | 6 - .../test/mochitest/interruptible.sjs | 38 -- .../extensions/test/mochitest/mochitest.ini | 2 - .../data}/file_download.html | 0 .../data}/file_download.txt | 0 .../extensions/test/xpcshell/head.js | 32 ++ .../test_ext_downloads.js} | 55 +-- .../test_ext_downloads_download.js} | 83 ++-- .../test_ext_downloads_misc.js} | 353 ++++++++++-------- .../test_ext_downloads_search.js} | 62 ++- .../extensions/test/xpcshell/xpcshell.ini | 9 + 11 files changed, 310 insertions(+), 330 deletions(-) delete mode 100644 toolkit/components/extensions/test/mochitest/interruptible.sjs rename toolkit/components/extensions/test/{mochitest => xpcshell/data}/file_download.html (100%) rename toolkit/components/extensions/test/{mochitest => xpcshell/data}/file_download.txt (100%) rename toolkit/components/extensions/test/{mochitest/test_ext_downloads.html => xpcshell/test_ext_downloads.js} (55%) rename toolkit/components/extensions/test/{mochitest/test_chrome_ext_downloads_download.html => xpcshell/test_ext_downloads_download.js} (69%) rename toolkit/components/extensions/test/{mochitest/test_chrome_ext_downloads_misc.html => xpcshell/test_ext_downloads_misc.js} (61%) rename toolkit/components/extensions/test/{mochitest/test_chrome_ext_downloads_search.html => xpcshell/test_ext_downloads_search.js} (89%) diff --git a/toolkit/components/extensions/test/mochitest/chrome.ini b/toolkit/components/extensions/test/mochitest/chrome.ini index fb0fa4c7e78d..fd42402e5c3b 100644 --- a/toolkit/components/extensions/test/mochitest/chrome.ini +++ b/toolkit/components/extensions/test/mochitest/chrome.ini @@ -2,18 +2,12 @@ support-files = chrome_head.js head.js - file_download.html - file_download.txt - interruptible.sjs file_sample.html [test_chrome_ext_background_debug_global.html] skip-if = (os == 'android') # android doesn't have devtools [test_chrome_ext_background_page.html] skip-if = (toolkit == 'android') # android doesn't have devtools -[test_chrome_ext_downloads_download.html] -[test_chrome_ext_downloads_misc.html] -[test_chrome_ext_downloads_search.html] [test_chrome_ext_eventpage_warning.html] [test_chrome_ext_native_messaging.html] skip-if = os == "android" # native messaging is not supported on android diff --git a/toolkit/components/extensions/test/mochitest/interruptible.sjs b/toolkit/components/extensions/test/mochitest/interruptible.sjs deleted file mode 100644 index eb81646d7025..000000000000 --- a/toolkit/components/extensions/test/mochitest/interruptible.sjs +++ /dev/null @@ -1,38 +0,0 @@ -const TEST_DATA = "This is 31 bytes of sample data"; -const TOTAL_LEN = TEST_DATA.length; -const PARTIAL_LEN = 15; - -// A handler to let us systematically test pausing/resuming/canceling -// of downloads. This target represents a small text file but a simple -// GET will stall after sending part of the data, to give the test code -// a chance to pause or do other operations on an in-progress download. -// A resumed download (ie, a GET with a Range: header) will allow the -// download to complete. -function handleRequest(request, response) { - response.setHeader("Content-Type", "text/plain", false); - - if (request.hasHeader("Range")) { - let start, end; - let matches = request.getHeader("Range") - .match(/^\s*bytes=(\d+)?-(\d+)?\s*$/); - if (matches != null) { - start = matches[1] ? parseInt(matches[1], 10) : 0; - end = matches[2] ? pareInt(matchs[2], 10) : (TOTAL_LEN - 1); - } - - if (end == undefined || end >= TOTAL_LEN) { - response.setStatusLine(request.httpVersion, 416, "Requested Range Not Satisfiable"); - response.setHeader("Content-Range", `*/${TOTAL_LEN}`, false); - response.finish(); - return; - } - - response.setStatusLine(request.httpVersion, 206, "Partial Content"); - response.setHeader("Content-Range", `${start}-${end}/${TOTAL_LEN}`, false); - response.write(TEST_DATA.slice(start, end + 1)); - } else { - response.processAsync(); - response.setHeader("Content-Length", `${TOTAL_LEN}`, false); - response.write(TEST_DATA.slice(0, PARTIAL_LEN)); - } -} diff --git a/toolkit/components/extensions/test/mochitest/mochitest.ini b/toolkit/components/extensions/test/mochitest/mochitest.ini index 9b70a0fd3ea5..44351c29b218 100644 --- a/toolkit/components/extensions/test/mochitest/mochitest.ini +++ b/toolkit/components/extensions/test/mochitest/mochitest.ini @@ -34,7 +34,6 @@ support-files = file_privilege_escalation.html file_ext_test_api_injection.js file_permission_xhr.html - file_download.txt [test_ext_inIncognitoContext_window.html] skip-if = os == 'android' # Android does not currently support windows. @@ -48,7 +47,6 @@ skip-if = buildapp == 'b2g' # runat != document_idle is not supported. [test_ext_contentscript_devtools_metadata.html] [test_ext_contentscript_exporthelpers.html] [test_ext_contentscript_css.html] -[test_ext_downloads.html] [test_ext_exclude_include_globs.html] [test_ext_i18n_css.html] [test_ext_generate.html] diff --git a/toolkit/components/extensions/test/mochitest/file_download.html b/toolkit/components/extensions/test/xpcshell/data/file_download.html similarity index 100% rename from toolkit/components/extensions/test/mochitest/file_download.html rename to toolkit/components/extensions/test/xpcshell/data/file_download.html diff --git a/toolkit/components/extensions/test/mochitest/file_download.txt b/toolkit/components/extensions/test/xpcshell/data/file_download.txt similarity index 100% rename from toolkit/components/extensions/test/mochitest/file_download.txt rename to toolkit/components/extensions/test/xpcshell/data/file_download.txt diff --git a/toolkit/components/extensions/test/xpcshell/head.js b/toolkit/components/extensions/test/xpcshell/head.js index e23c674e2dac..5b8fb1230615 100644 --- a/toolkit/components/extensions/test/xpcshell/head.js +++ b/toolkit/components/extensions/test/xpcshell/head.js @@ -2,8 +2,12 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +/* exported createHttpServer */ + Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "AppConstants", + "resource://gre/modules/AppConstants.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Extension", "resource://gre/modules/Extension.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "ExtensionData", @@ -12,6 +16,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "ExtensionManagement", "resource://gre/modules/ExtensionManagement.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "ExtensionTestUtils", "resource://testing-common/ExtensionXPCShellUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", + "resource://gre/modules/FileUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "HttpServer", + "resource://testing-common/httpd.js"); XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Schemas", @@ -20,3 +28,27 @@ XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); ExtensionTestUtils.init(this); + +/** + * Creates a new HttpServer for testing, and begins listening on the + * specified port. Automatically shuts down the server when the test + * unit ends. + * + * @param {integer} [port] + * The port to listen on. If omitted, listen on a random + * port. The latter is the preferred behavior. + * + * @returns {HttpServer} + */ +function createHttpServer(port = -1) { + let server = new HttpServer(); + server.start(port); + + do_register_cleanup(() => { + return new Promise(resolve => { + server.stop(resolve); + }); + }); + + return server; +} diff --git a/toolkit/components/extensions/test/mochitest/test_ext_downloads.html b/toolkit/components/extensions/test/xpcshell/test_ext_downloads.js similarity index 55% rename from toolkit/components/extensions/test/mochitest/test_ext_downloads.html rename to toolkit/components/extensions/test/xpcshell/test_ext_downloads.js index 1ecc6b9fe016..5d0da2c92122 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_downloads.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_downloads.js @@ -1,34 +1,23 @@ - - - - WebExtension test - - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_download.html b/toolkit/components/extensions/test/xpcshell/test_ext_downloads_download.js similarity index 69% rename from toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_download.html rename to toolkit/components/extensions/test/xpcshell/test_ext_downloads_download.js index bf728b6e874d..6cd1132d3e48 100644 --- a/toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_download.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_downloads_download.js @@ -1,29 +1,18 @@ - - - - WebExtension test - - - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_misc.html b/toolkit/components/extensions/test/xpcshell/test_ext_downloads_misc.js similarity index 61% rename from toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_misc.html rename to toolkit/components/extensions/test/xpcshell/test_ext_downloads_misc.js index 1e48da9c0cdb..6e14bcc7889a 100644 --- a/toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_misc.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_downloads_misc.js @@ -1,23 +1,14 @@ - - - - WebExtension test - - - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_search.html b/toolkit/components/extensions/test/xpcshell/test_ext_downloads_search.js similarity index 89% rename from toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_search.html rename to toolkit/components/extensions/test/xpcshell/test_ext_downloads_search.js index 6cb6bf1984b9..0c9d555c5f4e 100644 --- a/toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_search.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_downloads_search.js @@ -1,23 +1,13 @@ - - - - WebExtension test - - - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/xpcshell/xpcshell.ini b/toolkit/components/extensions/test/xpcshell/xpcshell.ini index cf36d4427c84..448d03d63402 100644 --- a/toolkit/components/extensions/test/xpcshell/xpcshell.ini +++ b/toolkit/components/extensions/test/xpcshell/xpcshell.ini @@ -3,12 +3,21 @@ head = head.js tail = firefox-appdir = browser skip-if = toolkit == 'gonk' || appname == "thunderbird" +support-files = + data/** [test_csp_custom_policies.js] [test_csp_validator.js] [test_ext_alarms.js] [test_ext_background_runtime_connect_params.js] [test_ext_contexts.js] +[test_ext_downloads.js] +[test_ext_downloads_download.js] +skip-if = os == "android" +[test_ext_downloads_misc.js] +skip-if = os == "android" +[test_ext_downloads_search.js] +skip-if = os == "android" [test_ext_extension.js] [test_ext_idle.js] [test_ext_json_parser.js] From d8c6a793a6d39b2faaa9c89592e962299de5b3ed Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Fri, 22 Jul 2016 18:44:27 -0700 Subject: [PATCH 055/120] Bug 1288885: Migrate background page mochitests to xpcshell. r=aswan MozReview-Commit-ID: Fiv7sArlWDw --HG-- rename : toolkit/components/extensions/test/mochitest/test_ext_background_generated_load_events.html => toolkit/components/extensions/test/xpcshell/test_ext_background_generated_load_events.js rename : toolkit/components/extensions/test/mochitest/test_ext_background_generated_reload.html => toolkit/components/extensions/test/xpcshell/test_ext_background_generated_reload.js rename : toolkit/components/extensions/test/mochitest/test_ext_background_sub_windows.html => toolkit/components/extensions/test/xpcshell/test_ext_background_sub_windows.js rename : toolkit/components/extensions/test/mochitest/test_ext_background_window_properties.html => toolkit/components/extensions/test/xpcshell/test_ext_background_window_properties.js extra : source : fca55647234643b6fde3b62b3337e491432ab0dc extra : histedit_source : cfb3890a200c9e49a3480701c66b3c94e88495d0 --- .../extensions/test/mochitest/mochitest.ini | 4 -- ..._ext_background_generated_load_events.html | 47 ----------------- .../test_ext_background_generated_reload.html | 50 ------------------- ...st_ext_background_generated_load_events.js | 23 +++++++++ .../test_ext_background_generated_reload.js | 24 +++++++++ .../test_ext_background_sub_windows.js} | 28 ++--------- .../test_ext_background_window_properties.js} | 27 ++-------- .../extensions/test/xpcshell/xpcshell.ini | 5 ++ 8 files changed, 60 insertions(+), 148 deletions(-) delete mode 100644 toolkit/components/extensions/test/mochitest/test_ext_background_generated_load_events.html delete mode 100644 toolkit/components/extensions/test/mochitest/test_ext_background_generated_reload.html create mode 100644 toolkit/components/extensions/test/xpcshell/test_ext_background_generated_load_events.js create mode 100644 toolkit/components/extensions/test/xpcshell/test_ext_background_generated_reload.js rename toolkit/components/extensions/test/{mochitest/test_ext_background_sub_windows.html => xpcshell/test_ext_background_sub_windows.js} (59%) rename toolkit/components/extensions/test/{mochitest/test_ext_background_window_properties.html => xpcshell/test_ext_background_window_properties.js} (56%) diff --git a/toolkit/components/extensions/test/mochitest/mochitest.ini b/toolkit/components/extensions/test/mochitest/mochitest.ini index 44351c29b218..23a9daa5b0bb 100644 --- a/toolkit/components/extensions/test/mochitest/mochitest.ini +++ b/toolkit/components/extensions/test/mochitest/mochitest.ini @@ -72,12 +72,8 @@ skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2 [test_ext_storage_tab.html] skip-if = os == 'android' # Android does not currently support tabs. [test_ext_cookies.html] -[test_ext_background_window_properties.html] -[test_ext_background_sub_windows.html] [test_ext_background_api_injection.html] [test_ext_background_generated_url.html] -[test_ext_background_generated_reload.html] -[test_ext_background_generated_load_events.html] [test_ext_i18n.html] skip-if = (os == 'android') # Bug 1258975 on android. [test_ext_web_accessible_resources.html] diff --git a/toolkit/components/extensions/test/mochitest/test_ext_background_generated_load_events.html b/toolkit/components/extensions/test/mochitest/test_ext_background_generated_load_events.html deleted file mode 100644 index c9ffc4bf2c48..000000000000 --- a/toolkit/components/extensions/test/mochitest/test_ext_background_generated_load_events.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - Test load events in _generated_background_page.html - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/mochitest/test_ext_background_generated_reload.html b/toolkit/components/extensions/test/mochitest/test_ext_background_generated_reload.html deleted file mode 100644 index 25f93e67f27e..000000000000 --- a/toolkit/components/extensions/test/mochitest/test_ext_background_generated_reload.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - Test reload of _generated_background_page.html - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_background_generated_load_events.js b/toolkit/components/extensions/test/xpcshell/test_ext_background_generated_load_events.js new file mode 100644 index 000000000000..26282fcb9ab3 --- /dev/null +++ b/toolkit/components/extensions/test/xpcshell/test_ext_background_generated_load_events.js @@ -0,0 +1,23 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +/* eslint-disable mozilla/balanced-listeners */ + +add_task(function* test_DOMContentLoaded_in_generated_background_page() { + let extension = ExtensionTestUtils.loadExtension({ + background() { + function reportListener(event) { + browser.test.sendMessage("eventname", event.type); + } + document.addEventListener("DOMContentLoaded", reportListener); + window.addEventListener("load", reportListener); + }, + }); + + yield extension.startup(); + equal("DOMContentLoaded", yield extension.awaitMessage("eventname")); + equal("load", yield extension.awaitMessage("eventname")); + + yield extension.unload(); +}); diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_background_generated_reload.js b/toolkit/components/extensions/test/xpcshell/test_ext_background_generated_reload.js new file mode 100644 index 000000000000..4bf59b798978 --- /dev/null +++ b/toolkit/components/extensions/test/xpcshell/test_ext_background_generated_reload.js @@ -0,0 +1,24 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +add_task(function* test_reload_generated_background_page() { + let extension = ExtensionTestUtils.loadExtension({ + background() { + if (location.hash !== "#firstrun") { + browser.test.sendMessage("first run"); + location.hash = "#firstrun"; + browser.test.assertEq("#firstrun", location.hash); + location.reload(); + } else { + browser.test.notifyPass("second run"); + } + }, + }); + + yield extension.startup(); + yield extension.awaitMessage("first run"); + yield extension.awaitFinish("second run"); + + yield extension.unload(); +}); diff --git a/toolkit/components/extensions/test/mochitest/test_ext_background_sub_windows.html b/toolkit/components/extensions/test/xpcshell/test_ext_background_sub_windows.js similarity index 59% rename from toolkit/components/extensions/test/mochitest/test_ext_background_sub_windows.html rename to toolkit/components/extensions/test/xpcshell/test_ext_background_sub_windows.js index 951249f53d87..c5f2f1332cc3 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_background_sub_windows.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_background_sub_windows.js @@ -1,21 +1,10 @@ - - - - Test for sub-frames of WebExtension background pages - - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/mochitest/test_ext_background_window_properties.html b/toolkit/components/extensions/test/xpcshell/test_ext_background_window_properties.js similarity index 56% rename from toolkit/components/extensions/test/mochitest/test_ext_background_window_properties.html rename to toolkit/components/extensions/test/xpcshell/test_ext_background_window_properties.js index 8c8972f68ecc..948e2913ea1b 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_background_window_properties.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_background_window_properties.js @@ -1,21 +1,10 @@ - - - - Test for simple WebExtension - - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/xpcshell/xpcshell.ini b/toolkit/components/extensions/test/xpcshell/xpcshell.ini index 448d03d63402..ae86bf06af70 100644 --- a/toolkit/components/extensions/test/xpcshell/xpcshell.ini +++ b/toolkit/components/extensions/test/xpcshell/xpcshell.ini @@ -9,7 +9,12 @@ support-files = [test_csp_custom_policies.js] [test_csp_validator.js] [test_ext_alarms.js] +[test_ext_background_generated_load_events.js] +[test_ext_background_generated_reload.js] [test_ext_background_runtime_connect_params.js] +[test_ext_background_sub_windows.js] +[test_ext_background_window_properties.js] +skip-if = os == "android" [test_ext_contexts.js] [test_ext_downloads.js] [test_ext_downloads_download.js] From bd9082edf759858ae87e921503f0480c524181cd Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Fri, 22 Jul 2016 18:57:38 -0700 Subject: [PATCH 056/120] Bug 1288885: Migrate history mochitests to xpcshell. r=aswan MozReview-Commit-ID: tzQdEJx6TN --HG-- rename : browser/components/extensions/test/browser/browser_ext_history.js => browser/components/extensions/test/xpcshell/test_ext_history.js extra : source : eeb6bc8a42e69e989bb70cc6daf56296936f60b0 extra : histedit_source : cd90f8cfa3040588aa2847d4192bf3ba47edc33b --- .../extensions/test/browser/browser.ini | 1 - .../test_ext_history.js} | 58 +++++++++---------- .../extensions/test/xpcshell/xpcshell.ini | 1 + 3 files changed, 30 insertions(+), 30 deletions(-) rename browser/components/extensions/test/{browser/browser_ext_history.js => xpcshell/test_ext_history.js} (84%) diff --git a/browser/components/extensions/test/browser/browser.ini b/browser/components/extensions/test/browser/browser.ini index 52bba6612b48..c88d51c1ce03 100644 --- a/browser/components/extensions/test/browser/browser.ini +++ b/browser/components/extensions/test/browser/browser.ini @@ -35,7 +35,6 @@ support-files = [browser_ext_contextMenus_urlPatterns.js] [browser_ext_currentWindow.js] [browser_ext_getViews.js] -[browser_ext_history.js] [browser_ext_incognito_popup.js] [browser_ext_lastError.js] [browser_ext_optionsPage_privileges.js] diff --git a/browser/components/extensions/test/browser/browser_ext_history.js b/browser/components/extensions/test/xpcshell/test_ext_history.js similarity index 84% rename from browser/components/extensions/test/browser/browser_ext_history.js rename to browser/components/extensions/test/xpcshell/test_ext_history.js index 6b1c2fc87210..29325e2a69a3 100644 --- a/browser/components/extensions/test/browser/browser_ext_history.js +++ b/browser/components/extensions/test/xpcshell/test_ext_history.js @@ -85,14 +85,14 @@ add_task(function* test_delete() { } yield PlacesUtils.history.insertMany(visits); - is(yield PlacesTestUtils.visitsInDB(visits[0].url), 5, "5 visits for uri found in history database"); + equal((yield PlacesTestUtils.visitsInDB(visits[0].url)), 5, "5 visits for uri found in history database"); let testUrl = visits[2].url; - ok(yield PlacesTestUtils.isPageInDB(testUrl), "expected url found in history database"); + ok((yield PlacesTestUtils.isPageInDB(testUrl)), "expected url found in history database"); extension.sendMessage("delete-url", testUrl); yield extension.awaitMessage("url-deleted"); - is(yield PlacesTestUtils.isPageInDB(testUrl), false, "expected url not found in history database"); + equal((yield PlacesTestUtils.isPageInDB(testUrl)), false, "expected url not found in history database"); // delete 3 of the 5 visits for url 1 let filter = { @@ -103,10 +103,10 @@ add_task(function* test_delete() { extension.sendMessage("delete-range", filter); let removedUrls = yield extension.awaitMessage("range-deleted"); ok(!removedUrls.includes(visits[0].url), `${visits[0].url} not received by onVisitRemoved`); - ok(yield PlacesTestUtils.isPageInDB(visits[0].url), "expected uri found in history database"); - is(yield PlacesTestUtils.visitsInDB(visits[0].url), 2, "2 visits for uri found in history database"); - ok(yield PlacesTestUtils.isPageInDB(visits[1].url), "expected uri found in history database"); - is(yield PlacesTestUtils.visitsInDB(visits[1].url), 1, "1 visit for uri found in history database"); + ok((yield PlacesTestUtils.isPageInDB(visits[0].url)), "expected uri found in history database"); + equal((yield PlacesTestUtils.visitsInDB(visits[0].url)), 2, "2 visits for uri found in history database"); + ok((yield PlacesTestUtils.isPageInDB(visits[1].url)), "expected uri found in history database"); + equal((yield PlacesTestUtils.visitsInDB(visits[1].url)), 1, "1 visit for uri found in history database"); // delete the rest of the visits for url 1, and the visit for url 2 filter.startTime = visits[0].visits[0].date; @@ -115,18 +115,18 @@ add_task(function* test_delete() { extension.sendMessage("delete-range", filter); yield extension.awaitMessage("range-deleted"); - is(yield PlacesTestUtils.isPageInDB(visits[0].url), false, "expected uri not found in history database"); - is(yield PlacesTestUtils.visitsInDB(visits[0].url), 0, "0 visits for uri found in history database"); - is(yield PlacesTestUtils.isPageInDB(visits[1].url), false, "expected uri not found in history database"); - is(yield PlacesTestUtils.visitsInDB(visits[1].url), 0, "0 visits for uri found in history database"); + equal((yield PlacesTestUtils.isPageInDB(visits[0].url)), false, "expected uri not found in history database"); + equal((yield PlacesTestUtils.visitsInDB(visits[0].url)), 0, "0 visits for uri found in history database"); + equal((yield PlacesTestUtils.isPageInDB(visits[1].url)), false, "expected uri not found in history database"); + equal((yield PlacesTestUtils.visitsInDB(visits[1].url)), 0, "0 visits for uri found in history database"); - ok(yield PlacesTestUtils.isPageInDB(visits[3].url), "expected uri found in history database"); + ok((yield PlacesTestUtils.isPageInDB(visits[3].url)), "expected uri found in history database"); extension.sendMessage("delete-all"); [historyClearedCount, removedUrls] = yield extension.awaitMessage("history-cleared"); - is(PlacesUtils.history.hasHistoryEntries, false, "history is empty"); - is(historyClearedCount, 2, "onVisitRemoved called for each clearing of history"); - is(removedUrls.length, 3, "onVisitRemoved called the expected number of times"); + equal(PlacesUtils.history.hasHistoryEntries, false, "history is empty"); + equal(historyClearedCount, 2, "onVisitRemoved called for each clearing of history"); + equal(removedUrls.length, 3, "onVisitRemoved called the expected number of times"); for (let i = 1; i < 3; ++i) { let url = visits[i].url; ok(removedUrls.includes(url), `${url} received by onVisitRemoved`); @@ -215,9 +215,9 @@ add_task(function* test_search() { function checkResult(results, url, expectedCount) { let result = findResult(url, results); - isnot(result, null, `history.search result was found for ${url}`); - is(result.visitCount, expectedCount, `history.search reports ${expectedCount} visit(s)`); - is(result.title, `test visit for ${url}`, "title for search result is correct"); + notEqual(result, null, `history.search result was found for ${url}`); + equal(result.visitCount, expectedCount, `history.search reports ${expectedCount} visit(s)`); + equal(result.title, `test visit for ${url}`, "title for search result is correct"); } yield extension.startup(); @@ -229,21 +229,21 @@ add_task(function* test_search() { extension.sendMessage("check-history"); let results = yield extension.awaitMessage("empty-search"); - is(results.length, 3, "history.search with empty text returned 3 results"); + equal(results.length, 3, "history.search with empty text returned 3 results"); checkResult(results, SINGLE_VISIT_URL, 1); checkResult(results, DOUBLE_VISIT_URL, 2); checkResult(results, MOZILLA_VISIT_URL, 1); results = yield extension.awaitMessage("text-search"); - is(results.length, 1, "history.search with specific text returned 1 result"); + equal(results.length, 1, "history.search with specific text returned 1 result"); checkResult(results, MOZILLA_VISIT_URL, 1); results = yield extension.awaitMessage("max-results-search"); - is(results.length, 1, "history.search with maxResults returned 1 result"); + equal(results.length, 1, "history.search with maxResults returned 1 result"); checkResult(results, DOUBLE_VISIT_URL, 2); results = yield extension.awaitMessage("date-range-search"); - is(results.length, 2, "history.search with a date range returned 2 result"); + equal(results.length, 2, "history.search with a date range returned 2 result"); checkResult(results, DOUBLE_VISIT_URL, 2); checkResult(results, SINGLE_VISIT_URL, 1); @@ -300,11 +300,11 @@ add_task(function* test_add_url() { ]; function* checkUrl(results) { - ok(yield PlacesTestUtils.isPageInDB(results.details.url), `${results.details.url} found in history database`); + ok((yield PlacesTestUtils.isPageInDB(results.details.url)), `${results.details.url} found in history database`); ok(PlacesUtils.isValidGuid(results.result.id), "URL was added with a valid id"); - is(results.result.title, results.details.title, "URL was added with the correct title"); + equal(results.result.title, results.details.title, "URL was added with the correct title"); if (results.details.visitTime) { - is(results.result.lastVisitTime, + equal(results.result.lastVisitTime, Number(ExtensionUtils.normalizeTime(results.details.visitTime)), "URL was added with the correct date"); } @@ -458,12 +458,12 @@ add_task(function* test_on_visited() { function checkOnVisitedData(index, expected) { let onVisited = onVisitedData[index]; ok(PlacesUtils.isValidGuid(onVisited.id), "onVisited received a valid id"); - is(onVisited.url, expected.url, "onVisited received the expected url"); + equal(onVisited.url, expected.url, "onVisited received the expected url"); // Title will be blank until bug 1287928 lands // https://bugzilla.mozilla.org/show_bug.cgi?id=1287928 - is(onVisited.title, "", "onVisited received a blank title"); - is(onVisited.lastVisitTime, expected.time, "onVisited received the expected time"); - is(onVisited.visitCount, expected.visitCount, "onVisited received the expected visitCount"); + equal(onVisited.title, "", "onVisited received a blank title"); + equal(onVisited.lastVisitTime, expected.time, "onVisited received the expected time"); + equal(onVisited.visitCount, expected.visitCount, "onVisited received the expected visitCount"); } let expected = { diff --git a/browser/components/extensions/test/xpcshell/xpcshell.ini b/browser/components/extensions/test/xpcshell/xpcshell.ini index cd06f185970f..db4934d23d5f 100644 --- a/browser/components/extensions/test/xpcshell/xpcshell.ini +++ b/browser/components/extensions/test/xpcshell/xpcshell.ini @@ -4,4 +4,5 @@ tail = firefox-appdir = browser [test_ext_bookmarks.js] +[test_ext_history.js] [test_ext_manifest_commands.js] From b164732faf8e789bbf22df2ab9c0c77599b80e10 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Fri, 22 Jul 2016 19:29:58 -0700 Subject: [PATCH 057/120] Bug 1288885: Split out the longest-running alarm tasks into separate units. r=aswan MozReview-Commit-ID: GwnRd6gncGI --HG-- rename : toolkit/components/extensions/test/xpcshell/test_ext_alarms.js => toolkit/components/extensions/test/xpcshell/test_ext_alarms_does_not_fire.js rename : toolkit/components/extensions/test/xpcshell/test_ext_alarms.js => toolkit/components/extensions/test/xpcshell/test_ext_alarms_periodic.js rename : toolkit/components/extensions/test/xpcshell/test_ext_alarms.js => toolkit/components/extensions/test/xpcshell/test_ext_alarms_replaces.js extra : source : 43cf27f0e2edb5136c1fa3fe415841f52ee62ec9 extra : histedit_source : 02fd17b1bacd8621c4b27394543d81f66bdb80c8 --- .../test/xpcshell/test_ext_alarms.js | 113 ------------------ .../xpcshell/test_ext_alarms_does_not_fire.js | 33 +++++ .../test/xpcshell/test_ext_alarms_periodic.js | 43 +++++++ .../test/xpcshell/test_ext_alarms_replaces.js | 45 +++++++ .../extensions/test/xpcshell/xpcshell.ini | 3 + 5 files changed, 124 insertions(+), 113 deletions(-) create mode 100644 toolkit/components/extensions/test/xpcshell/test_ext_alarms_does_not_fire.js create mode 100644 toolkit/components/extensions/test/xpcshell/test_ext_alarms_periodic.js create mode 100644 toolkit/components/extensions/test/xpcshell/test_ext_alarms_replaces.js diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_alarms.js b/toolkit/components/extensions/test/xpcshell/test_ext_alarms.js index 002f919d73c5..b81750410a3a 100644 --- a/toolkit/components/extensions/test/xpcshell/test_ext_alarms.js +++ b/toolkit/components/extensions/test/xpcshell/test_ext_alarms.js @@ -57,37 +57,6 @@ add_task(function* test_alarm_fires() { }); -add_task(function* test_cleared_alarm_does_not_fire() { - function backgroundScript() { - let ALARM_NAME = "test_ext_alarms"; - - browser.alarms.onAlarm.addListener(alarm => { - browser.test.fail("cleared alarm does not fire"); - browser.test.notifyFail("alarm-cleared"); - }); - browser.alarms.create(ALARM_NAME, {when: Date.now() + 1000}); - - browser.alarms.clear(ALARM_NAME).then(wasCleared => { - browser.test.assertTrue(wasCleared, "alarm was cleared"); - setTimeout(() => { - browser.test.notifyPass("alarm-cleared"); - }, 2000); - }); - } - - let extension = ExtensionTestUtils.loadExtension({ - background: `(${backgroundScript})()`, - manifest: { - permissions: ["alarms"], - }, - }); - - yield extension.startup(); - yield extension.awaitFinish("alarm-cleared"); - yield extension.unload(); -}); - - add_task(function* test_alarm_fires_with_when() { function backgroundScript() { let ALARM_NAME = "test_ext_alarms"; @@ -180,47 +149,6 @@ add_task(function* test_alarm_get_and_clear_single_argument() { }); -add_task(function* test_periodic_alarm_fires() { - function backgroundScript() { - const ALARM_NAME = "test_ext_alarms"; - let count = 0; - let timer; - - browser.alarms.onAlarm.addListener(alarm => { - browser.test.assertEq(alarm.name, ALARM_NAME, "alarm has the expected name"); - if (count++ === 3) { - clearTimeout(timer); - browser.alarms.clear(ALARM_NAME).then(wasCleared => { - browser.test.assertTrue(wasCleared, "alarm was cleared"); - browser.test.notifyPass("alarm-periodic"); - }); - } - }); - - browser.alarms.create(ALARM_NAME, {periodInMinutes: 0.02}); - - timer = setTimeout(() => { - browser.test.fail("alarm fired expected number of times"); - browser.alarms.clear(ALARM_NAME).then(wasCleared => { - browser.test.assertTrue(wasCleared, "alarm was cleared"); - }); - browser.test.notifyFail("alarm-periodic"); - }, 30000); - } - - let extension = ExtensionTestUtils.loadExtension({ - background: `(${backgroundScript})()`, - manifest: { - permissions: ["alarms"], - }, - }); - - yield extension.startup(); - yield extension.awaitFinish("alarm-periodic"); - yield extension.unload(); -}); - - add_task(function* test_get_get_all_clear_all_alarms() { function backgroundScript() { const ALARM_NAME = "test_alarm"; @@ -291,44 +219,3 @@ add_task(function* test_get_get_all_clear_all_alarms() { ]); yield extension.unload(); }); - -add_task(function* test_duplicate_alarm_name_replaces_alarm() { - function backgroundScript() { - let count = 0; - - browser.alarms.onAlarm.addListener(alarm => { - if (alarm.name === "master alarm") { - browser.alarms.create("child alarm", {delayInMinutes: 0.05}); - browser.alarms.getAll().then(results => { - browser.test.assertEq(2, results.length, "exactly two alarms exist"); - browser.test.assertEq("master alarm", results[0].name, "first alarm has the expected name"); - browser.test.assertEq("child alarm", results[1].name, "second alarm has the expected name"); - }).then(() => { - if (count++ === 3) { - browser.alarms.clear("master alarm").then(wasCleared => { - return browser.alarms.clear("child alarm"); - }).then(wasCleared => { - browser.test.notifyPass("alarm-duplicate"); - }); - } - }); - } else { - browser.test.fail("duplicate named alarm replaced existing alarm"); - browser.test.notifyFail("alarm-duplicate"); - } - }); - - browser.alarms.create("master alarm", {delayInMinutes: 0.025, periodInMinutes: 0.025}); - } - - let extension = ExtensionTestUtils.loadExtension({ - background: `(${backgroundScript})()`, - manifest: { - permissions: ["alarms"], - }, - }); - - yield extension.startup(); - yield extension.awaitFinish("alarm-duplicate"); - yield extension.unload(); -}); diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_alarms_does_not_fire.js b/toolkit/components/extensions/test/xpcshell/test_ext_alarms_does_not_fire.js new file mode 100644 index 000000000000..57abee26cfc4 --- /dev/null +++ b/toolkit/components/extensions/test/xpcshell/test_ext_alarms_does_not_fire.js @@ -0,0 +1,33 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +add_task(function* test_cleared_alarm_does_not_fire() { + function backgroundScript() { + let ALARM_NAME = "test_ext_alarms"; + + browser.alarms.onAlarm.addListener(alarm => { + browser.test.fail("cleared alarm does not fire"); + browser.test.notifyFail("alarm-cleared"); + }); + browser.alarms.create(ALARM_NAME, {when: Date.now() + 1000}); + + browser.alarms.clear(ALARM_NAME).then(wasCleared => { + browser.test.assertTrue(wasCleared, "alarm was cleared"); + setTimeout(() => { + browser.test.notifyPass("alarm-cleared"); + }, 2000); + }); + } + + let extension = ExtensionTestUtils.loadExtension({ + background: `(${backgroundScript})()`, + manifest: { + permissions: ["alarms"], + }, + }); + + yield extension.startup(); + yield extension.awaitFinish("alarm-cleared"); + yield extension.unload(); +}); diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_alarms_periodic.js b/toolkit/components/extensions/test/xpcshell/test_ext_alarms_periodic.js new file mode 100644 index 000000000000..8aac7f64b628 --- /dev/null +++ b/toolkit/components/extensions/test/xpcshell/test_ext_alarms_periodic.js @@ -0,0 +1,43 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +add_task(function* test_periodic_alarm_fires() { + function backgroundScript() { + const ALARM_NAME = "test_ext_alarms"; + let count = 0; + let timer; + + browser.alarms.onAlarm.addListener(alarm => { + browser.test.assertEq(alarm.name, ALARM_NAME, "alarm has the expected name"); + if (count++ === 3) { + clearTimeout(timer); + browser.alarms.clear(ALARM_NAME).then(wasCleared => { + browser.test.assertTrue(wasCleared, "alarm was cleared"); + browser.test.notifyPass("alarm-periodic"); + }); + } + }); + + browser.alarms.create(ALARM_NAME, {periodInMinutes: 0.02}); + + timer = setTimeout(() => { + browser.test.fail("alarm fired expected number of times"); + browser.alarms.clear(ALARM_NAME).then(wasCleared => { + browser.test.assertTrue(wasCleared, "alarm was cleared"); + }); + browser.test.notifyFail("alarm-periodic"); + }, 30000); + } + + let extension = ExtensionTestUtils.loadExtension({ + background: `(${backgroundScript})()`, + manifest: { + permissions: ["alarms"], + }, + }); + + yield extension.startup(); + yield extension.awaitFinish("alarm-periodic"); + yield extension.unload(); +}); diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_alarms_replaces.js b/toolkit/components/extensions/test/xpcshell/test_ext_alarms_replaces.js new file mode 100644 index 000000000000..5070fc50678e --- /dev/null +++ b/toolkit/components/extensions/test/xpcshell/test_ext_alarms_replaces.js @@ -0,0 +1,45 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + + +add_task(function* test_duplicate_alarm_name_replaces_alarm() { + function backgroundScript() { + let count = 0; + + browser.alarms.onAlarm.addListener(alarm => { + if (alarm.name === "master alarm") { + browser.alarms.create("child alarm", {delayInMinutes: 0.05}); + browser.alarms.getAll().then(results => { + browser.test.assertEq(2, results.length, "exactly two alarms exist"); + browser.test.assertEq("master alarm", results[0].name, "first alarm has the expected name"); + browser.test.assertEq("child alarm", results[1].name, "second alarm has the expected name"); + }).then(() => { + if (count++ === 3) { + browser.alarms.clear("master alarm").then(wasCleared => { + return browser.alarms.clear("child alarm"); + }).then(wasCleared => { + browser.test.notifyPass("alarm-duplicate"); + }); + } + }); + } else { + browser.test.fail("duplicate named alarm replaced existing alarm"); + browser.test.notifyFail("alarm-duplicate"); + } + }); + + browser.alarms.create("master alarm", {delayInMinutes: 0.025, periodInMinutes: 0.025}); + } + + let extension = ExtensionTestUtils.loadExtension({ + background: `(${backgroundScript})()`, + manifest: { + permissions: ["alarms"], + }, + }); + + yield extension.startup(); + yield extension.awaitFinish("alarm-duplicate"); + yield extension.unload(); +}); diff --git a/toolkit/components/extensions/test/xpcshell/xpcshell.ini b/toolkit/components/extensions/test/xpcshell/xpcshell.ini index ae86bf06af70..91d61ac2d1e6 100644 --- a/toolkit/components/extensions/test/xpcshell/xpcshell.ini +++ b/toolkit/components/extensions/test/xpcshell/xpcshell.ini @@ -9,6 +9,9 @@ support-files = [test_csp_custom_policies.js] [test_csp_validator.js] [test_ext_alarms.js] +[test_ext_alarms_does_not_fire.js] +[test_ext_alarms_periodic.js] +[test_ext_alarms_replaces.js] [test_ext_background_generated_load_events.js] [test_ext_background_generated_reload.js] [test_ext_background_runtime_connect_params.js] From 226ff6a3598f0e3d77fa3a0384a6fb7b08af8623 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Thu, 28 Jul 2016 12:50:10 -0700 Subject: [PATCH 058/120] Backed out changeset d32a26786b30 (bug 1285271) for mochitest failures in test_bug902651.html --- modules/libpref/init/all.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index dc761a4b8541..5128faef4931 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4595,7 +4595,7 @@ pref("layers.d3d11.disable-warp", true); #endif // Copy-on-write canvas -pref("layers.shared-buffer-provider.enabled", true); +pref("layers.shared-buffer-provider.enabled", false); // Force all possible layers to be always active layers pref("layers.force-active", false); From 886f5ab2055a5b365ee99124d5246b3419ad18b3 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Thu, 28 Jul 2016 15:51:49 -0400 Subject: [PATCH 059/120] Bug 1288915 P1 Make nsExternalAppHandler respect existing channel ApplyConversion flag. r=jdm --- uriloader/exthandler/nsExternalHelperAppService.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp index 34dce6b186ed..d797e9598a64 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -1569,6 +1569,13 @@ nsExternalAppHandler::MaybeApplyDecodingForExtension(nsIRequest *aRequest) // Turn off content encoding conversions if needed bool applyConversion = true; + // First, check to see if conversion is already disabled. If so, we + // have nothing to do here. + encChannel->GetApplyConversion(&applyConversion); + if (!applyConversion) { + return; + } + nsCOMPtr sourceURL(do_QueryInterface(mSourceUrl)); if (sourceURL) { From 1ba8e28352923e497ab8bf1a2385979be64db18d Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Thu, 28 Jul 2016 15:51:51 -0400 Subject: [PATCH 060/120] Bug 1288915 P2 Verify that synthetic download works with a Content-Encoding header set. r=jdm --- dom/workers/test/serviceworkers/download/worker.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dom/workers/test/serviceworkers/download/worker.js b/dom/workers/test/serviceworkers/download/worker.js index 810641cd8af3..fe46d1a3bd50 100644 --- a/dom/workers/test/serviceworkers/download/worker.js +++ b/dom/workers/test/serviceworkers/download/worker.js @@ -21,7 +21,9 @@ addEventListener('fetch', function(evt) { evt.respondWith(registration.unregister().then(function() { return new Response('service worker generated download', { headers: { - 'Content-Disposition': 'attachment; filename="fake_download.bin"' + 'Content-Disposition': 'attachment; filename="fake_download.bin"', + // fake encoding header that should have no effect + 'Content-Encoding': 'gzip', } }); })); From f64e0358022c351b1b818632cc6bf10873bc7c6f Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Thu, 28 Jul 2016 13:08:59 -0700 Subject: [PATCH 061/120] Backed out changeset d51327ec371e (bug 1289816) for canvas reftest failures --- gfx/layers/CopyableCanvasLayer.cpp | 97 ++++++++++++++++----------- gfx/layers/CopyableCanvasLayer.h | 5 ++ gfx/layers/basic/BasicCanvasLayer.cpp | 75 +-------------------- gfx/layers/basic/BasicCanvasLayer.h | 3 - 4 files changed, 67 insertions(+), 113 deletions(-) diff --git a/gfx/layers/CopyableCanvasLayer.cpp b/gfx/layers/CopyableCanvasLayer.cpp index 1870fecf4d59..69ca999c3b34 100644 --- a/gfx/layers/CopyableCanvasLayer.cpp +++ b/gfx/layers/CopyableCanvasLayer.cpp @@ -50,6 +50,8 @@ CopyableCanvasLayer::~CopyableCanvasLayer() void CopyableCanvasLayer::Initialize(const Data& aData) { + NS_ASSERTION(mSurface == nullptr, "BasicCanvasLayer::Initialize called twice!"); + if (aData.mGLContext) { mGLContext = aData.mGLContext; mIsAlphaPremultiplied = aData.mIsGLAlphaPremult; @@ -70,7 +72,7 @@ CopyableCanvasLayer::Initialize(const Data& aData) mAsyncRenderer = aData.mRenderer; mOriginPos = gl::OriginPos::BottomLeft; } else { - MOZ_CRASH("GFX: CanvasLayer created without BufferProvider, DrawTarget or GLContext?"); + MOZ_CRASH("GFX: CanvasLayer created without mSurface, mDrawTarget or mGLContext?"); } mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height); @@ -85,36 +87,40 @@ CopyableCanvasLayer::IsDataValid(const Data& aData) void CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) { - MOZ_ASSERT(aDestTarget); - if (!aDestTarget) { - return; + AutoReturnSnapshot autoReturn; + + if (mAsyncRenderer) { + mSurface = mAsyncRenderer->GetSurface(); + } else if (!mGLFrontbuffer && mBufferProvider) { + mSurface = mBufferProvider->BorrowSnapshot(); + if (aDestTarget) { + // If !aDestTarget we'll end up painting using mSurface later, + // so we can't return it to the provider (note that this will trigger a + // copy of the snapshot behind the scenes when the provider is unlocked). + autoReturn.mSnapshot = &mSurface; + } + // Either way we need to call ReturnSnapshot because ther may be an + // underlying TextureClient that has to be unlocked. + autoReturn.mBufferProvider = mBufferProvider; } - RefPtr surface; - - if (!mGLContext) { - AutoReturnSnapshot autoReturn; - - if (mAsyncRenderer) { - surface = mAsyncRenderer->GetSurface(); - } else if (mBufferProvider && !mGLContext) { - surface = mBufferProvider->BorrowSnapshot(); - autoReturn.mSnapshot = &surface; - autoReturn.mBufferProvider = mBufferProvider; - } - - NS_ASSERTION(surface, "Must have surface to draw!"); - if (surface) { - aDestTarget->CopySurface(surface, + if (!mGLContext && aDestTarget) { + NS_ASSERTION(mSurface, "Must have surface to draw!"); + if (mSurface) { + aDestTarget->CopySurface(mSurface, IntRect(0, 0, mBounds.width, mBounds.height), IntPoint(0, 0)); + mSurface = nullptr; } return; } - MOZ_ASSERT(!mBufferProvider); - MOZ_ASSERT(!mAsyncRenderer); + if ((!mGLFrontbuffer && mBufferProvider) || mAsyncRenderer) { + return; + } + + MOZ_ASSERT(mGLContext); SharedSurface* frontbuffer = nullptr; if (mGLFrontbuffer) { @@ -139,22 +145,24 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied; // Try to read back directly into aDestTarget's output buffer - uint8_t* destData; - IntSize destSize; - int32_t destStride; - SurfaceFormat destFormat; - if (aDestTarget->LockBits(&destData, &destSize, &destStride, &destFormat)) { - if (destSize == readSize && destFormat == format) { - RefPtr data = - Factory::CreateWrappingDataSourceSurface(destData, destStride, destSize, destFormat); - mGLContext->Readback(frontbuffer, data); - if (needsPremult) { - gfxUtils::PremultiplyDataSurface(data, data); + if (aDestTarget) { + uint8_t* destData; + IntSize destSize; + int32_t destStride; + SurfaceFormat destFormat; + if (aDestTarget->LockBits(&destData, &destSize, &destStride, &destFormat)) { + if (destSize == readSize && destFormat == format) { + RefPtr data = + Factory::CreateWrappingDataSourceSurface(destData, destStride, destSize, destFormat); + mGLContext->Readback(frontbuffer, data); + if (needsPremult) { + gfxUtils::PremultiplyDataSurface(data, data); + } + aDestTarget->ReleaseBits(destData); + return; } aDestTarget->ReleaseBits(destData); - return; } - aDestTarget->ReleaseBits(destData); } RefPtr resultSurf = GetTempSurface(readSize, format); @@ -169,10 +177,17 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) if (needsPremult) { gfxUtils::PremultiplyDataSurface(resultSurf, resultSurf); } + MOZ_ASSERT(resultSurf); - aDestTarget->CopySurface(resultSurf, - IntRect(0, 0, readSize.width, readSize.height), - IntPoint(0, 0)); + if (aDestTarget) { + aDestTarget->CopySurface(resultSurf, + IntRect(0, 0, readSize.width, readSize.height), + IntPoint(0, 0)); + } else { + // If !aDestSurface then we will end up painting using mSurface, so + // stick our surface into mSurface, so that the Paint() path is the same. + mSurface = resultSurf; + } } DataSourceSurface* @@ -191,5 +206,11 @@ CopyableCanvasLayer::GetTempSurface(const IntSize& aSize, return mCachedTempSurface; } +void +CopyableCanvasLayer::DiscardTempSurface() +{ + mCachedTempSurface = nullptr; +} + } // namespace layers } // namespace mozilla diff --git a/gfx/layers/CopyableCanvasLayer.h b/gfx/layers/CopyableCanvasLayer.h index 8fefece4f5df..6cefa8150d5e 100644 --- a/gfx/layers/CopyableCanvasLayer.h +++ b/gfx/layers/CopyableCanvasLayer.h @@ -49,8 +49,11 @@ public: protected: void UpdateTarget(gfx::DrawTarget* aDestTarget = nullptr); + RefPtr mSurface; RefPtr mGLContext; + GLuint mCanvasFrontbufferTexID; RefPtr mBufferProvider; + UniquePtr mGLFrontbuffer; bool mIsAlphaPremultiplied; @@ -61,6 +64,8 @@ protected: gfx::DataSourceSurface* GetTempSurface(const gfx::IntSize& aSize, const gfx::SurfaceFormat aFormat); + + void DiscardTempSurface(); }; } // namespace layers diff --git a/gfx/layers/basic/BasicCanvasLayer.cpp b/gfx/layers/basic/BasicCanvasLayer.cpp index f615ff31448b..074c12cd9d6e 100644 --- a/gfx/layers/basic/BasicCanvasLayer.cpp +++ b/gfx/layers/basic/BasicCanvasLayer.cpp @@ -11,11 +11,6 @@ #include "nsCOMPtr.h" // for already_AddRefed #include "nsISupportsImpl.h" // for Layer::AddRef, etc #include "gfx2DGlue.h" -#include "GLScreenBuffer.h" -#include "GLContext.h" -#include "gfxUtils.h" -#include "mozilla/layers/PersistentBufferProvider.h" -#include "client/TextureClientSharedSurface.h" class gfxContext; @@ -25,61 +20,6 @@ using namespace mozilla::gl; namespace mozilla { namespace layers { -already_AddRefed -BasicCanvasLayer::UpdateSurface() -{ - if (mAsyncRenderer) { - return mAsyncRenderer->GetSurface(); - } - - if (mBufferProvider) { - // This is handled separately in Paint. - return nullptr; - } - - if (!mGLContext) { - return nullptr; - } - - SharedSurface* frontbuffer = nullptr; - if (mGLFrontbuffer) { - frontbuffer = mGLFrontbuffer.get(); - } else { - GLScreenBuffer* screen = mGLContext->Screen(); - const auto& front = screen->Front(); - if (front) { - frontbuffer = front->Surf(); - } - } - - if (!frontbuffer) { - NS_WARNING("Null frame received."); - return nullptr; - } - - IntSize readSize(frontbuffer->mSize); - SurfaceFormat format = (GetContentFlags() & CONTENT_OPAQUE) - ? SurfaceFormat::B8G8R8X8 - : SurfaceFormat::B8G8R8A8; - bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied; - - RefPtr resultSurf = GetTempSurface(readSize, format); - // There will already be a warning from inside of GetTempSurface, but - // it doesn't hurt to complain: - if (NS_WARN_IF(!resultSurf)) { - return nullptr; - } - - // Readback handles Flush/MarkDirty. - mGLContext->Readback(frontbuffer, resultSurf); - if (needsPremult) { - gfxUtils::PremultiplyDataSurface(resultSurf, resultSurf); - } - MOZ_ASSERT(resultSurf); - - return resultSurf.forget(); -} - void BasicCanvasLayer::Paint(DrawTarget* aDT, const Point& aDeviceOffset, @@ -88,24 +28,15 @@ BasicCanvasLayer::Paint(DrawTarget* aDT, if (IsHidden()) return; - RefPtr surface; if (IsDirty()) { Painted(); FirePreTransactionCallback(); - surface = UpdateSurface(); + UpdateTarget(); FireDidTransactionCallback(); } - AutoReturnSnapshot autoReturn(mBufferProvider); - - if (mBufferProvider) { - MOZ_ASSERT(!surface); - surface = mBufferProvider->BorrowSnapshot(); - autoReturn.mSnapshot = &surface; - } - - if (!surface) { + if (!mSurface) { return; } @@ -121,7 +52,7 @@ BasicCanvasLayer::Paint(DrawTarget* aDT, FillRectWithMask(aDT, aDeviceOffset, Rect(0, 0, mBounds.width, mBounds.height), - surface, mSamplingFilter, + mSurface, mSamplingFilter, DrawOptions(GetEffectiveOpacity(), GetEffectiveOperator(this)), aMaskLayer); diff --git a/gfx/layers/basic/BasicCanvasLayer.h b/gfx/layers/basic/BasicCanvasLayer.h index a63d2b8c02ea..3cd930c1ea2e 100644 --- a/gfx/layers/basic/BasicCanvasLayer.h +++ b/gfx/layers/basic/BasicCanvasLayer.h @@ -36,9 +36,6 @@ public: Layer* aMaskLayer) override; protected: - - already_AddRefed UpdateSurface(); - BasicLayerManager* BasicManager() { return static_cast(mManager); From 9ed0f44087b135631cf1fd7402cf4e930530d84c Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Thu, 28 Jul 2016 13:09:07 -0700 Subject: [PATCH 062/120] Backed out changeset 67cb195b1b45 (bug 1290081) for canvas reftest failures --- gfx/layers/client/CanvasClient.cpp | 4 ++-- gfx/layers/client/ClientCanvasLayer.cpp | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp index 61ce67505f83..0c4f03317935 100644 --- a/gfx/layers/client/CanvasClient.cpp +++ b/gfx/layers/client/CanvasClient.cpp @@ -98,7 +98,8 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) mBufferProviderTexture = nullptr; AutoRemoveTexture autoRemove(this); - if (mBackBuffer && (mBackBuffer->IsReadLocked() || mBackBuffer->GetSize() != aSize)) { + if (mBackBuffer && + (mBackBuffer->IsImmutable() || mBackBuffer->GetSize() != aSize)) { autoRemove.mTexture = mBackBuffer; mBackBuffer = nullptr; } @@ -121,7 +122,6 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) NS_WARNING("Failed to allocate the TextureClient"); return; } - mBackBuffer->EnableReadLock(); MOZ_ASSERT(mBackBuffer->CanExposeDrawTarget()); bufferCreated = true; diff --git a/gfx/layers/client/ClientCanvasLayer.cpp b/gfx/layers/client/ClientCanvasLayer.cpp index e9fec82c3580..6ded430dbee9 100644 --- a/gfx/layers/client/ClientCanvasLayer.cpp +++ b/gfx/layers/client/ClientCanvasLayer.cpp @@ -90,11 +90,16 @@ ClientCanvasLayer::RenderLayer() RenderMaskLayers(this); if (!mCanvasClient) { - TextureFlags flags = TextureFlags::DEFAULT; + TextureFlags flags = TextureFlags::IMMEDIATE_UPLOAD; if (mOriginPos == gl::OriginPos::BottomLeft) { flags |= TextureFlags::ORIGIN_BOTTOM_LEFT; } + if (!mGLContext) { + // We don't support locking for buffer surfaces currently + flags |= TextureFlags::IMMEDIATE_UPLOAD; + } + if (!mIsAlphaPremultiplied) { flags |= TextureFlags::NON_PREMULTIPLIED; } From 266770b5fe93f5f35af0a6927194510f58155645 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Wed, 27 Jul 2016 15:14:57 -0700 Subject: [PATCH 063/120] Bug 1276390 - Use blocking polling in worker to handle subprocess IO. r=aswan MozReview-Commit-ID: KXqgCLnO7dR --HG-- extra : rebase_source : 89266d2f5bf3a3d0a1ed1d6707c8b76cb8a04a7d --- .../modules/subprocess/subprocess_common.jsm | 22 +++++- .../subprocess/subprocess_shared_win.js | 18 +++++ .../modules/subprocess/subprocess_unix.jsm | 48 +++++++++++- toolkit/modules/subprocess/subprocess_win.jsm | 28 ++++++- .../subprocess/subprocess_worker_common.js | 20 +++++ .../subprocess/subprocess_worker_unix.js | 75 ++++++++++++++++--- .../subprocess/subprocess_worker_win.js | 65 +++++++++++++--- .../test/xpcshell/test_subprocess.js | 39 ++++++++++ 8 files changed, 290 insertions(+), 25 deletions(-) diff --git a/toolkit/modules/subprocess/subprocess_common.jsm b/toolkit/modules/subprocess/subprocess_common.jsm index fca7a3ffd094..a899fcc49e9a 100644 --- a/toolkit/modules/subprocess/subprocess_common.jsm +++ b/toolkit/modules/subprocess/subprocess_common.jsm @@ -15,6 +15,8 @@ Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.importGlobalProperties(["TextDecoder"]); +XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown", + "resource://gre/modules/AsyncShutdown.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "setTimeout", "resource://gre/modules/Timer.jsm"); @@ -38,11 +40,25 @@ class PromiseWorker extends ChromeWorker { this.listeners = new Map(); this.pendingResponses = new Map(); + this.addListener("close", this.onClose.bind(this)); this.addListener("failure", this.onFailure.bind(this)); this.addListener("success", this.onSuccess.bind(this)); this.addListener("debug", this.onDebug.bind(this)); this.addEventListener("message", this.onmessage); + + this.shutdown = this.shutdown.bind(this); + AsyncShutdown.webWorkersShutdown.addBlocker( + "Subprocess.jsm: Shut down IO worker", + this.shutdown); + } + + onClose() { + AsyncShutdown.webWorkersShutdown.removeBlocker(this.shutdown); + } + + shutdown() { + return this.call("shutdown", []); } /** @@ -615,6 +631,10 @@ class BaseProcess { throw new Error("Not implemented"); } + static get WorkerClass() { + return PromiseWorker; + } + /** * Gets the current subprocess worker, or spawns a new one if it does not * currently exist. @@ -623,7 +643,7 @@ class BaseProcess { */ static getWorker() { if (!this._worker) { - this._worker = new PromiseWorker(this.WORKER_URL); + this._worker = new this.WorkerClass(this.WORKER_URL); } return this._worker; } diff --git a/toolkit/modules/subprocess/subprocess_shared_win.js b/toolkit/modules/subprocess/subprocess_shared_win.js index cf8925ab5219..32957bc9886c 100644 --- a/toolkit/modules/subprocess/subprocess_shared_win.js +++ b/toolkit/modules/subprocess/subprocess_shared_win.js @@ -22,6 +22,7 @@ var win32 = { BYTE: ctypes.uint8_t, WORD: ctypes.uint16_t, DWORD: ctypes.uint32_t, + LONG: ctypes.long, UINT: ctypes.unsigned_int, UCHAR: ctypes.unsigned_char, @@ -219,6 +220,15 @@ var libc = new Library("libc", LIBC_CHOICES, { win32.PROCESS_INFORMATION.ptr, /* out lpProcessInformation */ ], + CreateSemaphoreW: [ + win32.WINAPI, + win32.HANDLE, + win32.SECURITY_ATTRIBUTES.ptr, /* opt lpSemaphoreAttributes */ + win32.LONG, /* lInitialCount */ + win32.LONG, /* lMaximumCount */ + win32.LPCWSTR, /* opt lpName */ + ], + DeleteProcThreadAttributeList: [ win32.WINAPI, win32.VOID, @@ -299,6 +309,14 @@ var libc = new Library("libc", LIBC_CHOICES, { win32.OVERLAPPED.ptr, /* opt in/out lpOverlapped */ ], + ReleaseSemaphore: [ + win32.WINAPI, + win32.BOOL, + win32.HANDLE, /* hSemaphore */ + win32.LONG, /* lReleaseCount */ + win32.LONG.ptr, /* opt out lpPreviousCount */ + ], + TerminateProcess: [ win32.WINAPI, win32.BOOL, diff --git a/toolkit/modules/subprocess/subprocess_unix.jsm b/toolkit/modules/subprocess/subprocess_unix.jsm index be725126068c..47ce667d26cf 100644 --- a/toolkit/modules/subprocess/subprocess_unix.jsm +++ b/toolkit/modules/subprocess/subprocess_unix.jsm @@ -9,7 +9,7 @@ /* exported SubprocessImpl */ -/* globals BaseProcess */ +/* globals BaseProcess, PromiseWorker */ var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; @@ -24,10 +24,56 @@ Cu.import("resource://gre/modules/subprocess/subprocess_common.jsm"); Services.scriptloader.loadSubScript("resource://gre/modules/subprocess/subprocess_shared.js", this); Services.scriptloader.loadSubScript("resource://gre/modules/subprocess/subprocess_shared_unix.js", this); +class UnixPromiseWorker extends PromiseWorker { + constructor(...args) { + super(...args); + + let fds = ctypes.int.array(2)(); + let res = libc.pipe(fds); + if (res == -1) { + throw new Error("Unable to create pipe"); + } + + this.signalFd = fds[1]; + + libc.fcntl(fds[0], LIBC.F_SETFL, LIBC.O_NONBLOCK); + libc.fcntl(fds[0], LIBC.F_SETFD, LIBC.FD_CLOEXEC); + libc.fcntl(fds[1], LIBC.F_SETFD, LIBC.FD_CLOEXEC); + + this.call("init", [{signalFd: fds[0]}]); + } + + closePipe() { + if (this.signalFd) { + libc.close(this.signalFd); + this.signalFd = null; + } + } + + onClose() { + this.closePipe(); + super.onClose(); + } + + signalWorker() { + libc.write(this.signalFd, new ArrayBuffer(1), 1); + } + + postMessage(...args) { + this.signalWorker(); + return super.postMessage(...args); + } +} + + class Process extends BaseProcess { static get WORKER_URL() { return "resource://gre/modules/subprocess/subprocess_worker_unix.js"; } + + static get WorkerClass() { + return UnixPromiseWorker; + } } var SubprocessUnix = { diff --git a/toolkit/modules/subprocess/subprocess_win.jsm b/toolkit/modules/subprocess/subprocess_win.jsm index de8887b478f1..8d146729b6ae 100644 --- a/toolkit/modules/subprocess/subprocess_win.jsm +++ b/toolkit/modules/subprocess/subprocess_win.jsm @@ -9,7 +9,7 @@ /* exported SubprocessImpl */ -/* globals BaseProcess */ +/* globals BaseProcess, PromiseWorker */ var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; @@ -24,10 +24,35 @@ Cu.import("resource://gre/modules/subprocess/subprocess_common.jsm"); Services.scriptloader.loadSubScript("resource://gre/modules/subprocess/subprocess_shared.js", this); Services.scriptloader.loadSubScript("resource://gre/modules/subprocess/subprocess_shared_win.js", this); +class WinPromiseWorker extends PromiseWorker { + constructor(...args) { + super(...args); + + this.signalEvent = libc.CreateSemaphoreW(null, 0, 32, null); + + this.call("init", [{ + signalEvent: String(ctypes.cast(this.signalEvent, ctypes.uintptr_t).value), + }]); + } + + signalWorker() { + libc.ReleaseSemaphore(this.signalEvent, 1, null); + } + + postMessage(...args) { + this.signalWorker(); + return super.postMessage(...args); + } +} + class Process extends BaseProcess { static get WORKER_URL() { return "resource://gre/modules/subprocess/subprocess_worker_win.js"; } + + static get WorkerClass() { + return WinPromiseWorker; + } } var SubprocessWin = { @@ -37,7 +62,6 @@ var SubprocessWin = { return Process.create(options); }, - * getEnvironment() { let env = libc.GetEnvironmentStringsW(); try { diff --git a/toolkit/modules/subprocess/subprocess_worker_common.js b/toolkit/modules/subprocess/subprocess_worker_common.js index 77c6e6162d32..a211a8ec1ff8 100644 --- a/toolkit/modules/subprocess/subprocess_worker_common.js +++ b/toolkit/modules/subprocess/subprocess_worker_common.js @@ -88,6 +88,18 @@ class BaseProcess { } let requests = { + init(details) { + io.init(details); + + return {data: {}}; + }, + + shutdown() { + io.shutdown(); + + return {data: {}}; + }, + close(pipeId, force = false) { let pipe = io.getPipe(pipeId); @@ -156,6 +168,8 @@ let requests = { }; onmessage = event => { + io.messageCount--; + let {msg, msgId, args} = event.data; new Promise(resolve => { @@ -195,3 +209,9 @@ onmessage = event => { }); }); }; + +onclose = event => { + io.shutdown(); + + self.postMessage({msg: "close"}); +}; diff --git a/toolkit/modules/subprocess/subprocess_worker_unix.js b/toolkit/modules/subprocess/subprocess_worker_unix.js index 61f0fee7e1a8..1a2595c286fb 100644 --- a/toolkit/modules/subprocess/subprocess_worker_unix.js +++ b/toolkit/modules/subprocess/subprocess_worker_unix.js @@ -12,8 +12,7 @@ importScripts("resource://gre/modules/subprocess/subprocess_shared.js", "resource://gre/modules/subprocess/subprocess_shared_unix.js", "resource://gre/modules/subprocess/subprocess_worker_common.js"); -const POLL_INTERVAL = 50; -const POLL_TIMEOUT = 0; +const POLL_TIMEOUT = 5000; let io; @@ -248,6 +247,40 @@ class OutputPipe extends Pipe { } } +class Signal { + constructor(fd) { + this.fd = fd; + } + + cleanup() { + libc.close(this.fd); + this.fd = null; + } + + get pollEvents() { + return LIBC.POLLIN; + } + + /** + * Called when an error occurred while polling our file descriptor. + */ + onError() { + io.shutdown(); + } + + /** + * Called when one of the IO operations matching the `pollEvents` mask may be + * performed without blocking. + */ + onReady() { + let buffer = new ArrayBuffer(16); + let count = +libc.read(this.fd, buffer, buffer.byteLength); + if (count > 0) { + io.messageCount += count; + } + } +} + class Process extends BaseProcess { /** * Each Process object opens an additional pipe from the target object, which @@ -449,7 +482,27 @@ io = { processes: new Map(), - interval: null, + messageCount: 0, + + running: true, + + init(details) { + this.signal = new Signal(details.signalFd); + this.updatePollFds(); + + setTimeout(this.loop.bind(this), 0); + }, + + shutdown() { + if (this.running) { + this.running = false; + + this.signal.cleanup(); + this.signal = null; + + self.close(); + } + }, getPipe(pipeId) { let pipe = this.pipes.get(pipeId); @@ -472,7 +525,8 @@ io = { }, updatePollFds() { - let handlers = [...this.pipes.values(), + let handlers = [this.signal, + ...this.pipes.values(), ...this.processes.values()]; handlers = handlers.filter(handler => handler.pollEvents); @@ -489,12 +543,12 @@ io = { this.pollFds = pollfds; this.pollHandlers = handlers; + }, - if (pollfds.length && !this.interval) { - this.interval = setInterval(this.poll.bind(this), POLL_INTERVAL); - } else if (!pollfds.length && this.interval) { - clearInterval(this.interval); - this.interval = null; + loop() { + this.poll(); + if (this.running) { + setTimeout(this.loop.bind(this), 0); } }, @@ -502,7 +556,8 @@ io = { let handlers = this.pollHandlers; let pollfds = this.pollFds; - let count = libc.poll(pollfds, pollfds.length, POLL_TIMEOUT); + let timeout = this.messageCount > 0 ? 0 : POLL_TIMEOUT; + let count = libc.poll(pollfds, pollfds.length, timeout); for (let i = 0; count && i < pollfds.length; i++) { let pollfd = pollfds[i]; diff --git a/toolkit/modules/subprocess/subprocess_worker_win.js b/toolkit/modules/subprocess/subprocess_worker_win.js index fa13a58edd70..762994f1a56a 100644 --- a/toolkit/modules/subprocess/subprocess_worker_win.js +++ b/toolkit/modules/subprocess/subprocess_worker_win.js @@ -12,8 +12,7 @@ importScripts("resource://gre/modules/subprocess/subprocess_shared.js", "resource://gre/modules/subprocess/subprocess_shared_win.js", "resource://gre/modules/subprocess/subprocess_worker_common.js"); -const POLL_INTERVAL = 50; -const POLL_TIMEOUT = 0; +const POLL_TIMEOUT = 5000; // The exit code that we send when we forcibly terminate a process. const TERMINATE_EXIT_CODE = 0x7f; @@ -298,6 +297,25 @@ class OutputPipe extends Pipe { } } +class Signal { + constructor(event) { + this.event = event; + } + + cleanup() { + libc.CloseHandle(this.event); + this.event = null; + } + + onError() { + io.shutdown(); + } + + onReady() { + io.messageCount += 1; + } +} + class Process extends BaseProcess { constructor(...args) { super(...args); @@ -543,7 +561,29 @@ io = { processes: new Map(), - interval: null, + messageCount: 0, + + running: true, + + init(details) { + let signalEvent = ctypes.cast(ctypes.uintptr_t(details.signalEvent), + win32.HANDLE); + this.signal = new Signal(signalEvent); + this.updatePollEvents(); + + setTimeout(this.loop.bind(this), 0); + }, + + shutdown() { + if (this.running) { + this.running = false; + + this.signal.cleanup(); + this.signal = null; + + self.close(); + } + }, getPipe(pipeId) { let pipe = this.pipes.get(pipeId); @@ -566,7 +606,8 @@ io = { }, updatePollEvents() { - let handlers = [...this.pipes.values(), + let handlers = [this.signal, + ...this.pipes.values(), ...this.processes.values()]; handlers = handlers.filter(handler => handler.event); @@ -575,22 +616,24 @@ io = { let handles = handlers.map(handler => handler.event); this.events = win32.HANDLE.array()(handles); + }, - if (handles.length && !this.interval) { - this.interval = setInterval(this.poll.bind(this), POLL_INTERVAL); - } else if (!handlers.length && this.interval) { - clearInterval(this.interval); - this.interval = null; + loop() { + this.poll(); + if (this.running) { + setTimeout(this.loop.bind(this), 0); } }, + poll() { - for (;;) { + let timeout = this.messageCount > 0 ? 0 : POLL_TIMEOUT; + for (;; timeout = 0) { let events = this.events; let handlers = this.eventHandlers; let result = libc.WaitForMultipleObjects(events.length, events, - false, POLL_TIMEOUT); + false, timeout); if (result < handlers.length) { try { diff --git a/toolkit/modules/subprocess/test/xpcshell/test_subprocess.js b/toolkit/modules/subprocess/test/xpcshell/test_subprocess.js index f63dd195b674..66131d3013f1 100644 --- a/toolkit/modules/subprocess/test/xpcshell/test_subprocess.js +++ b/toolkit/modules/subprocess/test/xpcshell/test_subprocess.js @@ -1,11 +1,14 @@ "use strict"; +Cu.import("resource://gre/modules/AppConstants.jsm"); Cu.import("resource://gre/modules/Task.jsm"); Cu.import("resource://gre/modules/Timer.jsm"); const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment); +const MAX_ROUND_TRIP_TIME_MS = AppConstants.DEBUG ? 18 : 9; + let PYTHON; let PYTHON_BIN; let PYTHON_DIR; @@ -178,6 +181,42 @@ add_task(function* test_subprocess_huge() { }); +add_task(function* test_subprocess_round_trip_perf() { + let proc = yield Subprocess.call({ + command: PYTHON, + arguments: ["-u", TEST_SCRIPT, "echo"], + }); + + + const LINE = "I'm a leaf on the wind.\n"; + + let now = Date.now(); + const COUNT = 1000; + for (let i = 0; i < COUNT; i++) { + let [output] = yield Promise.all([ + read(proc.stdout), + proc.stdin.write(LINE), + ]); + + // We don't want to log this for every iteration, but we still need + // to fail if it goes wrong. + if (output !== LINE) { + equal(output, LINE, "Got expected output"); + } + } + + let roundTripTime = (Date.now() - now) / COUNT; + ok(roundTripTime <= MAX_ROUND_TRIP_TIME_MS, + `Expected round trip time (${roundTripTime}ms) to be less than ${MAX_ROUND_TRIP_TIME_MS}ms`); + + yield proc.stdin.close(); + + let {exitCode} = yield proc.wait(); + + equal(exitCode, 0, "Got expected exit code"); +}); + + add_task(function* test_subprocess_stderr_default() { const LINE1 = "I'm a leaf on the wind.\n"; const LINE2 = "Watch how I soar.\n"; From 4350d1fefd0b36dc603981f3a46cd3678b0d071c Mon Sep 17 00:00:00 2001 From: Haik Aftandilian Date: Mon, 25 Jul 2016 14:43:00 -0400 Subject: [PATCH 064/120] Bug 1288774 - Remove the OSX rule added in bug 1190032 for nsPluginHost::GetPluginTempDir. r=jimm --- security/sandbox/mac/Sandbox.mm | 4 ---- 1 file changed, 4 deletions(-) diff --git a/security/sandbox/mac/Sandbox.mm b/security/sandbox/mac/Sandbox.mm index 5c1259c7b48a..68019ed28793 100644 --- a/security/sandbox/mac/Sandbox.mm +++ b/security/sandbox/mac/Sandbox.mm @@ -458,10 +458,6 @@ static const char contentSandboxRules[] = " (iokit-user-client-class \"NVDVDContextTesla\")\n" " (iokit-user-client-class \"Gen6DVDContext\"))\n" "\n" - "; bug 1190032\n" - " (allow file*\n" - " (home-regex \"/Library/Caches/TemporaryItems/plugtmp.*\"))\n" - "\n" "; bug 1201935\n" " (allow file-read*\n" " (home-subpath \"/Library/Caches/TemporaryItems\"))\n" From 620a47f1e2b30b27a287c6931736e9ea1b680b8e Mon Sep 17 00:00:00 2001 From: Simon Lindholm Date: Thu, 14 Jul 2016 01:27:23 +0200 Subject: [PATCH 065/120] Bug 1287277 - Avoid repeated string reallocations in NS_UnescapeURL. r=nfroyd --HG-- extra : rebase_source : 67490a033fd6ef52d3047c6e194322b223d85b0f --- xpcom/io/nsEscape.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/xpcom/io/nsEscape.cpp b/xpcom/io/nsEscape.cpp index f8e60444f6a4..f16edc4ce7ef 100644 --- a/xpcom/io/nsEscape.cpp +++ b/xpcom/io/nsEscape.cpp @@ -580,6 +580,9 @@ NS_UnescapeURL(const char* aStr, int32_t aLen, uint32_t aFlags, return false; } + MOZ_ASSERT(aResult.IsEmpty(), + "Passing a non-empty string as an out parameter!"); + if (aLen < 0) { aLen = strlen(aStr); } @@ -590,6 +593,10 @@ NS_UnescapeURL(const char* aStr, int32_t aLen, uint32_t aFlags, bool skipControl = !!(aFlags & esc_SkipControl); bool skipInvalidHostChar = !!(aFlags & esc_Host); + if (writing) { + aResult.SetCapacity(aLen); + } + const char* last = aStr; const char* p = aStr; @@ -603,7 +610,10 @@ NS_UnescapeURL(const char* aStr, int32_t aLen, uint32_t aFlags, ((c1 < '8' && !ignoreAscii) || (c1 >= '8' && !ignoreNonAscii)) && !(skipControl && (c1 < '2' || (c1 == '7' && (c2 == 'f' || c2 == 'F'))))) { - writing = true; + if (!writing) { + writing = true; + aResult.SetCapacity(aLen); + } if (p > last) { aResult.Append(last, p - last); last = p; From c165632985da661e69fe86040098dca6f71c5a83 Mon Sep 17 00:00:00 2001 From: Simon Lindholm Date: Thu, 14 Jul 2016 01:26:38 +0200 Subject: [PATCH 066/120] Bug 1287277 - Use AsSharedUTF8String in MatchAutoCompleteFunction. r=mak --HG-- extra : rebase_source : 18cc798aefec0e82f638540242c404cf310f8961 --- toolkit/components/places/SQLFunctions.cpp | 25 +++++++++++++++------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/toolkit/components/places/SQLFunctions.cpp b/toolkit/components/places/SQLFunctions.cpp index 3a53769ccae6..d6989d5b15ed 100644 --- a/toolkit/components/places/SQLFunctions.cpp +++ b/toolkit/components/places/SQLFunctions.cpp @@ -176,6 +176,17 @@ namespace { return false; } + static + MOZ_ALWAYS_INLINE nsDependentCString + getSharedString(mozIStorageValueArray* aValues, uint32_t aIndex) { + uint32_t len; + const char* str = aValues->AsSharedUTF8String(aIndex, &len); + if (!str) { + return nsDependentCString("", (uint32_t)0); + } + return nsDependentCString(str, len); + } + } // End anonymous namespace namespace mozilla { @@ -332,10 +343,10 @@ namespace places { #define HAS_BEHAVIOR(aBitName) \ (searchBehavior & mozIPlacesAutoComplete::BEHAVIOR_##aBitName) - nsAutoCString searchString; - (void)aArguments->GetUTF8String(kArgSearchString, searchString); - nsCString url; - (void)aArguments->GetUTF8String(kArgIndexURL, url); + nsDependentCString searchString = + getSharedString(aArguments, kArgSearchString); + nsDependentCString url = + getSharedString(aArguments, kArgIndexURL); int32_t matchBehavior = aArguments->AsInt32(kArgIndexMatchBehavior); @@ -352,8 +363,7 @@ namespace places { int32_t visitCount = aArguments->AsInt32(kArgIndexVisitCount); bool typed = aArguments->AsInt32(kArgIndexTyped) ? true : false; bool bookmark = aArguments->AsInt32(kArgIndexBookmark) ? true : false; - nsAutoCString tags; - (void)aArguments->GetUTF8String(kArgIndexTags, tags); + nsDependentCString tags = getSharedString(aArguments, kArgIndexTags); int32_t openPageCount = aArguments->AsInt32(kArgIndexOpenPageCount); bool matches = false; if (HAS_BEHAVIOR(RESTRICT)) { @@ -389,8 +399,7 @@ namespace places { const nsDependentCSubstring& trimmedUrl = Substring(fixedUrl, 0, MAX_CHARS_TO_SEARCH_THROUGH); - nsAutoCString title; - (void)aArguments->GetUTF8String(kArgIndexTitle, title); + nsDependentCString title = getSharedString(aArguments, kArgIndexTitle); // Limit the number of chars we search through. const nsDependentCSubstring& trimmedTitle = Substring(title, 0, MAX_CHARS_TO_SEARCH_THROUGH); From 649d497cb1de65ede7cbe14c8491004feaa06981 Mon Sep 17 00:00:00 2001 From: Simon Lindholm Date: Thu, 14 Jul 2016 01:25:46 +0200 Subject: [PATCH 067/120] Bug 1287277 - Avoid unnecessary string copies in MatchAutoCompleteFunction::fixupURISpec. r=mak --HG-- extra : rebase_source : 773a62c2168ff3788d54e47ec928b132cd98844d --- toolkit/components/places/SQLFunctions.cpp | 55 ++++++++++++---------- toolkit/components/places/SQLFunctions.h | 10 ++-- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/toolkit/components/places/SQLFunctions.cpp b/toolkit/components/places/SQLFunctions.cpp index d6989d5b15ed..83b22817b60b 100644 --- a/toolkit/components/places/SQLFunctions.cpp +++ b/toolkit/components/places/SQLFunctions.cpp @@ -211,36 +211,40 @@ namespace places { } /* static */ - void - MatchAutoCompleteFunction::fixupURISpec(const nsCString &aURISpec, + nsDependentCSubstring + MatchAutoCompleteFunction::fixupURISpec(const nsACString &aURISpec, int32_t aMatchBehavior, - nsCString &_fixedSpec) + nsACString &aSpecBuf) { - nsCString unescapedSpec; - (void)NS_UnescapeURL(aURISpec, esc_SkipControl | esc_AlwaysCopy, - unescapedSpec); + nsDependentCSubstring fixedSpec; - // If this unescaped string is valid UTF-8, we'll use it. Otherwise, - // we will simply use our original string. - NS_ASSERTION(_fixedSpec.IsEmpty(), - "Passing a non-empty string as an out parameter!"); - if (IsUTF8(unescapedSpec)) - _fixedSpec.Assign(unescapedSpec); - else - _fixedSpec.Assign(aURISpec); + // Try to unescape the string. If that succeeds and yields a different + // string which is also valid UTF-8, we'll use it. + // Otherwise, we will simply use our original string. + bool unescaped = NS_UnescapeURL(aURISpec.BeginReading(), + aURISpec.Length(), esc_SkipControl, aSpecBuf); + if (unescaped && IsUTF8(aSpecBuf)) { + fixedSpec.Rebind(aSpecBuf, 0); + } else { + fixedSpec.Rebind(aURISpec, 0); + } if (aMatchBehavior == mozIPlacesAutoComplete::MATCH_ANYWHERE_UNMODIFIED) - return; + return fixedSpec; - if (StringBeginsWith(_fixedSpec, NS_LITERAL_CSTRING("http://"))) - _fixedSpec.Cut(0, 7); - else if (StringBeginsWith(_fixedSpec, NS_LITERAL_CSTRING("https://"))) - _fixedSpec.Cut(0, 8); - else if (StringBeginsWith(_fixedSpec, NS_LITERAL_CSTRING("ftp://"))) - _fixedSpec.Cut(0, 6); + if (StringBeginsWith(fixedSpec, NS_LITERAL_CSTRING("http://"))) { + fixedSpec.Rebind(fixedSpec, 7); + } else if (StringBeginsWith(fixedSpec, NS_LITERAL_CSTRING("https://"))) { + fixedSpec.Rebind(fixedSpec, 8); + } else if (StringBeginsWith(fixedSpec, NS_LITERAL_CSTRING("ftp://"))) { + fixedSpec.Rebind(fixedSpec, 6); + } - if (StringBeginsWith(_fixedSpec, NS_LITERAL_CSTRING("www."))) - _fixedSpec.Cut(0, 4); + if (StringBeginsWith(fixedSpec, NS_LITERAL_CSTRING("www."))) { + fixedSpec.Rebind(fixedSpec, 4); + } + + return fixedSpec; } /* static */ @@ -393,8 +397,9 @@ namespace places { searchFunctionPtr searchFunction = getSearchFunction(matchBehavior); // Clean up our URI spec and prepare it for searching. - nsCString fixedUrl; - fixupURISpec(url, matchBehavior, fixedUrl); + nsCString fixedUrlBuf; + nsDependentCSubstring fixedUrl = + fixupURISpec(url, matchBehavior, fixedUrlBuf); // Limit the number of chars we search through. const nsDependentCSubstring& trimmedUrl = Substring(fixedUrl, 0, MAX_CHARS_TO_SEARCH_THROUGH); diff --git a/toolkit/components/places/SQLFunctions.h b/toolkit/components/places/SQLFunctions.h index 44c55f29ae7b..bba159345630 100644 --- a/toolkit/components/places/SQLFunctions.h +++ b/toolkit/components/places/SQLFunctions.h @@ -166,11 +166,13 @@ private: * @param aMatchBehavior * The matching behavior to use defined by one of the * mozIPlacesAutoComplete::MATCH_* values. - * @param _fixedSpec - * An out parameter that is the fixed up string. + * @param aSpecBuf + * A string buffer that the returned slice can point into, if needed. + * @return the fixed up string. */ - static void fixupURISpec(const nsCString &aURISpec, int32_t aMatchBehavior, - nsCString &_fixedSpec); + static nsDependentCSubstring fixupURISpec(const nsACString &aURISpec, + int32_t aMatchBehavior, + nsACString &aSpecBuf); }; From 250514830ee668367aa289b7a98e6b34fd463f67 Mon Sep 17 00:00:00 2001 From: Simon Lindholm Date: Thu, 14 Jul 2016 14:10:20 +0200 Subject: [PATCH 068/120] Bug 1287277 - Silly micro-optimization. r=mak --HG-- extra : rebase_source : ec8d72d13a97133ae8392c5071980724e280ec24 --- toolkit/components/places/SQLFunctions.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/toolkit/components/places/SQLFunctions.cpp b/toolkit/components/places/SQLFunctions.cpp index 83b22817b60b..ababd5cd5bae 100644 --- a/toolkit/components/places/SQLFunctions.cpp +++ b/toolkit/components/places/SQLFunctions.cpp @@ -357,9 +357,9 @@ namespace places { // We only want to filter javascript: URLs if we are not supposed to search // for them, and the search does not start with "javascript:". if (matchBehavior != mozIPlacesAutoComplete::MATCH_ANYWHERE_UNMODIFIED && + StringBeginsWith(url, NS_LITERAL_CSTRING("javascript:")) && !HAS_BEHAVIOR(JAVASCRIPT) && - !StringBeginsWith(searchString, NS_LITERAL_CSTRING("javascript:")) && - StringBeginsWith(url, NS_LITERAL_CSTRING("javascript:"))) { + !StringBeginsWith(searchString, NS_LITERAL_CSTRING("javascript:"))) { NS_ADDREF(*_result = new IntegerVariant(0)); return NS_OK; } From 5c68ffe2b982eafb6dab7dd2469ec24e2d7b2241 Mon Sep 17 00:00:00 2001 From: Simon Lindholm Date: Thu, 14 Jul 2016 16:13:04 +0200 Subject: [PATCH 069/120] Bug 1287277 - Avoid querying bookmark title and tags for non-bookmarked items. r=mak --HG-- extra : rebase_source : 54104dcad3432d46adbe7c54a8afb914abb23fff --- toolkit/components/places/UnifiedComplete.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/toolkit/components/places/UnifiedComplete.js b/toolkit/components/places/UnifiedComplete.js index ef2a463015ea..55be2022db37 100644 --- a/toolkit/components/places/UnifiedComplete.js +++ b/toolkit/components/places/UnifiedComplete.js @@ -109,6 +109,8 @@ const SQL_BOOKMARK_TAGS_FRAGMENT = // TODO bug 412736: in case of a frecency tie, we might break it with h.typed // and h.visit_count. That is slower though, so not doing it yet... +// NB: as a slight performance optimization, we only evaluate the "btitle" +// and "tags" queries for bookmarked entries. function defaultQuery(conditions = "") { let query = `SELECT :query_type, h.url, h.title, f.url, ${SQL_BOOKMARK_TAGS_FRAGMENT}, @@ -118,7 +120,12 @@ function defaultQuery(conditions = "") { LEFT JOIN moz_openpages_temp t ON t.url = h.url WHERE h.frecency <> 0 AND AUTOCOMPLETE_MATCH(:searchString, h.url, - IFNULL(btitle, h.title), tags, + CASE WHEN bookmarked THEN + IFNULL(btitle, h.title) + ELSE h.title END, + CASE WHEN bookmarked THEN + tags + ELSE '' END, h.visit_count, h.typed, bookmarked, t.open_count, :matchBehavior, :searchBehavior) From e2c982dd729cacf2b136d91be14e9693210f9b86 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Fri, 15 Jul 2016 19:55:59 -0400 Subject: [PATCH 070/120] Bug 1286096 - Consider competing audio constraints as well. r=padenot MozReview-Commit-ID: APPg2UBgNYo --HG-- extra : rebase_source : 02e05f0e0677d80711a0d27902f17b3f31136db4 --- dom/media/webrtc/MediaEngine.h | 1 + dom/media/webrtc/MediaEngineWebRTC.h | 15 ++- dom/media/webrtc/MediaEngineWebRTCAudio.cpp | 120 +++++++++++--------- 3 files changed, 74 insertions(+), 62 deletions(-) diff --git a/dom/media/webrtc/MediaEngine.h b/dom/media/webrtc/MediaEngine.h index ef98cba8e306..9deac430ce5d 100644 --- a/dom/media/webrtc/MediaEngine.h +++ b/dom/media/webrtc/MediaEngine.h @@ -316,6 +316,7 @@ public: AllocationHandle** aOutHandle, const char** aOutBadConstraint) { + AssertIsOnOwningThread(); MOZ_ASSERT(aOutHandle); RefPtr handle = new AllocationHandle(aConstraints, aOrigin, aPrefs, aDeviceId); diff --git a/dom/media/webrtc/MediaEngineWebRTC.h b/dom/media/webrtc/MediaEngineWebRTC.h index 993446ef3d30..c3e3084c88da 100644 --- a/dom/media/webrtc/MediaEngineWebRTC.h +++ b/dom/media/webrtc/MediaEngineWebRTC.h @@ -432,7 +432,6 @@ public: , mThread(aThread) , mCapIndex(aIndex) , mChannel(-1) - , mNrAllocations(0) , mStarted(false) , mSampleFrequency(MediaEngine::DEFAULT_SAMPLE_RATE) , mPlayoutDelay(0) @@ -450,12 +449,6 @@ public: void GetName(nsAString& aName) const override; void GetUUID(nsACString& aUUID) const override; - nsresult Allocate(const dom::MediaTrackConstraints& aConstraints, - const MediaEnginePrefs& aPrefs, - const nsString& aDeviceId, - const nsACString& aOrigin, - AllocationHandle** aOutHandle, - const char** aOutBadConstraint) override; nsresult Deallocate(AllocationHandle* aHandle) override; nsresult Start(SourceMediaStream* aStream, TrackID aID, @@ -514,6 +507,13 @@ protected: ~MediaEngineWebRTCMicrophoneSource() {} private: + nsresult + UpdateSingleSource(const AllocationHandle* aHandle, + const NormalizedConstraints& aNetConstraints, + const MediaEnginePrefs& aPrefs, + const nsString& aDeviceId, + const char** aOutBadConstraint) override; + // These allocate/configure and release the channel bool AllocChannel(); void FreeChannel(); @@ -564,7 +564,6 @@ private: nsCOMPtr mThread; int mCapIndex; int mChannel; - int mNrAllocations; // Per-channel - When this becomes 0, we shut down HW for the channel TrackID mTrackID; bool mStarted; diff --git a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp index 0dbd56e58293..21686ce25f8c 100644 --- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp +++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp @@ -218,52 +218,6 @@ uint32_t MediaEngineWebRTCMicrophoneSource::GetBestFitnessDistance( return distance; } -nsresult -MediaEngineWebRTCMicrophoneSource::Allocate(const dom::MediaTrackConstraints &aConstraints, - const MediaEnginePrefs &aPrefs, - const nsString& aDeviceId, - const nsACString& aOrigin, - AllocationHandle** aOutHandle, - const char** aOutBadConstraint) -{ - AssertIsOnOwningThread(); - if (mState == kReleased) { - if (sChannelsOpen == 0) { - if (!InitEngine()) { - LOG(("Audio engine is not initalized")); - return NS_ERROR_FAILURE; - } - } - if (!AllocChannel()) { - if (sChannelsOpen == 0) { - DeInitEngine(); - } - LOG(("Audio device is not initalized")); - return NS_ERROR_FAILURE; - } - if (mAudioInput->SetRecordingDevice(mCapIndex)) { - FreeChannel(); - if (sChannelsOpen == 0) { - DeInitEngine(); - } - return NS_ERROR_FAILURE; - } - sChannelsOpen++; - mState = kAllocated; - LOG(("Audio device %d allocated", mCapIndex)); - } else if (MOZ_LOG_TEST(GetMediaManagerLog(), LogLevel::Debug)) { - MonitorAutoLock lock(mMonitor); - if (mSources.IsEmpty()) { - LOG(("Audio device %d reallocated", mCapIndex)); - } else { - LOG(("Audio device %d allocated shared", mCapIndex)); - } - } - ++mNrAllocations; - aOutHandle = nullptr; - return Restart(nullptr, aConstraints, aPrefs, aDeviceId, aOutBadConstraint); -} - nsresult MediaEngineWebRTCMicrophoneSource::Restart(AllocationHandle* aHandle, const dom::MediaTrackConstraints& aConstraints, @@ -271,8 +225,22 @@ MediaEngineWebRTCMicrophoneSource::Restart(AllocationHandle* aHandle, const nsString& aDeviceId, const char** aOutBadConstraint) { - MOZ_ASSERT(!aHandle); - FlattenedConstraints c(aConstraints); + AssertIsOnOwningThread(); + MOZ_ASSERT(aHandle); + NormalizedConstraints constraints(aConstraints); + return ReevaluateAllocation(aHandle, &constraints, aPrefs, aDeviceId, + aOutBadConstraint); +} + +nsresult +MediaEngineWebRTCMicrophoneSource::UpdateSingleSource( + const AllocationHandle* aHandle, + const NormalizedConstraints& aNetConstraints, + const MediaEnginePrefs& aPrefs, + const nsString& aDeviceId, + const char** aOutBadConstraint) +{ + FlattenedConstraints c(aNetConstraints); bool aec_on = c.mEchoCancellation.Get(aPrefs.mAecOn); bool agc_on = c.mMozAutoGainControl.Get(aPrefs.mAgcOn); @@ -286,6 +254,51 @@ MediaEngineWebRTCMicrophoneSource::Restart(AllocationHandle* aHandle, mPlayoutDelay = aPrefs.mPlayoutDelay; + switch (mState) { + case kReleased: + MOZ_ASSERT(aHandle); + if (sChannelsOpen == 0) { + if (!InitEngine()) { + LOG(("Audio engine is not initalized")); + return NS_ERROR_FAILURE; + } + } + if (!AllocChannel()) { + if (sChannelsOpen == 0) { + DeInitEngine(); + } + LOG(("Audio device is not initalized")); + return NS_ERROR_FAILURE; + } + if (mAudioInput->SetRecordingDevice(mCapIndex)) { + FreeChannel(); + if (sChannelsOpen == 0) { + DeInitEngine(); + } + return NS_ERROR_FAILURE; + } + sChannelsOpen++; + mState = kAllocated; + LOG(("Audio device %d allocated", mCapIndex)); + break; + + case kStarted: + if (MOZ_LOG_TEST(GetMediaManagerLog(), LogLevel::Debug)) { + MonitorAutoLock lock(mMonitor); + if (mSources.IsEmpty()) { + LOG(("Audio device %d reallocated", mCapIndex)); + } else { + LOG(("Audio device %d allocated shared", mCapIndex)); + } + } + break; + + default: + LOG(("Audio device %d %s in ignored state %d", mCapIndex, + (aHandle? aHandle->mOrigin.get() : ""), mState)); + break; + } + if (sChannelsOpen > 0) { int error; @@ -310,7 +323,6 @@ MediaEngineWebRTCMicrophoneSource::Restart(AllocationHandle* aHandle, if (mSkipProcessing) { mSampleFrequency = MediaEngine::USE_GRAPH_RATE; } - return NS_OK; } @@ -318,10 +330,10 @@ nsresult MediaEngineWebRTCMicrophoneSource::Deallocate(AllocationHandle* aHandle) { AssertIsOnOwningThread(); - MOZ_ASSERT(!aHandle); - --mNrAllocations; - MOZ_ASSERT(mNrAllocations >= 0, "Double-deallocations are prohibited"); - if (mNrAllocations == 0) { + + Super::Deallocate(aHandle); + + if (!mRegisteredHandles.Length()) { // If empty, no callbacks to deliver data should be occuring if (mState != kStopped && mState != kAllocated) { return NS_ERROR_FAILURE; @@ -740,7 +752,7 @@ MediaEngineWebRTCMicrophoneSource::Shutdown() MOZ_ASSERT(mState == kStopped); } - while (mNrAllocations) { + while (mRegisteredHandles.Length()) { MOZ_ASSERT(mState == kAllocated || mState == kStopped); Deallocate(nullptr); // XXX Extend concurrent constraints code to mics. } From abbd438d8f963c08870f80ff844dde18afd8eec4 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Sat, 16 Jul 2016 15:33:54 -0400 Subject: [PATCH 071/120] Bug 1286096 - Wire up audio getSettings(). r=padenot,smaug MozReview-Commit-ID: KH6xcAnd3DX --HG-- extra : rebase_source : a473d25cec56ee5bf2cd7b5114d7038e45d6a9d8 --- dom/media/MediaManager.cpp | 3 + dom/media/webrtc/MediaEngineWebRTC.h | 27 ++----- dom/media/webrtc/MediaEngineWebRTCAudio.cpp | 90 +++++++++++++++++---- dom/webidl/MediaTrackSettings.webidl | 3 + 4 files changed, 88 insertions(+), 35 deletions(-) diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 13e38b59f902..fd4ed5485b62 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -361,6 +361,9 @@ public: if (mVideoDevice) { mVideoDevice->GetSource()->GetSettings(aOutSettings); } + if (mAudioDevice) { + mAudioDevice->GetSource()->GetSettings(aOutSettings); + } } // implement in .cpp to avoid circular dependency with MediaOperationTask diff --git a/dom/media/webrtc/MediaEngineWebRTC.h b/dom/media/webrtc/MediaEngineWebRTC.h index c3e3084c88da..863af61f4db0 100644 --- a/dom/media/webrtc/MediaEngineWebRTC.h +++ b/dom/media/webrtc/MediaEngineWebRTC.h @@ -424,27 +424,7 @@ public: mozilla::AudioInput* aAudioInput, int aIndex, const char* name, - const char* uuid) - : MediaEngineAudioSource(kReleased) - , mVoiceEngine(aVoiceEnginePtr) - , mAudioInput(aAudioInput) - , mMonitor("WebRTCMic.Monitor") - , mThread(aThread) - , mCapIndex(aIndex) - , mChannel(-1) - , mStarted(false) - , mSampleFrequency(MediaEngine::DEFAULT_SAMPLE_RATE) - , mPlayoutDelay(0) - , mNullTransport(nullptr) - , mSkipProcessing(false) - { - MOZ_ASSERT(aVoiceEnginePtr); - MOZ_ASSERT(aAudioInput); - mDeviceName.Assign(NS_ConvertUTF8toUTF16(name)); - mDeviceUUID.Assign(uuid); - mListener = new mozilla::WebRTCAudioDataListener(this); - // We'll init lazily as needed - } + const char* uuid); void GetName(nsAString& aName) const override; void GetUUID(nsACString& aUUID) const override; @@ -514,6 +494,8 @@ private: const nsString& aDeviceId, const char** aOutBadConstraint) override; + void SetLastPrefs(const MediaEnginePrefs& aPrefs); + // These allocate/configure and release the channel bool AllocChannel(); void FreeChannel(); @@ -580,6 +562,9 @@ private: // because of prefs or constraints. This allows simply copying the audio into // the MSG, skipping resampling and the whole webrtc.org code. bool mSkipProcessing; + + // To only update microphone when needed, we keep track of previous settings. + MediaEnginePrefs mLastPrefs; }; class MediaEngineWebRTC : public MediaEngine diff --git a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp index 21686ce25f8c..51b3208549a5 100644 --- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp +++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp @@ -183,6 +183,37 @@ AudioOutputObserver::InsertFarEnd(const AudioDataValue *aBuffer, uint32_t aFrame } } +MediaEngineWebRTCMicrophoneSource::MediaEngineWebRTCMicrophoneSource( + nsIThread* aThread, + webrtc::VoiceEngine* aVoiceEnginePtr, + mozilla::AudioInput* aAudioInput, + int aIndex, + const char* name, + const char* uuid) + : MediaEngineAudioSource(kReleased) + , mVoiceEngine(aVoiceEnginePtr) + , mAudioInput(aAudioInput) + , mMonitor("WebRTCMic.Monitor") + , mThread(aThread) + , mCapIndex(aIndex) + , mChannel(-1) + , mStarted(false) + , mSampleFrequency(MediaEngine::DEFAULT_SAMPLE_RATE) + , mPlayoutDelay(0) + , mNullTransport(nullptr) + , mSkipProcessing(false) +{ + MOZ_ASSERT(aVoiceEnginePtr); + MOZ_ASSERT(aAudioInput); + mDeviceName.Assign(NS_ConvertUTF8toUTF16(name)); + mDeviceUUID.Assign(uuid); + mListener = new mozilla::WebRTCAudioDataListener(this); + mSettings.mEchoCancellation.Construct(0); + mSettings.mMozAutoGainControl.Construct(0); + mSettings.mMozNoiseSuppression.Construct(0); + // We'll init lazily as needed +} + void MediaEngineWebRTCMicrophoneSource::GetName(nsAString& aName) const { @@ -232,6 +263,11 @@ MediaEngineWebRTCMicrophoneSource::Restart(AllocationHandle* aHandle, aOutBadConstraint); } +bool operator == (const MediaEnginePrefs& a, const MediaEnginePrefs& b) +{ + return !memcmp(&a, &b, sizeof(MediaEnginePrefs)); +}; + nsresult MediaEngineWebRTCMicrophoneSource::UpdateSingleSource( const AllocationHandle* aHandle, @@ -242,17 +278,18 @@ MediaEngineWebRTCMicrophoneSource::UpdateSingleSource( { FlattenedConstraints c(aNetConstraints); - bool aec_on = c.mEchoCancellation.Get(aPrefs.mAecOn); - bool agc_on = c.mMozAutoGainControl.Get(aPrefs.mAgcOn); - bool noise_on = c.mMozNoiseSuppression.Get(aPrefs.mNoiseOn); + MediaEnginePrefs prefs = aPrefs; + prefs.mAecOn = c.mEchoCancellation.Get(prefs.mAecOn); + prefs.mAgcOn = c.mMozAutoGainControl.Get(prefs.mAgcOn); + prefs.mNoiseOn = c.mMozNoiseSuppression.Get(prefs.mNoiseOn); LOG(("Audio config: aec: %d, agc: %d, noise: %d, delay: %d", - aec_on ? aPrefs.mAec : -1, - agc_on ? aPrefs.mAgc : -1, - noise_on ? aPrefs.mNoise : -1, - aPrefs.mPlayoutDelay)); + prefs.mAecOn ? prefs.mAec : -1, + prefs.mAgcOn ? prefs.mAgc : -1, + prefs.mNoiseOn ? prefs.mNoise : -1, + prefs.mPlayoutDelay)); - mPlayoutDelay = aPrefs.mPlayoutDelay; + mPlayoutDelay = prefs.mPlayoutDelay; switch (mState) { case kReleased: @@ -283,6 +320,9 @@ MediaEngineWebRTCMicrophoneSource::UpdateSingleSource( break; case kStarted: + if (prefs == mLastPrefs) { + return NS_OK; + } if (MOZ_LOG_TEST(GetMediaManagerLog(), LogLevel::Debug)) { MonitorAutoLock lock(mMonitor); if (mSources.IsEmpty()) { @@ -302,30 +342,52 @@ MediaEngineWebRTCMicrophoneSource::UpdateSingleSource( if (sChannelsOpen > 0) { int error; - if (0 != (error = mVoEProcessing->SetEcStatus(aec_on, (webrtc::EcModes) aPrefs.mAec))) { + error = mVoEProcessing->SetEcStatus(prefs.mAecOn, (webrtc::EcModes)prefs.mAec); + if (error) { LOG(("%s Error setting Echo Status: %d ",__FUNCTION__, error)); // Overhead of capturing all the time is very low (<0.1% of an audio only call) - if (aec_on) { - if (0 != (error = mVoEProcessing->SetEcMetricsStatus(true))) { + if (prefs.mAecOn) { + error = mVoEProcessing->SetEcMetricsStatus(true); + if (error) { LOG(("%s Error setting Echo Metrics: %d ",__FUNCTION__, error)); } } } - if (0 != (error = mVoEProcessing->SetAgcStatus(agc_on, (webrtc::AgcModes) aPrefs.mAgc))) { + error = mVoEProcessing->SetAgcStatus(prefs.mAgcOn, (webrtc::AgcModes)prefs.mAgc); + if (error) { LOG(("%s Error setting AGC Status: %d ",__FUNCTION__, error)); } - if (0 != (error = mVoEProcessing->SetNsStatus(noise_on, (webrtc::NsModes) aPrefs.mNoise))) { + error = mVoEProcessing->SetNsStatus(prefs.mNoiseOn, (webrtc::NsModes)prefs.mNoise); + if (error) { LOG(("%s Error setting NoiseSuppression Status: %d ",__FUNCTION__, error)); } } - mSkipProcessing = !(aec_on || agc_on || noise_on); + mSkipProcessing = !(prefs.mAecOn || prefs.mAgcOn || prefs.mNoiseOn); if (mSkipProcessing) { mSampleFrequency = MediaEngine::USE_GRAPH_RATE; } + SetLastPrefs(prefs); return NS_OK; } +void +MediaEngineWebRTCMicrophoneSource::SetLastPrefs( + const MediaEnginePrefs& aPrefs) +{ + mLastPrefs = aPrefs; + + RefPtr that = this; + + NS_DispatchToMainThread(media::NewRunnableFrom([this, that, aPrefs]() mutable { + mSettings.mEchoCancellation.Value() = aPrefs.mAecOn; + mSettings.mMozAutoGainControl.Value() = aPrefs.mAgcOn; + mSettings.mMozNoiseSuppression.Value() = aPrefs.mNoiseOn; + return NS_OK; + })); +} + + nsresult MediaEngineWebRTCMicrophoneSource::Deallocate(AllocationHandle* aHandle) { diff --git a/dom/webidl/MediaTrackSettings.webidl b/dom/webidl/MediaTrackSettings.webidl index 14b841ecacb0..909b9f60b3d3 100644 --- a/dom/webidl/MediaTrackSettings.webidl +++ b/dom/webidl/MediaTrackSettings.webidl @@ -13,6 +13,9 @@ dictionary MediaTrackSettings { double frameRate; DOMString facingMode; DOMString deviceId; + boolean echoCancellation; + boolean mozNoiseSuppression; + boolean mozAutoGainControl; // Mozilla-specific extensions: From 44c9f33c2532573b7d76c78ba4d931dfb5c0e44b Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Thu, 28 Jul 2016 12:03:40 -0400 Subject: [PATCH 072/120] Bug 1289857 - Fix MediaTrackConstraints.cpp to compile with --disable-webrtc again. r=mjf MozReview-Commit-ID: GgVNQSbPCwf --HG-- extra : rebase_source : ac3a7c53c3ac8c5b98e05b6d72ddb2badd58617a --- dom/media/webrtc/MediaTrackConstraints.cpp | 7 ++++--- dom/media/webrtc/moz.build | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/dom/media/webrtc/MediaTrackConstraints.cpp b/dom/media/webrtc/MediaTrackConstraints.cpp index ce58ad468e75..7ed2839ede8b 100644 --- a/dom/media/webrtc/MediaTrackConstraints.cpp +++ b/dom/media/webrtc/MediaTrackConstraints.cpp @@ -4,6 +4,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "MediaTrackConstraints.h" +#include "mozilla/dom/MediaStreamTrackBinding.h" #include #include @@ -144,7 +145,7 @@ NormalizedConstraintSet::BooleanRange::BooleanRange( mIdeal.emplace(aOther.GetAsBoolean()); } } else { - const ConstrainBooleanParameters& r = aOther.GetAsConstrainBooleanParameters(); + const dom::ConstrainBooleanParameters& r = aOther.GetAsConstrainBooleanParameters(); if (r.mIdeal.WasPassed()) { mIdeal.emplace(r.mIdeal.Value()); } @@ -188,7 +189,7 @@ NormalizedConstraintSet::StringRange::StringRange( void NormalizedConstraintSet::StringRange::SetFrom( - const ConstrainDOMStringParameters& aOther) + const dom::ConstrainDOMStringParameters& aOther) { if (aOther.mIdeal.WasPassed()) { mIdeal.clear(); @@ -295,7 +296,7 @@ NormalizedConstraints::NormalizedConstraints( { // Create a list of member pointers. nsTArray list; - NormalizedConstraints dummy(MediaTrackConstraints(), &list); + NormalizedConstraints dummy(dom::MediaTrackConstraints(), &list); // Do intersection of all required constraints, and average of ideals, diff --git a/dom/media/webrtc/moz.build b/dom/media/webrtc/moz.build index e6825710a6c8..469c47226a81 100644 --- a/dom/media/webrtc/moz.build +++ b/dom/media/webrtc/moz.build @@ -33,7 +33,6 @@ if CONFIG['MOZ_WEBRTC']: 'MediaEngineRemoteVideoSource.cpp', 'MediaEngineTabVideoSource.cpp', 'MediaEngineWebRTCAudio.cpp', - 'MediaTrackConstraints.cpp', 'RTCCertificate.cpp', 'RTCIdentityProviderRegistrar.cpp', ] @@ -66,6 +65,7 @@ XPIDL_SOURCES += [ UNIFIED_SOURCES += [ 'MediaEngineDefault.cpp', + 'MediaTrackConstraints.cpp', 'PeerIdentity.cpp', ] From da1ba5c6ef526e829a5fb105974c3195aead7588 Mon Sep 17 00:00:00 2001 From: Jonathan Chan Date: Thu, 28 Jul 2016 14:51:12 -0700 Subject: [PATCH 073/120] Bug 1290269 - Add missing includes to nsStyleStruct.cpp. r=dholbert MozReview-Commit-ID: 1dsnqyvAanr --HG-- extra : rebase_source : d64f942cb059af1f2a1c7cea0d03bad140caaf84 --- layout/style/nsStyleStruct.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index e68f9fe11443..78e08d2f9ac3 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -20,6 +20,8 @@ #include "nsCRTGlue.h" #include "nsCSSParser.h" #include "nsCSSProps.h" +#include "nsDeviceContext.h" +#include "nsStyleUtil.h" #include "nsCOMPtr.h" From 0ce2b1771e9c22e16be4389d5378dad9c6415738 Mon Sep 17 00:00:00 2001 From: Masatoshi Kimura Date: Thu, 28 Jul 2016 19:57:28 +0900 Subject: [PATCH 074/120] Bug 1288760 - Fix point conversion in nsDragService::StartInvokingDragSession. r=jfkthame MozReview-Commit-ID: DgNtnsvEPnR --HG-- extra : rebase_source : 0c2c077cd36047bdce5f74b6a4672682e8120073 --- widget/windows/nsDragService.cpp | 57 ++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/widget/windows/nsDragService.cpp b/widget/windows/nsDragService.cpp index d8ae717571f9..272d66688459 100644 --- a/widget/windows/nsDragService.cpp +++ b/widget/windows/nsDragService.cpp @@ -26,6 +26,7 @@ #include "nsString.h" #include "nsEscape.h" +#include "nsIScreenManager.h" #include "nsISupportsPrimitives.h" #include "nsIURL.h" #include "nsCWebBrowserPersist.h" @@ -252,6 +253,40 @@ nsDragService::InvokeDragSessionImpl(nsISupportsArray* anArrayTransferables, return StartInvokingDragSession(itemToDrag, aActionType); } +static bool +LayoutDevicePointToCSSPoint(const LayoutDevicePoint& aDevPos, + CSSPoint& aCSSPos) +{ + nsCOMPtr screenMgr = + do_GetService("@mozilla.org/gfx/screenmanager;1"); + if (!screenMgr) { + return false; + } + + nsCOMPtr screen; + screenMgr->ScreenForRect(NSToIntRound(aDevPos.x), NSToIntRound(aDevPos.y), + 1, 1, getter_AddRefs(screen)); + if (!screen) { + return false; + } + + int32_t w,h; // unused + LayoutDeviceIntPoint screenOriginDev; + screen->GetRect(&screenOriginDev.x, &screenOriginDev.y, &w, &h); + + double scale; + screen->GetDefaultCSSScaleFactor(&scale); + LayoutDeviceToCSSScale devToCSSScale = + CSSToLayoutDeviceScale(scale).Inverse(); + + // Desktop pixels and CSS pixels share the same screen origin. + CSSIntPoint screenOriginCSS; + screen->GetRectDisplayPix(&screenOriginCSS.x, &screenOriginCSS.y, &w, &h); + + aCSSPos = (aDevPos - screenOriginDev) * devToCSSScale + screenOriginCSS; + return true; +} + //------------------------------------------------------------------------- NS_IMETHODIMP nsDragService::StartInvokingDragSession(IDataObject * aDataObj, @@ -326,12 +361,22 @@ nsDragService::StartInvokingDragSession(IDataObject * aDataObj, // Note that we must convert this from device pixels back to Windows logical // pixels (bug 818927). DWORD pos = ::GetMessagePos(); - POINT pt = { GET_X_LPARAM(pos), GET_Y_LPARAM(pos) }; - HMONITOR monitor = ::MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY); - double dpiScale = widget::WinUtils::LogToPhysFactor(monitor); - nsIntPoint logPos(NSToIntRound(GET_X_LPARAM(pos) / dpiScale), - NSToIntRound(GET_Y_LPARAM(pos) / dpiScale)); - SetDragEndPoint(logPos); + CSSPoint cssPos; + if (!LayoutDevicePointToCSSPoint(LayoutDevicePoint(GET_X_LPARAM(pos), + GET_Y_LPARAM(pos)), + cssPos)) { + // fallback to the simple scaling + POINT pt = { GET_X_LPARAM(pos), GET_Y_LPARAM(pos) }; + HMONITOR monitor = ::MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY); + double dpiScale = widget::WinUtils::LogToPhysFactor(monitor); + cssPos.x = GET_X_LPARAM(pos) / dpiScale; + cssPos.y = GET_Y_LPARAM(pos) / dpiScale; + } + // We have to abuse SetDragEndPoint to pass CSS pixels because + // Event::GetScreenCoords will not convert pixels for dragend events + // until bug 1224754 is fixed. + SetDragEndPoint(LayoutDeviceIntPoint(NSToIntRound(cssPos.x), + NSToIntRound(cssPos.y))); EndDragSession(true); mDoingDrag = false; From 96c8b2dca476f8231e3793059ff0e9a1052a14ab Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Thu, 28 Jul 2016 18:29:49 +0900 Subject: [PATCH 075/120] Bug 1290019 - Remove MT version check. r=chmanchester Before bug 1289294, the impossibility to find the version of MT was only issuing a warning. Warnings in configure are essentially useless, so since we weren't and still aren't doing anything with the result of that check, and since there are versions of MT that don't print out a version number, just remove the check. --HG-- extra : rebase_source : 4887cebf0f56ca1a297cd02ff1988809c5cb6fdf --- build/moz.configure/windows.configure | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/build/moz.configure/windows.configure b/build/moz.configure/windows.configure index e3ac10f564c0..db0bca5e0b10 100644 --- a/build/moz.configure/windows.configure +++ b/build/moz.configure/windows.configure @@ -185,7 +185,6 @@ mt = check_prog('_MT', depends_win()(lambda: ('mt.exe',)), what='mt', # utility". @depends_win(mt) @checking('whether MT is really Microsoft Manifest Tool', lambda x: bool(x)) -@imports('re') @imports('subprocess') def valid_mt(path): try: @@ -193,21 +192,13 @@ def valid_mt(path): out = '\n'.join(l for l in out if 'Microsoft (R) Manifest Tool' in l) if out: - m = re.search(r'(?<=[^!-~])[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+', - out) - if not m: - raise FatalCheckError( - 'Unknown version of the Microsoft Manifest Tool') - return namespace( - path=path, - version=Version(m.group(0)), - ) + return path except subprocess.CalledProcessError: pass raise FatalCheckError('%s is not Microsoft Manifest Tool') -set_config('MT', depends_if(valid_mt)(lambda x: os.path.basename(x.path))) +set_config('MT', depends_if(valid_mt)(lambda x: os.path.basename(x))) set_config('MSMANIFEST_TOOL', depends(valid_mt)(lambda x: bool(x))) From 2e27b626874565fd819634523741e1260cc7525b Mon Sep 17 00:00:00 2001 From: Makoto Kato Date: Fri, 22 Jul 2016 16:40:21 +0900 Subject: [PATCH 076/120] Bug 1288644 - Don't define RTLD_NOLOAD when __ANDROID_API__ >= 21. r=glandium MozReview-Commit-ID: AUEQjIBk50H --HG-- extra : rebase_source : 6ce4e2d3537951054432ce2a9689222a8923f69a --- security/manager/android_stub.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/security/manager/android_stub.h b/security/manager/android_stub.h index 708063cde2f0..6f5ad3f5588c 100644 --- a/security/manager/android_stub.h +++ b/security/manager/android_stub.h @@ -17,6 +17,11 @@ #include #include +#ifndef ANDROID_VERSION +#include +#define ANDROID_VERSION __ANDROID_API__ +#endif + /* Use this stub version of getdtablesize * instead of the one in the header */ __attribute__((unused)) From 8d5de8656a4a58ba2aa59f55615dc55c24a22451 Mon Sep 17 00:00:00 2001 From: Gerald Squelart Date: Wed, 27 Jul 2016 16:26:45 +1000 Subject: [PATCH 077/120] Bug 1289674 - Don't record video telemetry when there is no video - r=kamidphish MozReview-Commit-ID: nJniysQfpM --HG-- extra : rebase_source : 4d158a46f233dcefbbfc36a47a29af15be690f21 --- dom/html/HTMLMediaElement.cpp | 82 ++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index 0630cb3c4b6a..b2b2359dd2ca 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -3099,50 +3099,52 @@ HTMLMediaElement::ReportTelemetry() } } - double playTime = mPlayTime.Total(); - double hiddenPlayTime = mHiddenPlayTime.Total(); - - Telemetry::Accumulate(Telemetry::VIDEO_PLAY_TIME_MS, SECONDS_TO_MS(playTime)); - LOG(LogLevel::Debug, ("%p VIDEO_PLAY_TIME_MS = %f", this, playTime)); - - Telemetry::Accumulate(Telemetry::VIDEO_HIDDEN_PLAY_TIME_MS, SECONDS_TO_MS(hiddenPlayTime)); - LOG(LogLevel::Debug, ("%p VIDEO_HIDDEN_PLAY_TIME_MS = %f", this, hiddenPlayTime)); - - if (playTime > 0.0 && - mMediaInfo.HasVideo() && + if (mMediaInfo.HasVideo() && mMediaInfo.mVideo.mImage.height > 0) { - // We have actually played some valid video -> Report hidden/total ratio. - uint32_t hiddenPercentage = uint32_t(hiddenPlayTime / playTime * 100.0 + 0.5); + // We have a valid video. + double playTime = mPlayTime.Total(); + double hiddenPlayTime = mHiddenPlayTime.Total(); - // Keyed by audio+video or video alone, and by a resolution range. - nsCString key(mMediaInfo.HasAudio() ? "AV," : "V,"); - static const struct { int32_t mH; const char* mRes; } sResolutions[] = { - { 240, "0 0.0) { + // We have actually played something -> Report hidden/total ratio. + uint32_t hiddenPercentage = uint32_t(hiddenPlayTime / playTime * 100.0 + 0.5); + + // Keyed by audio+video or video alone, and by a resolution range. + nsCString key(mMediaInfo.HasAudio() ? "AV," : "V,"); + static const struct { int32_t mH; const char* mRes; } sResolutions[] = { + { 240, "0 Date: Fri, 15 Jul 2016 16:48:26 +1000 Subject: [PATCH 078/120] Bug 1289668 - VideoPlaybackQuality style - r=kamidphish MozReview-Commit-ID: EorsgpmZM1S --HG-- extra : rebase_source : cfaac027ac12b4a5e219b4eeb5b0360b5e464461 --- dom/media/VideoPlaybackQuality.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dom/media/VideoPlaybackQuality.h b/dom/media/VideoPlaybackQuality.h index 40c0b95785e8..6054240c69ce 100644 --- a/dom/media/VideoPlaybackQuality.h +++ b/dom/media/VideoPlaybackQuality.h @@ -36,17 +36,17 @@ public: return mCreationTime; } - uint32_t TotalVideoFrames() + uint32_t TotalVideoFrames() const { return mTotalFrames; } - uint32_t DroppedVideoFrames() + uint32_t DroppedVideoFrames() const { return mDroppedFrames; } - uint32_t CorruptedVideoFrames() + uint32_t CorruptedVideoFrames() const { return mCorruptedFrames; } @@ -64,4 +64,4 @@ private: } // namespace dom } // namespace mozilla -#endif /* mozilla_dom_VideoPlaybackQuality_h_ */ +#endif // mozilla_dom_VideoPlaybackQuality_h_ From 56c993321543707965beb2339da5c18005c776ad Mon Sep 17 00:00:00 2001 From: Gerald Squelart Date: Fri, 15 Jul 2016 16:48:56 +1000 Subject: [PATCH 079/120] Bug 1289668 - FrameStatistics style - r=kamidphish MozReview-Commit-ID: B9yEd7tqfAN --HG-- extra : rebase_source : 3b1bfd11c604f9e57321c842f4893192ca9b77b5 --- dom/media/FrameStatistics.h | 47 +++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/dom/media/FrameStatistics.h b/dom/media/FrameStatistics.h index 448530322500..d91918108c15 100644 --- a/dom/media/FrameStatistics.h +++ b/dom/media/FrameStatistics.h @@ -11,27 +11,31 @@ namespace mozilla { // Frame decoding/painting related performance counters. // Threadsafe. -class FrameStatistics { +class FrameStatistics +{ public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FrameStatistics); - FrameStatistics() : - mReentrantMonitor("FrameStats"), - mParsedFrames(0), - mDecodedFrames(0), - mPresentedFrames(0), - mDroppedFrames(0) {} + FrameStatistics() + : mReentrantMonitor("FrameStats") + , mParsedFrames(0) + , mDecodedFrames(0) + , mPresentedFrames(0) + , mDroppedFrames(0) + {} // Returns number of frames which have been parsed from the media. // Can be called on any thread. - uint32_t GetParsedFrames() { + uint32_t GetParsedFrames() const + { ReentrantMonitorAutoEnter mon(mReentrantMonitor); return mParsedFrames; } // Returns the number of parsed frames which have been decoded. // Can be called on any thread. - uint32_t GetDecodedFrames() { + uint32_t GetDecodedFrames() const + { ReentrantMonitorAutoEnter mon(mReentrantMonitor); return mDecodedFrames; } @@ -39,14 +43,16 @@ public: // Returns the number of decoded frames which have been sent to the rendering // pipeline for painting ("presented"). // Can be called on any thread. - uint32_t GetPresentedFrames() { + uint32_t GetPresentedFrames() const + { ReentrantMonitorAutoEnter mon(mReentrantMonitor); return mPresentedFrames; } - // Number of frames that have been skipped because they have missed their - // compoisition deadline. - uint32_t GetDroppedFrames() { + // Returns the number of frames that have been skipped because they have + // missed their composition deadline. + uint32_t GetDroppedFrames() const + { ReentrantMonitorAutoEnter mon(mReentrantMonitor); return mDroppedFrames; } @@ -54,9 +60,11 @@ public: // Increments the parsed and decoded frame counters by the passed in counts. // Can be called on any thread. void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded, - uint32_t aDropped) { - if (aParsed == 0 && aDecoded == 0 && aDropped == 0) + uint32_t aDropped) + { + if (aParsed == 0 && aDecoded == 0 && aDropped == 0) { return; + } ReentrantMonitorAutoEnter mon(mReentrantMonitor); mParsedFrames += aParsed; mDecodedFrames += aDecoded; @@ -65,7 +73,8 @@ public: // Increments the presented frame counters. // Can be called on any thread. - void NotifyPresentedFrame() { + void NotifyPresentedFrame() + { ReentrantMonitorAutoEnter mon(mReentrantMonitor); ++mPresentedFrames; } @@ -74,7 +83,7 @@ private: ~FrameStatistics() {} // ReentrantMonitor to protect access of playback statistics. - ReentrantMonitor mReentrantMonitor; + mutable ReentrantMonitor mReentrantMonitor; // Number of frames parsed and demuxed from media. // Access protected by mReentrantMonitor. @@ -88,9 +97,11 @@ private: // pipeline to be painted ("presented"). Access protected by mReentrantMonitor. uint32_t mPresentedFrames; + // Number of frames that have been skipped because they have missed their + // composition deadline. uint32_t mDroppedFrames; }; } // namespace mozilla -#endif +#endif // FrameStatistics_h_ From 9448bd8536292cc2923f0c0c8f5e91b3a2859d79 Mon Sep 17 00:00:00 2001 From: Gerald Squelart Date: Mon, 18 Jul 2016 09:51:25 +1000 Subject: [PATCH 080/120] Bug 1289668 - Refactor FrameStatistics - r=kamidphish Move FrameStatistics' data into separate struct, so that it can more easily be changed and passed around, outside of the lock-controlled FrameStatistics object. MozReview-Commit-ID: TfsMRJhVfQ --HG-- extra : rebase_source : 8c4c6a23c8c2d6ff4272f9f918c9510326691148 --- dom/html/HTMLVideoElement.cpp | 9 ++--- dom/media/FrameStatistics.h | 63 ++++++++++++++++++++--------------- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/dom/html/HTMLVideoElement.cpp b/dom/html/HTMLVideoElement.cpp index 0ca00a2720ab..8977524b90d3 100644 --- a/dom/html/HTMLVideoElement.cpp +++ b/dom/html/HTMLVideoElement.cpp @@ -242,11 +242,12 @@ HTMLVideoElement::GetVideoPlaybackQuality() } if (mDecoder) { - FrameStatistics& stats = mDecoder->GetFrameStatistics(); - static_assert(sizeof(uint32_t) >= sizeof (stats.GetParsedFrames()), + FrameStatisticsData stats = + mDecoder->GetFrameStatistics().GetFrameStatisticsData(); + static_assert(sizeof(totalFrames) >= sizeof(stats.mParsedFrames), "possible truncation from FrameStatistics to VideoPlaybackQuality"); - totalFrames = stats.GetParsedFrames(); - droppedFrames = stats.GetDroppedFrames(); + totalFrames = stats.mParsedFrames; + droppedFrames = stats.mDroppedFrames; corruptedFrames = 0; } } diff --git a/dom/media/FrameStatistics.h b/dom/media/FrameStatistics.h index d91918108c15..d975cfce4c71 100644 --- a/dom/media/FrameStatistics.h +++ b/dom/media/FrameStatistics.h @@ -9,6 +9,25 @@ namespace mozilla { +struct FrameStatisticsData +{ + // Number of frames parsed and demuxed from media. + // Access protected by mReentrantMonitor. + uint32_t mParsedFrames = 0; + + // Number of parsed frames which were actually decoded. + // Access protected by mReentrantMonitor. + uint32_t mDecodedFrames = 0; + + // Number of decoded frames which were actually sent down the rendering + // pipeline to be painted ("presented"). Access protected by mReentrantMonitor. + uint32_t mPresentedFrames = 0; + + // Number of frames that have been skipped because they have missed their + // composition deadline. + uint32_t mDroppedFrames = 0; +}; + // Frame decoding/painting related performance counters. // Threadsafe. class FrameStatistics @@ -18,18 +37,22 @@ public: FrameStatistics() : mReentrantMonitor("FrameStats") - , mParsedFrames(0) - , mDecodedFrames(0) - , mPresentedFrames(0) - , mDroppedFrames(0) {} + // Returns a copy of all frame statistics data. + // Can be called on any thread. + FrameStatisticsData GetFrameStatisticsData() const + { + ReentrantMonitorAutoEnter mon(mReentrantMonitor); + return mFrameStatisticsData; + } + // Returns number of frames which have been parsed from the media. // Can be called on any thread. uint32_t GetParsedFrames() const { ReentrantMonitorAutoEnter mon(mReentrantMonitor); - return mParsedFrames; + return mFrameStatisticsData.mParsedFrames; } // Returns the number of parsed frames which have been decoded. @@ -37,7 +60,7 @@ public: uint32_t GetDecodedFrames() const { ReentrantMonitorAutoEnter mon(mReentrantMonitor); - return mDecodedFrames; + return mFrameStatisticsData.mDecodedFrames; } // Returns the number of decoded frames which have been sent to the rendering @@ -46,7 +69,7 @@ public: uint32_t GetPresentedFrames() const { ReentrantMonitorAutoEnter mon(mReentrantMonitor); - return mPresentedFrames; + return mFrameStatisticsData.mPresentedFrames; } // Returns the number of frames that have been skipped because they have @@ -54,7 +77,7 @@ public: uint32_t GetDroppedFrames() const { ReentrantMonitorAutoEnter mon(mReentrantMonitor); - return mDroppedFrames; + return mFrameStatisticsData.mDroppedFrames; } // Increments the parsed and decoded frame counters by the passed in counts. @@ -66,9 +89,9 @@ public: return; } ReentrantMonitorAutoEnter mon(mReentrantMonitor); - mParsedFrames += aParsed; - mDecodedFrames += aDecoded; - mDroppedFrames += aDropped; + mFrameStatisticsData.mParsedFrames += aParsed; + mFrameStatisticsData.mDecodedFrames += aDecoded; + mFrameStatisticsData.mDroppedFrames += aDropped; } // Increments the presented frame counters. @@ -76,7 +99,7 @@ public: void NotifyPresentedFrame() { ReentrantMonitorAutoEnter mon(mReentrantMonitor); - ++mPresentedFrames; + ++mFrameStatisticsData.mPresentedFrames; } private: @@ -85,21 +108,7 @@ private: // ReentrantMonitor to protect access of playback statistics. mutable ReentrantMonitor mReentrantMonitor; - // Number of frames parsed and demuxed from media. - // Access protected by mReentrantMonitor. - uint32_t mParsedFrames; - - // Number of parsed frames which were actually decoded. - // Access protected by mReentrantMonitor. - uint32_t mDecodedFrames; - - // Number of decoded frames which were actually sent down the rendering - // pipeline to be painted ("presented"). Access protected by mReentrantMonitor. - uint32_t mPresentedFrames; - - // Number of frames that have been skipped because they have missed their - // composition deadline. - uint32_t mDroppedFrames; + FrameStatisticsData mFrameStatisticsData; }; } // namespace mozilla From 16ceda979400e8184dfd622b8f2f5ac24b90080c Mon Sep 17 00:00:00 2001 From: Gerald Squelart Date: Mon, 18 Jul 2016 10:51:30 +1000 Subject: [PATCH 081/120] Bug 1289668 - Use 64 bits to store FrameStatistics values - r=kamidphish Decoders uses 64-bit values to count frames, so we should use the same type in FrameStatistics. Because VideoPlaybackQuality can only use 32 bits (as defined in W3C specs), we need to ensure that imported FrameStatistics numbers can fit in 32 bits, while keeping their ratios the same. MozReview-Commit-ID: 3pUTGK0ekGv --HG-- extra : rebase_source : 627fada111b51b8830fd38bf6d60a79b899ce603 --- dom/html/HTMLVideoElement.cpp | 23 +++++++++++++++++++---- dom/media/FrameStatistics.h | 20 ++++++++++---------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/dom/html/HTMLVideoElement.cpp b/dom/html/HTMLVideoElement.cpp index 8977524b90d3..d7033aa188fb 100644 --- a/dom/html/HTMLVideoElement.cpp +++ b/dom/html/HTMLVideoElement.cpp @@ -31,6 +31,9 @@ #include "mozilla/dom/Performance.h" #include "mozilla/dom/VideoPlaybackQuality.h" +#include +#include + NS_IMPL_NS_NEW_HTML_ELEMENT(Video) namespace mozilla { @@ -244,10 +247,22 @@ HTMLVideoElement::GetVideoPlaybackQuality() if (mDecoder) { FrameStatisticsData stats = mDecoder->GetFrameStatistics().GetFrameStatisticsData(); - static_assert(sizeof(totalFrames) >= sizeof(stats.mParsedFrames), - "possible truncation from FrameStatistics to VideoPlaybackQuality"); - totalFrames = stats.mParsedFrames; - droppedFrames = stats.mDroppedFrames; + if (sizeof(totalFrames) >= sizeof(stats.mParsedFrames)) { + totalFrames = stats.mParsedFrames; + droppedFrames = stats.mDroppedFrames; + } else { + auto maxStat = std::max(stats.mParsedFrames, stats.mDroppedFrames); + const auto maxNumber = std::numeric_limits::max(); + if (maxStat <= maxNumber) { + totalFrames = static_cast(stats.mParsedFrames); + droppedFrames = static_cast(stats.mDroppedFrames); + } else { + // Too big number(s) -> Resize everything to fit in 32 bits. + double ratio = double(maxNumber) / double(maxStat); + totalFrames = double(stats.mParsedFrames) * ratio; + droppedFrames = double(stats.mDroppedFrames) * ratio; + } + } corruptedFrames = 0; } } diff --git a/dom/media/FrameStatistics.h b/dom/media/FrameStatistics.h index d975cfce4c71..bf3071dd6f7a 100644 --- a/dom/media/FrameStatistics.h +++ b/dom/media/FrameStatistics.h @@ -13,19 +13,19 @@ struct FrameStatisticsData { // Number of frames parsed and demuxed from media. // Access protected by mReentrantMonitor. - uint32_t mParsedFrames = 0; + uint64_t mParsedFrames = 0; // Number of parsed frames which were actually decoded. // Access protected by mReentrantMonitor. - uint32_t mDecodedFrames = 0; + uint64_t mDecodedFrames = 0; // Number of decoded frames which were actually sent down the rendering // pipeline to be painted ("presented"). Access protected by mReentrantMonitor. - uint32_t mPresentedFrames = 0; + uint64_t mPresentedFrames = 0; // Number of frames that have been skipped because they have missed their // composition deadline. - uint32_t mDroppedFrames = 0; + uint64_t mDroppedFrames = 0; }; // Frame decoding/painting related performance counters. @@ -49,7 +49,7 @@ public: // Returns number of frames which have been parsed from the media. // Can be called on any thread. - uint32_t GetParsedFrames() const + uint64_t GetParsedFrames() const { ReentrantMonitorAutoEnter mon(mReentrantMonitor); return mFrameStatisticsData.mParsedFrames; @@ -57,7 +57,7 @@ public: // Returns the number of parsed frames which have been decoded. // Can be called on any thread. - uint32_t GetDecodedFrames() const + uint64_t GetDecodedFrames() const { ReentrantMonitorAutoEnter mon(mReentrantMonitor); return mFrameStatisticsData.mDecodedFrames; @@ -66,7 +66,7 @@ public: // Returns the number of decoded frames which have been sent to the rendering // pipeline for painting ("presented"). // Can be called on any thread. - uint32_t GetPresentedFrames() const + uint64_t GetPresentedFrames() const { ReentrantMonitorAutoEnter mon(mReentrantMonitor); return mFrameStatisticsData.mPresentedFrames; @@ -74,7 +74,7 @@ public: // Returns the number of frames that have been skipped because they have // missed their composition deadline. - uint32_t GetDroppedFrames() const + uint64_t GetDroppedFrames() const { ReentrantMonitorAutoEnter mon(mReentrantMonitor); return mFrameStatisticsData.mDroppedFrames; @@ -82,8 +82,8 @@ public: // Increments the parsed and decoded frame counters by the passed in counts. // Can be called on any thread. - void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded, - uint32_t aDropped) + void NotifyDecodedFrames(uint64_t aParsed, uint64_t aDecoded, + uint64_t aDropped) { if (aParsed == 0 && aDecoded == 0 && aDropped == 0) { return; From 7bea2e1262ab657705c43eec5c8b44ea566943e9 Mon Sep 17 00:00:00 2001 From: Gerald Squelart Date: Mon, 18 Jul 2016 10:41:40 +1000 Subject: [PATCH 082/120] Bug 1289668 - Refactor FrameStatistics writers to use Data struct - r=kamidphish Decoders now use FrameStatisticsData to gather data for their frame-related notifications. This will ease introducing new members later on. MozReview-Commit-ID: DWdOSPX3JM --HG-- extra : rebase_source : a3e05f34353a397d1c82b3f4d935c0864f90556e --- dom/media/AbstractMediaDecoder.h | 14 ++++++------ dom/media/FrameStatistics.h | 28 +++++++++++++++++------- dom/media/MediaDecoder.h | 6 ++--- dom/media/MediaFormatReader.cpp | 10 ++++----- dom/media/android/AndroidMediaReader.cpp | 10 ++++----- dom/media/mediasink/VideoSink.cpp | 2 +- dom/media/ogg/OggReader.cpp | 4 ++-- dom/media/omx/MediaOmxReader.cpp | 6 ++--- dom/media/raw/RawReader.cpp | 4 ++-- dom/media/webaudio/BufferDecoder.cpp | 3 +-- dom/media/webaudio/BufferDecoder.h | 3 +-- 11 files changed, 49 insertions(+), 41 deletions(-) diff --git a/dom/media/AbstractMediaDecoder.h b/dom/media/AbstractMediaDecoder.h index 9edd17b10c7a..c5c35f6ed97d 100644 --- a/dom/media/AbstractMediaDecoder.h +++ b/dom/media/AbstractMediaDecoder.h @@ -10,6 +10,7 @@ #include "mozilla/Attributes.h" #include "mozilla/StateMirroring.h" +#include "FrameStatistics.h" #include "MediaEventSource.h" #include "MediaInfo.h" #include "nsISupports.h" @@ -57,8 +58,7 @@ public: // Increments the parsed, decoded and dropped frame counters by the passed in // counts. // Can be called on any thread. - virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded, - uint32_t aDropped) = 0; + virtual void NotifyDecodedFrames(const FrameStatisticsData& aStats) = 0; virtual AbstractCanonical* CanonicalDurationOrNull() { return nullptr; }; @@ -99,15 +99,15 @@ public: class AutoNotifyDecoded { public: explicit AutoNotifyDecoded(AbstractMediaDecoder* aDecoder) - : mParsed(0), mDecoded(0), mDropped(0), mDecoder(aDecoder) {} + : mDecoder(aDecoder) + {} ~AutoNotifyDecoded() { if (mDecoder) { - mDecoder->NotifyDecodedFrames(mParsed, mDecoded, mDropped); + mDecoder->NotifyDecodedFrames(mStats); } } - uint32_t mParsed; - uint32_t mDecoded; - uint32_t mDropped; + + FrameStatisticsData mStats; private: AbstractMediaDecoder* mDecoder; diff --git a/dom/media/FrameStatistics.h b/dom/media/FrameStatistics.h index bf3071dd6f7a..60add635d3a5 100644 --- a/dom/media/FrameStatistics.h +++ b/dom/media/FrameStatistics.h @@ -7,6 +7,8 @@ #ifndef FrameStatistics_h_ #define FrameStatistics_h_ +#include "mozilla/ReentrantMonitor.h" + namespace mozilla { struct FrameStatisticsData @@ -26,6 +28,22 @@ struct FrameStatisticsData // Number of frames that have been skipped because they have missed their // composition deadline. uint64_t mDroppedFrames = 0; + + FrameStatisticsData() = default; + FrameStatisticsData(uint64_t aParsed, uint64_t aDecoded, uint64_t aDropped) + : mParsedFrames(aParsed) + , mDecodedFrames(aDecoded) + , mDroppedFrames(aDropped) + {} + + void + Accumulate(const FrameStatisticsData& aStats) + { + mParsedFrames += aStats.mParsedFrames; + mDecodedFrames += aStats.mDecodedFrames; + mPresentedFrames += aStats.mPresentedFrames; + mDroppedFrames += aStats.mDroppedFrames; + } }; // Frame decoding/painting related performance counters. @@ -82,16 +100,10 @@ public: // Increments the parsed and decoded frame counters by the passed in counts. // Can be called on any thread. - void NotifyDecodedFrames(uint64_t aParsed, uint64_t aDecoded, - uint64_t aDropped) + void NotifyDecodedFrames(const FrameStatisticsData& aStats) { - if (aParsed == 0 && aDecoded == 0 && aDropped == 0) { - return; - } ReentrantMonitorAutoEnter mon(mReentrantMonitor); - mFrameStatisticsData.mParsedFrames += aParsed; - mFrameStatisticsData.mDecodedFrames += aDecoded; - mFrameStatisticsData.mDroppedFrames += aDropped; + mFrameStatisticsData.Accumulate(aStats); } // Increments the presented frame counters. diff --git a/dom/media/MediaDecoder.h b/dom/media/MediaDecoder.h index 637e884cd988..e826e0361eac 100644 --- a/dom/media/MediaDecoder.h +++ b/dom/media/MediaDecoder.h @@ -27,7 +27,6 @@ #include "nsITimer.h" #include "AbstractMediaDecoder.h" -#include "FrameStatistics.h" #include "MediaDecoderOwner.h" #include "MediaEventSource.h" #include "MediaMetadataManager.h" @@ -484,10 +483,9 @@ private: // Increments the parsed and decoded frame counters by the passed in counts. // Can be called on any thread. - virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded, - uint32_t aDropped) override + virtual void NotifyDecodedFrames(const FrameStatisticsData& aStats) override { - GetFrameStatistics().NotifyDecodedFrames(aParsed, aDecoded, aDropped); + GetFrameStatistics().NotifyDecodedFrames(aStats); } void UpdateReadyState() diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index 19a8736b12bb..945e4fcce9d7 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -1015,7 +1015,7 @@ MediaFormatReader::HandleDemuxedSamples(TrackType aTrack, decoder.mNumSamplesInput++; decoder.mSizeOfQueue++; if (aTrack == TrackInfo::kVideoTrack) { - aA.mParsed++; + aA.mStats.mParsedFrames++; } if (mDemuxOnly) { @@ -1192,7 +1192,7 @@ MediaFormatReader::Update(TrackType aTrack) if (aTrack == TrackType::kVideoTrack) { uint64_t delta = decoder.mNumSamplesOutputTotal - mLastReportedNumDecodedFrames; - a.mDecoded = static_cast(delta); + a.mStats.mDecodedFrames = static_cast(delta); mLastReportedNumDecodedFrames = decoder.mNumSamplesOutputTotal; nsCString error; mVideo.mIsHardwareAccelerated = @@ -1491,7 +1491,7 @@ MediaFormatReader::DropDecodedSamples(TrackType aTrack) decoder.mOutput.Clear(); decoder.mSizeOfQueue -= lengthDecodedQueue; if (aTrack == TrackInfo::kVideoTrack && mDecoder) { - mDecoder->NotifyDecodedFrames(0, 0, lengthDecodedQueue); + mDecoder->NotifyDecodedFrames({ 0, 0, lengthDecodedQueue }); } } @@ -1527,7 +1527,7 @@ MediaFormatReader::VideoSkipReset(uint32_t aSkipped) DropDecodedSamples(TrackInfo::kVideoTrack); // Report the pending frames as dropped. if (mDecoder) { - mDecoder->NotifyDecodedFrames(0, 0, SizeOfVideoQueueInFrames()); + mDecoder->NotifyDecodedFrames({ 0, 0, SizeOfVideoQueueInFrames() }); } // Cancel any pending demux request and pending demuxed samples. @@ -1535,7 +1535,7 @@ MediaFormatReader::VideoSkipReset(uint32_t aSkipped) Reset(TrackType::kVideoTrack); if (mDecoder) { - mDecoder->NotifyDecodedFrames(aSkipped, 0, aSkipped); + mDecoder->NotifyDecodedFrames({ aSkipped, 0, aSkipped }); } mVideo.mNumSamplesSkippedTotal += aSkipped; diff --git a/dom/media/android/AndroidMediaReader.cpp b/dom/media/android/AndroidMediaReader.cpp index 59f8441037f7..723f2a84e15a 100644 --- a/dom/media/android/AndroidMediaReader.cpp +++ b/dom/media/android/AndroidMediaReader.cpp @@ -155,8 +155,8 @@ bool AndroidMediaReader::DecodeVideoFrame(bool &aKeyframeSkip, // when a frame is a keyframe. #if 0 if (!frame.mKeyFrame) { - ++a.mParsed; - ++a.mDropped; + ++a.mStats.mParsedFrames; + ++a.mStats.mDroppedFrames; continue; } #endif @@ -244,9 +244,9 @@ bool AndroidMediaReader::DecodeVideoFrame(bool &aKeyframeSkip, if (!v) { return false; } - a.mParsed++; - a.mDecoded++; - NS_ASSERTION(a.mDecoded <= a.mParsed, "Expect to decode fewer frames than parsed in AndroidMedia..."); + a.mStats.mParsedFrames++; + a.mStats.mDecodedFrames++; + NS_ASSERTION(a.mStats.mDecodedFrames <= a.mStats.mParsedFrames, "Expect to decode fewer frames than parsed in AndroidMedia..."); // Since MPAPI doesn't give us the end time of frames, we keep one frame // buffered in AndroidMediaReader and push it into the queue as soon diff --git a/dom/media/mediasink/VideoSink.cpp b/dom/media/mediasink/VideoSink.cpp index f11be6029f20..0408fae13ca0 100644 --- a/dom/media/mediasink/VideoSink.cpp +++ b/dom/media/mediasink/VideoSink.cpp @@ -406,7 +406,7 @@ VideoSink::UpdateRenderedVideoFrames() } ++framesRemoved; if (!currentFrame->As()->mSentToCompositor) { - mFrameStats.NotifyDecodedFrames(0, 0, 1); + mFrameStats.NotifyDecodedFrames({ 0, 0, 1 }); VSINK_LOG_V("discarding video frame mTime=%lld clock_time=%lld", currentFrame->mTime, clockTime); } diff --git a/dom/media/ogg/OggReader.cpp b/dom/media/ogg/OggReader.cpp index de4f8f4961a0..b4e0b8896287 100644 --- a/dom/media/ogg/OggReader.cpp +++ b/dom/media/ogg/OggReader.cpp @@ -921,7 +921,7 @@ bool OggReader::DecodeVideoFrame(bool &aKeyframeSkip, } nsAutoRef autoRelease(packet); - a.mParsed++; + a.mStats.mParsedFrames++; NS_ASSERTION(packet && packet->granulepos != -1, "Must know first packet's granulepos"); bool eos = packet->e_o_s; @@ -931,7 +931,7 @@ bool OggReader::DecodeVideoFrame(bool &aKeyframeSkip, { aKeyframeSkip = false; nsresult res = DecodeTheora(packet, aTimeThreshold); - a.mDecoded++; + a.mStats.mDecodedFrames++; if (NS_FAILED(res)) { return false; } diff --git a/dom/media/omx/MediaOmxReader.cpp b/dom/media/omx/MediaOmxReader.cpp index 5da68bbdd1d5..171b5b46e326 100644 --- a/dom/media/omx/MediaOmxReader.cpp +++ b/dom/media/omx/MediaOmxReader.cpp @@ -357,7 +357,7 @@ bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip, continue; } - a.mParsed++; + a.mStats.mParsedFrames++; if (frame.mShouldSkip && mSkipCount < MAX_DROPPED_FRAMES) { mSkipCount++; continue; @@ -434,8 +434,8 @@ bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip, return false; } - a.mDecoded++; - NS_ASSERTION(a.mDecoded <= a.mParsed, "Expect to decode fewer frames than parsed in OMX decoder..."); + a.mStats.mDecodedFrames++; + NS_ASSERTION(a.mStats.mDecodedFrames <= a.mStats.mParsedFrames, "Expect to decode fewer frames than parsed in OMX decoder..."); mVideoQueue.Push(v); diff --git a/dom/media/raw/RawReader.cpp b/dom/media/raw/RawReader.cpp index 0098e821c9c0..dc899d43a510 100644 --- a/dom/media/raw/RawReader.cpp +++ b/dom/media/raw/RawReader.cpp @@ -156,7 +156,7 @@ bool RawReader::DecodeVideoFrame(bool &aKeyframeSkip, return false; } - a.mParsed++; + a.mStats.mParsedFrames++; if (currentFrameTime >= aTimeThreshold) break; @@ -200,7 +200,7 @@ bool RawReader::DecodeVideoFrame(bool &aKeyframeSkip, mVideoQueue.Push(v); mCurrentFrame++; - a.mDecoded++; + a.mStats.mDecodedFrames++; return true; } diff --git a/dom/media/webaudio/BufferDecoder.cpp b/dom/media/webaudio/BufferDecoder.cpp index c8715b1f77ae..a3fe46d10fc3 100644 --- a/dom/media/webaudio/BufferDecoder.cpp +++ b/dom/media/webaudio/BufferDecoder.cpp @@ -42,8 +42,7 @@ BufferDecoder::GetResource() const } void -BufferDecoder::NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded, - uint32_t aDropped) +BufferDecoder::NotifyDecodedFrames(const FrameStatisticsData& aStats) { // ignore } diff --git a/dom/media/webaudio/BufferDecoder.h b/dom/media/webaudio/BufferDecoder.h index ca18454f1a8b..287909595ded 100644 --- a/dom/media/webaudio/BufferDecoder.h +++ b/dom/media/webaudio/BufferDecoder.h @@ -33,8 +33,7 @@ public: MediaResource* GetResource() const final override; - void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded, - uint32_t aDropped) final override; + void NotifyDecodedFrames(const FrameStatisticsData& aStats) final override; VideoFrameContainer* GetVideoFrameContainer() final override; layers::ImageContainer* GetImageContainer() final override; From baaf9059ef4c219ab6ba30ea01c25763bc12c6ab Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Mon, 25 Jul 2016 11:10:15 -0700 Subject: [PATCH 083/120] Bug 1288793 - Part 1: Convert js::gc::State to an enum class; r=jonco * * * Bug _ - Add a test to ensure that abort works during decommit slices; NOT_REVIEWED --HG-- extra : rebase_source : b606dd26b62301f16079aae0e0085d86be502169 --- js/src/builtin/TestingFunctions.cpp | 18 +-- js/src/gc/GCRuntime.h | 6 +- js/src/gc/Marking.cpp | 8 +- js/src/gc/Statistics.h | 2 +- js/src/gc/Verifier.cpp | 8 +- js/src/jit-test/tests/gc/bug-1138390.js | 4 +- js/src/jit-test/tests/gc/incremental-abort.js | 12 +- .../tests/gc/incremental-compacting.js | 4 +- js/src/jit-test/tests/gc/incremental-state.js | 42 +++--- js/src/jsapi-tests/testGCFinalizeCallback.cpp | 2 +- js/src/jsgc.cpp | 127 +++++++++--------- js/src/jsgc.h | 22 +-- js/src/vm/Debugger.cpp | 6 +- 13 files changed, 122 insertions(+), 139 deletions(-) diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 3be8cd074ec7..510976d9736d 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -864,23 +864,7 @@ GCState(JSContext* cx, unsigned argc, Value* vp) return false; } - const char* state; - gc::State globalState = cx->runtime()->gc.state(); - if (globalState == gc::NO_INCREMENTAL) - state = "none"; - else if (globalState == gc::MARK) - state = "mark"; - else if (globalState == gc::SWEEP) - state = "sweep"; - else if (globalState == gc::FINALIZE) - state = "finalize"; - else if (globalState == gc::COMPACT) - state = "compact"; - else if (globalState == gc::DECOMMIT) - state = "decommit"; - else - MOZ_CRASH("Unobserveable global GC state"); - + const char* state = StateName(cx->runtime()->gc.state()); JSString* str = JS_NewStringCopyZ(cx, state); if (!str) return false; diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index 7ecb6ca17534..492fcbb280a5 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -689,8 +689,8 @@ class GCRuntime public: // Internal public interface State state() const { return incrementalState; } - bool isHeapCompacting() const { return state() == COMPACT; } - bool isForegroundSweeping() const { return state() == SWEEP; } + bool isHeapCompacting() const { return state() == State::Compact; } + bool isForegroundSweeping() const { return state() == State::Sweep; } bool isBackgroundSweeping() { return helperState.isBackgroundSweeping(); } void waitBackgroundSweepEnd() { helperState.waitBackgroundSweepEnd(); } void waitBackgroundSweepOrAllocEnd() { @@ -766,7 +766,7 @@ class GCRuntime void disallowIncrementalGC() { incrementalAllowed = false; } bool isIncrementalGCEnabled() const { return mode == JSGC_MODE_INCREMENTAL && incrementalAllowed; } - bool isIncrementalGCInProgress() const { return state() != NO_INCREMENTAL; } + bool isIncrementalGCInProgress() const { return state() != State::NotActive; } bool isGenerationalGCEnabled() const { return generationalDisabled == 0; } void disableGenerationalGC(); diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index f6a1fbbfc24f..d323b80fc1bc 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -346,8 +346,8 @@ static void AssertRootMarkingPhase(JSTracer* trc) { MOZ_ASSERT_IF(trc->isMarkingTracer(), - trc->runtime()->gc.state() == NO_INCREMENTAL || - trc->runtime()->gc.state() == MARK_ROOTS); + trc->runtime()->gc.state() == State::NotActive || + trc->runtime()->gc.state() == State::MarkRoots); } @@ -1945,7 +1945,7 @@ bool GCMarker::markDelayedChildren(SliceBudget& budget) { GCRuntime& gc = runtime()->gc; - gcstats::AutoPhase ap(gc.stats, gc.state() == MARK, gcstats::PHASE_MARK_DELAYED); + gcstats::AutoPhase ap(gc.stats, gc.state() == State::Mark, gcstats::PHASE_MARK_DELAYED); MOZ_ASSERT(unmarkedArenaStackTop); do { @@ -2439,7 +2439,7 @@ CheckIsMarkedThing(T* thingp) JSRuntime* rt = (*thingp)->runtimeFromAnyThread(); MOZ_ASSERT_IF(!ThingIsPermanentAtomOrWellKnownSymbol(*thingp), CurrentThreadCanAccessRuntime(rt) || - (rt->isHeapCollecting() && rt->gc.state() == SWEEP)); + (rt->isHeapCollecting() && rt->gc.state() == State::Sweep)); #endif } diff --git a/js/src/gc/Statistics.h b/js/src/gc/Statistics.h index 17446465f8c9..508aefc4bae0 100644 --- a/js/src/gc/Statistics.h +++ b/js/src/gc/Statistics.h @@ -253,7 +253,7 @@ struct Statistics double startTimestamp, size_t startFaults, gc::State initialState) : budget(budget), reason(reason), initialState(initialState), - finalState(gc::NO_INCREMENTAL), + finalState(gc::State::NotActive), resetReason(nullptr), start(start), startTimestamp(startTimestamp), startFaults(startFaults) diff --git a/js/src/gc/Verifier.cpp b/js/src/gc/Verifier.cpp index fe3f2049406e..2bf4e2a03759 100644 --- a/js/src/gc/Verifier.cpp +++ b/js/src/gc/Verifier.cpp @@ -203,7 +203,7 @@ gc::GCRuntime::startVerifyPreBarriers() /* Create the root node. */ trc->curnode = MakeNode(trc, nullptr, JS::TraceKind(0)); - incrementalState = MARK_ROOTS; + incrementalState = State::MarkRoots; /* Make all the roots be edges emanating from the root node. */ markRuntime(trc, TraceRuntime, prep.session().lock); @@ -230,7 +230,7 @@ gc::GCRuntime::startVerifyPreBarriers() } verifyPreData = trc; - incrementalState = MARK; + incrementalState = State::Mark; marker.start(); for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { @@ -244,7 +244,7 @@ gc::GCRuntime::startVerifyPreBarriers() return; oom: - incrementalState = NO_INCREMENTAL; + incrementalState = State::NotActive; js_delete(trc); verifyPreData = nullptr; } @@ -342,7 +342,7 @@ gc::GCRuntime::endVerifyPreBarriers() number++; verifyPreData = nullptr; - incrementalState = NO_INCREMENTAL; + incrementalState = State::NotActive; if (!compartmentCreated && IsIncrementalGCSafe(rt)) { CheckEdgeTracer cetrc(rt); diff --git a/js/src/jit-test/tests/gc/bug-1138390.js b/js/src/jit-test/tests/gc/bug-1138390.js index bc9faf49b54a..f0f46e2fb20a 100644 --- a/js/src/jit-test/tests/gc/bug-1138390.js +++ b/js/src/jit-test/tests/gc/bug-1138390.js @@ -17,12 +17,12 @@ var g = newGlobal(); // Start an off thread compilation that will not run until GC has finished if ("gcstate" in this) - assertEq(gcstate(), "mark"); + assertEq(gcstate(), "Mark"); g.offThreadCompileScript('23;', {}); // Wait for the compilation to finish, which must finish the GC first assertEq(23, g.runOffThreadScript()); if ("gcstate" in this) - assertEq(gcstate(), "none"); + assertEq(gcstate(), "NotActive"); print("done"); diff --git a/js/src/jit-test/tests/gc/incremental-abort.js b/js/src/jit-test/tests/gc/incremental-abort.js index a4bead260a1a..db42c70511e3 100644 --- a/js/src/jit-test/tests/gc/incremental-abort.js +++ b/js/src/jit-test/tests/gc/incremental-abort.js @@ -27,7 +27,7 @@ function testAbort(zoneCount, objectCount, sliceCount, abortState) var didAbort = false; startgc(sliceCount, "shrinking"); - while (gcstate() !== "none") { + while (gcstate() !== "NotActive") { var state = gcstate(); if (state == abortState) { abortgc(); @@ -38,7 +38,7 @@ function testAbort(zoneCount, objectCount, sliceCount, abortState) gcslice(sliceCount); } - assertEq(gcstate(), "none"); + assertEq(gcstate(), "NotActive"); if (abortState) assertEq(didAbort, true); @@ -47,6 +47,8 @@ function testAbort(zoneCount, objectCount, sliceCount, abortState) gczeal(0); testAbort(10, 10000, 10000); -testAbort(10, 10000, 10000, "mark"); -testAbort(10, 10000, 10000, "sweep"); -testAbort(10, 10000, 10000, "compact"); +testAbort(10, 10000, 10000, "Mark"); +testAbort(10, 10000, 10000, "Sweep"); +testAbort(10, 10000, 10000, "Compact"); +// Note: we do not yield automatically before Finalize or Decommit, as they yield internally. +// Thus, we may not witness an incremental state in this phase and cannot test it explicitly. diff --git a/js/src/jit-test/tests/gc/incremental-compacting.js b/js/src/jit-test/tests/gc/incremental-compacting.js index bb367b0f8bf3..25f770ae6391 100644 --- a/js/src/jit-test/tests/gc/incremental-compacting.js +++ b/js/src/jit-test/tests/gc/incremental-compacting.js @@ -27,11 +27,11 @@ function testCompacting(zoneCount, objectCount, sliceCount) } // Finish any alloc-triggered incremental GC - if (gcstate() !== "none") + if (gcstate() !== "NotActive") gc(); startgc(sliceCount, "shrinking"); - while (gcstate() !== "none") { + while (gcstate() !== "NotActive") { gcslice(sliceCount); } diff --git a/js/src/jit-test/tests/gc/incremental-state.js b/js/src/jit-test/tests/gc/incremental-state.js index 4e807f7e93c7..0d6566d0ee77 100644 --- a/js/src/jit-test/tests/gc/incremental-state.js +++ b/js/src/jit-test/tests/gc/incremental-state.js @@ -6,26 +6,26 @@ gczeal(0); // Non-incremental GC. gc(); -assertEq(gcstate(), "none"); +assertEq(gcstate(), "NotActive"); // Incremental GC in minimal slice. Note that finalization always uses zero- // sized slices while background finalization is on-going, so we need to loop. gcslice(1000000); -while (gcstate() == "finalize") { gcslice(1); } -while (gcstate() == "decommit") { gcslice(1); } -assertEq(gcstate(), "none"); +while (gcstate() == "Finalize") { gcslice(1); } +while (gcstate() == "Decommit") { gcslice(1); } +assertEq(gcstate(), "NotActive"); // Incremental GC in multiple slices: if marking takes more than one slice, // we yield before we start sweeping. gczeal(0); gcslice(1); -assertEq(gcstate(), "mark"); +assertEq(gcstate(), "Mark"); gcslice(1000000); -assertEq(gcstate(), "mark"); +assertEq(gcstate(), "Mark"); gcslice(1000000); -while (gcstate() == "finalize") { gcslice(1); } -while (gcstate() == "decommit") { gcslice(1); } -assertEq(gcstate(), "none"); +while (gcstate() == "Finalize") { gcslice(1); } +while (gcstate() == "Decommit") { gcslice(1); } +assertEq(gcstate(), "NotActive"); // Zeal mode 8: Incremental GC in two main slices: // 1) mark roots @@ -33,11 +33,11 @@ assertEq(gcstate(), "none"); // *) finalize. gczeal(8, 0); gcslice(1); -assertEq(gcstate(), "mark"); +assertEq(gcstate(), "Mark"); gcslice(1); -while (gcstate() == "finalize") { gcslice(1); } -while (gcstate() == "decommit") { gcslice(1); } -assertEq(gcstate(), "none"); +while (gcstate() == "Finalize") { gcslice(1); } +while (gcstate() == "Decommit") { gcslice(1); } +assertEq(gcstate(), "NotActive"); // Zeal mode 9: Incremental GC in two main slices: // 1) mark roots and marking @@ -45,19 +45,19 @@ assertEq(gcstate(), "none"); // *) finalize. gczeal(9, 0); gcslice(1); -assertEq(gcstate(), "mark"); +assertEq(gcstate(), "Mark"); gcslice(1); -while (gcstate() == "finalize") { gcslice(1); } -while (gcstate() == "decommit") { gcslice(1); } -assertEq(gcstate(), "none"); +while (gcstate() == "Finalize") { gcslice(1); } +while (gcstate() == "Decommit") { gcslice(1); } +assertEq(gcstate(), "NotActive"); // Zeal mode 10: Incremental GC in multiple slices (always yeilds before // sweeping). This test uses long slices to prove that this zeal mode yields // in sweeping, where normal IGC (above) does not. gczeal(10, 0); gcslice(1000000); -assertEq(gcstate(), "sweep"); +assertEq(gcstate(), "Sweep"); gcslice(1000000); -while (gcstate() == "finalize") { gcslice(1); } -while (gcstate() == "decommit") { gcslice(1); } -assertEq(gcstate(), "none"); +while (gcstate() == "Finalize") { gcslice(1); } +while (gcstate() == "Decommit") { gcslice(1); } +assertEq(gcstate(), "NotActive"); diff --git a/js/src/jsapi-tests/testGCFinalizeCallback.cpp b/js/src/jsapi-tests/testGCFinalizeCallback.cpp index 90d6cbcbc669..48612ff6700e 100644 --- a/js/src/jsapi-tests/testGCFinalizeCallback.cpp +++ b/js/src/jsapi-tests/testGCFinalizeCallback.cpp @@ -103,7 +103,7 @@ BEGIN_TEST(testGCFinalizeCallback) JS::PrepareForFullGC(cx); js::SliceBudget budget(js::WorkBudget(1)); cx->gc.startDebugGC(GC_NORMAL, budget); - CHECK(cx->gc.state() == js::gc::MARK); + CHECK(cx->gc.state() == js::gc::State::Mark); CHECK(cx->gc.isFullGc()); JS::RootedObject global4(cx, createTestGlobal()); diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 25cda157a2aa..7c44bbd67ef6 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -53,46 +53,49 @@ * The collector proceeds through the following states, the current state being * held in JSRuntime::gcIncrementalState: * - * - MARK_ROOTS - marks the stack and other roots - * - MARK - incrementally marks reachable things - * - SWEEP - sweeps zones in groups and continues marking unswept zones + * - MarkRoots - marks the stack and other roots + * - Mark - incrementally marks reachable things + * - Sweep - sweeps zones in groups and continues marking unswept zones + * - Finalize - performs background finalization, concurrent with mutator + * - Compact - incrementally compacts by zone + * - Decommit - performs background decommit and chunk removal * - * The MARK_ROOTS activity always takes place in the first slice. The next two + * The MarkRoots activity always takes place in the first slice. The next two * states can take place over one or more slices. * * In other words an incremental collection proceeds like this: * - * Slice 1: MARK_ROOTS: Roots pushed onto the mark stack. - * MARK: The mark stack is processed by popping an element, + * Slice 1: MarkRoots: Roots pushed onto the mark stack. + * Mark: The mark stack is processed by popping an element, * marking it, and pushing its children. * * ... JS code runs ... * - * Slice 2: MARK: More mark stack processing. + * Slice 2: Mark: More mark stack processing. * * ... JS code runs ... * - * Slice n-1: MARK: More mark stack processing. + * Slice n-1: Mark: More mark stack processing. * * ... JS code runs ... * - * Slice n: MARK: Mark stack is completely drained. - * SWEEP: Select first group of zones to sweep and sweep them. + * Slice n: Mark: Mark stack is completely drained. + * Sweep: Select first group of zones to sweep and sweep them. * * ... JS code runs ... * - * Slice n+1: SWEEP: Mark objects in unswept zones that were newly + * Slice n+1: Sweep: Mark objects in unswept zones that were newly * identified as alive (see below). Then sweep more zone * groups. * * ... JS code runs ... * - * Slice n+2: SWEEP: Mark objects in unswept zones that were newly + * Slice n+2: Sweep: Mark objects in unswept zones that were newly * identified as alive. Then sweep more zone groups. * * ... JS code runs ... * - * Slice m: SWEEP: Sweeping is finished, and background sweeping + * Slice m: Sweep: Sweeping is finished, and background sweeping * started on the helper thread. * * ... JS code runs, remaining sweeping done on background thread ... @@ -141,7 +144,7 @@ * * The order of sweeping is restricted by cross compartment pointers - for * example say that object |a| from zone A points to object |b| in zone B and - * neither object was marked when we transitioned to the SWEEP phase. Imagine we + * neither object was marked when we transitioned to the Sweep phase. Imagine we * sweep B first and then return to the mutator. It's possible that the mutator * could cause |a| to become alive through a read barrier (perhaps it was a * shape that was accessed via a shape table). Then we would need to mark |b|, @@ -822,7 +825,7 @@ GCRuntime::GCRuntime(JSRuntime* rt) : #ifdef DEBUG disableStrictProxyCheckingCount(0), #endif - incrementalState(gc::NO_INCREMENTAL), + incrementalState(gc::State::NotActive), lastMarkSlice(false), sweepOnBackgroundThread(false), foundBlackGrayEdges(false), @@ -4176,7 +4179,7 @@ js::gc::MarkingValidator::nonIncrementalMark(AutoLockForExclusiveAccess& lock) /* Re-do all the marking, but non-incrementally. */ js::gc::State state = gc->incrementalState; - gc->incrementalState = MARK_ROOTS; + gc->incrementalState = State::MarkRoots; { gcstats::AutoPhase ap(gc->stats, gcstats::PHASE_MARK); @@ -4196,12 +4199,12 @@ js::gc::MarkingValidator::nonIncrementalMark(AutoLockForExclusiveAccess& lock) gc->markRuntime(gcmarker, GCRuntime::MarkRuntime, lock); - gc->incrementalState = MARK; + gc->incrementalState = State::Mark; auto unlimited = SliceBudget::unlimited(); MOZ_RELEASE_ASSERT(gc->marker.drainMarkStack(unlimited)); } - gc->incrementalState = SWEEP; + gc->incrementalState = State::Sweep; { gcstats::AutoPhase ap1(gc->stats, gcstats::PHASE_SWEEP); gcstats::AutoPhase ap2(gc->stats, gcstats::PHASE_SWEEP_MARK); @@ -5621,10 +5624,14 @@ void GCRuntime::resetIncrementalGC(const char* reason, AutoLockForExclusiveAccess& lock) { switch (incrementalState) { - case NO_INCREMENTAL: + case State::NotActive: return; - case MARK: { + case State::MarkRoots: + MOZ_CRASH("resetIncrementalGC did not expect MarkRoots state"); + break; + + case State::Mark: { /* Cancel any ongoing marking. */ marker.reset(); marker.stop(); @@ -5641,14 +5648,14 @@ GCRuntime::resetIncrementalGC(const char* reason, AutoLockForExclusiveAccess& lo blocksToFreeAfterSweeping.freeAll(); - incrementalState = NO_INCREMENTAL; + incrementalState = State::NotActive; MOZ_ASSERT(!marker.shouldCheckCompartments()); break; } - case SWEEP: { + case State::Sweep: { marker.reset(); for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) @@ -5673,7 +5680,7 @@ GCRuntime::resetIncrementalGC(const char* reason, AutoLockForExclusiveAccess& lo break; } - case FINALIZE: { + case State::Finalize: { { gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD); rt->gc.waitBackgroundSweepOrAllocEnd(); @@ -5690,7 +5697,7 @@ GCRuntime::resetIncrementalGC(const char* reason, AutoLockForExclusiveAccess& lo break; } - case COMPACT: { + case State::Compact: { bool wasCompacting = isCompacting; isCompacting = true; @@ -5704,14 +5711,11 @@ GCRuntime::resetIncrementalGC(const char* reason, AutoLockForExclusiveAccess& lo break; } - case DECOMMIT: { + case State::Decommit: { auto unlimited = SliceBudget::unlimited(); incrementalCollectSlice(unlimited, JS::gcreason::RESET, lock); break; } - - default: - MOZ_CRASH("Invalid incremental GC state"); } stats.reset(reason); @@ -5724,7 +5728,7 @@ GCRuntime::resetIncrementalGC(const char* reason, AutoLockForExclusiveAccess& lo MOZ_ASSERT(!zone->isOnList()); } MOZ_ASSERT(zonesToMaybeCompact.isEmpty()); - MOZ_ASSERT(incrementalState == NO_INCREMENTAL); + MOZ_ASSERT(incrementalState == State::NotActive); #endif } @@ -5843,33 +5847,33 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea } switch (incrementalState) { - case NO_INCREMENTAL: + case State::NotActive: initialReason = reason; cleanUpEverything = ShouldCleanUpEverything(reason, invocationKind); isCompacting = shouldCompact(); lastMarkSlice = false; - incrementalState = MARK_ROOTS; + incrementalState = State::MarkRoots; MOZ_FALLTHROUGH; - case MARK_ROOTS: + case State::MarkRoots: if (!beginMarkPhase(reason, lock)) { - incrementalState = NO_INCREMENTAL; + incrementalState = State::NotActive; return; } if (!destroyingRuntime) pushZealSelectedObjects(); - incrementalState = MARK; + incrementalState = State::Mark; if (isIncremental && useZeal && hasZealMode(ZealMode::IncrementalRootsThenFinish)) break; MOZ_FALLTHROUGH; - case MARK: + case State::Mark: AutoGCRooter::traceAllWrappers(&marker); /* If we needed delayed marking for gray roots, then collect until done. */ @@ -5884,19 +5888,19 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea MOZ_ASSERT(marker.isDrained()); if (!lastMarkSlice && isIncremental && useZeal && - ((initialState == MARK && !hasZealMode(ZealMode::IncrementalRootsThenFinish)) || + ((initialState == State::Mark && !hasZealMode(ZealMode::IncrementalRootsThenFinish)) || hasZealMode(ZealMode::IncrementalMarkAllThenFinish))) { /* * Yield with the aim of starting the sweep in the next * slice. We will need to mark anything new on the stack - * when we resume, so we stay in MARK state. + * when we resume, so we stay in Mark state. */ lastMarkSlice = true; break; } - incrementalState = SWEEP; + incrementalState = State::Sweep; /* * This runs to completion, but we don't continue if the budget is @@ -5915,13 +5919,13 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea MOZ_FALLTHROUGH; - case SWEEP: + case State::Sweep: if (sweepPhase(budget, lock) == NotFinished) break; endSweepPhase(destroyingRuntime, lock); - incrementalState = FINALIZE; + incrementalState = State::Finalize; /* Yield before compacting since it is not incremental. */ if (isCompacting && isIncremental) @@ -5929,7 +5933,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea MOZ_FALLTHROUGH; - case FINALIZE: + case State::Finalize: { gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD); @@ -5955,11 +5959,11 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea } MOZ_ASSERT(!startedCompacting); - incrementalState = COMPACT; + incrementalState = State::Compact; MOZ_FALLTHROUGH; - case COMPACT: + case State::Compact: if (isCompacting) { if (!startedCompacting) beginCompactPhase(); @@ -5971,11 +5975,11 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea } startDecommit(); - incrementalState = DECOMMIT; + incrementalState = State::Decommit; MOZ_FALLTHROUGH; - case DECOMMIT: + case State::Decommit: { gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD); @@ -5987,11 +5991,8 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea } finishCollection(reason); - incrementalState = NO_INCREMENTAL; + incrementalState = State::NotActive; break; - - default: - MOZ_CRASH("unexpected GC incrementalState"); } } @@ -6154,7 +6155,7 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason:: } /* The GC was reset, so we need a do-over. */ - if (prevState != NO_INCREMENTAL && !isIncrementalGCInProgress()) + if (prevState != State::NotActive && !isIncrementalGCInProgress()) return true; TraceMajorGCStart(); @@ -6361,7 +6362,7 @@ GCRuntime::finishGC(JS::gcreason::Reason reason) // compacting phase if we need to finish an ongoing incremental GC // non-incrementally to avoid janking the browser. if (!IsOOMReason(initialReason)) { - if (incrementalState == COMPACT) { + if (incrementalState == State::Compact) { abortGC(); return; } @@ -6799,8 +6800,8 @@ GCRuntime::runDebugGC() * or compact phases. */ if (hasZealMode(ZealMode::IncrementalMultipleSlices)) { - if ((initialState == MARK && incrementalState == SWEEP) || - (initialState == SWEEP && incrementalState == COMPACT)) + if ((initialState == State::Mark && incrementalState == State::Sweep) || + (initialState == State::Sweep && incrementalState == State::Compact)) { incrementalLimit = zealFrequency / 2; } @@ -7313,7 +7314,7 @@ JS::IsIncrementalGCInProgress(JSContext* cx) JS_PUBLIC_API(bool) JS::IsIncrementalBarrierNeeded(JSContext* cx) { - return cx->gc.state() == gc::MARK && !cx->isHeapBusy(); + return cx->gc.state() == gc::State::Mark && !cx->isHeapBusy(); } struct IncrementalReferenceBarrierFunctor { @@ -7596,18 +7597,12 @@ NewMemoryInfoObject(JSContext* cx) const char* StateName(State state) { - static const char* names[] = { - "None", - "MarkRoots", - "Mark", - "Sweep", - "Finalize", - "Compact", - "Decommit" - }; - MOZ_ASSERT(ArrayLength(names) == NUM_STATES); - MOZ_ASSERT(state < NUM_STATES); - return names[state]; + switch(state) { +#define MAKE_CASE(name) case State::name: return #name; + GCSTATES(MAKE_CASE) +#undef MAKE_CASE + } + MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("invalide gc::State enum value"); } void diff --git a/js/src/jsgc.h b/js/src/jsgc.h index c9c73fcce514..87b7ac867d48 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -43,16 +43,18 @@ namespace gc { struct FinalizePhase; -enum State { - NO_INCREMENTAL, - MARK_ROOTS, - MARK, - SWEEP, - FINALIZE, - COMPACT, - DECOMMIT, - - NUM_STATES +#define GCSTATES(D) \ + D(NotActive) \ + D(MarkRoots) \ + D(Mark) \ + D(Sweep) \ + D(Finalize) \ + D(Compact) \ + D(Decommit) +enum class State { +#define MAKE_STATE(name) name, + GCSTATES(MAKE_STATE) +#undef MAKE_STATE }; /* diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index c0bef4877ff4..6e58033cd1db 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -2829,12 +2829,12 @@ Debugger::markIncomingCrossCompartmentEdges(JSTracer* trc) { JSRuntime* rt = trc->runtime(); gc::State state = rt->gc.state(); - MOZ_ASSERT(state == gc::MARK_ROOTS || state == gc::COMPACT); + MOZ_ASSERT(state == gc::State::MarkRoots || state == gc::State::Compact); for (Debugger* dbg : rt->debuggerList) { Zone* zone = MaybeForwarded(dbg->object.get())->zone(); - if ((state == gc::MARK_ROOTS && !zone->isCollecting()) || - (state == gc::COMPACT && !zone->isGCCompacting())) + if ((state == gc::State::MarkRoots && !zone->isCollecting()) || + (state == gc::State::Compact && !zone->isGCCompacting())) { dbg->markCrossCompartmentEdges(trc); } From 0ddab9429a32292f24c08129504ed73fcded96a2 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Thu, 28 Jul 2016 09:34:11 -0700 Subject: [PATCH 084/120] Bug 1288793 - Part 2: Test slice callback and message formatting; r=jonco --HG-- extra : rebase_source : 6fc7be0397fbea501c99925d41d2377897b60504 --- js/src/jsapi-tests/moz.build | 1 + js/src/jsapi-tests/testGCHooks.cpp | 36 ++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 js/src/jsapi-tests/testGCHooks.cpp diff --git a/js/src/jsapi-tests/moz.build b/js/src/jsapi-tests/moz.build index 0fde7a44be01..0d93734e5220 100644 --- a/js/src/jsapi-tests/moz.build +++ b/js/src/jsapi-tests/moz.build @@ -44,6 +44,7 @@ UNIFIED_SOURCES += [ 'testGCExactRooting.cpp', 'testGCFinalizeCallback.cpp', 'testGCHeapPostBarriers.cpp', + 'testGCHooks.cpp', 'testGCMarking.cpp', 'testGCOutOfMemory.cpp', 'testGCStoreBufferRemoval.cpp', diff --git a/js/src/jsapi-tests/testGCHooks.cpp b/js/src/jsapi-tests/testGCHooks.cpp new file mode 100644 index 000000000000..0106549fe0ea --- /dev/null +++ b/js/src/jsapi-tests/testGCHooks.cpp @@ -0,0 +1,36 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/UniquePtr.h" + +#include "js/GCAPI.h" + +#include "jsapi-tests/tests.h" + +static unsigned gSliceCallbackCount = 0; + +static void +NonIncrementalGCSliceCallback(JSContext* cx, JS::GCProgress progress, const JS::GCDescription& desc) +{ + ++gSliceCallbackCount; + MOZ_RELEASE_ASSERT(progress == JS::GC_CYCLE_BEGIN || progress == JS::GC_CYCLE_END); + MOZ_RELEASE_ASSERT(desc.isCompartment_ == false); + MOZ_RELEASE_ASSERT(desc.invocationKind_ == GC_NORMAL); + MOZ_RELEASE_ASSERT(desc.reason_ == JS::gcreason::API); + if (progress == JS::GC_CYCLE_END) { + mozilla::UniquePtr summary(desc.formatSummaryMessage(cx)); + mozilla::UniquePtr message(desc.formatSliceMessage(cx)); + mozilla::UniquePtr json(desc.formatJSON(cx, 0)); + } +} + +BEGIN_TEST(testGCSliceCallback) +{ + JS::SetGCSliceCallback(cx, NonIncrementalGCSliceCallback); + JS_GC(cx); + JS::SetGCSliceCallback(cx, nullptr); + CHECK(gSliceCallbackCount == 2); + return true; +} +END_TEST(testGCSliceCallback) From 55cbd3e6012214700ce6791e53affef25f7b76dd Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Thu, 28 Jul 2016 13:42:02 -0700 Subject: [PATCH 085/120] Backed out changeset af745bd5c209 for xpcshell test failures. MozReview-Commit-ID: Dt6n5mRFLgN --HG-- extra : amend_source : 2be72943ed781129bed07c3723d87b0f3d7eca9c --- .../extensions/test/mochitest/mochitest.ini | 7 ++++ ...xt_background_runtime_connect_params.html} | 23 ++++++++++-- .../test_ext_extension.html} | 30 ++++++++++++---- .../test_ext_idle.html} | 19 ++++++++-- .../test_ext_onmessage_removelistener.html} | 23 ++++++++++-- .../test_ext_runtime_getPlatformInfo.html} | 21 +++++++++-- .../test_ext_runtime_sendMessage.html} | 21 +++++++++-- .../test_ext_simple.html} | 35 +++++++++++++++---- .../test_ext_runtime_connect_no_receiver.js | 19 ---------- ...est_ext_runtime_sendMessage_no_receiver.js | 22 ------------ .../extensions/test/xpcshell/xpcshell.ini | 8 ----- 11 files changed, 151 insertions(+), 77 deletions(-) rename toolkit/components/extensions/test/{xpcshell/test_ext_background_runtime_connect_params.js => mochitest/test_ext_background_runtime_connect_params.html} (74%) rename toolkit/components/extensions/test/{xpcshell/test_ext_extension.js => mochitest/test_ext_extension.html} (67%) rename toolkit/components/extensions/test/{xpcshell/test_ext_idle.js => mochitest/test_ext_idle.html} (50%) rename toolkit/components/extensions/test/{xpcshell/test_ext_onmessage_removelistener.js => mochitest/test_ext_onmessage_removelistener.html} (54%) rename toolkit/components/extensions/test/{xpcshell/test_ext_runtime_getPlatformInfo.js => mochitest/test_ext_runtime_getPlatformInfo.html} (54%) rename toolkit/components/extensions/test/{xpcshell/test_ext_runtime_sendMessage.js => mochitest/test_ext_runtime_sendMessage.html} (82%) rename toolkit/components/extensions/test/{xpcshell/test_ext_simple.js => mochitest/test_ext_simple.html} (55%) delete mode 100644 toolkit/components/extensions/test/xpcshell/test_ext_runtime_connect_no_receiver.js delete mode 100644 toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_no_receiver.js diff --git a/toolkit/components/extensions/test/mochitest/mochitest.ini b/toolkit/components/extensions/test/mochitest/mochitest.ini index 23a9daa5b0bb..3fa0e4e33404 100644 --- a/toolkit/components/extensions/test/mochitest/mochitest.ini +++ b/toolkit/components/extensions/test/mochitest/mochitest.ini @@ -35,8 +35,10 @@ support-files = file_ext_test_api_injection.js file_permission_xhr.html +[test_ext_extension.html] [test_ext_inIncognitoContext_window.html] skip-if = os == 'android' # Android does not currently support windows. +[test_ext_simple.html] [test_ext_geturl.html] [test_ext_background_canvas.html] [test_ext_content_security_policy.html] @@ -50,6 +52,8 @@ skip-if = buildapp == 'b2g' # runat != document_idle is not supported. [test_ext_exclude_include_globs.html] [test_ext_i18n_css.html] [test_ext_generate.html] +[test_ext_idle.html] +[test_ext_onmessage_removelistener.html] [test_ext_notifications.html] [test_ext_permission_xhr.html] skip-if = buildapp == 'b2g' # JavaScript error: jar:remoteopenfile:///data/local/tmp/generated-extension.xpi!/content.js, line 46: NS_ERROR_ILLEGAL_VALUE: @@ -60,7 +64,9 @@ skip-if = (os == 'android' || buildapp == 'b2g') # port.sender.tab is undefined [test_ext_runtime_connect2.html] skip-if = (os == 'android' || buildapp == 'b2g') # port.sender.tab is undefined on b2g. Bug 1258975 on android. [test_ext_runtime_disconnect.html] +[test_ext_runtime_getPlatformInfo.html] [test_ext_runtime_id.html] +[test_ext_runtime_sendMessage.html] [test_ext_sandbox_var.html] [test_ext_sendmessage_reply.html] skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2g. Bug 1258975 on android. @@ -71,6 +77,7 @@ skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2 [test_ext_storage_content.html] [test_ext_storage_tab.html] skip-if = os == 'android' # Android does not currently support tabs. +[test_ext_background_runtime_connect_params.html] [test_ext_cookies.html] [test_ext_background_api_injection.html] [test_ext_background_generated_url.html] diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_background_runtime_connect_params.js b/toolkit/components/extensions/test/mochitest/test_ext_background_runtime_connect_params.html similarity index 74% rename from toolkit/components/extensions/test/xpcshell/test_ext_background_runtime_connect_params.js rename to toolkit/components/extensions/test/mochitest/test_ext_background_runtime_connect_params.html index 008bdbbed1a9..8296ec335ca0 100644 --- a/toolkit/components/extensions/test/xpcshell/test_ext_background_runtime_connect_params.js +++ b/toolkit/components/extensions/test/mochitest/test_ext_background_runtime_connect_params.html @@ -1,5 +1,16 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ + + + + WebExtension test + + + + + + + + + + + + diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_extension.js b/toolkit/components/extensions/test/mochitest/test_ext_extension.html similarity index 67% rename from toolkit/components/extensions/test/xpcshell/test_ext_extension.js rename to toolkit/components/extensions/test/mochitest/test_ext_extension.html index 28e4890538ad..a8d225573799 100644 --- a/toolkit/components/extensions/test/xpcshell/test_ext_extension.js +++ b/toolkit/components/extensions/test/mochitest/test_ext_extension.html @@ -1,5 +1,16 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ + + + + WebExtension test + + + + + + + + + + + + diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_idle.js b/toolkit/components/extensions/test/mochitest/test_ext_idle.html similarity index 50% rename from toolkit/components/extensions/test/xpcshell/test_ext_idle.js rename to toolkit/components/extensions/test/mochitest/test_ext_idle.html index 8e128791d426..8e2d92383801 100644 --- a/toolkit/components/extensions/test/xpcshell/test_ext_idle.js +++ b/toolkit/components/extensions/test/mochitest/test_ext_idle.html @@ -1,5 +1,16 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ + + + + WebExtension idle API test + + + + + + + + + + diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_onmessage_removelistener.js b/toolkit/components/extensions/test/mochitest/test_ext_onmessage_removelistener.html similarity index 54% rename from toolkit/components/extensions/test/xpcshell/test_ext_onmessage_removelistener.js rename to toolkit/components/extensions/test/mochitest/test_ext_onmessage_removelistener.html index 6f8b553fc6b2..eadbed1411a9 100644 --- a/toolkit/components/extensions/test/xpcshell/test_ext_onmessage_removelistener.js +++ b/toolkit/components/extensions/test/mochitest/test_ext_onmessage_removelistener.html @@ -1,5 +1,16 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ + + + + WebExtension test + + + + + + + + + + + + diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_getPlatformInfo.js b/toolkit/components/extensions/test/mochitest/test_ext_runtime_getPlatformInfo.html similarity index 54% rename from toolkit/components/extensions/test/xpcshell/test_ext_runtime_getPlatformInfo.js rename to toolkit/components/extensions/test/mochitest/test_ext_runtime_getPlatformInfo.html index 3487321d86dc..0dc80a7cf443 100644 --- a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_getPlatformInfo.js +++ b/toolkit/components/extensions/test/mochitest/test_ext_runtime_getPlatformInfo.html @@ -1,5 +1,16 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ + + + + WebExtension test + + + + + + + + + + + + diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage.js b/toolkit/components/extensions/test/mochitest/test_ext_runtime_sendMessage.html similarity index 82% rename from toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage.js rename to toolkit/components/extensions/test/mochitest/test_ext_runtime_sendMessage.html index a85b7fb7299f..d360580ea380 100644 --- a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage.js +++ b/toolkit/components/extensions/test/mochitest/test_ext_runtime_sendMessage.html @@ -1,5 +1,16 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ + + + + WebExtension test + + + + + + + + + + + + diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_simple.js b/toolkit/components/extensions/test/mochitest/test_ext_simple.html similarity index 55% rename from toolkit/components/extensions/test/xpcshell/test_ext_simple.js rename to toolkit/components/extensions/test/mochitest/test_ext_simple.html index f91ec3c2c310..dd545d9c7e61 100644 --- a/toolkit/components/extensions/test/xpcshell/test_ext_simple.js +++ b/toolkit/components/extensions/test/mochitest/test_ext_simple.html @@ -1,5 +1,16 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ + + + + Test for simple WebExtension + + + + + + + + + + + + diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_connect_no_receiver.js b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_connect_no_receiver.js deleted file mode 100644 index 7c22a8a4b0dc..000000000000 --- a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_connect_no_receiver.js +++ /dev/null @@ -1,19 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -add_task(function* test_connect_without_listener() { - function background() { - let port = browser.runtime.connect(); - port.onDisconnect.addListener(() => { - browser.test.notifyPass("port.onDisconnect was called"); - }); - } - - let extension = ExtensionTestUtils.loadExtension({background}); - yield extension.startup(); - - yield extension.awaitFinish("port.onDisconnect was called"); - - yield extension.unload(); -}); diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_no_receiver.js b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_no_receiver.js deleted file mode 100644 index 6640bbe8ea22..000000000000 --- a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_no_receiver.js +++ /dev/null @@ -1,22 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -add_task(function* test_sendMessage_without_listener() { - function background() { - browser.runtime.sendMessage("msg").then(reply => { - browser.test.assertEq(undefined, reply); - browser.test.notifyFail("Did not expect a reply to sendMessage"); - }, error => { - browser.test.assertEq("Could not establish connection. Receiving end does not exist.", error.message); - browser.test.notifyPass("sendMessage callback was invoked"); - }); - } - - let extension = ExtensionTestUtils.loadExtension({background}); - yield extension.startup(); - - yield extension.awaitFinish("sendMessage callback was invoked"); - - yield extension.unload(); -}); diff --git a/toolkit/components/extensions/test/xpcshell/xpcshell.ini b/toolkit/components/extensions/test/xpcshell/xpcshell.ini index 91d61ac2d1e6..51615c02adeb 100644 --- a/toolkit/components/extensions/test/xpcshell/xpcshell.ini +++ b/toolkit/components/extensions/test/xpcshell/xpcshell.ini @@ -26,19 +26,11 @@ skip-if = os == "android" skip-if = os == "android" [test_ext_downloads_search.js] skip-if = os == "android" -[test_ext_extension.js] -[test_ext_idle.js] [test_ext_json_parser.js] [test_ext_localStorage.js] [test_ext_manifest_content_security_policy.js] [test_ext_manifest_incognito.js] -[test_ext_onmessage_removelistener.js] -[test_ext_runtime_connect_no_receiver.js] -[test_ext_runtime_getPlatformInfo.js] -[test_ext_runtime_sendMessage.js] -[test_ext_runtime_sendMessage_no_receiver.js] [test_ext_schemas.js] -[test_ext_simple.js] [test_ext_storage.js] [test_getAPILevelForWindow.js] [test_locale_converter.js] From 6cab4846679593562094211756e2ea4dc9d4a8f3 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Thu, 28 Jul 2016 13:49:38 -0700 Subject: [PATCH 086/120] Fix botched backout for changeset af745bd5c209 (bug 1288885) MozReview-Commit-ID: KCC6FQ0yn45 --HG-- extra : amend_source : 1d7255b7fa215407c958d3ba51915f22461d6526 --- toolkit/components/extensions/test/xpcshell/xpcshell.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/toolkit/components/extensions/test/xpcshell/xpcshell.ini b/toolkit/components/extensions/test/xpcshell/xpcshell.ini index 51615c02adeb..890d3c6d6075 100644 --- a/toolkit/components/extensions/test/xpcshell/xpcshell.ini +++ b/toolkit/components/extensions/test/xpcshell/xpcshell.ini @@ -14,7 +14,6 @@ support-files = [test_ext_alarms_replaces.js] [test_ext_background_generated_load_events.js] [test_ext_background_generated_reload.js] -[test_ext_background_runtime_connect_params.js] [test_ext_background_sub_windows.js] [test_ext_background_window_properties.js] skip-if = os == "android" From 55707f2b84e83980662de66fa4fa358d2687114f Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Fri, 22 Jul 2016 16:57:58 -0700 Subject: [PATCH 087/120] Bug 1288885: Migrate simple extension mochitests to xpcshell. r=aswan MozReview-Commit-ID: BiaTf6u43XP --HG-- rename : toolkit/components/extensions/test/mochitest/test_ext_background_runtime_connect_params.html => toolkit/components/extensions/test/xpcshell/test_ext_background_runtime_connect_params.js rename : toolkit/components/extensions/test/mochitest/test_ext_extension.html => toolkit/components/extensions/test/xpcshell/test_ext_extension.js rename : toolkit/components/extensions/test/mochitest/test_ext_idle.html => toolkit/components/extensions/test/xpcshell/test_ext_idle.js rename : toolkit/components/extensions/test/mochitest/test_ext_onmessage_removelistener.html => toolkit/components/extensions/test/xpcshell/test_ext_onmessage_removelistener.js rename : toolkit/components/extensions/test/mochitest/test_ext_runtime_getPlatformInfo.html => toolkit/components/extensions/test/xpcshell/test_ext_runtime_getPlatformInfo.js rename : toolkit/components/extensions/test/mochitest/test_ext_runtime_sendMessage.html => toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage.js rename : toolkit/components/extensions/test/mochitest/test_ext_simple.html => toolkit/components/extensions/test/xpcshell/test_ext_simple.js extra : rebase_source : a4931c7a6165193c45ea99538d4cc8300317929f extra : amend_source : eb3ec077285d7ad83b89b6f1a8df73230a58ab20 extra : intermediate-source : af745bd5c20928ef776a7c94c76cb9c87ac77c71 extra : source : f9fd137c9691e75d9e01d61be14608e7f28c7815 --- .../extensions/test/mochitest/mochitest.ini | 7 ---- ..._ext_background_runtime_connect_params.js} | 23 ++---------- .../test_ext_extension.js} | 30 ++++------------ .../test_ext_idle.js} | 19 ++-------- .../test_ext_onmessage_removelistener.js} | 23 ++---------- .../test_ext_runtime_getPlatformInfo.js} | 21 ++--------- .../test_ext_runtime_sendMessage.js} | 21 ++--------- .../test_ext_simple.js} | 35 ++++--------------- .../extensions/test/xpcshell/xpcshell.ini | 7 ++++ 9 files changed, 35 insertions(+), 151 deletions(-) rename toolkit/components/extensions/test/{mochitest/test_ext_background_runtime_connect_params.html => xpcshell/test_ext_background_runtime_connect_params.js} (74%) rename toolkit/components/extensions/test/{mochitest/test_ext_extension.html => xpcshell/test_ext_extension.js} (67%) rename toolkit/components/extensions/test/{mochitest/test_ext_idle.html => xpcshell/test_ext_idle.js} (50%) rename toolkit/components/extensions/test/{mochitest/test_ext_onmessage_removelistener.html => xpcshell/test_ext_onmessage_removelistener.js} (54%) rename toolkit/components/extensions/test/{mochitest/test_ext_runtime_getPlatformInfo.html => xpcshell/test_ext_runtime_getPlatformInfo.js} (54%) rename toolkit/components/extensions/test/{mochitest/test_ext_runtime_sendMessage.html => xpcshell/test_ext_runtime_sendMessage.js} (82%) rename toolkit/components/extensions/test/{mochitest/test_ext_simple.html => xpcshell/test_ext_simple.js} (55%) diff --git a/toolkit/components/extensions/test/mochitest/mochitest.ini b/toolkit/components/extensions/test/mochitest/mochitest.ini index 3fa0e4e33404..23a9daa5b0bb 100644 --- a/toolkit/components/extensions/test/mochitest/mochitest.ini +++ b/toolkit/components/extensions/test/mochitest/mochitest.ini @@ -35,10 +35,8 @@ support-files = file_ext_test_api_injection.js file_permission_xhr.html -[test_ext_extension.html] [test_ext_inIncognitoContext_window.html] skip-if = os == 'android' # Android does not currently support windows. -[test_ext_simple.html] [test_ext_geturl.html] [test_ext_background_canvas.html] [test_ext_content_security_policy.html] @@ -52,8 +50,6 @@ skip-if = buildapp == 'b2g' # runat != document_idle is not supported. [test_ext_exclude_include_globs.html] [test_ext_i18n_css.html] [test_ext_generate.html] -[test_ext_idle.html] -[test_ext_onmessage_removelistener.html] [test_ext_notifications.html] [test_ext_permission_xhr.html] skip-if = buildapp == 'b2g' # JavaScript error: jar:remoteopenfile:///data/local/tmp/generated-extension.xpi!/content.js, line 46: NS_ERROR_ILLEGAL_VALUE: @@ -64,9 +60,7 @@ skip-if = (os == 'android' || buildapp == 'b2g') # port.sender.tab is undefined [test_ext_runtime_connect2.html] skip-if = (os == 'android' || buildapp == 'b2g') # port.sender.tab is undefined on b2g. Bug 1258975 on android. [test_ext_runtime_disconnect.html] -[test_ext_runtime_getPlatformInfo.html] [test_ext_runtime_id.html] -[test_ext_runtime_sendMessage.html] [test_ext_sandbox_var.html] [test_ext_sendmessage_reply.html] skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2g. Bug 1258975 on android. @@ -77,7 +71,6 @@ skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2 [test_ext_storage_content.html] [test_ext_storage_tab.html] skip-if = os == 'android' # Android does not currently support tabs. -[test_ext_background_runtime_connect_params.html] [test_ext_cookies.html] [test_ext_background_api_injection.html] [test_ext_background_generated_url.html] diff --git a/toolkit/components/extensions/test/mochitest/test_ext_background_runtime_connect_params.html b/toolkit/components/extensions/test/xpcshell/test_ext_background_runtime_connect_params.js similarity index 74% rename from toolkit/components/extensions/test/mochitest/test_ext_background_runtime_connect_params.html rename to toolkit/components/extensions/test/xpcshell/test_ext_background_runtime_connect_params.js index 8296ec335ca0..008bdbbed1a9 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_background_runtime_connect_params.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_background_runtime_connect_params.js @@ -1,16 +1,5 @@ - - - - WebExtension test - - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/mochitest/test_ext_extension.html b/toolkit/components/extensions/test/xpcshell/test_ext_extension.js similarity index 67% rename from toolkit/components/extensions/test/mochitest/test_ext_extension.html rename to toolkit/components/extensions/test/xpcshell/test_ext_extension.js index a8d225573799..28e4890538ad 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_extension.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_extension.js @@ -1,16 +1,5 @@ - - - - WebExtension test - - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/mochitest/test_ext_idle.html b/toolkit/components/extensions/test/xpcshell/test_ext_idle.js similarity index 50% rename from toolkit/components/extensions/test/mochitest/test_ext_idle.html rename to toolkit/components/extensions/test/xpcshell/test_ext_idle.js index 8e2d92383801..8e128791d426 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_idle.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_idle.js @@ -1,16 +1,5 @@ - - - - WebExtension idle API test - - - - - - - - - - diff --git a/toolkit/components/extensions/test/mochitest/test_ext_onmessage_removelistener.html b/toolkit/components/extensions/test/xpcshell/test_ext_onmessage_removelistener.js similarity index 54% rename from toolkit/components/extensions/test/mochitest/test_ext_onmessage_removelistener.html rename to toolkit/components/extensions/test/xpcshell/test_ext_onmessage_removelistener.js index eadbed1411a9..6f8b553fc6b2 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_onmessage_removelistener.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_onmessage_removelistener.js @@ -1,16 +1,5 @@ - - - - WebExtension test - - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/mochitest/test_ext_runtime_getPlatformInfo.html b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_getPlatformInfo.js similarity index 54% rename from toolkit/components/extensions/test/mochitest/test_ext_runtime_getPlatformInfo.html rename to toolkit/components/extensions/test/xpcshell/test_ext_runtime_getPlatformInfo.js index 0dc80a7cf443..3487321d86dc 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_runtime_getPlatformInfo.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_getPlatformInfo.js @@ -1,16 +1,5 @@ - - - - WebExtension test - - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/mochitest/test_ext_runtime_sendMessage.html b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage.js similarity index 82% rename from toolkit/components/extensions/test/mochitest/test_ext_runtime_sendMessage.html rename to toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage.js index d360580ea380..a85b7fb7299f 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_runtime_sendMessage.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage.js @@ -1,16 +1,5 @@ - - - - WebExtension test - - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/mochitest/test_ext_simple.html b/toolkit/components/extensions/test/xpcshell/test_ext_simple.js similarity index 55% rename from toolkit/components/extensions/test/mochitest/test_ext_simple.html rename to toolkit/components/extensions/test/xpcshell/test_ext_simple.js index dd545d9c7e61..f91ec3c2c310 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_simple.html +++ b/toolkit/components/extensions/test/xpcshell/test_ext_simple.js @@ -1,16 +1,5 @@ - - - - Test for simple WebExtension - - - - - - - - - - - - diff --git a/toolkit/components/extensions/test/xpcshell/xpcshell.ini b/toolkit/components/extensions/test/xpcshell/xpcshell.ini index 890d3c6d6075..a5a9a52e4d65 100644 --- a/toolkit/components/extensions/test/xpcshell/xpcshell.ini +++ b/toolkit/components/extensions/test/xpcshell/xpcshell.ini @@ -14,6 +14,7 @@ support-files = [test_ext_alarms_replaces.js] [test_ext_background_generated_load_events.js] [test_ext_background_generated_reload.js] +[test_ext_background_runtime_connect_params.js] [test_ext_background_sub_windows.js] [test_ext_background_window_properties.js] skip-if = os == "android" @@ -25,11 +26,17 @@ skip-if = os == "android" skip-if = os == "android" [test_ext_downloads_search.js] skip-if = os == "android" +[test_ext_extension.js] +[test_ext_idle.js] [test_ext_json_parser.js] [test_ext_localStorage.js] [test_ext_manifest_content_security_policy.js] [test_ext_manifest_incognito.js] +[test_ext_onmessage_removelistener.js] +[test_ext_runtime_getPlatformInfo.js] +[test_ext_runtime_sendMessage.js] [test_ext_schemas.js] +[test_ext_simple.js] [test_ext_storage.js] [test_getAPILevelForWindow.js] [test_locale_converter.js] From 374f22a5660ce73d2ec1cffa608763cfdab93350 Mon Sep 17 00:00:00 2001 From: Gerald Squelart Date: Tue, 26 Jul 2016 11:32:58 +1000 Subject: [PATCH 088/120] Bug 1289668 - HTMLMediaElement uses video decoder's frame statistics - r=kamidphish HTMLVideoElement can expose its thread-safe FrameStatistics object, so that HTMLMediaElement can access more adequate data for its telemetry, without having to use an intermediary (and potentially less accurate) VideoPlaybackQuality object. This will also help with accessing other/new FrameStatistics members later on. MozReview-Commit-ID: AT7mEGy0zGr --HG-- extra : rebase_source : 35bf6673cc0acd9d4e6e1a58c573749689614d43 --- dom/html/HTMLMediaElement.cpp | 25 +++++++++++++------------ dom/html/HTMLVideoElement.cpp | 6 ++++++ dom/html/HTMLVideoElement.h | 3 +++ 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index b2b2359dd2ca..ccbe13daf3a4 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -3084,18 +3084,19 @@ HTMLMediaElement::ReportTelemetry() LOG(LogLevel::Debug, ("%p VIDEO_UNLOAD_STATE = %d", this, state)); if (HTMLVideoElement* vid = HTMLVideoElement::FromContentOrNull(this)) { - RefPtr quality = vid->GetVideoPlaybackQuality(); - uint32_t totalFrames = quality->TotalVideoFrames(); - if (totalFrames) { - uint32_t droppedFrames = quality->DroppedVideoFrames(); - MOZ_ASSERT(droppedFrames <= totalFrames); - // Dropped frames <= total frames, so 'percentage' cannot be higher than - // 100 and therefore can fit in a uint32_t (that Telemetry takes). - uint32_t percentage = 100 * droppedFrames / totalFrames; - LOG(LogLevel::Debug, - ("Reporting telemetry DROPPED_FRAMES_IN_VIDEO_PLAYBACK")); - Telemetry::Accumulate(Telemetry::VIDEO_DROPPED_FRAMES_PROPORTION, - percentage); + FrameStatistics* stats = vid->GetFrameStatistics(); + if (stats) { + FrameStatisticsData data = stats->GetFrameStatisticsData(); + if (data.mParsedFrames) { + MOZ_ASSERT(data.mDroppedFrames <= data.mParsedFrames); + // Dropped frames <= total frames, so 'percentage' cannot be higher than + // 100 and therefore can fit in a uint32_t (that Telemetry takes). + uint32_t percentage = 100 * data.mDroppedFrames / data.mParsedFrames; + LOG(LogLevel::Debug, + ("Reporting telemetry DROPPED_FRAMES_IN_VIDEO_PLAYBACK")); + Telemetry::Accumulate(Telemetry::VIDEO_DROPPED_FRAMES_PROPORTION, + percentage); + } } } diff --git a/dom/html/HTMLVideoElement.cpp b/dom/html/HTMLVideoElement.cpp index d7033aa188fb..0bf722cf8586 100644 --- a/dom/html/HTMLVideoElement.cpp +++ b/dom/html/HTMLVideoElement.cpp @@ -228,6 +228,12 @@ HTMLVideoElement::NotifyOwnerDocumentActivityChangedInternal() return pauseElement; } +FrameStatistics* +HTMLVideoElement::GetFrameStatistics() +{ + return mDecoder ? &(mDecoder->GetFrameStatistics()) : nullptr; +} + already_AddRefed HTMLVideoElement::GetVideoPlaybackQuality() { diff --git a/dom/html/HTMLVideoElement.h b/dom/html/HTMLVideoElement.h index 403d5d2e0846..a996c8ba57d0 100644 --- a/dom/html/HTMLVideoElement.h +++ b/dom/html/HTMLVideoElement.h @@ -130,6 +130,9 @@ public: bool NotifyOwnerDocumentActivityChangedInternal() override; + // Gives access to the decoder's frame statistics, if present. + FrameStatistics* GetFrameStatistics(); + already_AddRefed GetVideoPlaybackQuality(); protected: From 2a787d25216dee851c6ba1884ef3ccb63134d6c8 Mon Sep 17 00:00:00 2001 From: Gerald Squelart Date: Tue, 26 Jul 2016 09:36:55 +1000 Subject: [PATCH 089/120] Bug 1289668 - Record inter-keyframe statistics - r=kamidphish FrameStatisticsData can now store inter-keyframe information, which is provided by the MediaFormatReader (based on live decoding). MozReview-Commit-ID: HhBy6pgT6ZX --HG-- extra : rebase_source : 6a072623e8a5b0f23b81307e8ea4b19a3e21b252 --- dom/media/FrameStatistics.h | 15 +++++++++++++++ dom/media/MediaFormatReader.cpp | 30 ++++++++++++++++++++++++++++++ dom/media/MediaFormatReader.h | 15 +++++++-------- 3 files changed, 52 insertions(+), 8 deletions(-) diff --git a/dom/media/FrameStatistics.h b/dom/media/FrameStatistics.h index 60add635d3a5..e7d38262935d 100644 --- a/dom/media/FrameStatistics.h +++ b/dom/media/FrameStatistics.h @@ -29,6 +29,15 @@ struct FrameStatisticsData // composition deadline. uint64_t mDroppedFrames = 0; + // Sum of all inter-keyframe segment durations, in microseconds. + // Dividing by count will give the average inter-keyframe time. + uint64_t mInterKeyframeSum_us = 0; + // Number of inter-keyframe segments summed so far. + size_t mInterKeyframeCount = 0; + + // Maximum inter-keyframe segment duration, in microseconds. + uint64_t mInterKeyFrameMax_us = 0; + FrameStatisticsData() = default; FrameStatisticsData(uint64_t aParsed, uint64_t aDecoded, uint64_t aDropped) : mParsedFrames(aParsed) @@ -43,6 +52,12 @@ struct FrameStatisticsData mDecodedFrames += aStats.mDecodedFrames; mPresentedFrames += aStats.mPresentedFrames; mDroppedFrames += aStats.mDroppedFrames; + mInterKeyframeSum_us += aStats.mInterKeyframeSum_us; + mInterKeyframeCount += aStats.mInterKeyframeCount; + // It doesn't make sense to add max numbers, instead keep the bigger one. + if (mInterKeyFrameMax_us < aStats.mInterKeyFrameMax_us) { + mInterKeyFrameMax_us = aStats.mInterKeyFrameMax_us; + } } }; diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index 945e4fcce9d7..b39c167309e7 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -67,6 +67,7 @@ MediaFormatReader::MediaFormatReader(AbstractMediaDecoder* aDecoder, , mDemuxer(aDemuxer) , mDemuxerInitDone(false) , mLastReportedNumDecodedFrames(0) + , mPreviousDecodedKeyframeTime_us(sNoPreviousDecodedKeyframe) , mLayersBackendType(aLayersBackend) , mInitDone(false) , mIsEncrypted(false) @@ -1159,6 +1160,8 @@ MediaFormatReader::Update(TrackType aTrack) if (time >= target.Time()) { // We have reached our internal seek target. decoder.mTimeThreshold.reset(); + // We might have dropped some keyframes. + mPreviousDecodedKeyframeTime_us = sNoPreviousDecodedKeyframe; } if (time < target.Time() || (target.mDropTarget && target.Contains(time))) { LOGV("Internal Seeking: Dropping %s frame time:%f wanted:%f (kf:%d)", @@ -1194,6 +1197,18 @@ MediaFormatReader::Update(TrackType aTrack) decoder.mNumSamplesOutputTotal - mLastReportedNumDecodedFrames; a.mStats.mDecodedFrames = static_cast(delta); mLastReportedNumDecodedFrames = decoder.mNumSamplesOutputTotal; + if (output->mKeyframe) { + if (mPreviousDecodedKeyframeTime_us < output->mTime) { + // There is a previous keyframe -> Record inter-keyframe stats. + uint64_t segment_us = output->mTime - mPreviousDecodedKeyframeTime_us; + a.mStats.mInterKeyframeSum_us += segment_us; + a.mStats.mInterKeyframeCount += 1; + if (a.mStats.mInterKeyFrameMax_us < segment_us) { + a.mStats.mInterKeyFrameMax_us = segment_us; + } + } + mPreviousDecodedKeyframeTime_us = output->mTime; + } nsCString error; mVideo.mIsHardwareAccelerated = mVideo.mDecoder && mVideo.mDecoder->IsHardwareAccelerated(error); @@ -1757,6 +1772,8 @@ MediaFormatReader::OnVideoSeekCompleted(media::TimeUnit aTime) LOGV("Video seeked to %lld", aTime.ToMicroseconds()); mVideo.mSeekRequest.Complete(); + mPreviousDecodedKeyframeTime_us = sNoPreviousDecodedKeyframe; + SetVideoDecodeThreshold(); if (HasAudio() && !mOriginalSeekTarget.IsVideoOnly()) { @@ -1773,6 +1790,13 @@ MediaFormatReader::OnVideoSeekCompleted(media::TimeUnit aTime) } } +void +MediaFormatReader::OnVideoSeekFailed(DemuxerFailureReason aFailure) +{ + mPreviousDecodedKeyframeTime_us = sNoPreviousDecodedKeyframe; + OnSeekFailed(TrackType::kVideoTrack, aFailure); +} + void MediaFormatReader::SetVideoDecodeThreshold() { @@ -1833,6 +1857,12 @@ MediaFormatReader::OnAudioSeekCompleted(media::TimeUnit aTime) mSeekPromise.Resolve(aTime, __func__); } +void +MediaFormatReader::OnAudioSeekFailed(DemuxerFailureReason aFailure) +{ + OnSeekFailed(TrackType::kAudioTrack, aFailure); +} + media::TimeIntervals MediaFormatReader::GetBuffered() { diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h index 88914e3ca8d1..0acf6d197d8c 100644 --- a/dom/media/MediaFormatReader.h +++ b/dom/media/MediaFormatReader.h @@ -515,6 +515,11 @@ private: // delta there. uint64_t mLastReportedNumDecodedFrames; + // Timestamp of the previous decoded keyframe, in microseconds. + int64_t mPreviousDecodedKeyframeTime_us; + // Default mLastDecodedKeyframeTime_us value, must be bigger than anything. + static const int64_t sNoPreviousDecodedKeyframe = INT64_MAX; + layers::LayersBackend mLayersBackendType; // Metadata objects @@ -546,18 +551,12 @@ private: void OnSeekFailed(TrackType aTrack, DemuxerFailureReason aFailure); void DoVideoSeek(); void OnVideoSeekCompleted(media::TimeUnit aTime); - void OnVideoSeekFailed(DemuxerFailureReason aFailure) - { - OnSeekFailed(TrackType::kVideoTrack, aFailure); - } + void OnVideoSeekFailed(DemuxerFailureReason aFailure); bool mSeekScheduled; void DoAudioSeek(); void OnAudioSeekCompleted(media::TimeUnit aTime); - void OnAudioSeekFailed(DemuxerFailureReason aFailure) - { - OnSeekFailed(TrackType::kAudioTrack, aFailure); - } + void OnAudioSeekFailed(DemuxerFailureReason aFailure); // The SeekTarget that was last given to Seek() SeekTarget mOriginalSeekTarget; // Temporary seek information while we wait for the data From d3a3da966b06554f0595c3c29326c33bd21ea5d8 Mon Sep 17 00:00:00 2001 From: Gerald Squelart Date: Thu, 28 Jul 2016 10:16:17 +1000 Subject: [PATCH 090/120] Bug 1289668 - Inter-keyframe telemetry histograms - r=francois,kamidphish r?francois for telemetry-peer feedback through mozreview. The goal of this telemetry is to gather statistics about inter-keyframe timings of played videos, so we have a better understanding of typical values in the field. This inter-keyframe time is important for the background-suspend functionality, as it will impact the recovery time (i.e., when moving a video back to the foreground, what is the average & max time to the next random-access point?) MozReview-Commit-ID: NISIf1wGtU --HG-- extra : rebase_source : 34eb0bc852d4ae05701c56e38b3b0dc9c75d708e --- toolkit/components/telemetry/Histograms.json | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 4596ea20c7ad..8b27b531e859 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -8273,6 +8273,26 @@ "n_buckets": 50, "bug_numbers": [1287987] }, + "VIDEO_INTER_KEYFRAME_AVERAGE_MS" : { + "alert_emails": ["ajones@mozilla.com", "gsquelart@mozilla.com"], + "expires_in_version": "55", + "description": "Average interval between video keyframes in played videos, in milliseconds. Keyed by audio presence and by height ranges (boundaries: 240. 480, 576, 720, 1080, 2160), e.g.: 'V,02180'; and 'All' will accumulate all percentages. This is reported whenever an HTML Media Element is suspended or resumed, such as when the page is unloaded.", + "keyed": true, + "kind": "exponential", + "high": 60000, + "n_buckets": 100, + "bug_numbers": [1289668] + }, + "VIDEO_INTER_KEYFRAME_MAX_MS" : { + "alert_emails": ["ajones@mozilla.com", "gsquelart@mozilla.com"], + "expires_in_version": "55", + "description": "Maximum interval between video keyframes in played videos, in milliseconds. Keyed by audio presence and by height ranges (boundaries: 240. 480, 576, 720, 1080, 2160), e.g.: 'V,02180'; and 'All' will accumulate all percentages. This is reported whenever an HTML Media Element is suspended or resumed, such as when the page is unloaded.", + "keyed": true, + "kind": "exponential", + "high": 60000, + "n_buckets": 100, + "bug_numbers": [1289668] + }, "VIDEO_UNLOAD_STATE": { "alert_emails": ["ajones@mozilla.com"], "expires_in_version": "55", From 0ea69c7f48f5ce4ce3bcf0fbcfe467af815ed5a5 Mon Sep 17 00:00:00 2001 From: Gerald Squelart Date: Wed, 27 Jul 2016 15:43:01 +1000 Subject: [PATCH 091/120] Bug 1289668 - Report inter-keyframe telemetry - r=kamidphish Use the new FrameStatistics members to report telemetry about inter-keyframe timings. MozReview-Commit-ID: 1ZWU2qpSWyC --HG-- extra : rebase_source : f13fffc2bc81ad6090c3f494cc99e1d198f3256d --- dom/html/HTMLMediaElement.cpp | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index ccbe13daf3a4..8970a46f1ba8 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -3083,10 +3083,12 @@ HTMLMediaElement::ReportTelemetry() Telemetry::Accumulate(Telemetry::VIDEO_UNLOAD_STATE, state); LOG(LogLevel::Debug, ("%p VIDEO_UNLOAD_STATE = %d", this, state)); + FrameStatisticsData data; + if (HTMLVideoElement* vid = HTMLVideoElement::FromContentOrNull(this)) { FrameStatistics* stats = vid->GetFrameStatistics(); if (stats) { - FrameStatisticsData data = stats->GetFrameStatisticsData(); + data = stats->GetFrameStatisticsData(); if (data.mParsedFrames) { MOZ_ASSERT(data.mDroppedFrames <= data.mParsedFrames); // Dropped frames <= total frames, so 'percentage' cannot be higher than @@ -3145,6 +3147,35 @@ HTMLMediaElement::ReportTelemetry() hiddenPercentage); LOG(LogLevel::Debug, ("%p VIDEO_HIDDEN_PLAY_TIME_PERCENTAGE = %u, keys: '%s' and 'All'", this, hiddenPercentage, key.get())); + + if (data.mInterKeyframeCount != 0) { + uint32_t average_ms = + uint32_t(std::min(double(data.mInterKeyframeSum_us) + / double(data.mInterKeyframeCount) + / 1000.0 + + 0.5, + UINT32_MAX)); + Telemetry::Accumulate(Telemetry::VIDEO_INTER_KEYFRAME_AVERAGE_MS, + key, + average_ms); + Telemetry::Accumulate(Telemetry::VIDEO_INTER_KEYFRAME_AVERAGE_MS, + NS_LITERAL_CSTRING("All"), + average_ms); + LOG(LogLevel::Debug, ("%p VIDEO_INTER_KEYFRAME_AVERAGE_MS = %u, keys: '%s' and 'All'", + this, average_ms, key.get())); + + uint32_t max_ms = + uint32_t(std::min((data.mInterKeyFrameMax_us + 500) / 1000, + UINT32_MAX)); + Telemetry::Accumulate(Telemetry::VIDEO_INTER_KEYFRAME_MAX_MS, + key, + max_ms); + Telemetry::Accumulate(Telemetry::VIDEO_INTER_KEYFRAME_MAX_MS, + NS_LITERAL_CSTRING("All"), + max_ms); + LOG(LogLevel::Debug, ("%p VIDEO_INTER_KEYFRAME_MAX_MS = %u, keys: '%s' and 'All'", + this, max_ms, key.get())); + } } } } From fdb454227707041f9ef16437303313489f2ba3d8 Mon Sep 17 00:00:00 2001 From: Cameron McCormack Date: Thu, 28 Jul 2016 17:48:50 +0800 Subject: [PATCH 092/120] Bug 1290035 - Remove the explicit Type parameter to MakeEnumeratedRange. r=Waldo MozReview-Commit-ID: BtFVn9pTQpU --HG-- extra : rebase_source : be83c74953e2fbc7ace2ce49ceebb060da394c50 --- js/src/gc/Heap.h | 12 ++--- mfbt/EnumeratedRange.h | 116 ++++++++++++++++++----------------------- 2 files changed, 57 insertions(+), 71 deletions(-) diff --git a/js/src/gc/Heap.h b/js/src/gc/Heap.h index 2fe32dc2fe1a..eea66207dbcb 100644 --- a/js/src/gc/Heap.h +++ b/js/src/gc/Heap.h @@ -183,28 +183,28 @@ IsShapeAllocKind(AllocKind kind) // Returns a sequence for use in a range-based for loop, // to iterate over all alloc kinds. -inline decltype(mozilla::MakeEnumeratedRange(AllocKind::FIRST, AllocKind::LIMIT)) +inline decltype(mozilla::MakeEnumeratedRange(AllocKind::FIRST, AllocKind::LIMIT)) AllAllocKinds() { - return mozilla::MakeEnumeratedRange(AllocKind::FIRST, AllocKind::LIMIT); + return mozilla::MakeEnumeratedRange(AllocKind::FIRST, AllocKind::LIMIT); } // Returns a sequence for use in a range-based for loop, // to iterate over all object alloc kinds. -inline decltype(mozilla::MakeEnumeratedRange(AllocKind::OBJECT_FIRST, AllocKind::OBJECT_LIMIT)) +inline decltype(mozilla::MakeEnumeratedRange(AllocKind::OBJECT_FIRST, AllocKind::OBJECT_LIMIT)) ObjectAllocKinds() { - return mozilla::MakeEnumeratedRange(AllocKind::OBJECT_FIRST, AllocKind::OBJECT_LIMIT); + return mozilla::MakeEnumeratedRange(AllocKind::OBJECT_FIRST, AllocKind::OBJECT_LIMIT); } // Returns a sequence for use in a range-based for loop, // to iterate over alloc kinds from |first| to |limit|, exclusive. -inline decltype(mozilla::MakeEnumeratedRange(AllocKind::FIRST, AllocKind::LIMIT)) +inline decltype(mozilla::MakeEnumeratedRange(AllocKind::FIRST, AllocKind::LIMIT)) SomeAllocKinds(AllocKind first = AllocKind::FIRST, AllocKind limit = AllocKind::LIMIT) { MOZ_ASSERT(IsAllocKind(first), "|first| is not a valid AllocKind!"); MOZ_ASSERT(IsAllocKind(limit), "|limit| is not a valid AllocKind!"); - return mozilla::MakeEnumeratedRange(first, limit); + return mozilla::MakeEnumeratedRange(first, limit); } // AllAllocKindArray gives an enumerated array of ValueTypes, diff --git a/mfbt/EnumeratedRange.h b/mfbt/EnumeratedRange.h index fdca95632146..b158f8a3ac1c 100644 --- a/mfbt/EnumeratedRange.h +++ b/mfbt/EnumeratedRange.h @@ -20,23 +20,26 @@ #ifndef mozilla_EnumeratedRange_h #define mozilla_EnumeratedRange_h -#include "mozilla/IntegerTypeTraits.h" +#include + #include "mozilla/ReverseIterator.h" namespace mozilla { namespace detail { -template +template class EnumeratedIterator { public: + typedef typename std::underlying_type::type IntTypeT; + template explicit EnumeratedIterator(EnumType aCurrent) : mCurrent(aCurrent) { } - template - explicit EnumeratedIterator(const EnumeratedIterator& aOther) + template + explicit EnumeratedIterator(const EnumeratedIterator& aOther) : mCurrent(aOther.mCurrent) { } EnumTypeT operator*() const { return mCurrent; } @@ -68,77 +71,77 @@ public: /* Comparison operators */ - template - friend bool operator==(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2); - template - friend bool operator!=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2); - template - friend bool operator<(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2); - template - friend bool operator<=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2); - template - friend bool operator>(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2); - template - friend bool operator>=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2); + template + friend bool operator==(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2); + template + friend bool operator!=(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2); + template + friend bool operator<(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2); + template + friend bool operator<=(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2); + template + friend bool operator>(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2); + template + friend bool operator>=(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2); private: EnumTypeT mCurrent; }; -template -bool operator==(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) +template +bool operator==(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2) { return aIter1.mCurrent == aIter2.mCurrent; } -template -bool operator!=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) +template +bool operator!=(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2) { return aIter1.mCurrent != aIter2.mCurrent; } -template -bool operator<(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) +template +bool operator<(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2) { return aIter1.mCurrent < aIter2.mCurrent; } -template -bool operator<=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) +template +bool operator<=(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2) { return aIter1.mCurrent <= aIter2.mCurrent; } -template -bool operator>(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) +template +bool operator>(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2) { return aIter1.mCurrent > aIter2.mCurrent; } -template -bool operator>=(const EnumeratedIterator& aIter1, - const EnumeratedIterator& aIter2) +template +bool operator>=(const EnumeratedIterator& aIter1, + const EnumeratedIterator& aIter2) { return aIter1.mCurrent >= aIter2.mCurrent; } -template +template class EnumeratedRange { public: - typedef EnumeratedIterator iterator; - typedef EnumeratedIterator const_iterator; + typedef EnumeratedIterator iterator; + typedef EnumeratedIterator const_iterator; typedef ReverseIterator reverse_iterator; typedef ReverseIterator const_reverse_iterator; @@ -171,38 +174,21 @@ private: #endif // Create a range to iterate from aBegin to aEnd, exclusive. -// -// (Once we can rely on std::underlying_type, we can remove the IntType -// template parameter.) -template -inline detail::EnumeratedRange +template +inline detail::EnumeratedRange MakeEnumeratedRange(EnumType aBegin, EnumType aEnd) { -#ifdef DEBUG - typedef typename MakeUnsigned::Type UnsignedType; -#endif - static_assert(sizeof(IntType) >= sizeof(EnumType), - "IntType should be at least as big as EnumType!"); MOZ_ASSERT(aBegin <= aEnd, "Cannot generate invalid, unbounded range!"); - MOZ_ASSERT_IF(aBegin < EnumType(0), IsSigned::value); - MOZ_ASSERT_IF(aBegin >= EnumType(0) && IsSigned::value, - UnsignedType(aEnd) <= UnsignedType(MaxValue::value)); - return detail::EnumeratedRange(aBegin, aEnd); + return detail::EnumeratedRange(aBegin, aEnd); } // Create a range to iterate from EnumType(0) to aEnd, exclusive. EnumType(0) // should exist, but note that there is no way for us to ensure that it does! -// Since the enumeration starts at EnumType(0), we know for sure that the values -// will be in range of our deduced IntType. template -inline detail::EnumeratedRange< - typename UnsignedStdintTypeForSize::Type, - EnumType> +inline detail::EnumeratedRange MakeEnumeratedRange(EnumType aEnd) { - return MakeEnumeratedRange< - typename UnsignedStdintTypeForSize::Type>(EnumType(0), - aEnd); + return MakeEnumeratedRange(EnumType(0), aEnd); } #ifdef __GNUC__ From 8d82fea425b75b8e74cf8c223bf1f1ed33907251 Mon Sep 17 00:00:00 2001 From: JW Wang Date: Wed, 27 Jul 2016 15:04:07 +0800 Subject: [PATCH 093/120] Bug 1289683 - Prevent notifications from AudioOffloadPlayer after shutdown. r=sotaro MozReview-Commit-ID: J4t4aYZyfVz --HG-- extra : rebase_source : 16597bdf0f31264bbdb51764de06a99bb6ff8c95 --- dom/media/omx/AudioOffloadPlayer.cpp | 38 ++++++++++++++++--------- dom/media/omx/AudioOffloadPlayer.h | 18 ++++++++---- dom/media/omx/MediaOmxCommonDecoder.cpp | 8 ++++++ dom/media/omx/MediaOmxCommonDecoder.h | 2 ++ 4 files changed, 47 insertions(+), 19 deletions(-) diff --git a/dom/media/omx/AudioOffloadPlayer.cpp b/dom/media/omx/AudioOffloadPlayer.cpp index ccdd82ba846c..d4262497b2cc 100644 --- a/dom/media/omx/AudioOffloadPlayer.cpp +++ b/dom/media/omx/AudioOffloadPlayer.cpp @@ -20,6 +20,7 @@ #include "AudioOffloadPlayer.h" #include "nsComponentManagerUtils.h" #include "nsITimer.h" +#include "MediaOmxCommonDecoder.h" #include "mozilla/dom/HTMLMediaElement.h" #include "VideoUtils.h" #include "mozilla/dom/power/PowerManagerService.h" @@ -58,8 +59,7 @@ AudioOffloadPlayer::AudioOffloadPlayer(MediaOmxCommonDecoder* aObserver) : mSampleRate(0), mStartPosUs(0), mPositionTimeMediaUs(-1), - mInputBuffer(nullptr), - mObserver(aObserver) + mInputBuffer(nullptr) { MOZ_ASSERT(NS_IsMainThread()); @@ -73,6 +73,17 @@ AudioOffloadPlayer::AudioOffloadPlayer(MediaOmxCommonDecoder* aObserver) : #endif mAudioSink = new AudioOutput(mSessionId, IPCThreadState::self()->getCallingUid()); + + nsCOMPtr thread; + MOZ_ALWAYS_SUCCEEDS(NS_GetMainThread(getter_AddRefs(thread))); + mPositionChanged = mOnPositionChanged.Connect( + thread, aObserver, &MediaOmxCommonDecoder::NotifyOffloadPlayerPositionChanged); + mPlaybackEnded = mOnPlaybackEnded.Connect( + thread, aObserver, &MediaDecoder::PlaybackEnded); + mPlayerTearDown = mOnPlayerTearDown.Connect( + thread, aObserver, &MediaOmxCommonDecoder::AudioOffloadTearDown); + mSeekingStarted = mOnSeekingStarted.Connect( + thread, aObserver, &MediaDecoder::SeekingStarted); } AudioOffloadPlayer::~AudioOffloadPlayer() @@ -83,6 +94,13 @@ AudioOffloadPlayer::~AudioOffloadPlayer() #else AudioSystem::releaseAudioSessionId(mSessionId); #endif + + // Disconnect the listeners to prevent notifications from reaching + // the MediaOmxCommonDecoder object after shutdown. + mPositionChanged.Disconnect(); + mPlaybackEnded.Disconnect(); + mPlayerTearDown.Disconnect(); + mSeekingStarted.Disconnect(); } void AudioOffloadPlayer::SetSource(const sp &aSource) @@ -353,12 +371,7 @@ status_t AudioOffloadPlayer::DoSeek() mStartPosUs = mSeekTarget.GetTime().ToMicroseconds(); if (!mSeekPromise.IsEmpty()) { - nsCOMPtr nsEvent = - NewRunnableMethod( - mObserver, - &MediaDecoder::SeekingStarted, - mSeekTarget.mEventVisibility); - NS_DispatchToCurrentThread(nsEvent); + mOnSeekingStarted.Notify(mSeekTarget.mEventVisibility); } if (mPlaying) { @@ -425,14 +438,12 @@ void AudioOffloadPlayer::NotifyAudioEOS() MediaDecoder::SeekResolveValue val(mReachedEOS, mSeekTarget.mEventVisibility); mSeekPromise.Resolve(val, __func__); } - NS_DispatchToMainThread(NewRunnableMethod(mObserver, - &MediaDecoder::PlaybackEnded)); + mOnPlaybackEnded.Notify(); } void AudioOffloadPlayer::NotifyPositionChanged() { - NS_DispatchToMainThread(NewRunnableMethod(mObserver, - &MediaOmxCommonDecoder::NotifyOffloadPlayerPositionChanged)); + mOnPositionChanged.Notify(); } void AudioOffloadPlayer::NotifyAudioTearDown() @@ -446,8 +457,7 @@ void AudioOffloadPlayer::NotifyAudioTearDown() MediaDecoder::SeekResolveValue val(mReachedEOS, mSeekTarget.mEventVisibility); mSeekPromise.Resolve(val, __func__); } - NS_DispatchToMainThread(NewRunnableMethod(mObserver, - &MediaOmxCommonDecoder::AudioOffloadTearDown)); + mOnPlayerTearDown.Notify(); } // static diff --git a/dom/media/omx/AudioOffloadPlayer.h b/dom/media/omx/AudioOffloadPlayer.h index 50fed70a1b4c..82860c115851 100644 --- a/dom/media/omx/AudioOffloadPlayer.h +++ b/dom/media/omx/AudioOffloadPlayer.h @@ -29,7 +29,7 @@ #include "AudioOutput.h" #include "AudioOffloadPlayerBase.h" #include "MediaDecoderOwner.h" -#include "MediaOmxCommonDecoder.h" +#include "MediaEventSource.h" namespace mozilla { @@ -58,6 +58,8 @@ class WakeLock; * offload playback */ +class MediaOmxCommonDecoder; + class AudioOffloadPlayer : public AudioOffloadPlayerBase { typedef android::Mutex Mutex; @@ -73,7 +75,7 @@ public: SEEK_COMPLETE }; - AudioOffloadPlayer(MediaOmxCommonDecoder* aDecoder = nullptr); + AudioOffloadPlayer(MediaOmxCommonDecoder* aDecoder); ~AudioOffloadPlayer(); @@ -175,9 +177,6 @@ private: // Buffer used to get date from audio source. Used in offload callback thread MediaBuffer* mInputBuffer; - // MediaOmxCommonDecoder object used mainly to notify the audio sink status - MediaOmxCommonDecoder* mObserver; - TimeStamp mLastFireUpdateTime; // Timer to trigger position changed events @@ -192,6 +191,15 @@ private: // Used only from main thread so no lock is needed. RefPtr mWakeLock; + MediaEventProducer mOnPositionChanged; + MediaEventProducer mOnPlaybackEnded; + MediaEventProducer mOnPlayerTearDown; + MediaEventProducer mOnSeekingStarted; + MediaEventListener mPositionChanged; + MediaEventListener mPlaybackEnded; + MediaEventListener mPlayerTearDown; + MediaEventListener mSeekingStarted; + // Provide the playback position in microseconds from total number of // frames played by audio track int64_t GetOutputPlayPositionUs_l() const; diff --git a/dom/media/omx/MediaOmxCommonDecoder.cpp b/dom/media/omx/MediaOmxCommonDecoder.cpp index 8f01c6b74415..d413d985d609 100644 --- a/dom/media/omx/MediaOmxCommonDecoder.cpp +++ b/dom/media/omx/MediaOmxCommonDecoder.cpp @@ -165,6 +165,7 @@ void MediaOmxCommonDecoder::AudioOffloadTearDown() { MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!IsShutdown()); DECODER_LOG(LogLevel::Debug, ("%s", __PRETTY_FUNCTION__)); // mAudioOffloadPlayer can be null here if ResumeStateMachine was called @@ -286,4 +287,11 @@ MediaOmxCommonDecoder::CreateStateMachine() return CreateStateMachineFromReader(mReader); } +void +MediaOmxCommonDecoder::Shutdown() +{ + mAudioOffloadPlayer = nullptr; + MediaDecoder::Shutdown(); +} + } // namespace mozilla diff --git a/dom/media/omx/MediaOmxCommonDecoder.h b/dom/media/omx/MediaOmxCommonDecoder.h index 5423fdf29ffd..0e42df45ea31 100644 --- a/dom/media/omx/MediaOmxCommonDecoder.h +++ b/dom/media/omx/MediaOmxCommonDecoder.h @@ -46,6 +46,8 @@ public: void NotifyOffloadPlayerPositionChanged() { UpdateLogicalPosition(); } + void Shutdown() override; + protected: virtual ~MediaOmxCommonDecoder(); void PauseStateMachine(); From 650d5a0e6473c16c90772df00ac665e10b9d4a52 Mon Sep 17 00:00:00 2001 From: "Nils Ohlmeier [:drno]" Date: Wed, 27 Jul 2016 17:13:43 -0700 Subject: [PATCH 094/120] Bug 1289984: fix Windows compiler warnings. r=bwc MozReview-Commit-ID: EWSJZdxPzQk --HG-- extra : rebase_source : 5d5c2e088c6e0dffcba9d8692d4e1a878b24ae44 --- media/mtransport/third_party/nICEr/src/net/transport_addr.c | 1 + media/mtransport/third_party/nICEr/src/net/transport_addr_reg.c | 1 + 2 files changed, 2 insertions(+) diff --git a/media/mtransport/third_party/nICEr/src/net/transport_addr.c b/media/mtransport/third_party/nICEr/src/net/transport_addr.c index 7aa183064ec8..b44ad5b2c726 100644 --- a/media/mtransport/third_party/nICEr/src/net/transport_addr.c +++ b/media/mtransport/third_party/nICEr/src/net/transport_addr.c @@ -50,6 +50,7 @@ static char *RCSSTRING __UNUSED__="$Id: transport_addr.c,v 1.2 2008/04/28 17:59: #endif #include #include "nr_api.h" +#include "util.h" #include "transport_addr.h" int nr_transport_addr_fmt_addr_string(nr_transport_addr *addr) diff --git a/media/mtransport/third_party/nICEr/src/net/transport_addr_reg.c b/media/mtransport/third_party/nICEr/src/net/transport_addr_reg.c index eca70c16376f..6a8a64bb90a4 100644 --- a/media/mtransport/third_party/nICEr/src/net/transport_addr_reg.c +++ b/media/mtransport/third_party/nICEr/src/net/transport_addr_reg.c @@ -50,6 +50,7 @@ static char *RCSSTRING __UNUSED__="$Id: transport_addr_reg.c,v 1.2 2008/04/28 17 #endif #include #include "nr_api.h" +#include "util.h" #include "transport_addr.h" #include "transport_addr_reg.h" From 46090031f120beee0908df78c721084ac18d57c5 Mon Sep 17 00:00:00 2001 From: Mark Goodwin Date: Thu, 28 Jul 2016 08:13:33 +0100 Subject: [PATCH 095/120] Bug 1265008 - Enable kinto.js OneCRL client for release channels. r=MattN MozReview-Commit-ID: EsgtFfMGcz4 --HG-- extra : rebase_source : 104156e1d6bb83366b20e72763f8c3bd37278668 --- modules/libpref/init/all.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 5128faef4931..68289b03b4d1 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -2149,16 +2149,13 @@ pref("services.blocklist.gfx.checked", 0); // Controls whether signing should be enforced on signature-capable blocklist // collections. -pref("services.blocklist.signing.enforced", false); +pref("services.blocklist.signing.enforced", true); -// For now, let's keep settings server update out of the release builds -#ifdef RELEASE_BUILD -pref("services.blocklist.update_enabled", false); -pref("security.onecrl.via.amo", true); -#else +// Enable blocklists via the services settings mechanism pref("services.blocklist.update_enabled", true); + +// Enable certificate blocklist updates via services settings pref("security.onecrl.via.amo", false); -#endif // Modifier key prefs: default to Windows settings, From 2d3a353980d5528c924bbd7b363bed9ddfd00a62 Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Tue, 26 Jul 2016 19:39:16 -0700 Subject: [PATCH 096/120] Bug 1289652 - Disabled arrays don't change getVertexAttrib for SIZE,TYPE. - r=mtseng MozReview-Commit-ID: 71RJlIFayNH --- dom/canvas/WebGLContextVertices.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/dom/canvas/WebGLContextVertices.cpp b/dom/canvas/WebGLContextVertices.cpp index 940621800a76..35ec3f6db638 100644 --- a/dom/canvas/WebGLContextVertices.cpp +++ b/dom/canvas/WebGLContextVertices.cpp @@ -346,16 +346,10 @@ WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname, return JS::Int32Value(mBoundVertexArray->mAttribs[index].stride); case LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE: - if (!mBoundVertexArray->mAttribs[index].enabled) - return JS::Int32Value(4); - return JS::Int32Value(mBoundVertexArray->mAttribs[index].size); case LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE: - if (!mBoundVertexArray->mAttribs[index].enabled) - return JS::NumberValue(uint32_t(LOCAL_GL_FLOAT)); - - return JS::NumberValue(uint32_t(mBoundVertexArray->mAttribs[index].type)); + return JS::Int32Value(mBoundVertexArray->mAttribs[index].type); case LOCAL_GL_VERTEX_ATTRIB_ARRAY_INTEGER: if (IsWebGL2()) From d6af553fb81ddbc99fa9cd6ba3f2a955a6900635 Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Tue, 26 Jul 2016 19:49:33 -0700 Subject: [PATCH 097/120] Bug 1289653 - Disallow null `pixels` in texSubImage. - r=mtseng MozReview-Commit-ID: HgbJEhykEda --- dom/canvas/WebGLTextureUpload.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dom/canvas/WebGLTextureUpload.cpp b/dom/canvas/WebGLTextureUpload.cpp index 1783bc86c232..8acb0e53d1ea 100644 --- a/dom/canvas/WebGLTextureUpload.cpp +++ b/dom/canvas/WebGLTextureUpload.cpp @@ -262,6 +262,9 @@ WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarge bytes = view.DataAllowShared(); byteCount = view.LengthAllowShared(); } + } else if (isSubImage) { + mContext->ErrorInvalidValue("%s: `pixels` must not be null.", funcName); + return; } const bool isClientData = true; From 0ee365e60aa94bbd011970d4d5f7f0bac68df64a Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Thu, 28 Jul 2016 14:36:17 -0700 Subject: [PATCH 098/120] Bug 1289653 - Mark tests. MozReview-Commit-ID: IWB8gBthP2v --- dom/canvas/test/webgl-conf/generated-mochitest.ini | 2 -- dom/canvas/test/webgl-conf/mochitest-errata.ini | 4 ---- 2 files changed, 6 deletions(-) diff --git a/dom/canvas/test/webgl-conf/generated-mochitest.ini b/dom/canvas/test/webgl-conf/generated-mochitest.ini index ef5af972c8fe..9268b8dbe04a 100644 --- a/dom/canvas/test/webgl-conf/generated-mochitest.ini +++ b/dom/canvas/test/webgl-conf/generated-mochitest.ini @@ -5838,7 +5838,6 @@ skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5. [generated/test_2_conformance__textures__misc__tex-image-with-invalid-data.html] skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2')) [generated/test_2_conformance__textures__misc__tex-sub-image-2d-bad-args.html] -fail-if = (os == 'mac') || (os == 'win') skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2')) [generated/test_2_conformance__textures__misc__tex-sub-image-2d.html] skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2')) @@ -6722,7 +6721,6 @@ skip-if = (os == 'android') skip-if = (os == 'android') [generated/test_conformance__textures__misc__tex-input-validation.html] [generated/test_conformance__textures__misc__tex-sub-image-2d-bad-args.html] -fail-if = (os == 'mac') || (os == 'win') || (os == 'android') || (os == 'linux') [generated/test_conformance__textures__misc__tex-sub-image-2d.html] [generated/test_conformance__textures__misc__texparameter-test.html] [generated/test_conformance__textures__misc__texture-active-bind-2.html] diff --git a/dom/canvas/test/webgl-conf/mochitest-errata.ini b/dom/canvas/test/webgl-conf/mochitest-errata.ini index d964b8244396..fbeac0b4177c 100644 --- a/dom/canvas/test/webgl-conf/mochitest-errata.ini +++ b/dom/canvas/test/webgl-conf/mochitest-errata.ini @@ -148,8 +148,6 @@ fail-if = (os == 'mac') fail-if = (os == 'mac') || (os == 'win') [generated/test_2_conformance2__glsl3__forbidden-operators.html] fail-if = (os == 'mac') || (os == 'win') -[generated/test_conformance__textures__misc__tex-sub-image-2d-bad-args.html] -fail-if = (os == 'mac') || (os == 'win') || (os == 'android') || (os == 'linux') [generated/test_2_conformance2__vertex_arrays__vertex-array-object.html] fail-if = (os == 'mac') || (os == 'win') [generated/test_2_conformance__rendering__negative-one-index.html] @@ -160,8 +158,6 @@ fail-if = (os == 'mac') || (os == 'win') || (os == 'android') || (os == 'linux') fail-if = (os == 'mac') || (os == 'win') [generated/test_conformance__attribs__gl-vertexattribpointer.html] fail-if = (os == 'mac') || (os == 'win') || (os == 'android') || (os == 'linux') -[generated/test_2_conformance__textures__misc__tex-sub-image-2d-bad-args.html] -fail-if = (os == 'mac') || (os == 'win') [generated/test_conformance__ogles__GL__biuDepthRange__biuDepthRange_001_to_002.html] fail-if = (os == 'android') || (os == 'linux') [generated/test_conformance__ogles__GL__gl_FragCoord__gl_FragCoord_001_to_003.html] From 4e30f133995df74d206ae7b272d2b45d57fcb5d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Sun, 24 Jul 2016 02:40:01 -0700 Subject: [PATCH 099/120] Bug 1288938: layout: Move the GlyphObserver to the text run instead of the frame. r=jfkthame MozReview-Commit-ID: KphTCkcZeid --- gfx/thebes/gfxFont.h | 2 - layout/generic/nsTextFrame.cpp | 333 +++++++++++++++++++++--------- layout/generic/nsTextFrameUtils.h | 5 +- 3 files changed, 237 insertions(+), 103 deletions(-) diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index 3ff9efb27e14..4ed9fac21883 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -568,8 +568,6 @@ public: // Set if the textrun should use the OpenType 'math' script. TEXT_USE_MATH_SCRIPT = 0x80000000, - - TEXT_UNUSED_FLAGS = 0x10000000 }; /** diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index d91bef3171eb..add0628c40d5 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -180,24 +180,22 @@ NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(UninflatedTextRunProperty, gfxTextRun) NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(FontSizeInflationProperty, float) +/** + * A glyph observer for the change of a font glyph in a text run. + * + * This is stored in {Simple, Complex}TextRunUserData. + */ class GlyphObserver : public gfxFont::GlyphChangeObserver { public: - GlyphObserver(gfxFont* aFont, nsTextFrame* aFrame) - : gfxFont::GlyphChangeObserver(aFont), mFrame(aFrame) {} + GlyphObserver(gfxFont* aFont, gfxTextRun* aTextRun) + : gfxFont::GlyphChangeObserver(aFont), mTextRun(aTextRun) { + MOZ_ASSERT(aTextRun->GetUserData()); + } virtual void NotifyGlyphsChanged() override; private: - nsTextFrame* mFrame; + gfxTextRun* mTextRun; }; -/** - * This property is set on text frames with TEXT_IN_TEXTRUN_USER_DATA set that - * have potentially-animated glyphs. - * The only reason this list is in a property is to automatically destroy the - * list when the frame is deleted, unregistering the observers. - */ -NS_DECLARE_FRAME_PROPERTY_DELETABLE(TextFrameGlyphObservers, - nsTArray>) - static const nsFrameState TEXT_REFLOW_FLAGS = TEXT_FIRST_LETTER | TEXT_START_OF_LINE | @@ -223,21 +221,55 @@ static const nsFrameState TEXT_WHITESPACE_FLAGS = * * A gfxTextRun can cover more than one DOM text node. This is necessary to * get kerning, ligatures and shaping for text that spans multiple text nodes - * but is all the same font. The userdata for a gfxTextRun object is a - * TextRunUserData* or an nsIFrame*. - * + * but is all the same font. + * + * The userdata for a gfxTextRun object can be: + * + * - A nsTextFrame* in the case a text run maps to only one flow. In this + * case, the textrun's user data pointer is a pointer to mStartFrame for that + * flow, mDOMOffsetToBeforeTransformOffset is zero, and mContentLength is the + * length of the text node. + * + * - A SimpleTextRunUserData in the case a text run maps to one flow, but we + * still have to keep a list of glyph observers. + * + * - A ComplexTextRunUserData in the case a text run maps to multiple flows, + * but we need to keep a list of glyph observers. + * + * - A TextRunUserData in the case a text run maps multiple flows, but it + * doesn't have any glyph observer for changes in SVG fonts. + * + * You can differentiate between the four different cases with the + * TEXT_IS_SIMPLE_FLOW and TEXT_MIGHT_HAVE_GLYPH_CHANGES flags. + * * We go to considerable effort to make sure things work even if in-flow * siblings have different style contexts (i.e., first-letter and first-line). - * + * * Our convention is that unsigned integer character offsets are offsets into * the transformed string. Signed integer character offsets are offsets into * the DOM string. - * + * * XXX currently we don't handle hyphenated breaks between text frames where the * hyphen occurs at the end of the first text frame, e.g. * Kit­ty */ +/** + * This is our user data for the textrun, when textRun->GetFlags() has + * TEXT_IS_SIMPLE_FLOW set, and also TEXT_MIGHT_HAVE_GLYPH_CHANGES. + * + * This allows having an array of observers if there are fonts whose glyphs + * might change, but also avoid allocation in the simple case that there aren't. + */ +struct SimpleTextRunUserData { + nsTArray> mGlyphObservers; + nsTextFrame* mFrame; + explicit SimpleTextRunUserData(nsTextFrame* aFrame) + : mFrame(aFrame) + { + } +}; + /** * We use an array of these objects to record which text frames * are associated with the textrun. mStartFrame is the start of a list of @@ -259,11 +291,11 @@ struct TextRunMappedFlow { }; /** - * This is our user data for the textrun, when textRun->GetFlags() does not - * have TEXT_IS_SIMPLE_FLOW set. When TEXT_IS_SIMPLE_FLOW is set, there is - * just one flow, the textrun's user data pointer is a pointer to mStartFrame - * for that flow, mDOMOffsetToBeforeTransformOffset is zero, and mContentLength - * is the length of the text node. + * This is the type in the gfxTextRun's userdata field in the common case that + * the text run maps to multiple flows, but no fonts have been found with + * animatable glyphs. + * + * This way, we avoid allocating and constructing the extra nsTArray. */ struct TextRunUserData { TextRunMappedFlow* mMappedFlows; @@ -271,6 +303,14 @@ struct TextRunUserData { uint32_t mLastFlowIndex; }; +/** + * This is our user data for the textrun, when textRun->GetFlags() does not + * have TEXT_IS_SIMPLE_FLOW set and has the TEXT_MIGHT HAVE_GLYPH_CHANGES flag. + */ +struct ComplexTextRunUserData : public TextRunUserData { + nsTArray> mGlyphObservers; +}; + /** * This helper object computes colors used for painting, and also IME * underline information. The data is computed lazily and cached as necessary. @@ -413,15 +453,84 @@ protected: nscolor aBackColor); }; -static void -DestroyUserData(void* aUserData) +static TextRunUserData* +CreateUserData(uint32_t aMappedFlowCount) { - TextRunUserData* userData = static_cast(aUserData); - if (userData) { - free(userData); + TextRunUserData* data = static_cast + (moz_xmalloc(sizeof(TextRunUserData) + + aMappedFlowCount * sizeof(TextRunMappedFlow))); + data->mMappedFlows = reinterpret_cast(data + 1); + data->mMappedFlowCount = aMappedFlowCount; + data->mLastFlowIndex = 0; + return data; +} + +static void +DestroyUserData(TextRunUserData* aUserData) +{ + if (aUserData) { + free(aUserData); } } +static ComplexTextRunUserData* +CreateComplexUserData(uint32_t aMappedFlowCount) +{ + ComplexTextRunUserData* data = static_cast + (moz_xmalloc(sizeof(ComplexTextRunUserData) + + aMappedFlowCount * sizeof(TextRunMappedFlow))); + new (data) ComplexTextRunUserData(); + data->mMappedFlows = reinterpret_cast(data + 1); + data->mMappedFlowCount = aMappedFlowCount; + data->mLastFlowIndex = 0; + return data; +} + +static void +DestroyComplexUserData(ComplexTextRunUserData* aUserData) +{ + if (aUserData) { + aUserData->~ComplexTextRunUserData(); + free(aUserData); + } +} + +static void +DestroyTextRunUserData(gfxTextRun* aTextRun) +{ + MOZ_ASSERT(aTextRun->GetUserData()); + if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) { + if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_MIGHT_HAVE_GLYPH_CHANGES) { + delete static_cast(aTextRun->GetUserData()); + } + } else { + if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_MIGHT_HAVE_GLYPH_CHANGES) { + DestroyComplexUserData( + static_cast(aTextRun->GetUserData())); + } else { + DestroyUserData( + static_cast(aTextRun->GetUserData())); + } + } + aTextRun->SetUserData(nullptr); +} + +/** + * These are utility functions just for helping with the complexity related with + * the text runs user data. + */ +static nsTextFrame* +GetFrameForSimpleFlow(gfxTextRun* aTextRun) +{ + MOZ_ASSERT(aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW, + "Not so simple flow?"); + if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_MIGHT_HAVE_GLYPH_CHANGES) { + return static_cast(aTextRun->GetUserData())->mFrame; + } + + return static_cast(aTextRun->GetUserData()); +} + /** * Remove |aTextRun| from the frame continuation chain starting at * |aStartContinuation| if non-null, otherwise starting at |aFrame|. @@ -475,12 +584,12 @@ ClearAllTextRunReferences(nsTextFrame* aFrame, gfxTextRun* aTextRun, static void UnhookTextRunFromFrames(gfxTextRun* aTextRun, nsTextFrame* aStartContinuation) { - if (!aTextRun->GetUserData()) + if (!aTextRun->GetUserData()) { return; + } if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) { - nsTextFrame* userDataFrame = static_cast( - static_cast(aTextRun->GetUserData())); + nsTextFrame* userDataFrame = GetFrameForSimpleFlow(aTextRun); nsFrameState whichTextRunState = userDataFrame->GetTextRun(nsTextFrame::eInflated) == aTextRun ? TEXT_IN_TEXTRUN_USER_DATA @@ -491,11 +600,11 @@ UnhookTextRunFromFrames(gfxTextRun* aTextRun, nsTextFrame* aStartContinuation) NS_ASSERTION(!aStartContinuation || found, "aStartContinuation wasn't found in simple flow text run"); if (!(userDataFrame->GetStateBits() & whichTextRunState)) { - aTextRun->SetUserData(nullptr); + DestroyTextRunUserData(aTextRun); + aTextRun->ClearFlagBits(nsTextFrameUtils::TEXT_MIGHT_HAVE_GLYPH_CHANGES); } } else { - TextRunUserData* userData = - static_cast(aTextRun->GetUserData()); + auto userData = static_cast(aTextRun->GetUserData()); int32_t destroyFromIndex = aStartContinuation ? -1 : 0; for (uint32_t i = 0; i < userData->mMappedFlowCount; ++i) { nsTextFrame* userDataFrame = userData->mMappedFlows[i].mStartFrame; @@ -509,8 +618,7 @@ UnhookTextRunFromFrames(gfxTextRun* aTextRun, nsTextFrame* aStartContinuation) if (found) { if (userDataFrame->GetStateBits() & whichTextRunState) { destroyFromIndex = i + 1; - } - else { + } else { destroyFromIndex = i; } aStartContinuation = nullptr; @@ -519,10 +627,9 @@ UnhookTextRunFromFrames(gfxTextRun* aTextRun, nsTextFrame* aStartContinuation) NS_ASSERTION(destroyFromIndex >= 0, "aStartContinuation wasn't found in multi flow text run"); if (destroyFromIndex == 0) { - DestroyUserData(userData); - aTextRun->SetUserData(nullptr); - } - else { + DestroyTextRunUserData(aTextRun); + aTextRun->ClearFlagBits(nsTextFrameUtils::TEXT_MIGHT_HAVE_GLYPH_CHANGES); + } else { userData->mMappedFlowCount = uint32_t(destroyFromIndex); if (userData->mLastFlowIndex >= uint32_t(destroyFromIndex)) { userData->mLastFlowIndex = uint32_t(destroyFromIndex) - 1; @@ -531,16 +638,14 @@ UnhookTextRunFromFrames(gfxTextRun* aTextRun, nsTextFrame* aStartContinuation) } } -void -GlyphObserver::NotifyGlyphsChanged() +static void +InvalidateFrameDueToGlyphsChanged(nsIFrame* aFrame) { - nsIPresShell* shell = mFrame->PresContext()->PresShell(); - for (nsIFrame* f = mFrame; f; + MOZ_ASSERT(aFrame); + + nsIPresShell* shell = aFrame->PresContext()->PresShell(); + for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(f)) { - if (f != mFrame && f->HasAnyStateBits(TEXT_IN_TEXTRUN_USER_DATA)) { - // f will have its own GlyphObserver (if needed) so we can stop here. - break; - } f->InvalidateFrame(); // If this is a non-display text frame within SVG , we need @@ -563,6 +668,20 @@ GlyphObserver::NotifyGlyphsChanged() } } +void +GlyphObserver::NotifyGlyphsChanged() +{ + if (mTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) { + InvalidateFrameDueToGlyphsChanged(GetFrameForSimpleFlow(mTextRun)); + return; + } + + auto data = static_cast(mTextRun->GetUserData()); + for (uint32_t i = 0; i < data->mMappedFlowCount; ++i) { + InvalidateFrameDueToGlyphsChanged(data->mMappedFlows[i].mStartFrame); + } +} + int32_t nsTextFrame::GetContentEnd() const { nsTextFrame* next = static_cast(GetNextContinuation()); return next ? next->GetContentOffset() : mContent->GetText()->GetLength(); @@ -744,27 +863,19 @@ IsAllWhitespace(const nsTextFragment* aFrag, bool aAllowNewline) } static void -CreateObserverForAnimatedGlyphs(nsTextFrame* aFrame, const nsTArray& aFonts) +ClearObserversFromTextRun(gfxTextRun* aTextRun) { - if (!(aFrame->GetStateBits() & TEXT_IN_TEXTRUN_USER_DATA)) { - // Maybe the textrun was created for uninflated text. + if (!(aTextRun->GetFlags() & nsTextFrameUtils::TEXT_MIGHT_HAVE_GLYPH_CHANGES)) { return; } - nsTArray>* observers = - new nsTArray>(); - for (uint32_t i = 0, count = aFonts.Length(); i < count; ++i) { - observers->AppendElement(new GlyphObserver(aFonts[i], aFrame)); + if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) { + static_cast(aTextRun->GetUserData()) + ->mGlyphObservers.Clear(); + } else { + static_cast(aTextRun->GetUserData()) + ->mGlyphObservers.Clear(); } - aFrame->Properties().Set(TextFrameGlyphObservers(), observers); - // We are lazy and don't try to remove a property value that might be - // obsolete due to style changes or font selection changes. That is - // likely to be rarely needed, and we don't want to eat the overhead of - // doing it for the overwhelmingly common case of no property existing. - // (And we're out of state bits to conveniently use for a fast property - // existence check.) The only downside is that in some rare cases we might - // keep fonts alive for longer than necessary, or unnecessarily invalidate - // frames. } static void @@ -773,6 +884,9 @@ CreateObserversForAnimatedGlyphs(gfxTextRun* aTextRun) if (!aTextRun->GetUserData()) { return; } + + ClearObserversFromTextRun(aTextRun); + nsTArray fontsWithAnimatedGlyphs; uint32_t numGlyphRuns; const gfxTextRun::GlyphRun* glyphRuns = @@ -784,19 +898,46 @@ CreateObserversForAnimatedGlyphs(gfxTextRun* aTextRun) } } if (fontsWithAnimatedGlyphs.IsEmpty()) { + // NB: Theoretically, we should clear the TEXT_MIGHT_HAVE_GLYPH_CHANGES + // here. That would involve de-allocating the simple user data struct if + // present too, and resetting the pointer to the frame. In practice, I + // don't think worth doing that work here, given the flag's only purpose is + // to distinguish what kind of user data is there. return; } + nsTArray>* observers; + if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) { - CreateObserverForAnimatedGlyphs(static_cast( - static_cast(aTextRun->GetUserData())), fontsWithAnimatedGlyphs); - } else { - TextRunUserData* userData = - static_cast(aTextRun->GetUserData()); - for (uint32_t i = 0; i < userData->mMappedFlowCount; ++i) { - CreateObserverForAnimatedGlyphs(userData->mMappedFlows[i].mStartFrame, - fontsWithAnimatedGlyphs); + // Swap the frame pointer for a just-allocated SimpleTextRunUserData if + // appropriate. + if (!(aTextRun->GetFlags() & nsTextFrameUtils::TEXT_MIGHT_HAVE_GLYPH_CHANGES)) { + auto frame = static_cast(aTextRun->GetUserData()); + aTextRun->SetUserData(new SimpleTextRunUserData(frame)); } + + auto data = + static_cast(aTextRun->GetUserData()); + observers = &data->mGlyphObservers; + } else { + if (!(aTextRun->GetFlags() & nsTextFrameUtils::TEXT_MIGHT_HAVE_GLYPH_CHANGES)) { + auto oldData = static_cast(aTextRun->GetUserData()); + auto data = CreateComplexUserData(oldData->mMappedFlowCount); + data->mLastFlowIndex = oldData->mLastFlowIndex; + for (uint32_t i = 0; i < oldData->mMappedFlowCount; ++i) { + data->mMappedFlows[i] = oldData->mMappedFlows[i]; + } + DestroyUserData(oldData); + aTextRun->SetUserData(data); + } + auto data = static_cast(aTextRun->GetUserData()); + observers = &data->mGlyphObservers; + } + + aTextRun->SetFlagBits(nsTextFrameUtils::TEXT_MIGHT_HAVE_GLYPH_CHANGES); + + for (auto font : fontsWithAnimatedGlyphs) { + observers->AppendElement(new GlyphObserver(font, aTextRun)); } } @@ -945,9 +1086,7 @@ public: } void Finish(gfxMissingFontRecorder* aMFR) { - MOZ_ASSERT(!(mTextRun->GetFlags() & - (gfxTextRunFactory::TEXT_UNUSED_FLAGS | - nsTextFrameUtils::TEXT_UNUSED_FLAG)), + MOZ_ASSERT(!(mTextRun->GetFlags() & nsTextFrameUtils::TEXT_UNUSED_FLAG), "Flag set that should never be set! (memory safety error?)"); if (mTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_TRANSFORMED) { nsTransformedTextRun* transformedTextRun = @@ -1400,12 +1539,13 @@ ExpandBuffer(char16_t* aDest, uint8_t* aSrc, uint32_t aCount) bool BuildTextRunsScanner::IsTextRunValidForMappedFlows(gfxTextRun* aTextRun) { - if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) + if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) { return mMappedFlows.Length() == 1 && - mMappedFlows[0].mStartFrame == static_cast(aTextRun->GetUserData()) && + mMappedFlows[0].mStartFrame == GetFrameForSimpleFlow(aTextRun) && mMappedFlows[0].mEndFrame == nullptr; + } - TextRunUserData* userData = static_cast(aTextRun->GetUserData()); + auto userData = static_cast(aTextRun->GetUserData()); if (userData->mMappedFlowCount != mMappedFlows.Length()) return false; for (uint32_t i = 0; i < mMappedFlows.Length(); ++i) { @@ -1875,14 +2015,12 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer) userData = &dummyData; userDataToDestroy = nullptr; dummyData.mMappedFlows = &dummyMappedFlow; + dummyData.mMappedFlowCount = mMappedFlows.Length(); + dummyData.mLastFlowIndex = 0; } else { - userData = static_cast - (moz_xmalloc(sizeof(TextRunUserData) + mMappedFlows.Length()*sizeof(TextRunMappedFlow))); + userData = CreateUserData(mMappedFlows.Length()); userDataToDestroy = userData; - userData->mMappedFlows = reinterpret_cast(userData + 1); } - userData->mMappedFlowCount = mMappedFlows.Length(); - userData->mLastFlowIndex = 0; uint32_t currentTransformedTextOffset = 0; @@ -2280,14 +2418,12 @@ BuildTextRunsScanner::SetupLineBreakerContext(gfxTextRun *aTextRun) userData = &dummyData; userDataToDestroy = nullptr; dummyData.mMappedFlows = &dummyMappedFlow; + dummyData.mMappedFlowCount = mMappedFlows.Length(); + dummyData.mLastFlowIndex = 0; } else { - userData = static_cast - (moz_xmalloc(sizeof(TextRunUserData) + mMappedFlows.Length()*sizeof(TextRunMappedFlow))); + userData = CreateUserData(mMappedFlows.Length()); userDataToDestroy = userData; - userData->mMappedFlows = reinterpret_cast(userData + 1); } - userData->mMappedFlowCount = mMappedFlows.Length(); - userData->mLastFlowIndex = 0; uint32_t nextBreakIndex = 0; nsTextFrame* nextBreakBeforeFrame = GetNextBreakBeforeFrame(&nextBreakIndex); @@ -2576,16 +2712,14 @@ BuildTextRunsScanner::AssignTextRun(gfxTextRun* aTextRun, float aInflation) if (f->GetTextRun(mWhichTextRun)) { gfxTextRun* textRun = f->GetTextRun(mWhichTextRun); if (textRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) { - if (mMappedFlows[0].mStartFrame != static_cast(textRun->GetUserData())) { + if (mMappedFlows[0].mStartFrame != GetFrameForSimpleFlow(textRun)) { NS_WARNING("REASSIGNING SIMPLE FLOW TEXT RUN!"); } } else { - TextRunUserData* userData = - static_cast(textRun->GetUserData()); - + auto userData = static_cast(aTextRun->GetUserData()); if (userData->mMappedFlowCount >= mMappedFlows.Length() || userData->mMappedFlows[userData->mMappedFlowCount - 1].mStartFrame != - mMappedFlows[userData->mMappedFlowCount - 1].mStartFrame) { + mMappedFlows[userdata->mMappedFlowCount - 1].mStartFrame) { NS_WARNING("REASSIGNING MULTIFLOW TEXT RUN (not append)!"); } } @@ -2597,17 +2731,16 @@ BuildTextRunsScanner::AssignTextRun(gfxTextRun* aTextRun, float aInflation) nsTextFrame* firstFrame = nullptr; uint32_t startOffset = 0; if (oldTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) { - firstFrame = static_cast(oldTextRun->GetUserData()); - } - else { - TextRunUserData* userData = static_cast(oldTextRun->GetUserData()); + firstFrame = GetFrameForSimpleFlow(oldTextRun); + } else { + auto userData = static_cast(oldTextRun->GetUserData()); firstFrame = userData->mMappedFlows[0].mStartFrame; if (MOZ_UNLIKELY(f != firstFrame)) { - TextRunMappedFlow* flow = FindFlowForContent(userData, f->GetContent()); + TextRunMappedFlow* flow = FindFlowForContent(userData, + f->GetContent()); if (flow) { startOffset = flow->mDOMOffsetToBeforeTransformOffset; - } - else { + } else { NS_ERROR("Can't find flow containing frame 'f'"); } } @@ -2687,7 +2820,7 @@ nsTextFrame::EnsureTextRun(TextRunType aWhichTextRun, return gfxSkipCharsIterator(textRun->GetSkipChars(), 0, mContentOffset); } - TextRunUserData* userData = static_cast(textRun->GetUserData()); + auto userData = static_cast(textRun->GetUserData()); TextRunMappedFlow* flow = FindFlowForContent(userData, mContent); if (flow) { // Since textruns can only contain one flow for a given content element, diff --git a/layout/generic/nsTextFrameUtils.h b/layout/generic/nsTextFrameUtils.h index 26ddf0b6eef5..6274705bc32e 100644 --- a/layout/generic/nsTextFrameUtils.h +++ b/layout/generic/nsTextFrameUtils.h @@ -50,7 +50,10 @@ public: // NS_FRAME_IS_IN_SINGLE_CHAR_MI flag is set. This occurs if the textframe // belongs to a MathML element whose embedded text consists of a // single character. - TEXT_IS_SINGLE_CHAR_MI = 0x8000000 + TEXT_IS_SINGLE_CHAR_MI = 0x8000000, + + // This is set if the text run might be observing for glyph changes. + TEXT_MIGHT_HAVE_GLYPH_CHANGES = 0x10000000, // The following are defined by gfxTextRunWordCache rather than here, // so that it also has access to the _INCOMING flag From 98a30f1426897b4f720db6d00f0c5da29b9120c8 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Thu, 28 Jul 2016 16:03:23 -0700 Subject: [PATCH 100/120] Backed out changeset 48cff1c9b619 (bug 1276390) for xpcshell bustage CLOSED TREE --- .../modules/subprocess/subprocess_common.jsm | 22 +----- .../subprocess/subprocess_shared_win.js | 18 ----- .../modules/subprocess/subprocess_unix.jsm | 48 +----------- toolkit/modules/subprocess/subprocess_win.jsm | 28 +------ .../subprocess/subprocess_worker_common.js | 20 ----- .../subprocess/subprocess_worker_unix.js | 75 +++---------------- .../subprocess/subprocess_worker_win.js | 65 +++------------- .../test/xpcshell/test_subprocess.js | 39 ---------- 8 files changed, 25 insertions(+), 290 deletions(-) diff --git a/toolkit/modules/subprocess/subprocess_common.jsm b/toolkit/modules/subprocess/subprocess_common.jsm index a899fcc49e9a..fca7a3ffd094 100644 --- a/toolkit/modules/subprocess/subprocess_common.jsm +++ b/toolkit/modules/subprocess/subprocess_common.jsm @@ -15,8 +15,6 @@ Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.importGlobalProperties(["TextDecoder"]); -XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown", - "resource://gre/modules/AsyncShutdown.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "setTimeout", "resource://gre/modules/Timer.jsm"); @@ -40,25 +38,11 @@ class PromiseWorker extends ChromeWorker { this.listeners = new Map(); this.pendingResponses = new Map(); - this.addListener("close", this.onClose.bind(this)); this.addListener("failure", this.onFailure.bind(this)); this.addListener("success", this.onSuccess.bind(this)); this.addListener("debug", this.onDebug.bind(this)); this.addEventListener("message", this.onmessage); - - this.shutdown = this.shutdown.bind(this); - AsyncShutdown.webWorkersShutdown.addBlocker( - "Subprocess.jsm: Shut down IO worker", - this.shutdown); - } - - onClose() { - AsyncShutdown.webWorkersShutdown.removeBlocker(this.shutdown); - } - - shutdown() { - return this.call("shutdown", []); } /** @@ -631,10 +615,6 @@ class BaseProcess { throw new Error("Not implemented"); } - static get WorkerClass() { - return PromiseWorker; - } - /** * Gets the current subprocess worker, or spawns a new one if it does not * currently exist. @@ -643,7 +623,7 @@ class BaseProcess { */ static getWorker() { if (!this._worker) { - this._worker = new this.WorkerClass(this.WORKER_URL); + this._worker = new PromiseWorker(this.WORKER_URL); } return this._worker; } diff --git a/toolkit/modules/subprocess/subprocess_shared_win.js b/toolkit/modules/subprocess/subprocess_shared_win.js index 32957bc9886c..cf8925ab5219 100644 --- a/toolkit/modules/subprocess/subprocess_shared_win.js +++ b/toolkit/modules/subprocess/subprocess_shared_win.js @@ -22,7 +22,6 @@ var win32 = { BYTE: ctypes.uint8_t, WORD: ctypes.uint16_t, DWORD: ctypes.uint32_t, - LONG: ctypes.long, UINT: ctypes.unsigned_int, UCHAR: ctypes.unsigned_char, @@ -220,15 +219,6 @@ var libc = new Library("libc", LIBC_CHOICES, { win32.PROCESS_INFORMATION.ptr, /* out lpProcessInformation */ ], - CreateSemaphoreW: [ - win32.WINAPI, - win32.HANDLE, - win32.SECURITY_ATTRIBUTES.ptr, /* opt lpSemaphoreAttributes */ - win32.LONG, /* lInitialCount */ - win32.LONG, /* lMaximumCount */ - win32.LPCWSTR, /* opt lpName */ - ], - DeleteProcThreadAttributeList: [ win32.WINAPI, win32.VOID, @@ -309,14 +299,6 @@ var libc = new Library("libc", LIBC_CHOICES, { win32.OVERLAPPED.ptr, /* opt in/out lpOverlapped */ ], - ReleaseSemaphore: [ - win32.WINAPI, - win32.BOOL, - win32.HANDLE, /* hSemaphore */ - win32.LONG, /* lReleaseCount */ - win32.LONG.ptr, /* opt out lpPreviousCount */ - ], - TerminateProcess: [ win32.WINAPI, win32.BOOL, diff --git a/toolkit/modules/subprocess/subprocess_unix.jsm b/toolkit/modules/subprocess/subprocess_unix.jsm index 47ce667d26cf..be725126068c 100644 --- a/toolkit/modules/subprocess/subprocess_unix.jsm +++ b/toolkit/modules/subprocess/subprocess_unix.jsm @@ -9,7 +9,7 @@ /* exported SubprocessImpl */ -/* globals BaseProcess, PromiseWorker */ +/* globals BaseProcess */ var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; @@ -24,56 +24,10 @@ Cu.import("resource://gre/modules/subprocess/subprocess_common.jsm"); Services.scriptloader.loadSubScript("resource://gre/modules/subprocess/subprocess_shared.js", this); Services.scriptloader.loadSubScript("resource://gre/modules/subprocess/subprocess_shared_unix.js", this); -class UnixPromiseWorker extends PromiseWorker { - constructor(...args) { - super(...args); - - let fds = ctypes.int.array(2)(); - let res = libc.pipe(fds); - if (res == -1) { - throw new Error("Unable to create pipe"); - } - - this.signalFd = fds[1]; - - libc.fcntl(fds[0], LIBC.F_SETFL, LIBC.O_NONBLOCK); - libc.fcntl(fds[0], LIBC.F_SETFD, LIBC.FD_CLOEXEC); - libc.fcntl(fds[1], LIBC.F_SETFD, LIBC.FD_CLOEXEC); - - this.call("init", [{signalFd: fds[0]}]); - } - - closePipe() { - if (this.signalFd) { - libc.close(this.signalFd); - this.signalFd = null; - } - } - - onClose() { - this.closePipe(); - super.onClose(); - } - - signalWorker() { - libc.write(this.signalFd, new ArrayBuffer(1), 1); - } - - postMessage(...args) { - this.signalWorker(); - return super.postMessage(...args); - } -} - - class Process extends BaseProcess { static get WORKER_URL() { return "resource://gre/modules/subprocess/subprocess_worker_unix.js"; } - - static get WorkerClass() { - return UnixPromiseWorker; - } } var SubprocessUnix = { diff --git a/toolkit/modules/subprocess/subprocess_win.jsm b/toolkit/modules/subprocess/subprocess_win.jsm index 8d146729b6ae..de8887b478f1 100644 --- a/toolkit/modules/subprocess/subprocess_win.jsm +++ b/toolkit/modules/subprocess/subprocess_win.jsm @@ -9,7 +9,7 @@ /* exported SubprocessImpl */ -/* globals BaseProcess, PromiseWorker */ +/* globals BaseProcess */ var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; @@ -24,35 +24,10 @@ Cu.import("resource://gre/modules/subprocess/subprocess_common.jsm"); Services.scriptloader.loadSubScript("resource://gre/modules/subprocess/subprocess_shared.js", this); Services.scriptloader.loadSubScript("resource://gre/modules/subprocess/subprocess_shared_win.js", this); -class WinPromiseWorker extends PromiseWorker { - constructor(...args) { - super(...args); - - this.signalEvent = libc.CreateSemaphoreW(null, 0, 32, null); - - this.call("init", [{ - signalEvent: String(ctypes.cast(this.signalEvent, ctypes.uintptr_t).value), - }]); - } - - signalWorker() { - libc.ReleaseSemaphore(this.signalEvent, 1, null); - } - - postMessage(...args) { - this.signalWorker(); - return super.postMessage(...args); - } -} - class Process extends BaseProcess { static get WORKER_URL() { return "resource://gre/modules/subprocess/subprocess_worker_win.js"; } - - static get WorkerClass() { - return WinPromiseWorker; - } } var SubprocessWin = { @@ -62,6 +37,7 @@ var SubprocessWin = { return Process.create(options); }, + * getEnvironment() { let env = libc.GetEnvironmentStringsW(); try { diff --git a/toolkit/modules/subprocess/subprocess_worker_common.js b/toolkit/modules/subprocess/subprocess_worker_common.js index a211a8ec1ff8..77c6e6162d32 100644 --- a/toolkit/modules/subprocess/subprocess_worker_common.js +++ b/toolkit/modules/subprocess/subprocess_worker_common.js @@ -88,18 +88,6 @@ class BaseProcess { } let requests = { - init(details) { - io.init(details); - - return {data: {}}; - }, - - shutdown() { - io.shutdown(); - - return {data: {}}; - }, - close(pipeId, force = false) { let pipe = io.getPipe(pipeId); @@ -168,8 +156,6 @@ let requests = { }; onmessage = event => { - io.messageCount--; - let {msg, msgId, args} = event.data; new Promise(resolve => { @@ -209,9 +195,3 @@ onmessage = event => { }); }); }; - -onclose = event => { - io.shutdown(); - - self.postMessage({msg: "close"}); -}; diff --git a/toolkit/modules/subprocess/subprocess_worker_unix.js b/toolkit/modules/subprocess/subprocess_worker_unix.js index 1a2595c286fb..61f0fee7e1a8 100644 --- a/toolkit/modules/subprocess/subprocess_worker_unix.js +++ b/toolkit/modules/subprocess/subprocess_worker_unix.js @@ -12,7 +12,8 @@ importScripts("resource://gre/modules/subprocess/subprocess_shared.js", "resource://gre/modules/subprocess/subprocess_shared_unix.js", "resource://gre/modules/subprocess/subprocess_worker_common.js"); -const POLL_TIMEOUT = 5000; +const POLL_INTERVAL = 50; +const POLL_TIMEOUT = 0; let io; @@ -247,40 +248,6 @@ class OutputPipe extends Pipe { } } -class Signal { - constructor(fd) { - this.fd = fd; - } - - cleanup() { - libc.close(this.fd); - this.fd = null; - } - - get pollEvents() { - return LIBC.POLLIN; - } - - /** - * Called when an error occurred while polling our file descriptor. - */ - onError() { - io.shutdown(); - } - - /** - * Called when one of the IO operations matching the `pollEvents` mask may be - * performed without blocking. - */ - onReady() { - let buffer = new ArrayBuffer(16); - let count = +libc.read(this.fd, buffer, buffer.byteLength); - if (count > 0) { - io.messageCount += count; - } - } -} - class Process extends BaseProcess { /** * Each Process object opens an additional pipe from the target object, which @@ -482,27 +449,7 @@ io = { processes: new Map(), - messageCount: 0, - - running: true, - - init(details) { - this.signal = new Signal(details.signalFd); - this.updatePollFds(); - - setTimeout(this.loop.bind(this), 0); - }, - - shutdown() { - if (this.running) { - this.running = false; - - this.signal.cleanup(); - this.signal = null; - - self.close(); - } - }, + interval: null, getPipe(pipeId) { let pipe = this.pipes.get(pipeId); @@ -525,8 +472,7 @@ io = { }, updatePollFds() { - let handlers = [this.signal, - ...this.pipes.values(), + let handlers = [...this.pipes.values(), ...this.processes.values()]; handlers = handlers.filter(handler => handler.pollEvents); @@ -543,12 +489,12 @@ io = { this.pollFds = pollfds; this.pollHandlers = handlers; - }, - loop() { - this.poll(); - if (this.running) { - setTimeout(this.loop.bind(this), 0); + if (pollfds.length && !this.interval) { + this.interval = setInterval(this.poll.bind(this), POLL_INTERVAL); + } else if (!pollfds.length && this.interval) { + clearInterval(this.interval); + this.interval = null; } }, @@ -556,8 +502,7 @@ io = { let handlers = this.pollHandlers; let pollfds = this.pollFds; - let timeout = this.messageCount > 0 ? 0 : POLL_TIMEOUT; - let count = libc.poll(pollfds, pollfds.length, timeout); + let count = libc.poll(pollfds, pollfds.length, POLL_TIMEOUT); for (let i = 0; count && i < pollfds.length; i++) { let pollfd = pollfds[i]; diff --git a/toolkit/modules/subprocess/subprocess_worker_win.js b/toolkit/modules/subprocess/subprocess_worker_win.js index 762994f1a56a..fa13a58edd70 100644 --- a/toolkit/modules/subprocess/subprocess_worker_win.js +++ b/toolkit/modules/subprocess/subprocess_worker_win.js @@ -12,7 +12,8 @@ importScripts("resource://gre/modules/subprocess/subprocess_shared.js", "resource://gre/modules/subprocess/subprocess_shared_win.js", "resource://gre/modules/subprocess/subprocess_worker_common.js"); -const POLL_TIMEOUT = 5000; +const POLL_INTERVAL = 50; +const POLL_TIMEOUT = 0; // The exit code that we send when we forcibly terminate a process. const TERMINATE_EXIT_CODE = 0x7f; @@ -297,25 +298,6 @@ class OutputPipe extends Pipe { } } -class Signal { - constructor(event) { - this.event = event; - } - - cleanup() { - libc.CloseHandle(this.event); - this.event = null; - } - - onError() { - io.shutdown(); - } - - onReady() { - io.messageCount += 1; - } -} - class Process extends BaseProcess { constructor(...args) { super(...args); @@ -561,29 +543,7 @@ io = { processes: new Map(), - messageCount: 0, - - running: true, - - init(details) { - let signalEvent = ctypes.cast(ctypes.uintptr_t(details.signalEvent), - win32.HANDLE); - this.signal = new Signal(signalEvent); - this.updatePollEvents(); - - setTimeout(this.loop.bind(this), 0); - }, - - shutdown() { - if (this.running) { - this.running = false; - - this.signal.cleanup(); - this.signal = null; - - self.close(); - } - }, + interval: null, getPipe(pipeId) { let pipe = this.pipes.get(pipeId); @@ -606,8 +566,7 @@ io = { }, updatePollEvents() { - let handlers = [this.signal, - ...this.pipes.values(), + let handlers = [...this.pipes.values(), ...this.processes.values()]; handlers = handlers.filter(handler => handler.event); @@ -616,24 +575,22 @@ io = { let handles = handlers.map(handler => handler.event); this.events = win32.HANDLE.array()(handles); - }, - loop() { - this.poll(); - if (this.running) { - setTimeout(this.loop.bind(this), 0); + if (handles.length && !this.interval) { + this.interval = setInterval(this.poll.bind(this), POLL_INTERVAL); + } else if (!handlers.length && this.interval) { + clearInterval(this.interval); + this.interval = null; } }, - poll() { - let timeout = this.messageCount > 0 ? 0 : POLL_TIMEOUT; - for (;; timeout = 0) { + for (;;) { let events = this.events; let handlers = this.eventHandlers; let result = libc.WaitForMultipleObjects(events.length, events, - false, timeout); + false, POLL_TIMEOUT); if (result < handlers.length) { try { diff --git a/toolkit/modules/subprocess/test/xpcshell/test_subprocess.js b/toolkit/modules/subprocess/test/xpcshell/test_subprocess.js index 66131d3013f1..f63dd195b674 100644 --- a/toolkit/modules/subprocess/test/xpcshell/test_subprocess.js +++ b/toolkit/modules/subprocess/test/xpcshell/test_subprocess.js @@ -1,14 +1,11 @@ "use strict"; -Cu.import("resource://gre/modules/AppConstants.jsm"); Cu.import("resource://gre/modules/Task.jsm"); Cu.import("resource://gre/modules/Timer.jsm"); const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment); -const MAX_ROUND_TRIP_TIME_MS = AppConstants.DEBUG ? 18 : 9; - let PYTHON; let PYTHON_BIN; let PYTHON_DIR; @@ -181,42 +178,6 @@ add_task(function* test_subprocess_huge() { }); -add_task(function* test_subprocess_round_trip_perf() { - let proc = yield Subprocess.call({ - command: PYTHON, - arguments: ["-u", TEST_SCRIPT, "echo"], - }); - - - const LINE = "I'm a leaf on the wind.\n"; - - let now = Date.now(); - const COUNT = 1000; - for (let i = 0; i < COUNT; i++) { - let [output] = yield Promise.all([ - read(proc.stdout), - proc.stdin.write(LINE), - ]); - - // We don't want to log this for every iteration, but we still need - // to fail if it goes wrong. - if (output !== LINE) { - equal(output, LINE, "Got expected output"); - } - } - - let roundTripTime = (Date.now() - now) / COUNT; - ok(roundTripTime <= MAX_ROUND_TRIP_TIME_MS, - `Expected round trip time (${roundTripTime}ms) to be less than ${MAX_ROUND_TRIP_TIME_MS}ms`); - - yield proc.stdin.close(); - - let {exitCode} = yield proc.wait(); - - equal(exitCode, 0, "Got expected exit code"); -}); - - add_task(function* test_subprocess_stderr_default() { const LINE1 = "I'm a leaf on the wind.\n"; const LINE2 = "Watch how I soar.\n"; From b75d78272f51ff998dd66cb20a1ce6811268770e Mon Sep 17 00:00:00 2001 From: Jarda Snajdr Date: Thu, 28 Jul 2016 14:18:00 -0400 Subject: [PATCH 101/120] Bug 1289811 - Give nsIOutputStreamCallback a [function] attribute. r=nfroyd --- xpcom/io/nsIAsyncOutputStream.idl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xpcom/io/nsIAsyncOutputStream.idl b/xpcom/io/nsIAsyncOutputStream.idl index 68d0464b1586..7e74579c6cda 100644 --- a/xpcom/io/nsIAsyncOutputStream.idl +++ b/xpcom/io/nsIAsyncOutputStream.idl @@ -91,7 +91,7 @@ interface nsIAsyncOutputStream : nsIOutputStream /** * This is a companion interface for nsIAsyncOutputStream::asyncWait. */ -[scriptable, uuid(40dbcdff-9053-42c5-a57c-3ec910d0f148)] +[function, scriptable, uuid(40dbcdff-9053-42c5-a57c-3ec910d0f148)] interface nsIOutputStreamCallback : nsISupports { /** From 3b57299a1d4360137d36b21fc37f89844565ad95 Mon Sep 17 00:00:00 2001 From: Zibi Braniecki Date: Thu, 28 Jul 2016 16:01:00 -0400 Subject: [PATCH 102/120] Bug 1289923 - Fix the minor errors found while writing test262 tests for DateTimeFormat.prototype.formatToParts. r=Waldo --HG-- extra : amend_source : 1cd9313aecfc76dc77dfb4520fb5b77fb15cf16b --- js/src/builtin/Intl.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/js/src/builtin/Intl.cpp b/js/src/builtin/Intl.cpp index 17c5e1073be5..f9c5edfd3a26 100644 --- a/js/src/builtin/Intl.cpp +++ b/js/src/builtin/Intl.cpp @@ -1792,8 +1792,11 @@ InitDateTimeFormatClass(JSContext* cx, HandleObject Intl, Handle // is enabled, also add it. if (cx->compartment()->creationOptions().experimentalDateTimeFormatFormatToPartsEnabled()) { RootedValue ftp(cx); - if (!GlobalObject::getIntrinsicValue(cx, cx->global(), - cx->names().DateTimeFormatFormatToParts, &ftp)) + HandlePropertyName name = cx->names().formatToParts; + if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), + cx->names().DateTimeFormatFormatToParts, + name, + 0, &ftp)) { return nullptr; } From 5dd417a0d953b80cdb1f366154e613f1ec5a6e2f Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Thu, 28 Jul 2016 20:20:42 +1000 Subject: [PATCH 103/120] Bug 373621 - Make mime-type of PDF not overridable. r=bz MozReview-Commit-ID: 8k2XorDX0z9 --HG-- extra : transplant_source : %86J%CA%F9%E6%B3%85jk%CB%E7%0AX%8C%F1y%D9%B4%95%D9 --- uriloader/exthandler/nsExternalHelperAppService.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp index d797e9598a64..793d001cff3f 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -522,6 +522,7 @@ static const nsDefaultMimeTypeEntry defaultMimeEntries[] = { APPLICATION_OGG, "ogg" }, { AUDIO_OGG, "oga" }, { AUDIO_OGG, "opus" }, + { APPLICATION_PDF, "pdf" }, { VIDEO_WEBM, "webm" }, { AUDIO_WEBM, "webm" }, #if defined(MOZ_WMF) From 95f96fd0dd3ce3cb1d9adf894e8032e419d152f9 Mon Sep 17 00:00:00 2001 From: Jonathan Chan Date: Thu, 28 Jul 2016 18:41:08 -0700 Subject: [PATCH 104/120] Bug 1290320 - Add missing include to nsStyleSet.h. r=bholley MozReview-Commit-ID: PRSFRX9Oru --HG-- extra : rebase_source : 7f964a1b0371eb6b986b165e3fc100139469ce1c --- layout/style/nsStyleSet.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/layout/style/nsStyleSet.cpp b/layout/style/nsStyleSet.cpp index 463b08b42694..3faa23ff898a 100644 --- a/layout/style/nsStyleSet.cpp +++ b/layout/style/nsStyleSet.cpp @@ -18,6 +18,7 @@ #include "mozilla/EventStates.h" #include "mozilla/MemoryReporting.h" #include "mozilla/RuleProcessorCache.h" +#include "mozilla/StyleSheetHandleInlines.h" #include "nsIDocumentInlines.h" #include "nsRuleWalker.h" #include "nsStyleContext.h" From d660b8cb844962079e3bd685cf938e30a47cd52f Mon Sep 17 00:00:00 2001 From: Neerja Pancholi Date: Thu, 28 Jul 2016 15:06:02 -0700 Subject: [PATCH 105/120] Bug 1288797 - Replace nsAutoPtr with UniquePtr in nsStyleStruct.h (for variable "mCropRect") r=dholbert MozReview-Commit-ID: 1UFbO0jgM1k --HG-- extra : rebase_source : 577c45b90653482ec2d5baab679c743cc68ac872 --- layout/style/nsComputedDOMStyle.cpp | 2 +- layout/style/nsRuleNode.cpp | 2 +- layout/style/nsStyleStruct.cpp | 17 ++++++++--------- layout/style/nsStyleStruct.h | 8 ++++---- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index 0cc01d76025e..f7ad78951865 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -2088,7 +2088,7 @@ nsComputedDOMStyle::SetValueToStyleImage(const nsStyleImage& aStyleImage, nsCOMPtr uri; req->GetURI(getter_AddRefs(uri)); - const nsStyleSides* cropRect = aStyleImage.GetCropRect(); + const UniquePtr& cropRect = aStyleImage.GetCropRect(); if (cropRect) { nsAutoString imageRectString; GetImageRectString(uri, *cropRect, imageRectString); diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index 3bff57315ae2..e595a8ed86d4 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -1216,7 +1216,7 @@ static void SetStyleImageToImageRect(nsStyleContext* aStyleContext, MOZ_ASSERT(unitOk, "Incorrect data structure created by CSS parser"); cropRect.Set(side, coord); } - aResult.SetCropRect(&cropRect); + aResult.SetCropRect(MakeUnique(cropRect)); } static void SetStyleImage(nsStyleContext* aStyleContext, diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index 78e08d2f9ac3..abcd11df086c 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -1969,7 +1969,11 @@ nsStyleImage::DoCopy(const nsStyleImage& aOther) SetElementId(aOther.mElementId); } - SetCropRect(aOther.mCropRect); + UniquePtr cropRectCopy; + if (aOther.mCropRect) { + cropRectCopy = MakeUnique(*aOther.mCropRect.get()); + } + SetCropRect(Move(cropRectCopy)); } void @@ -2080,14 +2084,9 @@ nsStyleImage::SetElementId(const char16_t* aElementId) } void -nsStyleImage::SetCropRect(nsStyleSides* aCropRect) +nsStyleImage::SetCropRect(UniquePtr aCropRect) { - if (aCropRect) { - mCropRect = new nsStyleSides(*aCropRect); - // There is really not much we can do if 'new' fails - } else { - mCropRect = nullptr; - } + mCropRect = Move(aCropRect); } static int32_t @@ -2239,7 +2238,7 @@ nsStyleImage::IsLoaded() const } static inline bool -EqualRects(const nsStyleSides* aRect1, const nsStyleSides* aRect2) +EqualRects(const UniquePtr& aRect1, const UniquePtr& aRect2) { return aRect1 == aRect2 || /* handles null== null, and optimize */ (aRect1 && aRect2 && *aRect1 == *aRect2); diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index 31cd677feabb..6824affb63d9 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -18,7 +18,7 @@ #include "mozilla/SheetType.h" #include "mozilla/StaticPtr.h" #include "mozilla/StyleStructContext.h" -#include "nsAutoPtr.h" +#include "mozilla/UniquePtr.h" #include "nsColor.h" #include "nsCoord.h" #include "nsMargin.h" @@ -269,7 +269,7 @@ struct nsStyleImage void UntrackImage(nsPresContext* aContext); void SetGradientData(nsStyleGradient* aGradient); void SetElementId(const char16_t* aElementId); - void SetCropRect(nsStyleSides* aCropRect); + void SetCropRect(mozilla::UniquePtr aCropRect); nsStyleImageType GetType() const { return mType; @@ -288,7 +288,7 @@ struct nsStyleImage NS_ASSERTION(mType == eStyleImageType_Element, "Data is not an element!"); return mElementId; } - nsStyleSides* GetCropRect() const { + const mozilla::UniquePtr& GetCropRect() const { NS_ASSERTION(mType == eStyleImageType_Image, "Only image data can have a crop rect"); return mCropRect; @@ -373,7 +373,7 @@ private: }; // This is _currently_ used only in conjunction with eStyleImageType_Image. - nsAutoPtr mCropRect; + mozilla::UniquePtr mCropRect; #ifdef DEBUG bool mImageTracked; #endif From b92154b20aa9fbf3f6327480a3596c9acbec87ee Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Thu, 28 Jul 2016 12:18:59 -0700 Subject: [PATCH 106/120] Bug 1290214 - Stop asserting when we don't have enough information to use the servo backend. r=emilio In practice I'm pretty sure these cases wouldn't have a content docshell anyway. We probably don't need more robust machinery here, since eventually we'll just make stylo pref-based for every new prescontext regardless of type. --- dom/base/nsDocument.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 3ffe4da4480c..89fff1a62930 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -13439,6 +13439,10 @@ nsIDocument::UpdateStyleBackendType() { MOZ_ASSERT(mStyleBackendType == StyleBackendType(0), "no need to call UpdateStyleBackendType now"); + + // Assume Gecko by default. + mStyleBackendType = StyleBackendType::Gecko; + #ifdef MOZ_STYLO // XXX For now we use a Servo-backed style set only for (X)HTML documents // in content docshells. This should let us avoid implementing XUL-specific @@ -13447,15 +13451,11 @@ nsIDocument::UpdateStyleBackendType() // document before we have a pres shell (i.e. before we make the decision // here about whether to use a Gecko- or Servo-backed style system), so // we avoid Servo-backed style sets for SVG documents. - NS_ASSERTION(mDocumentContainer, "stylo: calling UpdateStyleBackendType " - "before we have a docshell"); - mStyleBackendType = - nsLayoutUtils::SupportsServoStyleBackend(this) && - mDocumentContainer ? - StyleBackendType::Servo : - StyleBackendType::Gecko; -#else - mStyleBackendType = StyleBackendType::Gecko; + if (!mDocumentContainer) { + NS_WARNING("stylo: No docshell yet, assuming Gecko style system"); + } else if (nsLayoutUtils::SupportsServoStyleBackend(this)) { + mStyleBackendType = StyleBackendType::Servo; + } #endif } From d5aeede8914b075679e7b510468b2368ae2ed118 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Thu, 28 Jul 2016 12:23:26 -0700 Subject: [PATCH 107/120] Bug 1290214 - Remove NS_ERRORs in css::Loader. r=emilio --- layout/style/Loader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/layout/style/Loader.cpp b/layout/style/Loader.cpp index efcfe2de7b80..e28157914032 100644 --- a/layout/style/Loader.cpp +++ b/layout/style/Loader.cpp @@ -1294,7 +1294,7 @@ Loader::PrepareSheet(StyleSheetHandle aSheet, // XXXheycam Need to set media, title, etc. on ServoStyleSheets. if (aSheet->IsServo()) { - NS_ERROR("stylo: should set metadata on ServoStyleSheets"); + NS_WARNING("stylo: should set metadata on ServoStyleSheets. See bug 1290209."); return; } @@ -1976,7 +1976,7 @@ Loader::DoSheetComplete(SheetLoadData* aLoadData, nsresult aStatus, } #endif } else { - NS_ERROR("stylo: not caching ServoStyleSheet"); + NS_WARNING("stylo: Stylesheet caching not yet supported - see bug 1290218."); } } From 81084cfef0f1dbf5c565bc7de1e203cef279a39b Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Thu, 28 Jul 2016 12:38:06 -0700 Subject: [PATCH 108/120] Bug 1290214 - Remove NS_ERROR in the case where we skip checking the stylesheet service. r=emilio --- dom/base/nsDocument.cpp | 3 ++- layout/base/nsDocumentViewer.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 89fff1a62930..4bd3e85f69e2 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -2425,7 +2425,8 @@ nsDocument::FillStyleSet(StyleSetHandle aStyleSet) } } } else { - NS_ERROR("stylo: nsStyleSheetService doesn't handle ServoStyleSheets yet"); + NS_WARNING("stylo: Not yet checking nsStyleSheetService for Servo-backed " + "documents. See bug 1290224"); } AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAgentSheet], diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index 7a5044e01045..b0dcbe0f6bc4 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -2347,7 +2347,8 @@ nsDocumentViewer::CreateStyleSet(nsIDocument* aDocument) } } } else { - NS_ERROR("stylo: nsStyleSheetService doesn't handle ServoStyleSheets yet"); + NS_WARNING("stylo: Not yet checking nsStyleSheetService for Servo-backed " + "documents. See bug 1290224"); } // Caller will handle calling EndUpdate, per contract. From 7c2695a9d038642eb789e503199435aafb4a636e Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Thu, 28 Jul 2016 12:57:40 -0700 Subject: [PATCH 109/120] Bug 1290214 - Remove NS_ERROR for media queries and @font-face. r=emilio --- dom/base/nsDocument.cpp | 3 ++- layout/base/nsPresContext.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 4bd3e85f69e2..44afda23510f 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -13351,7 +13351,8 @@ nsIDocument::FlushUserFontSet() return; } } else { - NS_ERROR("stylo: ServoStyleSets cannot handle @font-face rules yet"); + NS_WARNING("stylo: ServoStyleSets cannot handle @font-face rules yet. " + "See bug 1290237."); } } diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 38df8e59bc33..21284d2bd27e 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -1867,8 +1867,8 @@ nsPresContext::MediaFeatureValuesChanged(nsRestyleHint aRestyleHint, aRestyleHint |= eRestyle_Subtree; } } else { - NS_ERROR("stylo: ServoStyleSets don't support responding to medium " - "changes yet"); + NS_WARNING("stylo: ServoStyleSets don't support responding to medium " + "changes yet. See bug 1290228."); } } From 5cc53812efa07e95895f36e0063016afef44b671 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Thu, 28 Jul 2016 13:14:02 -0700 Subject: [PATCH 110/120] Bug 1290214 - Make ServoRestyleManager::AttributeChanged a no-op. r=emilio We do all the work we need to do with the snapshot model in AttributeWillChange. --- layout/base/ServoRestyleManager.cpp | 8 -------- layout/base/ServoRestyleManager.h | 5 ++++- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/layout/base/ServoRestyleManager.cpp b/layout/base/ServoRestyleManager.cpp index 6ca7463795d9..e11157dcf339 100644 --- a/layout/base/ServoRestyleManager.cpp +++ b/layout/base/ServoRestyleManager.cpp @@ -296,14 +296,6 @@ ServoRestyleManager::AttributeWillChange(Element* aElement, snapshot->AddAttrs(aElement); } -void -ServoRestyleManager::AttributeChanged(Element* aElement, int32_t aNameSpaceID, - nsIAtom* aAttribute, int32_t aModType, - const nsAttrValue* aOldValue) -{ - NS_ERROR("stylo: ServoRestyleManager::AttributeChanged not implemented"); -} - nsresult ServoRestyleManager::ReparentStyleContext(nsIFrame* aFrame) { diff --git a/layout/base/ServoRestyleManager.h b/layout/base/ServoRestyleManager.h index ebc5bb90bbff..404ce2fd2bfa 100644 --- a/layout/base/ServoRestyleManager.h +++ b/layout/base/ServoRestyleManager.h @@ -62,9 +62,12 @@ public: nsIAtom* aAttribute, int32_t aModType, const nsAttrValue* aNewValue); + + // XXXbholley: We should assert that the element is already snapshotted. void AttributeChanged(dom::Element* aElement, int32_t aNameSpaceID, nsIAtom* aAttribute, int32_t aModType, - const nsAttrValue* aOldValue); + const nsAttrValue* aOldValue) {} + nsresult ReparentStyleContext(nsIFrame* aFrame); bool HasPendingRestyles() { return !mModifiedElements.IsEmpty(); } From ff7b93c2e8962dc98ad2a1d5d99729902897bab8 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Thu, 28 Jul 2016 15:00:32 -0700 Subject: [PATCH 111/120] Bug 1290214 - Remove NS_ERROR for XBL stylesheet management. r=emilio --- layout/base/nsCSSFrameConstructor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index c8934d844f09..8e6d2671b58c 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -2691,7 +2691,7 @@ nsCSSFrameConstructor::ConstructRootFrame() // ServoStyleSets yet. styleSet->AsGecko()->SetBindingManager(mDocument->BindingManager()); } else { - NS_ERROR("stylo: cannot get ServoStyleSheets from XBL bindings yet"); + NS_WARNING("stylo: cannot get ServoStyleSheets from XBL bindings yet. See bug 1290276."); } // --------- BUILD VIEWPORT ----------- From 7e2a8f642f3ab200be65fbf543a22a8c5636ef4a Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Thu, 28 Jul 2016 15:22:26 -0700 Subject: [PATCH 112/120] Bug 1290214 - Remove NS_ERROR for unhandled document state changes. r=emilio --- layout/base/nsPresShell.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 9e59e3d9b1d8..29213962dfe1 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -4232,8 +4232,8 @@ PresShell::DocumentStatesChanged(nsIDocument* aDocument, // XXXheycam ServoStyleSets don't support document state selectors, // but these are only used in chrome documents, which we are not // aiming to support yet. - NS_ERROR("stylo: ServoStyleSets cannot respond to document state " - "changes yet"); + NS_WARNING("stylo: ServoStyleSets cannot respond to document state " + "changes yet (only matters for chrome documents). See bug 1290285."); return; } From 6255cd0c72191fae140e05496845d6f8fbef2cdd Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Thu, 28 Jul 2016 15:22:54 -0700 Subject: [PATCH 113/120] Bug 1290214 - Remove NS_ERROR for {un,partially-}implemented ServoRestyleManager and ServoStyleSet methods. r=emilio These are core methods that we know we need to implement, and I'm not worried that we'll forget about them. The warnings should be enough here. --- layout/base/ServoRestyleManager.cpp | 14 +++++++------- layout/style/ServoStyleSet.cpp | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/layout/base/ServoRestyleManager.cpp b/layout/base/ServoRestyleManager.cpp index e11157dcf339..c1884eda4a6c 100644 --- a/layout/base/ServoRestyleManager.cpp +++ b/layout/base/ServoRestyleManager.cpp @@ -50,14 +50,14 @@ ServoRestyleManager::PostRestyleEvent(Element* aElement, void ServoRestyleManager::PostRestyleEventForLazyConstruction() { - NS_ERROR("stylo: ServoRestyleManager::PostRestyleEventForLazyConstruction not implemented"); + NS_WARNING("stylo: ServoRestyleManager::PostRestyleEventForLazyConstruction not implemented"); } void ServoRestyleManager::RebuildAllStyleData(nsChangeHint aExtraHint, nsRestyleHint aRestyleHint) { - NS_ERROR("stylo: ServoRestyleManager::RebuildAllStyleData not implemented"); + NS_WARNING("stylo: ServoRestyleManager::RebuildAllStyleData not implemented"); } void @@ -166,7 +166,7 @@ ServoRestyleManager::NoteRestyleHint(Element* aElement, nsRestyleHint aHint) // TODO: Handle all other nsRestyleHint values. if (aHint & ~(eRestyle_Self | eRestyle_Subtree | eRestyle_LaterSiblings)) { - NS_ERROR(nsPrintfCString("stylo: Unhandled restyle hint %s", + NS_WARNING(nsPrintfCString("stylo: Unhandled restyle hint %s", RestyleManagerBase::RestyleHintToString(aHint).get()).get()); } } @@ -226,14 +226,14 @@ void ServoRestyleManager::RestyleForInsertOrChange(Element* aContainer, nsIContent* aChild) { - NS_ERROR("stylo: ServoRestyleManager::RestyleForInsertOrChange not implemented"); + NS_WARNING("stylo: ServoRestyleManager::RestyleForInsertOrChange not implemented"); } void ServoRestyleManager::RestyleForAppend(Element* aContainer, nsIContent* aFirstNewContent) { - NS_ERROR("stylo: ServoRestyleManager::RestyleForAppend not implemented"); + NS_WARNING("stylo: ServoRestyleManager::RestyleForAppend not implemented"); } void @@ -241,7 +241,7 @@ ServoRestyleManager::RestyleForRemove(Element* aContainer, nsIContent* aOldChild, nsIContent* aFollowingSibling) { - NS_ERROR("stylo: ServoRestyleManager::RestyleForRemove not implemented"); + NS_WARNING("stylo: ServoRestyleManager::RestyleForRemove not implemented"); } nsresult @@ -299,7 +299,7 @@ ServoRestyleManager::AttributeWillChange(Element* aElement, nsresult ServoRestyleManager::ReparentStyleContext(nsIFrame* aFrame) { - NS_ERROR("stylo: ServoRestyleManager::ReparentStyleContext not implemented"); + NS_WARNING("stylo: ServoRestyleManager::ReparentStyleContext not implemented"); return NS_OK; } diff --git a/layout/style/ServoStyleSet.cpp b/layout/style/ServoStyleSet.cpp index 3ef14d18f74c..629fee429c8f 100644 --- a/layout/style/ServoStyleSet.cpp +++ b/layout/style/ServoStyleSet.cpp @@ -378,7 +378,7 @@ nsRestyleHint ServoStyleSet::HasStateDependentStyle(dom::Element* aElement, EventStates aStateMask) { - NS_ERROR("stylo: HasStateDependentStyle not implemented"); + NS_WARNING("stylo: HasStateDependentStyle always returns zero!"); return nsRestyleHint(0); } @@ -388,7 +388,7 @@ ServoStyleSet::HasStateDependentStyle(dom::Element* aElement, dom::Element* aPseudoElement, EventStates aStateMask) { - NS_ERROR("stylo: HasStateDependentStyle not implemented"); + NS_WARNING("stylo: HasStateDependentStyle always returns zero!"); return nsRestyleHint(0); } From bd7e3664e49d04aebb9d8dafa65378c8161d8ea1 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Thu, 28 Jul 2016 16:27:25 -0700 Subject: [PATCH 114/120] Bug 1276390 - Use blocking polling in worker to handle subprocess IO. r=aswan MozReview-Commit-ID: KXqgCLnO7dR --HG-- extra : source : 48cff1c9b619bb224dd763332836522fd60c160f extra : histedit_source : dd214d7b0835a3dcf361b9a6f65625fa2434cd81%2Cd7c9dc53cb4e020a66d716ec538e2f7c7664e91c --- toolkit/modules/AppConstants.jsm | 7 ++ .../modules/subprocess/subprocess_common.jsm | 22 +++++- .../subprocess/subprocess_shared_win.js | 18 +++++ .../modules/subprocess/subprocess_unix.jsm | 48 +++++++++++- toolkit/modules/subprocess/subprocess_win.jsm | 28 ++++++- .../subprocess/subprocess_worker_common.js | 20 +++++ .../subprocess/subprocess_worker_unix.js | 75 ++++++++++++++++--- .../subprocess/subprocess_worker_win.js | 65 +++++++++++++--- .../test/xpcshell/test_subprocess.js | 46 +++++++++++- 9 files changed, 301 insertions(+), 28 deletions(-) diff --git a/toolkit/modules/AppConstants.jsm b/toolkit/modules/AppConstants.jsm index 652b7491a163..1ad24cbacab3 100644 --- a/toolkit/modules/AppConstants.jsm +++ b/toolkit/modules/AppConstants.jsm @@ -211,6 +211,13 @@ this.AppConstants = Object.freeze({ false, #endif + ASAN: +#ifdef MOZ_ASAN + true, +#else + false, +#endif + MOZ_B2G_RIL: #ifdef MOZ_B2G_RIL true, diff --git a/toolkit/modules/subprocess/subprocess_common.jsm b/toolkit/modules/subprocess/subprocess_common.jsm index fca7a3ffd094..a899fcc49e9a 100644 --- a/toolkit/modules/subprocess/subprocess_common.jsm +++ b/toolkit/modules/subprocess/subprocess_common.jsm @@ -15,6 +15,8 @@ Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.importGlobalProperties(["TextDecoder"]); +XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown", + "resource://gre/modules/AsyncShutdown.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "setTimeout", "resource://gre/modules/Timer.jsm"); @@ -38,11 +40,25 @@ class PromiseWorker extends ChromeWorker { this.listeners = new Map(); this.pendingResponses = new Map(); + this.addListener("close", this.onClose.bind(this)); this.addListener("failure", this.onFailure.bind(this)); this.addListener("success", this.onSuccess.bind(this)); this.addListener("debug", this.onDebug.bind(this)); this.addEventListener("message", this.onmessage); + + this.shutdown = this.shutdown.bind(this); + AsyncShutdown.webWorkersShutdown.addBlocker( + "Subprocess.jsm: Shut down IO worker", + this.shutdown); + } + + onClose() { + AsyncShutdown.webWorkersShutdown.removeBlocker(this.shutdown); + } + + shutdown() { + return this.call("shutdown", []); } /** @@ -615,6 +631,10 @@ class BaseProcess { throw new Error("Not implemented"); } + static get WorkerClass() { + return PromiseWorker; + } + /** * Gets the current subprocess worker, or spawns a new one if it does not * currently exist. @@ -623,7 +643,7 @@ class BaseProcess { */ static getWorker() { if (!this._worker) { - this._worker = new PromiseWorker(this.WORKER_URL); + this._worker = new this.WorkerClass(this.WORKER_URL); } return this._worker; } diff --git a/toolkit/modules/subprocess/subprocess_shared_win.js b/toolkit/modules/subprocess/subprocess_shared_win.js index cf8925ab5219..32957bc9886c 100644 --- a/toolkit/modules/subprocess/subprocess_shared_win.js +++ b/toolkit/modules/subprocess/subprocess_shared_win.js @@ -22,6 +22,7 @@ var win32 = { BYTE: ctypes.uint8_t, WORD: ctypes.uint16_t, DWORD: ctypes.uint32_t, + LONG: ctypes.long, UINT: ctypes.unsigned_int, UCHAR: ctypes.unsigned_char, @@ -219,6 +220,15 @@ var libc = new Library("libc", LIBC_CHOICES, { win32.PROCESS_INFORMATION.ptr, /* out lpProcessInformation */ ], + CreateSemaphoreW: [ + win32.WINAPI, + win32.HANDLE, + win32.SECURITY_ATTRIBUTES.ptr, /* opt lpSemaphoreAttributes */ + win32.LONG, /* lInitialCount */ + win32.LONG, /* lMaximumCount */ + win32.LPCWSTR, /* opt lpName */ + ], + DeleteProcThreadAttributeList: [ win32.WINAPI, win32.VOID, @@ -299,6 +309,14 @@ var libc = new Library("libc", LIBC_CHOICES, { win32.OVERLAPPED.ptr, /* opt in/out lpOverlapped */ ], + ReleaseSemaphore: [ + win32.WINAPI, + win32.BOOL, + win32.HANDLE, /* hSemaphore */ + win32.LONG, /* lReleaseCount */ + win32.LONG.ptr, /* opt out lpPreviousCount */ + ], + TerminateProcess: [ win32.WINAPI, win32.BOOL, diff --git a/toolkit/modules/subprocess/subprocess_unix.jsm b/toolkit/modules/subprocess/subprocess_unix.jsm index be725126068c..47ce667d26cf 100644 --- a/toolkit/modules/subprocess/subprocess_unix.jsm +++ b/toolkit/modules/subprocess/subprocess_unix.jsm @@ -9,7 +9,7 @@ /* exported SubprocessImpl */ -/* globals BaseProcess */ +/* globals BaseProcess, PromiseWorker */ var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; @@ -24,10 +24,56 @@ Cu.import("resource://gre/modules/subprocess/subprocess_common.jsm"); Services.scriptloader.loadSubScript("resource://gre/modules/subprocess/subprocess_shared.js", this); Services.scriptloader.loadSubScript("resource://gre/modules/subprocess/subprocess_shared_unix.js", this); +class UnixPromiseWorker extends PromiseWorker { + constructor(...args) { + super(...args); + + let fds = ctypes.int.array(2)(); + let res = libc.pipe(fds); + if (res == -1) { + throw new Error("Unable to create pipe"); + } + + this.signalFd = fds[1]; + + libc.fcntl(fds[0], LIBC.F_SETFL, LIBC.O_NONBLOCK); + libc.fcntl(fds[0], LIBC.F_SETFD, LIBC.FD_CLOEXEC); + libc.fcntl(fds[1], LIBC.F_SETFD, LIBC.FD_CLOEXEC); + + this.call("init", [{signalFd: fds[0]}]); + } + + closePipe() { + if (this.signalFd) { + libc.close(this.signalFd); + this.signalFd = null; + } + } + + onClose() { + this.closePipe(); + super.onClose(); + } + + signalWorker() { + libc.write(this.signalFd, new ArrayBuffer(1), 1); + } + + postMessage(...args) { + this.signalWorker(); + return super.postMessage(...args); + } +} + + class Process extends BaseProcess { static get WORKER_URL() { return "resource://gre/modules/subprocess/subprocess_worker_unix.js"; } + + static get WorkerClass() { + return UnixPromiseWorker; + } } var SubprocessUnix = { diff --git a/toolkit/modules/subprocess/subprocess_win.jsm b/toolkit/modules/subprocess/subprocess_win.jsm index de8887b478f1..8d146729b6ae 100644 --- a/toolkit/modules/subprocess/subprocess_win.jsm +++ b/toolkit/modules/subprocess/subprocess_win.jsm @@ -9,7 +9,7 @@ /* exported SubprocessImpl */ -/* globals BaseProcess */ +/* globals BaseProcess, PromiseWorker */ var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; @@ -24,10 +24,35 @@ Cu.import("resource://gre/modules/subprocess/subprocess_common.jsm"); Services.scriptloader.loadSubScript("resource://gre/modules/subprocess/subprocess_shared.js", this); Services.scriptloader.loadSubScript("resource://gre/modules/subprocess/subprocess_shared_win.js", this); +class WinPromiseWorker extends PromiseWorker { + constructor(...args) { + super(...args); + + this.signalEvent = libc.CreateSemaphoreW(null, 0, 32, null); + + this.call("init", [{ + signalEvent: String(ctypes.cast(this.signalEvent, ctypes.uintptr_t).value), + }]); + } + + signalWorker() { + libc.ReleaseSemaphore(this.signalEvent, 1, null); + } + + postMessage(...args) { + this.signalWorker(); + return super.postMessage(...args); + } +} + class Process extends BaseProcess { static get WORKER_URL() { return "resource://gre/modules/subprocess/subprocess_worker_win.js"; } + + static get WorkerClass() { + return WinPromiseWorker; + } } var SubprocessWin = { @@ -37,7 +62,6 @@ var SubprocessWin = { return Process.create(options); }, - * getEnvironment() { let env = libc.GetEnvironmentStringsW(); try { diff --git a/toolkit/modules/subprocess/subprocess_worker_common.js b/toolkit/modules/subprocess/subprocess_worker_common.js index 77c6e6162d32..a211a8ec1ff8 100644 --- a/toolkit/modules/subprocess/subprocess_worker_common.js +++ b/toolkit/modules/subprocess/subprocess_worker_common.js @@ -88,6 +88,18 @@ class BaseProcess { } let requests = { + init(details) { + io.init(details); + + return {data: {}}; + }, + + shutdown() { + io.shutdown(); + + return {data: {}}; + }, + close(pipeId, force = false) { let pipe = io.getPipe(pipeId); @@ -156,6 +168,8 @@ let requests = { }; onmessage = event => { + io.messageCount--; + let {msg, msgId, args} = event.data; new Promise(resolve => { @@ -195,3 +209,9 @@ onmessage = event => { }); }); }; + +onclose = event => { + io.shutdown(); + + self.postMessage({msg: "close"}); +}; diff --git a/toolkit/modules/subprocess/subprocess_worker_unix.js b/toolkit/modules/subprocess/subprocess_worker_unix.js index 61f0fee7e1a8..1a2595c286fb 100644 --- a/toolkit/modules/subprocess/subprocess_worker_unix.js +++ b/toolkit/modules/subprocess/subprocess_worker_unix.js @@ -12,8 +12,7 @@ importScripts("resource://gre/modules/subprocess/subprocess_shared.js", "resource://gre/modules/subprocess/subprocess_shared_unix.js", "resource://gre/modules/subprocess/subprocess_worker_common.js"); -const POLL_INTERVAL = 50; -const POLL_TIMEOUT = 0; +const POLL_TIMEOUT = 5000; let io; @@ -248,6 +247,40 @@ class OutputPipe extends Pipe { } } +class Signal { + constructor(fd) { + this.fd = fd; + } + + cleanup() { + libc.close(this.fd); + this.fd = null; + } + + get pollEvents() { + return LIBC.POLLIN; + } + + /** + * Called when an error occurred while polling our file descriptor. + */ + onError() { + io.shutdown(); + } + + /** + * Called when one of the IO operations matching the `pollEvents` mask may be + * performed without blocking. + */ + onReady() { + let buffer = new ArrayBuffer(16); + let count = +libc.read(this.fd, buffer, buffer.byteLength); + if (count > 0) { + io.messageCount += count; + } + } +} + class Process extends BaseProcess { /** * Each Process object opens an additional pipe from the target object, which @@ -449,7 +482,27 @@ io = { processes: new Map(), - interval: null, + messageCount: 0, + + running: true, + + init(details) { + this.signal = new Signal(details.signalFd); + this.updatePollFds(); + + setTimeout(this.loop.bind(this), 0); + }, + + shutdown() { + if (this.running) { + this.running = false; + + this.signal.cleanup(); + this.signal = null; + + self.close(); + } + }, getPipe(pipeId) { let pipe = this.pipes.get(pipeId); @@ -472,7 +525,8 @@ io = { }, updatePollFds() { - let handlers = [...this.pipes.values(), + let handlers = [this.signal, + ...this.pipes.values(), ...this.processes.values()]; handlers = handlers.filter(handler => handler.pollEvents); @@ -489,12 +543,12 @@ io = { this.pollFds = pollfds; this.pollHandlers = handlers; + }, - if (pollfds.length && !this.interval) { - this.interval = setInterval(this.poll.bind(this), POLL_INTERVAL); - } else if (!pollfds.length && this.interval) { - clearInterval(this.interval); - this.interval = null; + loop() { + this.poll(); + if (this.running) { + setTimeout(this.loop.bind(this), 0); } }, @@ -502,7 +556,8 @@ io = { let handlers = this.pollHandlers; let pollfds = this.pollFds; - let count = libc.poll(pollfds, pollfds.length, POLL_TIMEOUT); + let timeout = this.messageCount > 0 ? 0 : POLL_TIMEOUT; + let count = libc.poll(pollfds, pollfds.length, timeout); for (let i = 0; count && i < pollfds.length; i++) { let pollfd = pollfds[i]; diff --git a/toolkit/modules/subprocess/subprocess_worker_win.js b/toolkit/modules/subprocess/subprocess_worker_win.js index fa13a58edd70..762994f1a56a 100644 --- a/toolkit/modules/subprocess/subprocess_worker_win.js +++ b/toolkit/modules/subprocess/subprocess_worker_win.js @@ -12,8 +12,7 @@ importScripts("resource://gre/modules/subprocess/subprocess_shared.js", "resource://gre/modules/subprocess/subprocess_shared_win.js", "resource://gre/modules/subprocess/subprocess_worker_common.js"); -const POLL_INTERVAL = 50; -const POLL_TIMEOUT = 0; +const POLL_TIMEOUT = 5000; // The exit code that we send when we forcibly terminate a process. const TERMINATE_EXIT_CODE = 0x7f; @@ -298,6 +297,25 @@ class OutputPipe extends Pipe { } } +class Signal { + constructor(event) { + this.event = event; + } + + cleanup() { + libc.CloseHandle(this.event); + this.event = null; + } + + onError() { + io.shutdown(); + } + + onReady() { + io.messageCount += 1; + } +} + class Process extends BaseProcess { constructor(...args) { super(...args); @@ -543,7 +561,29 @@ io = { processes: new Map(), - interval: null, + messageCount: 0, + + running: true, + + init(details) { + let signalEvent = ctypes.cast(ctypes.uintptr_t(details.signalEvent), + win32.HANDLE); + this.signal = new Signal(signalEvent); + this.updatePollEvents(); + + setTimeout(this.loop.bind(this), 0); + }, + + shutdown() { + if (this.running) { + this.running = false; + + this.signal.cleanup(); + this.signal = null; + + self.close(); + } + }, getPipe(pipeId) { let pipe = this.pipes.get(pipeId); @@ -566,7 +606,8 @@ io = { }, updatePollEvents() { - let handlers = [...this.pipes.values(), + let handlers = [this.signal, + ...this.pipes.values(), ...this.processes.values()]; handlers = handlers.filter(handler => handler.event); @@ -575,22 +616,24 @@ io = { let handles = handlers.map(handler => handler.event); this.events = win32.HANDLE.array()(handles); + }, - if (handles.length && !this.interval) { - this.interval = setInterval(this.poll.bind(this), POLL_INTERVAL); - } else if (!handlers.length && this.interval) { - clearInterval(this.interval); - this.interval = null; + loop() { + this.poll(); + if (this.running) { + setTimeout(this.loop.bind(this), 0); } }, + poll() { - for (;;) { + let timeout = this.messageCount > 0 ? 0 : POLL_TIMEOUT; + for (;; timeout = 0) { let events = this.events; let handlers = this.eventHandlers; let result = libc.WaitForMultipleObjects(events.length, events, - false, POLL_TIMEOUT); + false, timeout); if (result < handlers.length) { try { diff --git a/toolkit/modules/subprocess/test/xpcshell/test_subprocess.js b/toolkit/modules/subprocess/test/xpcshell/test_subprocess.js index f63dd195b674..6ac2ddb17a1f 100644 --- a/toolkit/modules/subprocess/test/xpcshell/test_subprocess.js +++ b/toolkit/modules/subprocess/test/xpcshell/test_subprocess.js @@ -1,11 +1,14 @@ "use strict"; +Cu.import("resource://gre/modules/AppConstants.jsm"); Cu.import("resource://gre/modules/Task.jsm"); Cu.import("resource://gre/modules/Timer.jsm"); const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment); +const MAX_ROUND_TRIP_TIME_MS = AppConstants.DEBUG || AppConstants.ASAN ? 18 : 9; + let PYTHON; let PYTHON_BIN; let PYTHON_DIR; @@ -178,6 +181,42 @@ add_task(function* test_subprocess_huge() { }); +add_task(function* test_subprocess_round_trip_perf() { + let proc = yield Subprocess.call({ + command: PYTHON, + arguments: ["-u", TEST_SCRIPT, "echo"], + }); + + + const LINE = "I'm a leaf on the wind.\n"; + + let now = Date.now(); + const COUNT = 1000; + for (let i = 0; i < COUNT; i++) { + let [output] = yield Promise.all([ + read(proc.stdout), + proc.stdin.write(LINE), + ]); + + // We don't want to log this for every iteration, but we still need + // to fail if it goes wrong. + if (output !== LINE) { + equal(output, LINE, "Got expected output"); + } + } + + let roundTripTime = (Date.now() - now) / COUNT; + ok(roundTripTime <= MAX_ROUND_TRIP_TIME_MS, + `Expected round trip time (${roundTripTime}ms) to be less than ${MAX_ROUND_TRIP_TIME_MS}ms`); + + yield proc.stdin.close(); + + let {exitCode} = yield proc.wait(); + + equal(exitCode, 0, "Got expected exit code"); +}); + + add_task(function* test_subprocess_stderr_default() { const LINE1 = "I'm a leaf on the wind.\n"; const LINE2 = "Watch how I soar.\n"; @@ -325,9 +364,10 @@ add_task(function* test_subprocess_lazy_close_input() { yield closedPromise; - let {exitCode} = yield proc.wait(); - - equal(exitCode, 0, "Got expected exit code"); + // Don't test for a successful exit here. The process may exit with a + // write error if we close the pipe after it's written the message + // size but before it's written the message. + yield proc.wait(); }); From 16ab15420c7d6c75ecea21ea633e99bf21473c73 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Fri, 29 Jul 2016 13:55:25 +0900 Subject: [PATCH 115/120] Bug 1280046 - Search codepoints with same uppercase on ignoreCase match with non-unicode RegExp. r=jwalden --- js/src/irregexp/RegExpEngine.cpp | 41 ++- .../ecma_6/RegExp/ignoreCase-multiple.js | 71 ++++ js/src/vm/Unicode.cpp | 316 ++++++++++++++++++ js/src/vm/Unicode.h | 70 ++++ js/src/vm/make_unicode.py | 69 +++- 5 files changed, 557 insertions(+), 10 deletions(-) create mode 100644 js/src/tests/ecma_6/RegExp/ignoreCase-multiple.js diff --git a/js/src/irregexp/RegExpEngine.cpp b/js/src/irregexp/RegExpEngine.cpp index b544e0515113..d944fe622a45 100644 --- a/js/src/irregexp/RegExpEngine.cpp +++ b/js/src/irregexp/RegExpEngine.cpp @@ -286,13 +286,6 @@ GetCaseIndependentLetters(char16_t character, for (size_t i = 0; i < choices_length; i++) { char16_t c = choices[i]; - // The standard requires that non-ASCII characters cannot have ASCII - // character codes in their equivalence class, even though this - // situation occurs multiple times in the unicode tables. - static const unsigned kMaxAsciiCharCode = 127; - if (!unicode && character > kMaxAsciiCharCode && c <= kMaxAsciiCharCode) - continue; - // Skip characters that can't appear in one byte strings. if (!unicode && ascii_subject && c > kMaxOneByteCharCode) continue; @@ -332,10 +325,40 @@ GetCaseIndependentLetters(char16_t character, choices, ArrayLength(choices), letters); } + char16_t upper = unicode::ToUpperCase(character); + unicode::CodepointsWithSameUpperCase others(character); + char16_t other1 = others.other1(); + char16_t other2 = others.other2(); + char16_t other3 = others.other3(); + + // ES 2017 draft 996af87b7072b3c3dd2b1def856c66f456102215 21.2.4.2 + // step 3.g. + // The standard requires that non-ASCII characters cannot have ASCII + // character codes in their equivalence class, even though this + // situation occurs multiple times in the unicode tables. + static const unsigned kMaxAsciiCharCode = 127; + if (upper <= kMaxAsciiCharCode) { + if (character > kMaxAsciiCharCode) { + // If Canonicalize(character) == character, all other characters + // should be ignored. + return GetCaseIndependentLetters(character, ascii_subject, unicode, + &character, 1, letters); + } + + if (other1 > kMaxAsciiCharCode) + other1 = character; + if (other2 > kMaxAsciiCharCode) + other2 = character; + if (other3 > kMaxAsciiCharCode) + other3 = character; + } + const char16_t choices[] = { character, - unicode::ToLowerCase(character), - unicode::ToUpperCase(character) + upper, + other1, + other2, + other3 }; return GetCaseIndependentLetters(character, ascii_subject, unicode, choices, ArrayLength(choices), letters); diff --git a/js/src/tests/ecma_6/RegExp/ignoreCase-multiple.js b/js/src/tests/ecma_6/RegExp/ignoreCase-multiple.js new file mode 100644 index 000000000000..e52cf499b3f9 --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/ignoreCase-multiple.js @@ -0,0 +1,71 @@ +var BUGNUMBER = 1280046; +var summary = "ignoreCase match should perform Canonicalize both on input and pattern."; + +print(BUGNUMBER + ": " + summary); + +// Each element [code1, upper, code2] satisfies the following condition: +// ToUpperCase(code1) == upper +// ToUpperCase(code2) == upper +var pairs = + [ + // U+00B5: MICRO SIGN + // U+039C: GREEK CAPITAL LETTER MU + // U+03BC: GREEK SMALL LETTER MU + ["\u00B5", "\u039C", "\u03BC"], + // U+0345: COMBINING GREEK YPOGEGRAMMENI + // U+0399: GREEK CAPITAL LETTER IOTA + // U+03B9: GREEK SMALL LETTER IOTA + ["\u0345", "\u0399", "\u03B9"], + // U+03C2: GREEK SMALL LETTER FINAL SIGMA + // U+03A3: GREEK CAPITAL LETTER SIGMA + // U+03C3: GREEK SMALL LETTER SIGMA + ["\u03C2", "\u03A3", "\u03C3"], + // U+03D0: GREEK BETA SYMBOL + // U+0392: GREEK CAPITAL LETTER BETA + // U+03B2: GREEK SMALL LETTER BETA + ["\u03D0", "\u0392", "\u03B2"], + // U+03D1: GREEK THETA SYMBOL + // U+0398: GREEK CAPITAL LETTER THETA + // U+03B8: GREEK SMALL LETTER THETA + ["\u03D1", "\u0398", "\u03B8"], + // U+03D5: GREEK PHI SYMBOL + // U+03A6: GREEK CAPITAL LETTER PHI + // U+03C6: GREEK SMALL LETTER PHI + ["\u03D5", "\u03A6", "\u03C6"], + // U+03D6: GREEK PI SYMBOL + // U+03A0: GREEK CAPITAL LETTER PI + // U+03C0: GREEK SMALL LETTER PI + ["\u03D6", "\u03A0", "\u03C0"], + // U+03F0: GREEK KAPPA SYMBOL + // U+039A: GREEK CAPITAL LETTER KAPPA + // U+03BA: GREEK SMALL LETTER KAPPA + ["\u03F0", "\u039A", "\u03BA"], + // U+03F1: GREEK RHO SYMBOL + // U+03A1: GREEK CAPITAL LETTER RHO + // U+03C1: GREEK SMALL LETTER RHO + ["\u03F1", "\u03A1", "\u03C1"], + // U+03F5: GREEK LUNATE EPSILON SYMBOL + // U+0395: GREEK CAPITAL LETTER EPSILON + // U+03B5: GREEK SMALL LETTER EPSILON + ["\u03F5", "\u0395", "\u03B5"], + // U+1E9B: LATIN SMALL LETTER LONG S WITH DOT ABOVE + // U+1E60: LATIN CAPITAL LETTER S WITH DOT ABOVE + // U+1E61: LATIN SMALL LETTER S WITH DOT ABOVE + ["\u1E9B", "\u1E60", "\u1E61"], + // U+1FBE: GREEK PROSGEGRAMMENI + // U+0399: GREEK CAPITAL LETTER IOTA + // U+03B9: GREEK SMALL LETTER IOTA + ["\u1FBE", "\u0399", "\u03B9"], + ]; + +for (var [code1, upper, code2] of pairs) { + assertEq(new RegExp(code1, "i").test(code2), true); + assertEq(new RegExp(code1, "i").test(upper), true); + assertEq(new RegExp(upper, "i").test(code1), true); + assertEq(new RegExp(upper, "i").test(code2), true); + assertEq(new RegExp(code2, "i").test(code1), true); + assertEq(new RegExp(code2, "i").test(upper), true); +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/vm/Unicode.cpp b/js/src/vm/Unicode.cpp index 9214450ac262..ff4142400893 100644 --- a/js/src/vm/Unicode.cpp +++ b/js/src/vm/Unicode.cpp @@ -772,6 +772,322 @@ const uint8_t unicode::index2[] = { 5, 5, 5, 0, 0, 0, }; +const CodepointsWithSameUpperCaseInfo unicode::js_codepoints_with_same_upper_info[] = { + {0, 0, 0}, + {32, 0, 0}, + {32, 232, 0}, + {32, 300, 0}, + {0, 200, 0}, + {0, 268, 0}, + {0, 775, 0}, + {1, 0, 0}, + {65336, 0, 0}, + {65415, 0, 0}, + {65268, 0, 0}, + {210, 0, 0}, + {206, 0, 0}, + {205, 0, 0}, + {79, 0, 0}, + {202, 0, 0}, + {203, 0, 0}, + {207, 0, 0}, + {211, 0, 0}, + {209, 0, 0}, + {213, 0, 0}, + {214, 0, 0}, + {218, 0, 0}, + {217, 0, 0}, + {219, 0, 0}, + {1, 2, 0}, + {0, 1, 0}, + {65535, 0, 0}, + {65439, 0, 0}, + {65480, 0, 0}, + {65406, 0, 0}, + {10795, 0, 0}, + {65373, 0, 0}, + {10792, 0, 0}, + {65341, 0, 0}, + {69, 0, 0}, + {71, 0, 0}, + {0, 116, 7289}, + {38, 0, 0}, + {37, 0, 0}, + {64, 0, 0}, + {63, 0, 0}, + {32, 62, 0}, + {32, 96, 0}, + {32, 57, 0}, + {65452, 32, 7205}, + {32, 86, 0}, + {64793, 32, 0}, + {32, 54, 0}, + {32, 80, 0}, + {31, 32, 0}, + {32, 47, 0}, + {0, 30, 0}, + {0, 64, 0}, + {0, 25, 0}, + {65420, 0, 7173}, + {0, 54, 0}, + {64761, 0, 0}, + {0, 22, 0}, + {0, 48, 0}, + {0, 15, 0}, + {8, 0, 0}, + {65506, 0, 0}, + {65511, 0, 0}, + {65521, 0, 0}, + {65514, 0, 0}, + {65482, 0, 0}, + {65488, 0, 0}, + {65472, 0, 0}, + {65529, 0, 0}, + {80, 0, 0}, + {15, 0, 0}, + {48, 0, 0}, + {7264, 0, 0}, + {1, 59, 0}, + {0, 58, 0}, + {65478, 0, 0}, + {65528, 0, 0}, + {65462, 0, 0}, + {65527, 0, 0}, + {58247, 58363, 0}, + {65450, 0, 0}, + {65436, 0, 0}, + {65424, 0, 0}, + {65408, 0, 0}, + {65410, 0, 0}, + {28, 0, 0}, + {16, 0, 0}, + {26, 0, 0}, + {54793, 0, 0}, + {61722, 0, 0}, + {54809, 0, 0}, + {54756, 0, 0}, + {54787, 0, 0}, + {54753, 0, 0}, + {54754, 0, 0}, + {54721, 0, 0}, + {30204, 0, 0}, + {23256, 0, 0}, + {23228, 0, 0}, +}; + +const uint8_t unicode::codepoints_with_same_upper_index1[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22, 23, 21, 24, 25, + 26, 27, 0, 0, 0, 0, 28, 29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 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, 33, 34, 21, 35, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, + 37, 0, 38, 39, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, +}; + +const uint8_t unicode::codepoints_with_same_upper_index2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 8, + 7, 0, 7, 0, 7, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, + 0, 7, 0, 7, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 9, 7, + 0, 7, 0, 7, 0, 10, 0, 11, 7, 0, 7, 0, 12, 7, 0, 13, 13, 7, + 0, 0, 14, 15, 16, 7, 0, 13, 17, 0, 18, 19, 7, 0, 0, 0, 18, 20, + 0, 21, 7, 0, 7, 0, 7, 0, 22, 7, 0, 22, 0, 0, 7, 0, 22, 7, + 0, 23, 23, 7, 0, 7, 0, 24, 7, 0, 0, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 25, 26, 27, 25, 26, 27, 25, 26, 27, 7, 0, 7, 0, 7, 0, 7, + 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 25, 26, 27, 7, 0, 28, 29, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 30, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 31, 7, 0, 32, 33, 0, + 0, 7, 0, 34, 35, 36, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 7, 0, 7, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 39, 39, 39, 0, 40, 0, 41, 41, + 0, 1, 42, 1, 1, 43, 1, 1, 44, 45, 46, 1, 47, 1, 1, 1, 48, 49, + 0, 50, 1, 1, 51, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 52, 0, + 0, 53, 0, 0, 54, 55, 56, 0, 57, 0, 0, 0, 58, 59, 26, 27, 0, 0, + 60, 0, 0, 0, 0, 0, 0, 0, 0, 61, 62, 63, 0, 0, 0, 64, 65, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 66, 67, 0, 0, 0, 68, 0, 7, 0, 69, 7, 0, + 0, 30, 30, 30, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 71, 7, + 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 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, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 0, 73, 0, 0, 0, 0, 0, 73, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 74, 75, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 0, 0, 0, 0, 0, 76, 0, 0, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, + 77, 77, 77, 77, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, 77, 77, + 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, 77, 77, 0, 0, + 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 77, 0, 77, 0, 77, 0, 77, 0, 0, 0, 0, 0, 0, + 0, 0, 77, 77, 77, 77, 77, 77, 77, 77, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, + 77, 77, 77, 77, 77, 77, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, + 77, 77, 77, 77, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, + 77, 77, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 78, 78, 79, 0, 80, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 81, 81, 81, 81, 79, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 77, 77, 82, 82, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 77, 77, 83, 83, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 84, 84, 85, 85, 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, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 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, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 89, 90, 91, 0, + 0, 7, 0, 7, 0, 7, 0, 92, 93, 94, 95, 0, 7, 0, 0, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 96, 96, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, + 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, + 7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, + 0, 97, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 0, 7, 0, 98, + 0, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 99, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, +}; + const FoldingInfo unicode::js_foldinfo[] = { {0, 0, 0, 0}, {32, 0, 0, 0}, diff --git a/js/src/vm/Unicode.h b/js/src/vm/Unicode.h index caaa7923d66a..5954930d5d3e 100644 --- a/js/src/vm/Unicode.h +++ b/js/src/vm/Unicode.h @@ -279,6 +279,76 @@ ToLowerCaseNonBMPTrail(char16_t lead, char16_t trail) return trail; } +/* + * For a codepoint C, CodepointsWithSameUpperCaseInfo stores three offsets + * from C to up to three codepoints with same uppercase (no codepoint in + * UnicodeData.txt has more than three such codepoints). + * + * To illustrate, consider the codepoint U+0399 GREEK CAPITAL LETTER IOTA, the + * uppercased form of these three codepoints: + * + * U+03B9 GREEK SMALL LETTER IOTA + * U+1FBE GREEK PROSGEGRAMMENI + * U+0345 COMBINING GREEK YPOGEGRAMMENI + * + * For the CodepointsWithSameUpperCaseInfo corresponding to this codepoint, + * delta{1,2,3} are 16-bit modular deltas from 0x0399 to each respective + * codepoint: + * uint16_t(0x03B9 - 0x0399), + * uint16_t(0x1FBE - 0x0399), + * uint16_t(0x0345 - 0x0399) + * in an unimportant order. + * + * If there are fewer than three other codepoints, some fields are zero. + * Consider the codepoint U+03B9 above, the other two codepoints U+1FBE and + * U+0345 have same uppercase (U+0399 is not). For the + * CodepointsWithSameUpperCaseInfo corresponding to this codepoint, + * delta{1,2,3} are: + * uint16_t(0x1FBE - 0x03B9), + * uint16_t(0x0345 - 0x03B9), + * uint16_t(0) + * in an unimportant order. + * + * Because multiple codepoints map to a single CodepointsWithSameUpperCaseInfo, + * a CodepointsWithSameUpperCaseInfo and its delta{1,2,3} have no meaning + * standing alone: they have meaning only with respect to a codepoint mapping + * to that CodepointsWithSameUpperCaseInfo. + */ +class CodepointsWithSameUpperCaseInfo +{ + public: + uint16_t delta1; + uint16_t delta2; + uint16_t delta3; +}; + +extern const uint8_t codepoints_with_same_upper_index1[]; +extern const uint8_t codepoints_with_same_upper_index2[]; +extern const CodepointsWithSameUpperCaseInfo js_codepoints_with_same_upper_info[]; + +class CodepointsWithSameUpperCase +{ + const CodepointsWithSameUpperCaseInfo& info_; + const char16_t code_; + + static const CodepointsWithSameUpperCaseInfo& computeInfo(char16_t code) { + const size_t shift = 6; + size_t index = codepoints_with_same_upper_index1[code >> shift]; + index = codepoints_with_same_upper_index2[(index << shift) + (code & ((1 << shift) - 1))]; + return js_codepoints_with_same_upper_info[index]; + } + + public: + explicit CodepointsWithSameUpperCase(char16_t code) + : info_(computeInfo(code)), + code_(code) + {} + + char16_t other1() const { return uint16_t(code_) + info_.delta1; } + char16_t other2() const { return uint16_t(code_) + info_.delta2; } + char16_t other3() const { return uint16_t(code_) + info_.delta3; } +}; + class FoldingInfo { public: uint16_t folding; diff --git a/js/src/vm/make_unicode.py b/js/src/vm/make_unicode.py index 74fae06d2daa..43334ef88cfd 100644 --- a/js/src/vm/make_unicode.py +++ b/js/src/vm/make_unicode.py @@ -145,6 +145,11 @@ def generate_unicode_stuff(unicode_data, case_folding, table = [dummy] cache = {dummy: 0} index = [0] * (MAX + 1) + same_upper_map = {} + same_upper_dummy = (0, 0, 0) + same_upper_table = [same_upper_dummy] + same_upper_cache = {same_upper_dummy: 0} + same_upper_index = [0] * (MAX + 1) folding_map = {} rev_folding_map = {} folding_dummy = (0, 0, 0, 0) @@ -172,6 +177,11 @@ def generate_unicode_stuff(unicode_data, case_folding, if uppercase: upper = int(uppercase, 16) + + if upper not in same_upper_map: + same_upper_map[upper] = [code] + else: + same_upper_map[upper].append(code) else: upper = code @@ -216,6 +226,36 @@ def generate_unicode_stuff(unicode_data, case_folding, table.append(item) index[code] = i + for code in range(0, MAX + 1): + entry = test_table.get(code) + + if not entry: + continue + + (upper, lower, name, alias) = entry + + if upper not in same_upper_map: + continue + + same_upper_ds = [v - code for v in same_upper_map[upper]] + + assert len(same_upper_ds) <= 3 + assert all([v > -65535 and v < 65535 for v in same_upper_ds]) + + same_upper = [v & 0xffff for v in same_upper_ds] + same_upper_0 = same_upper[0] if len(same_upper) >= 1 else 0 + same_upper_1 = same_upper[1] if len(same_upper) >= 2 else 0 + same_upper_2 = same_upper[2] if len(same_upper) >= 3 else 0 + + item = (same_upper_0, same_upper_1, same_upper_2) + + i = same_upper_cache.get(item) + if i is None: + assert item not in same_upper_table + same_upper_cache[item] = i = len(same_upper_table) + same_upper_table.append(item) + same_upper_index[code] = i + for row in read_case_folding(case_folding): code = row[0] mapping = row[2] @@ -310,7 +350,7 @@ def generate_unicode_stuff(unicode_data, case_folding, entry = test_table.get(code) if entry: - upper, lower, name, alias = entry + (upper, lower, name, alias) = entry test_mapping.write(' [' + hex(upper) + ', ' + hex(lower) + '], /* ' + name + (' (' + alias + ')' if alias else '') + ' */\n') else: @@ -389,6 +429,11 @@ if (typeof reportCompare === "function") # Don't forget to update CharInfo in Unicode.cpp if you need to change this assert shift == 5 + same_upper_index1, same_upper_index2, same_upper_shift = splitbins(same_upper_index) + + # Don't forget to update CharInfo in Unicode.cpp if you need to change this + assert same_upper_shift == 6 + folding_index1, folding_index2, folding_shift = splitbins(folding_index) # Don't forget to update CharInfo in Unicode.cpp if you need to change this @@ -403,6 +448,15 @@ if (typeof reportCompare === "function") assert test == table[idx] + # verify correctness + for char in same_upper_index: + test = same_upper_table[same_upper_index[char]] + + idx = same_upper_index1[char >> same_upper_shift] + idx = same_upper_index2[(idx << same_upper_shift) + (char & ((1 << same_upper_shift) - 1))] + + assert test == same_upper_table[idx] + # verify correctness for char in folding_index: test = folding_table[folding_index[char]] @@ -497,6 +551,19 @@ if (typeof reportCompare === "function") dump(index2, 'index2', data_file) data_file.write('\n') + data_file.write('const CodepointsWithSameUpperCaseInfo unicode::js_codepoints_with_same_upper_info[] = {\n') + for d in same_upper_table: + data_file.write(' {') + data_file.write(', '.join((str(e) for e in d))) + data_file.write('},\n') + data_file.write('};\n') + data_file.write('\n') + + dump(same_upper_index1, 'codepoints_with_same_upper_index1', data_file) + data_file.write('\n') + dump(same_upper_index2, 'codepoints_with_same_upper_index2', data_file) + data_file.write('\n') + data_file.write('const FoldingInfo unicode::js_foldinfo[] = {\n') for d in folding_table: data_file.write(' {') From 414b89d4d3a11d45c84cd033f20838eaf4c5fcfe Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Fri, 29 Jul 2016 13:55:26 +0900 Subject: [PATCH 116/120] Bug 1287524 - Check RegExp.prototype.unicode in RegExpPrototypeOptimizable. r=h4writer --- js/src/builtin/RegExp.cpp | 9 +++++++++ .../ecma_6/RegExp/replace-global-unicode.js | 18 ++++++++++++++++++ js/src/vm/RegExpObject.h | 1 + 3 files changed, 28 insertions(+) create mode 100644 js/src/tests/ecma_6/RegExp/replace-global-unicode.js diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index 1ef8de0293d5..588f0f72c204 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -1559,6 +1559,15 @@ js::RegExpPrototypeOptimizableRaw(JSContext* cx, JSObject* proto, uint8_t* resul return true; } + JSNative unicodeGetter; + if (!GetOwnNativeGetterPure(cx, proto, NameToId(cx->names().unicode), &unicodeGetter)) + return false; + + if (unicodeGetter != regexp_unicode) { + *result = false; + return true; + } + // Check if @@match, @@search, and exec are own data properties, // those values should be tested in selfhosted JS. bool has = false; diff --git a/js/src/tests/ecma_6/RegExp/replace-global-unicode.js b/js/src/tests/ecma_6/RegExp/replace-global-unicode.js new file mode 100644 index 000000000000..80b3ea19962f --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/replace-global-unicode.js @@ -0,0 +1,18 @@ +var BUGNUMBER = 1287524; +var summary = 'RegExp.prototype[@@replace] should not use optimized path if RegExp.prototype.unicode is modified.'; + +print(BUGNUMBER + ": " + summary); + +Object.defineProperty(RegExp.prototype, "unicode", { + get() { + RegExp.prototype.exec = () => null; + } +}); + +var rx = RegExp("a", "g"); +var s = "abba"; +var r = rx[Symbol.replace](s, "c"); +assertEq(r, "abba"); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/vm/RegExpObject.h b/js/src/vm/RegExpObject.h index c02c9e746ce8..0d68fabd6a33 100644 --- a/js/src/vm/RegExpObject.h +++ b/js/src/vm/RegExpObject.h @@ -326,6 +326,7 @@ class RegExpCompartment * The shape of RegExp.prototype object that satisfies following: * * RegExp.prototype.global getter is not modified * * RegExp.prototype.sticky getter is not modified + * * RegExp.prototype.unicode getter is not modified * * RegExp.prototype.exec is an own data property * * RegExp.prototype[@@match] is an own data property * * RegExp.prototype[@@search] is an own data property From 1de3de00d83ec863c2a0db12ba294a8e305442f1 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Fri, 29 Jul 2016 13:55:26 +0900 Subject: [PATCH 117/120] Bug 1287525 - Part 1: Do not use RegExp.prototype[@@split] optimized path if |this| object has extra property. r=h4writer --- js/src/builtin/RegExp.js | 1 + .../tests/ecma_6/RegExp/split-prop-access.js | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 js/src/tests/ecma_6/RegExp/split-prop-access.js diff --git a/js/src/builtin/RegExp.js b/js/src/builtin/RegExp.js index 156183bcf49f..96a08420233e 100644 --- a/js/src/builtin/RegExp.js +++ b/js/src/builtin/RegExp.js @@ -579,6 +579,7 @@ function IsRegExpSplitOptimizable(rx, C) { // If RegExpPrototypeOptimizable succeeds, `RegExpProto.exec` is guaranteed // to be a data property. return RegExpPrototypeOptimizable(RegExpProto) && + RegExpInstanceOptimizable(rx, RegExpProto) && RegExpProto.exec === RegExp_prototype_Exec; } diff --git a/js/src/tests/ecma_6/RegExp/split-prop-access.js b/js/src/tests/ecma_6/RegExp/split-prop-access.js new file mode 100644 index 000000000000..73c5bebb31e4 --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/split-prop-access.js @@ -0,0 +1,19 @@ +var BUGNUMBER = 1287525; +var summary = 'String.prototype.split should call ToUint32(limit) before ToString(separator).'; + +print(BUGNUMBER + ": " + summary); + +var accessed = false; + +var rx = /a/; +Object.defineProperty(rx, Symbol.match, { + get() { + accessed = true; + } +}); +rx[Symbol.split]("abba"); + +assertEq(accessed, true); + +if (typeof reportCompare === "function") + reportCompare(true, true); From a3fa8a6a1c2728a79e6b44def106e159d7bb59e2 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Fri, 29 Jul 2016 13:55:26 +0900 Subject: [PATCH 118/120] Bug 1287525 - Part 2: Do not use RegExp.prototype[@@split] optimized path if limit is not number. r=h4writer --- js/src/builtin/RegExp.js | 3 ++- js/src/tests/ecma_6/RegExp/split-limit.js | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 js/src/tests/ecma_6/RegExp/split-limit.js diff --git a/js/src/builtin/RegExp.js b/js/src/builtin/RegExp.js index 96a08420233e..1833593a3299 100644 --- a/js/src/builtin/RegExp.js +++ b/js/src/builtin/RegExp.js @@ -604,7 +604,8 @@ function RegExpSplit(string, limit) { // Steps 6-7. var unicodeMatching = callFunction(std_String_includes, flags, "u"); - var optimizable = IsRegExpSplitOptimizable(rx, C); + var optimizable = IsRegExpSplitOptimizable(rx, C) && + (limit === undefined || typeof limit == "number"); var splitter; if (optimizable) { // Steps 8-9 (skipped). diff --git a/js/src/tests/ecma_6/RegExp/split-limit.js b/js/src/tests/ecma_6/RegExp/split-limit.js new file mode 100644 index 000000000000..5fa194b90bc6 --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/split-limit.js @@ -0,0 +1,14 @@ +var BUGNUMBER = 1287525; +var summary = "RegExp.prototype[@@split] shouldn't use optimized path if limit is not number."; + +print(BUGNUMBER + ": " + summary); + +var rx = /a/; +var r = rx[Symbol.split]("abba", {valueOf() { + RegExp.prototype.exec = () => null; + return 100; +}}); +assertEq(r.length, 1); + +if (typeof reportCompare === "function") + reportCompare(true, true); From ab4c2ebe2c3f5980db6e6c33fa2b686066a92e64 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Fri, 29 Jul 2016 13:55:26 +0900 Subject: [PATCH 119/120] Bug 1287520 - Check IsPackedArray for the result array in Array.prototype.concat. r=efaust --- js/src/builtin/Array.js | 2 +- js/src/tests/ecma_6/Array/concat-proxy.js | 25 +++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 js/src/tests/ecma_6/Array/concat-proxy.js diff --git a/js/src/builtin/Array.js b/js/src/builtin/Array.js index 76477ce5fd5e..e17bddfbec24 100644 --- a/js/src/builtin/Array.js +++ b/js/src/builtin/Array.js @@ -990,7 +990,7 @@ function ArrayConcat(arg1) { if (n + len > MAX_NUMERIC_INDEX) ThrowTypeError(JSMSG_TOO_LONG_ARRAY); - if (IsPackedArray(E)) { + if (IsPackedArray(A) && IsPackedArray(E)) { // Step 5.c.i, 5.c.iv, and 5.c.iv.5. for (k = 0; k < len; k++) { // Steps 5.c.iv.1-3. diff --git a/js/src/tests/ecma_6/Array/concat-proxy.js b/js/src/tests/ecma_6/Array/concat-proxy.js new file mode 100644 index 000000000000..ab733e2f10d1 --- /dev/null +++ b/js/src/tests/ecma_6/Array/concat-proxy.js @@ -0,0 +1,25 @@ +var BUGNUMBER = 1287520; +var summary = 'Array.prototype.concat should check HasProperty everytime for non-dense array'; + +print(BUGNUMBER + ": " + summary); + +var a = [1, 2, 3]; +a.constructor = { + [Symbol.species]: function(...args) { + var p = new Proxy(new Array(...args), { + defineProperty(target, propertyKey, receiver) { + if (propertyKey === "0") delete a[1]; + return Reflect.defineProperty(target, propertyKey, receiver); + } + }); + return p; + } +}; + +var p = a.concat(); +assertEq(0 in p, true); +assertEq(1 in p, false); +assertEq(2 in p, true); + +if (typeof reportCompare === "function") + reportCompare(true, true); From 0291de30b7426c92cdd989bab74095f2a311a1ec Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Thu, 28 Jul 2016 22:43:49 -0700 Subject: [PATCH 120/120] Backed out changeset 7d6baa38a04c (bug 1288938) for reftest crashes --- gfx/thebes/gfxFont.h | 2 + layout/generic/nsTextFrame.cpp | 329 +++++++++--------------------- layout/generic/nsTextFrameUtils.h | 5 +- 3 files changed, 101 insertions(+), 235 deletions(-) diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index 4ed9fac21883..3ff9efb27e14 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -568,6 +568,8 @@ public: // Set if the textrun should use the OpenType 'math' script. TEXT_USE_MATH_SCRIPT = 0x80000000, + + TEXT_UNUSED_FLAGS = 0x10000000 }; /** diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index add0628c40d5..d91bef3171eb 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -180,22 +180,24 @@ NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(UninflatedTextRunProperty, gfxTextRun) NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(FontSizeInflationProperty, float) -/** - * A glyph observer for the change of a font glyph in a text run. - * - * This is stored in {Simple, Complex}TextRunUserData. - */ class GlyphObserver : public gfxFont::GlyphChangeObserver { public: - GlyphObserver(gfxFont* aFont, gfxTextRun* aTextRun) - : gfxFont::GlyphChangeObserver(aFont), mTextRun(aTextRun) { - MOZ_ASSERT(aTextRun->GetUserData()); - } + GlyphObserver(gfxFont* aFont, nsTextFrame* aFrame) + : gfxFont::GlyphChangeObserver(aFont), mFrame(aFrame) {} virtual void NotifyGlyphsChanged() override; private: - gfxTextRun* mTextRun; + nsTextFrame* mFrame; }; +/** + * This property is set on text frames with TEXT_IN_TEXTRUN_USER_DATA set that + * have potentially-animated glyphs. + * The only reason this list is in a property is to automatically destroy the + * list when the frame is deleted, unregistering the observers. + */ +NS_DECLARE_FRAME_PROPERTY_DELETABLE(TextFrameGlyphObservers, + nsTArray>) + static const nsFrameState TEXT_REFLOW_FLAGS = TEXT_FIRST_LETTER | TEXT_START_OF_LINE | @@ -221,55 +223,21 @@ static const nsFrameState TEXT_WHITESPACE_FLAGS = * * A gfxTextRun can cover more than one DOM text node. This is necessary to * get kerning, ligatures and shaping for text that spans multiple text nodes - * but is all the same font. - * - * The userdata for a gfxTextRun object can be: - * - * - A nsTextFrame* in the case a text run maps to only one flow. In this - * case, the textrun's user data pointer is a pointer to mStartFrame for that - * flow, mDOMOffsetToBeforeTransformOffset is zero, and mContentLength is the - * length of the text node. - * - * - A SimpleTextRunUserData in the case a text run maps to one flow, but we - * still have to keep a list of glyph observers. - * - * - A ComplexTextRunUserData in the case a text run maps to multiple flows, - * but we need to keep a list of glyph observers. - * - * - A TextRunUserData in the case a text run maps multiple flows, but it - * doesn't have any glyph observer for changes in SVG fonts. - * - * You can differentiate between the four different cases with the - * TEXT_IS_SIMPLE_FLOW and TEXT_MIGHT_HAVE_GLYPH_CHANGES flags. - * + * but is all the same font. The userdata for a gfxTextRun object is a + * TextRunUserData* or an nsIFrame*. + * * We go to considerable effort to make sure things work even if in-flow * siblings have different style contexts (i.e., first-letter and first-line). - * + * * Our convention is that unsigned integer character offsets are offsets into * the transformed string. Signed integer character offsets are offsets into * the DOM string. - * + * * XXX currently we don't handle hyphenated breaks between text frames where the * hyphen occurs at the end of the first text frame, e.g. * Kit­ty */ -/** - * This is our user data for the textrun, when textRun->GetFlags() has - * TEXT_IS_SIMPLE_FLOW set, and also TEXT_MIGHT_HAVE_GLYPH_CHANGES. - * - * This allows having an array of observers if there are fonts whose glyphs - * might change, but also avoid allocation in the simple case that there aren't. - */ -struct SimpleTextRunUserData { - nsTArray> mGlyphObservers; - nsTextFrame* mFrame; - explicit SimpleTextRunUserData(nsTextFrame* aFrame) - : mFrame(aFrame) - { - } -}; - /** * We use an array of these objects to record which text frames * are associated with the textrun. mStartFrame is the start of a list of @@ -291,11 +259,11 @@ struct TextRunMappedFlow { }; /** - * This is the type in the gfxTextRun's userdata field in the common case that - * the text run maps to multiple flows, but no fonts have been found with - * animatable glyphs. - * - * This way, we avoid allocating and constructing the extra nsTArray. + * This is our user data for the textrun, when textRun->GetFlags() does not + * have TEXT_IS_SIMPLE_FLOW set. When TEXT_IS_SIMPLE_FLOW is set, there is + * just one flow, the textrun's user data pointer is a pointer to mStartFrame + * for that flow, mDOMOffsetToBeforeTransformOffset is zero, and mContentLength + * is the length of the text node. */ struct TextRunUserData { TextRunMappedFlow* mMappedFlows; @@ -303,14 +271,6 @@ struct TextRunUserData { uint32_t mLastFlowIndex; }; -/** - * This is our user data for the textrun, when textRun->GetFlags() does not - * have TEXT_IS_SIMPLE_FLOW set and has the TEXT_MIGHT HAVE_GLYPH_CHANGES flag. - */ -struct ComplexTextRunUserData : public TextRunUserData { - nsTArray> mGlyphObservers; -}; - /** * This helper object computes colors used for painting, and also IME * underline information. The data is computed lazily and cached as necessary. @@ -453,84 +413,15 @@ protected: nscolor aBackColor); }; -static TextRunUserData* -CreateUserData(uint32_t aMappedFlowCount) -{ - TextRunUserData* data = static_cast - (moz_xmalloc(sizeof(TextRunUserData) + - aMappedFlowCount * sizeof(TextRunMappedFlow))); - data->mMappedFlows = reinterpret_cast(data + 1); - data->mMappedFlowCount = aMappedFlowCount; - data->mLastFlowIndex = 0; - return data; -} - static void -DestroyUserData(TextRunUserData* aUserData) +DestroyUserData(void* aUserData) { - if (aUserData) { - free(aUserData); + TextRunUserData* userData = static_cast(aUserData); + if (userData) { + free(userData); } } -static ComplexTextRunUserData* -CreateComplexUserData(uint32_t aMappedFlowCount) -{ - ComplexTextRunUserData* data = static_cast - (moz_xmalloc(sizeof(ComplexTextRunUserData) + - aMappedFlowCount * sizeof(TextRunMappedFlow))); - new (data) ComplexTextRunUserData(); - data->mMappedFlows = reinterpret_cast(data + 1); - data->mMappedFlowCount = aMappedFlowCount; - data->mLastFlowIndex = 0; - return data; -} - -static void -DestroyComplexUserData(ComplexTextRunUserData* aUserData) -{ - if (aUserData) { - aUserData->~ComplexTextRunUserData(); - free(aUserData); - } -} - -static void -DestroyTextRunUserData(gfxTextRun* aTextRun) -{ - MOZ_ASSERT(aTextRun->GetUserData()); - if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) { - if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_MIGHT_HAVE_GLYPH_CHANGES) { - delete static_cast(aTextRun->GetUserData()); - } - } else { - if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_MIGHT_HAVE_GLYPH_CHANGES) { - DestroyComplexUserData( - static_cast(aTextRun->GetUserData())); - } else { - DestroyUserData( - static_cast(aTextRun->GetUserData())); - } - } - aTextRun->SetUserData(nullptr); -} - -/** - * These are utility functions just for helping with the complexity related with - * the text runs user data. - */ -static nsTextFrame* -GetFrameForSimpleFlow(gfxTextRun* aTextRun) -{ - MOZ_ASSERT(aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW, - "Not so simple flow?"); - if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_MIGHT_HAVE_GLYPH_CHANGES) { - return static_cast(aTextRun->GetUserData())->mFrame; - } - - return static_cast(aTextRun->GetUserData()); -} - /** * Remove |aTextRun| from the frame continuation chain starting at * |aStartContinuation| if non-null, otherwise starting at |aFrame|. @@ -584,12 +475,12 @@ ClearAllTextRunReferences(nsTextFrame* aFrame, gfxTextRun* aTextRun, static void UnhookTextRunFromFrames(gfxTextRun* aTextRun, nsTextFrame* aStartContinuation) { - if (!aTextRun->GetUserData()) { + if (!aTextRun->GetUserData()) return; - } if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) { - nsTextFrame* userDataFrame = GetFrameForSimpleFlow(aTextRun); + nsTextFrame* userDataFrame = static_cast( + static_cast(aTextRun->GetUserData())); nsFrameState whichTextRunState = userDataFrame->GetTextRun(nsTextFrame::eInflated) == aTextRun ? TEXT_IN_TEXTRUN_USER_DATA @@ -600,11 +491,11 @@ UnhookTextRunFromFrames(gfxTextRun* aTextRun, nsTextFrame* aStartContinuation) NS_ASSERTION(!aStartContinuation || found, "aStartContinuation wasn't found in simple flow text run"); if (!(userDataFrame->GetStateBits() & whichTextRunState)) { - DestroyTextRunUserData(aTextRun); - aTextRun->ClearFlagBits(nsTextFrameUtils::TEXT_MIGHT_HAVE_GLYPH_CHANGES); + aTextRun->SetUserData(nullptr); } } else { - auto userData = static_cast(aTextRun->GetUserData()); + TextRunUserData* userData = + static_cast(aTextRun->GetUserData()); int32_t destroyFromIndex = aStartContinuation ? -1 : 0; for (uint32_t i = 0; i < userData->mMappedFlowCount; ++i) { nsTextFrame* userDataFrame = userData->mMappedFlows[i].mStartFrame; @@ -618,7 +509,8 @@ UnhookTextRunFromFrames(gfxTextRun* aTextRun, nsTextFrame* aStartContinuation) if (found) { if (userDataFrame->GetStateBits() & whichTextRunState) { destroyFromIndex = i + 1; - } else { + } + else { destroyFromIndex = i; } aStartContinuation = nullptr; @@ -627,9 +519,10 @@ UnhookTextRunFromFrames(gfxTextRun* aTextRun, nsTextFrame* aStartContinuation) NS_ASSERTION(destroyFromIndex >= 0, "aStartContinuation wasn't found in multi flow text run"); if (destroyFromIndex == 0) { - DestroyTextRunUserData(aTextRun); - aTextRun->ClearFlagBits(nsTextFrameUtils::TEXT_MIGHT_HAVE_GLYPH_CHANGES); - } else { + DestroyUserData(userData); + aTextRun->SetUserData(nullptr); + } + else { userData->mMappedFlowCount = uint32_t(destroyFromIndex); if (userData->mLastFlowIndex >= uint32_t(destroyFromIndex)) { userData->mLastFlowIndex = uint32_t(destroyFromIndex) - 1; @@ -638,14 +531,16 @@ UnhookTextRunFromFrames(gfxTextRun* aTextRun, nsTextFrame* aStartContinuation) } } -static void -InvalidateFrameDueToGlyphsChanged(nsIFrame* aFrame) +void +GlyphObserver::NotifyGlyphsChanged() { - MOZ_ASSERT(aFrame); - - nsIPresShell* shell = aFrame->PresContext()->PresShell(); - for (nsIFrame* f = aFrame; f; + nsIPresShell* shell = mFrame->PresContext()->PresShell(); + for (nsIFrame* f = mFrame; f; f = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(f)) { + if (f != mFrame && f->HasAnyStateBits(TEXT_IN_TEXTRUN_USER_DATA)) { + // f will have its own GlyphObserver (if needed) so we can stop here. + break; + } f->InvalidateFrame(); // If this is a non-display text frame within SVG , we need @@ -668,20 +563,6 @@ InvalidateFrameDueToGlyphsChanged(nsIFrame* aFrame) } } -void -GlyphObserver::NotifyGlyphsChanged() -{ - if (mTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) { - InvalidateFrameDueToGlyphsChanged(GetFrameForSimpleFlow(mTextRun)); - return; - } - - auto data = static_cast(mTextRun->GetUserData()); - for (uint32_t i = 0; i < data->mMappedFlowCount; ++i) { - InvalidateFrameDueToGlyphsChanged(data->mMappedFlows[i].mStartFrame); - } -} - int32_t nsTextFrame::GetContentEnd() const { nsTextFrame* next = static_cast(GetNextContinuation()); return next ? next->GetContentOffset() : mContent->GetText()->GetLength(); @@ -863,19 +744,27 @@ IsAllWhitespace(const nsTextFragment* aFrag, bool aAllowNewline) } static void -ClearObserversFromTextRun(gfxTextRun* aTextRun) +CreateObserverForAnimatedGlyphs(nsTextFrame* aFrame, const nsTArray& aFonts) { - if (!(aTextRun->GetFlags() & nsTextFrameUtils::TEXT_MIGHT_HAVE_GLYPH_CHANGES)) { + if (!(aFrame->GetStateBits() & TEXT_IN_TEXTRUN_USER_DATA)) { + // Maybe the textrun was created for uninflated text. return; } - if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) { - static_cast(aTextRun->GetUserData()) - ->mGlyphObservers.Clear(); - } else { - static_cast(aTextRun->GetUserData()) - ->mGlyphObservers.Clear(); + nsTArray>* observers = + new nsTArray>(); + for (uint32_t i = 0, count = aFonts.Length(); i < count; ++i) { + observers->AppendElement(new GlyphObserver(aFonts[i], aFrame)); } + aFrame->Properties().Set(TextFrameGlyphObservers(), observers); + // We are lazy and don't try to remove a property value that might be + // obsolete due to style changes or font selection changes. That is + // likely to be rarely needed, and we don't want to eat the overhead of + // doing it for the overwhelmingly common case of no property existing. + // (And we're out of state bits to conveniently use for a fast property + // existence check.) The only downside is that in some rare cases we might + // keep fonts alive for longer than necessary, or unnecessarily invalidate + // frames. } static void @@ -884,9 +773,6 @@ CreateObserversForAnimatedGlyphs(gfxTextRun* aTextRun) if (!aTextRun->GetUserData()) { return; } - - ClearObserversFromTextRun(aTextRun); - nsTArray fontsWithAnimatedGlyphs; uint32_t numGlyphRuns; const gfxTextRun::GlyphRun* glyphRuns = @@ -898,46 +784,19 @@ CreateObserversForAnimatedGlyphs(gfxTextRun* aTextRun) } } if (fontsWithAnimatedGlyphs.IsEmpty()) { - // NB: Theoretically, we should clear the TEXT_MIGHT_HAVE_GLYPH_CHANGES - // here. That would involve de-allocating the simple user data struct if - // present too, and resetting the pointer to the frame. In practice, I - // don't think worth doing that work here, given the flag's only purpose is - // to distinguish what kind of user data is there. return; } - nsTArray>* observers; - if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) { - // Swap the frame pointer for a just-allocated SimpleTextRunUserData if - // appropriate. - if (!(aTextRun->GetFlags() & nsTextFrameUtils::TEXT_MIGHT_HAVE_GLYPH_CHANGES)) { - auto frame = static_cast(aTextRun->GetUserData()); - aTextRun->SetUserData(new SimpleTextRunUserData(frame)); - } - - auto data = - static_cast(aTextRun->GetUserData()); - observers = &data->mGlyphObservers; + CreateObserverForAnimatedGlyphs(static_cast( + static_cast(aTextRun->GetUserData())), fontsWithAnimatedGlyphs); } else { - if (!(aTextRun->GetFlags() & nsTextFrameUtils::TEXT_MIGHT_HAVE_GLYPH_CHANGES)) { - auto oldData = static_cast(aTextRun->GetUserData()); - auto data = CreateComplexUserData(oldData->mMappedFlowCount); - data->mLastFlowIndex = oldData->mLastFlowIndex; - for (uint32_t i = 0; i < oldData->mMappedFlowCount; ++i) { - data->mMappedFlows[i] = oldData->mMappedFlows[i]; - } - DestroyUserData(oldData); - aTextRun->SetUserData(data); + TextRunUserData* userData = + static_cast(aTextRun->GetUserData()); + for (uint32_t i = 0; i < userData->mMappedFlowCount; ++i) { + CreateObserverForAnimatedGlyphs(userData->mMappedFlows[i].mStartFrame, + fontsWithAnimatedGlyphs); } - auto data = static_cast(aTextRun->GetUserData()); - observers = &data->mGlyphObservers; - } - - aTextRun->SetFlagBits(nsTextFrameUtils::TEXT_MIGHT_HAVE_GLYPH_CHANGES); - - for (auto font : fontsWithAnimatedGlyphs) { - observers->AppendElement(new GlyphObserver(font, aTextRun)); } } @@ -1086,7 +945,9 @@ public: } void Finish(gfxMissingFontRecorder* aMFR) { - MOZ_ASSERT(!(mTextRun->GetFlags() & nsTextFrameUtils::TEXT_UNUSED_FLAG), + MOZ_ASSERT(!(mTextRun->GetFlags() & + (gfxTextRunFactory::TEXT_UNUSED_FLAGS | + nsTextFrameUtils::TEXT_UNUSED_FLAG)), "Flag set that should never be set! (memory safety error?)"); if (mTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_TRANSFORMED) { nsTransformedTextRun* transformedTextRun = @@ -1539,13 +1400,12 @@ ExpandBuffer(char16_t* aDest, uint8_t* aSrc, uint32_t aCount) bool BuildTextRunsScanner::IsTextRunValidForMappedFlows(gfxTextRun* aTextRun) { - if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) { + if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) return mMappedFlows.Length() == 1 && - mMappedFlows[0].mStartFrame == GetFrameForSimpleFlow(aTextRun) && + mMappedFlows[0].mStartFrame == static_cast(aTextRun->GetUserData()) && mMappedFlows[0].mEndFrame == nullptr; - } - auto userData = static_cast(aTextRun->GetUserData()); + TextRunUserData* userData = static_cast(aTextRun->GetUserData()); if (userData->mMappedFlowCount != mMappedFlows.Length()) return false; for (uint32_t i = 0; i < mMappedFlows.Length(); ++i) { @@ -2015,12 +1875,14 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer) userData = &dummyData; userDataToDestroy = nullptr; dummyData.mMappedFlows = &dummyMappedFlow; - dummyData.mMappedFlowCount = mMappedFlows.Length(); - dummyData.mLastFlowIndex = 0; } else { - userData = CreateUserData(mMappedFlows.Length()); + userData = static_cast + (moz_xmalloc(sizeof(TextRunUserData) + mMappedFlows.Length()*sizeof(TextRunMappedFlow))); userDataToDestroy = userData; + userData->mMappedFlows = reinterpret_cast(userData + 1); } + userData->mMappedFlowCount = mMappedFlows.Length(); + userData->mLastFlowIndex = 0; uint32_t currentTransformedTextOffset = 0; @@ -2418,12 +2280,14 @@ BuildTextRunsScanner::SetupLineBreakerContext(gfxTextRun *aTextRun) userData = &dummyData; userDataToDestroy = nullptr; dummyData.mMappedFlows = &dummyMappedFlow; - dummyData.mMappedFlowCount = mMappedFlows.Length(); - dummyData.mLastFlowIndex = 0; } else { - userData = CreateUserData(mMappedFlows.Length()); + userData = static_cast + (moz_xmalloc(sizeof(TextRunUserData) + mMappedFlows.Length()*sizeof(TextRunMappedFlow))); userDataToDestroy = userData; + userData->mMappedFlows = reinterpret_cast(userData + 1); } + userData->mMappedFlowCount = mMappedFlows.Length(); + userData->mLastFlowIndex = 0; uint32_t nextBreakIndex = 0; nsTextFrame* nextBreakBeforeFrame = GetNextBreakBeforeFrame(&nextBreakIndex); @@ -2712,14 +2576,16 @@ BuildTextRunsScanner::AssignTextRun(gfxTextRun* aTextRun, float aInflation) if (f->GetTextRun(mWhichTextRun)) { gfxTextRun* textRun = f->GetTextRun(mWhichTextRun); if (textRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) { - if (mMappedFlows[0].mStartFrame != GetFrameForSimpleFlow(textRun)) { + if (mMappedFlows[0].mStartFrame != static_cast(textRun->GetUserData())) { NS_WARNING("REASSIGNING SIMPLE FLOW TEXT RUN!"); } } else { - auto userData = static_cast(aTextRun->GetUserData()); + TextRunUserData* userData = + static_cast(textRun->GetUserData()); + if (userData->mMappedFlowCount >= mMappedFlows.Length() || userData->mMappedFlows[userData->mMappedFlowCount - 1].mStartFrame != - mMappedFlows[userdata->mMappedFlowCount - 1].mStartFrame) { + mMappedFlows[userData->mMappedFlowCount - 1].mStartFrame) { NS_WARNING("REASSIGNING MULTIFLOW TEXT RUN (not append)!"); } } @@ -2731,16 +2597,17 @@ BuildTextRunsScanner::AssignTextRun(gfxTextRun* aTextRun, float aInflation) nsTextFrame* firstFrame = nullptr; uint32_t startOffset = 0; if (oldTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) { - firstFrame = GetFrameForSimpleFlow(oldTextRun); - } else { - auto userData = static_cast(oldTextRun->GetUserData()); + firstFrame = static_cast(oldTextRun->GetUserData()); + } + else { + TextRunUserData* userData = static_cast(oldTextRun->GetUserData()); firstFrame = userData->mMappedFlows[0].mStartFrame; if (MOZ_UNLIKELY(f != firstFrame)) { - TextRunMappedFlow* flow = FindFlowForContent(userData, - f->GetContent()); + TextRunMappedFlow* flow = FindFlowForContent(userData, f->GetContent()); if (flow) { startOffset = flow->mDOMOffsetToBeforeTransformOffset; - } else { + } + else { NS_ERROR("Can't find flow containing frame 'f'"); } } @@ -2820,7 +2687,7 @@ nsTextFrame::EnsureTextRun(TextRunType aWhichTextRun, return gfxSkipCharsIterator(textRun->GetSkipChars(), 0, mContentOffset); } - auto userData = static_cast(textRun->GetUserData()); + TextRunUserData* userData = static_cast(textRun->GetUserData()); TextRunMappedFlow* flow = FindFlowForContent(userData, mContent); if (flow) { // Since textruns can only contain one flow for a given content element, diff --git a/layout/generic/nsTextFrameUtils.h b/layout/generic/nsTextFrameUtils.h index 6274705bc32e..26ddf0b6eef5 100644 --- a/layout/generic/nsTextFrameUtils.h +++ b/layout/generic/nsTextFrameUtils.h @@ -50,10 +50,7 @@ public: // NS_FRAME_IS_IN_SINGLE_CHAR_MI flag is set. This occurs if the textframe // belongs to a MathML element whose embedded text consists of a // single character. - TEXT_IS_SINGLE_CHAR_MI = 0x8000000, - - // This is set if the text run might be observing for glyph changes. - TEXT_MIGHT_HAVE_GLYPH_CHANGES = 0x10000000, + TEXT_IS_SINGLE_CHAR_MI = 0x8000000 // The following are defined by gfxTextRunWordCache rather than here, // so that it also has access to the _INCOMING flag