From 02bdb2d1abafe8ca672e6fa54218f525aa8344fd Mon Sep 17 00:00:00 2001 From: "Byron Campen [:bwc]" Date: Mon, 6 Aug 2018 18:08:55 +0000 Subject: [PATCH 01/28] Bug 1479853: Prevent more than one VideoConduit having the same remote SSRC. r=ng Differential Revision: https://phabricator.services.mozilla.com/D2738 --HG-- extra : moz-landing-system : lando --- .../src/media-conduit/AudioConduit.h | 4 + .../src/media-conduit/MediaConduitInterface.h | 142 +++++++++++------- .../src/media-conduit/VideoConduit.cpp | 70 +++++++-- .../src/media-conduit/VideoConduit.h | 1 + 4 files changed, 148 insertions(+), 69 deletions(-) diff --git a/media/webrtc/signaling/src/media-conduit/AudioConduit.h b/media/webrtc/signaling/src/media-conduit/AudioConduit.h index f771b2279359..45dd635bbaa8 100644 --- a/media/webrtc/signaling/src/media-conduit/AudioConduit.h +++ b/media/webrtc/signaling/src/media-conduit/AudioConduit.h @@ -208,6 +208,10 @@ public: { return false; } + bool UnsetRemoteSSRC(uint32_t ssrc) override + { + return true; + } bool GetRemoteSSRC(unsigned int* ssrc) override; bool SetLocalCNAME(const char* cname) override; bool SetLocalMID(const std::string& mid) override; diff --git a/media/webrtc/signaling/src/media-conduit/MediaConduitInterface.h b/media/webrtc/signaling/src/media-conduit/MediaConduitInterface.h index 271f7fe245e1..dc28c7b65542 100644 --- a/media/webrtc/signaling/src/media-conduit/MediaConduitInterface.h +++ b/media/webrtc/signaling/src/media-conduit/MediaConduitInterface.h @@ -26,6 +26,7 @@ #include "webrtc/logging/rtc_event_log/rtc_event_log.h" #include +#include namespace webrtc { class VideoFrame; @@ -40,64 +41,6 @@ enum class MediaSessionConduitLocalDirection : int { using RtpExtList = std::vector; -// Wrap the webrtc.org Call class adding mozilla add/ref support. -class WebRtcCallWrapper : public RefCounted -{ -public: - typedef webrtc::Call::Config Config; - - static RefPtr Create() - { - return new WebRtcCallWrapper(); - } - - static RefPtr Create(UniquePtr&& aCall) - { - return new WebRtcCallWrapper(std::move(aCall)); - } - - webrtc::Call* Call() const - { - return mCall.get(); - } - - virtual ~WebRtcCallWrapper() - { - if (mCall->voice_engine()) { - webrtc::VoiceEngine* voice_engine = mCall->voice_engine(); - mCall.reset(nullptr); // Force it to release the voice engine reference - // Delete() must be after all refs are released - webrtc::VoiceEngine::Delete(voice_engine); - } else { - // Must ensure it's destroyed *before* the EventLog! - mCall.reset(nullptr); - } - } - - MOZ_DECLARE_REFCOUNTED_TYPENAME(WebRtcCallWrapper) - -private: - WebRtcCallWrapper() - { - webrtc::Call::Config config(&mEventLog); - mCall.reset(webrtc::Call::Create(config)); - } - - explicit WebRtcCallWrapper(UniquePtr&& aCall) - { - MOZ_ASSERT(aCall); - mCall = std::move(aCall); - } - - // Don't allow copying/assigning. - WebRtcCallWrapper(const WebRtcCallWrapper&) = delete; - void operator=(const WebRtcCallWrapper&) = delete; - - UniquePtr mCall; - webrtc::RtcEventLogNullImpl mEventLog; -}; - - /** * Abstract Interface for transporting RTP packets - audio/vidoeo * The consumers of this interface are responsible for passing in @@ -268,6 +211,7 @@ public: virtual bool GetRemoteSSRC(unsigned int* ssrc) = 0; virtual bool SetRemoteSSRC(unsigned int ssrc) = 0; + virtual bool UnsetRemoteSSRC(uint32_t ssrc) = 0; virtual bool SetLocalCNAME(const char* cname) = 0; virtual bool SetLocalMID(const std::string& mid) = 0; @@ -319,6 +263,87 @@ public: }; +// Wrap the webrtc.org Call class adding mozilla add/ref support. +class WebRtcCallWrapper : public RefCounted +{ +public: + typedef webrtc::Call::Config Config; + + static RefPtr Create() + { + return new WebRtcCallWrapper(); + } + + static RefPtr Create(UniquePtr&& aCall) + { + return new WebRtcCallWrapper(std::move(aCall)); + } + + // Don't allow copying/assigning. + WebRtcCallWrapper(const WebRtcCallWrapper&) = delete; + void operator=(const WebRtcCallWrapper&) = delete; + + webrtc::Call* Call() const + { + return mCall.get(); + } + + virtual ~WebRtcCallWrapper() + { + if (mCall->voice_engine()) { + webrtc::VoiceEngine* voice_engine = mCall->voice_engine(); + mCall.reset(nullptr); // Force it to release the voice engine reference + // Delete() must be after all refs are released + webrtc::VoiceEngine::Delete(voice_engine); + } else { + // Must ensure it's destroyed *before* the EventLog! + mCall.reset(nullptr); + } + } + + bool UnsetRemoteSSRC(uint32_t ssrc) + { + for (auto conduit : mConduits) { + if (!conduit->UnsetRemoteSSRC(ssrc)) { + return false; + } + } + + return true; + } + + void RegisterConduit(MediaSessionConduit* conduit) + { + mConduits.insert(conduit); + } + + void UnregisterConduit(MediaSessionConduit* conduit) + { + mConduits.erase(conduit); + } + + MOZ_DECLARE_REFCOUNTED_TYPENAME(WebRtcCallWrapper) + +private: + WebRtcCallWrapper() + { + webrtc::Call::Config config(&mEventLog); + mCall.reset(webrtc::Call::Create(config)); + } + + explicit WebRtcCallWrapper(UniquePtr&& aCall) + { + MOZ_ASSERT(aCall); + mCall = std::move(aCall); + } + + UniquePtr mCall; + webrtc::RtcEventLogNullImpl mEventLog; + // Allows conduits to know about one another, to avoid remote SSRC + // collisions. + std::set mConduits; +}; + // Abstract base classes for external encoder/decoder. class CodecPluginID { @@ -389,6 +414,7 @@ public: virtual void DisableSsrcChanges() = 0; bool SetRemoteSSRC(unsigned int ssrc) override = 0; + bool UnsetRemoteSSRC(uint32_t ssrc) override = 0; /** * Function to deliver a capture video frame for encoding and transport. diff --git a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp index 502d1dd0366d..7507e6e5796e 100644 --- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp +++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp @@ -277,6 +277,7 @@ WebrtcVideoConduit::WebrtcVideoConduit(RefPtr aCall, , mRecvCodecPlugin(nullptr) , mVideoStatsTimer(NS_NewTimer()) { + mCall->RegisterConduit(this); mRecvStreamConfig.renderer = this; // Video Stats Callback @@ -307,6 +308,7 @@ WebrtcVideoConduit::~WebrtcVideoConduit() { CSFLogDebug(LOGTAG, "%s ", __FUNCTION__); NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); + mCall->UnregisterConduit(this); if (mVideoStatsTimer) { CSFLogDebug(LOGTAG, "canceling StreamStats for VideoConduit: %p", this); MutexAutoLock lock(mCodecMutex); @@ -884,6 +886,22 @@ WebrtcVideoConduit::ConfigureSendMediaCodec(const VideoCodecConfig* codecConfig) return condError; } +static uint32_t +GenerateRandomSSRC() +{ + uint32_t ssrc; + do { + SECStatus rv = PK11_GenerateRandom(reinterpret_cast(&ssrc), sizeof(ssrc)); + if (rv != SECSuccess) { + CSFLogError(LOGTAG, "%s: PK11_GenerateRandom failed with error %d", + __FUNCTION__, rv); + return 0; + } + } while (ssrc == 0); // webrtc.org code has fits if you select an SSRC of 0 + + return ssrc; +} + bool WebrtcVideoConduit::SetRemoteSSRC(unsigned int ssrc) { @@ -902,6 +920,11 @@ WebrtcVideoConduit::SetRemoteSSRC(unsigned int ssrc) } CSFLogDebug(LOGTAG, "%s: SSRC %u (0x%x)", __FUNCTION__, ssrc, ssrc); + if (!mCall->UnsetRemoteSSRC(ssrc)) { + CSFLogError(LOGTAG, "%s: Failed to unset SSRC %u (0x%x) on other conduits," + " bailing", __FUNCTION__, ssrc, ssrc); + return false; + } mRecvStreamConfig.rtp.remote_ssrc = ssrc; mWaitingForInitialSsrc = false; @@ -926,6 +949,33 @@ WebrtcVideoConduit::SetRemoteSSRC(unsigned int ssrc) return (StartReceiving() == kMediaConduitNoError); } +bool +WebrtcVideoConduit::UnsetRemoteSSRC(uint32_t ssrc) +{ + unsigned int our_ssrc; + if (!GetRemoteSSRC(&our_ssrc)) { + // This only fails when we aren't sending, which isn't really an error here + return true; + } + + if (our_ssrc != ssrc) { + return true; + } + + while (our_ssrc == ssrc) { + our_ssrc = GenerateRandomSSRC(); + if (our_ssrc == 0) { + return false; + } + } + + // There is a (tiny) chance that this new random ssrc will collide with some + // other conduit's remote ssrc, in which case that conduit will choose a new + // one. + SetRemoteSSRC(our_ssrc); + return true; +} + bool WebrtcVideoConduit::GetRemoteSSRC(unsigned int* ssrc) { @@ -1428,13 +1478,12 @@ WebrtcVideoConduit::ConfigureRecvMediaCodecs( // Handle un-signalled SSRCs by creating a random one and then when it actually gets set, // we'll destroy and recreate. Simpler than trying to unwind all the logic that assumes // the receive stream is created and started when we ConfigureRecvMediaCodecs() - unsigned int ssrc; - do { - SECStatus rv = PK11_GenerateRandom(reinterpret_cast(&ssrc), sizeof(ssrc)); - if (rv != SECSuccess) { - return kMediaConduitUnknownError; - } - } while (ssrc == 0); // webrtc.org code has fits if you select an SSRC of 0 + uint32_t ssrc = GenerateRandomSSRC(); + if (ssrc == 0) { + // webrtc.org code has fits if you select an SSRC of 0, so that's how + // we signal an error. + return kMediaConduitUnknownError; + } mRecvStreamConfig.rtp.remote_ssrc = ssrc; mRecvSSRC = ssrc; @@ -1451,13 +1500,12 @@ WebrtcVideoConduit::ConfigureRecvMediaCodecs( auto ssrc = mSendStreamConfig.rtp.ssrcs.front(); Unused << NS_WARN_IF(ssrc == mRecvStreamConfig.rtp.remote_ssrc); - while (ssrc == mRecvStreamConfig.rtp.remote_ssrc || ssrc == 0) { - SECStatus rv = PK11_GenerateRandom(reinterpret_cast(&ssrc), sizeof(ssrc)); - if (rv != SECSuccess) { + while (ssrc == mRecvStreamConfig.rtp.remote_ssrc) { + ssrc = GenerateRandomSSRC(); + if (ssrc == 0) { return kMediaConduitUnknownError; } } - // webrtc.org code has fits if you select an SSRC of 0 mRecvStreamConfig.rtp.local_ssrc = ssrc; CSFLogDebug(LOGTAG, "%s (%p): Local SSRC 0x%08x (of %u), remote SSRC 0x%08x", diff --git a/media/webrtc/signaling/src/media-conduit/VideoConduit.h b/media/webrtc/signaling/src/media-conduit/VideoConduit.h index 6d09e828a027..cbba2ad41d6c 100644 --- a/media/webrtc/signaling/src/media-conduit/VideoConduit.h +++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.h @@ -275,6 +275,7 @@ public: bool SetLocalSSRCs(const std::vector & ssrcs) override; bool GetRemoteSSRC(unsigned int* ssrc) override; bool SetRemoteSSRC(unsigned int ssrc) override; + bool UnsetRemoteSSRC(uint32_t ssrc) override; bool SetLocalCNAME(const char* cname) override; bool SetLocalMID(const std::string& mid) override; From d7600324bbee128fb03113ba0f6df3b69201b49a Mon Sep 17 00:00:00 2001 From: Mark Striemer Date: Wed, 11 Jul 2018 22:30:36 -0500 Subject: [PATCH 02/28] Bug 1470865 - Dynamically show hidden audio tabs in all tabs menu r=dao When a hidden audio tab is muted it isn't pulled into the main all tabs panel. Unmuting that tab will now add it to the main all tabs panel, even if the all tabs menu it open. MozReview-Commit-ID: 2HtZvy7aBsG --HG-- extra : rebase_source : d728739ef382f14f3a759e9c6aef7cb2771f7c95 --- browser/modules/TabsList.jsm | 50 ++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/browser/modules/TabsList.jsm b/browser/modules/TabsList.jsm index f497afbf3372..082fbadfd5ef 100644 --- a/browser/modules/TabsList.jsm +++ b/browser/modules/TabsList.jsm @@ -67,27 +67,18 @@ class TabsListBase { for (let tab of this.gBrowser.tabs) { if (this.filterFn(tab)) { - let row = this._createRow(tab); - row.tab = tab; - row.addEventListener("command", this); - this.tabToElement.set(tab, row); - if (this.className) { - row.classList.add(this.className); - } - - fragment.appendChild(row); + fragment.appendChild(this._createRow(tab)); } } - if (this.insertBefore) { - this.insertBefore.parentNode.insertBefore(fragment, this.insertBefore); - } else { - this.containerNode.appendChild(fragment); - } - + this._addElement(fragment); this._setupListeners(); } + _addElement(elementOrFragment) { + this.containerNode.insertBefore(elementOrFragment, this.insertBefore); + } + /* * Remove the menuitems from the DOM, cleanup internal state and listeners. */ @@ -115,11 +106,32 @@ class TabsListBase { let item = this.tabToElement.get(tab); if (item) { if (!this.filterFn(tab)) { - // If the tab is no longer in this set of tabs, hide the item. + // The tab no longer matches our criteria, remove it. this._removeItem(item, tab); } else { this._setRowAttributes(item, tab); } + } else if (this.filterFn(tab)) { + // The tab now matches our criteria, add a row for it. + this._addTab(tab); + } + } + + _addTab(newTab) { + let newRow = this._createRow(newTab); + let nextTab = newTab.nextSibling; + + while (nextTab && !this.filterFn(nextTab)) { + nextTab = nextTab.nextSibling; + } + + if (nextTab) { + // If we found a tab after this one in the list, insert the new row before it. + let nextRow = this.tabToElement.get(nextTab); + nextRow.parentNode.insertBefore(newRow, nextRow); + } else { + // If there's no next tab then insert it as usual. + this._addElement(newRow); } } @@ -206,6 +218,12 @@ class TabsPanel extends TabsListBase { let {doc} = this; let row = doc.createElementNS(NSXUL, "toolbaritem"); row.setAttribute("class", "all-tabs-item"); + if (this.className) { + row.classList.add(this.className); + } + row.tab = tab; + row.addEventListener("command", this); + this.tabToElement.set(tab, row); let button = doc.createElementNS(NSXUL, "toolbarbutton"); button.setAttribute("class", "all-tabs-button subviewbutton subviewbutton-iconic"); From 226f6e804294baaa18561d203222aa23e3bf393d Mon Sep 17 00:00:00 2001 From: Mark Striemer Date: Mon, 30 Jul 2018 14:43:40 -0500 Subject: [PATCH 03/28] Bug 1477591 - Use default favicon in all tabs menu r=dao MozReview-Commit-ID: 31kPOLp1IVV --HG-- extra : rebase_source : ef17514450e1911fdd3a183828e71430acc0738f --- browser/themes/shared/tabs.inc.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/browser/themes/shared/tabs.inc.css b/browser/themes/shared/tabs.inc.css index cab8f51d195e..0bf3e785ffb8 100644 --- a/browser/themes/shared/tabs.inc.css +++ b/browser/themes/shared/tabs.inc.css @@ -804,6 +804,10 @@ box-shadow: inset -4px 0 var(--blue-40); } +.all-tabs-button { + list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.svg"); +} + .all-tabs-secondary-button > label { display: none; margin: 0 5.5px; From 40503db0b4b7c5eb1a8c9ff51ddeb34496f189ef Mon Sep 17 00:00:00 2001 From: Nico Grunbaum Date: Thu, 2 Aug 2018 20:50:24 +0000 Subject: [PATCH 04/28] Bug 1480498 - P1 - Rename RTCRTPStreamStats in WebIDL to match the spec IDL r=smaug This renames the RTCRTPStreamStats partial dictionary to match the recent spec changes Differential Revision: https://phabricator.services.mozilla.com/D2682 --HG-- extra : moz-landing-system : lando --- dom/webidl/RTCStatsReport.webidl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dom/webidl/RTCStatsReport.webidl b/dom/webidl/RTCStatsReport.webidl index 4f95a4b3ca19..ec54f56f981e 100644 --- a/dom/webidl/RTCStatsReport.webidl +++ b/dom/webidl/RTCStatsReport.webidl @@ -26,7 +26,7 @@ dictionary RTCStats { DOMString id; }; -dictionary RTCRTPStreamStats : RTCStats { +dictionary RTCRtpStreamStats : RTCStats { unsigned long ssrc; DOMString mediaType; DOMString remoteId; @@ -48,7 +48,7 @@ dictionary RTCRTPStreamStats : RTCStats { unsigned long nackCount; }; -dictionary RTCInboundRTPStreamStats : RTCRTPStreamStats { +dictionary RTCInboundRTPStreamStats : RTCRtpStreamStats { unsigned long packetsReceived; unsigned long long bytesReceived; double jitter; @@ -62,7 +62,7 @@ dictionary RTCInboundRTPStreamStats : RTCRTPStreamStats { unsigned long framesDecoded; }; -dictionary RTCOutboundRTPStreamStats : RTCRTPStreamStats { +dictionary RTCOutboundRTPStreamStats : RTCRtpStreamStats { unsigned long packetsSent; unsigned long long bytesSent; double targetBitrate; // config encoder bitrate target of this SSRC in bits/s From 87231d61930fdb87da36b39e2bc7ee99fc9ae903 Mon Sep 17 00:00:00 2001 From: Nico Grunbaum Date: Fri, 3 Aug 2018 17:41:30 +0000 Subject: [PATCH 05/28] Bug 1480498 - P2 - renaming RTCRTPStreamStats in the WebRTCGlobals r=mjf Renaming RTCRTPStreamStats in the WebRTCGlobals. Differential Revision: https://phabricator.services.mozilla.com/D2683 --HG-- extra : moz-landing-system : lando --- dom/media/webrtc/WebrtcGlobal.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dom/media/webrtc/WebrtcGlobal.h b/dom/media/webrtc/WebrtcGlobal.h index 15b9bcecc87c..d5892777f75f 100644 --- a/dom/media/webrtc/WebrtcGlobal.h +++ b/dom/media/webrtc/WebrtcGlobal.h @@ -280,9 +280,9 @@ struct ParamTraits } }; -static void WriteRTCRTPStreamStats( +static void WriteRTCRtpStreamStats( Message* aMsg, - const mozilla::dom::RTCRTPStreamStats& aParam) + const mozilla::dom::RTCRtpStreamStats& aParam) { WriteParam(aMsg, aParam.mBitrateMean); WriteParam(aMsg, aParam.mBitrateStdDev); @@ -297,9 +297,9 @@ static void WriteRTCRTPStreamStats( WriteParam(aMsg, aParam.mTransportId); } -static bool ReadRTCRTPStreamStats( +static bool ReadRTCRtpStreamStats( const Message* aMsg, PickleIterator* aIter, - mozilla::dom::RTCRTPStreamStats* aResult) + mozilla::dom::RTCRtpStreamStats* aResult) { if (!ReadParam(aMsg, aIter, &(aResult->mBitrateMean)) || !ReadParam(aMsg, aIter, &(aResult->mBitrateStdDev)) || @@ -334,7 +334,7 @@ struct ParamTraits WriteParam(aMsg, aParam.mRoundTripTime); WriteParam(aMsg, aParam.mPacketsLost); WriteParam(aMsg, aParam.mPacketsReceived); - WriteRTCRTPStreamStats(aMsg, aParam); + WriteRTCRtpStreamStats(aMsg, aParam); WriteRTCStats(aMsg, aParam); } @@ -349,7 +349,7 @@ struct ParamTraits !ReadParam(aMsg, aIter, &(aResult->mRoundTripTime)) || !ReadParam(aMsg, aIter, &(aResult->mPacketsLost)) || !ReadParam(aMsg, aIter, &(aResult->mPacketsReceived)) || - !ReadRTCRTPStreamStats(aMsg, aIter, aResult) || + !ReadRTCRtpStreamStats(aMsg, aIter, aResult) || !ReadRTCStats(aMsg, aIter, aResult)) { return false; } @@ -373,7 +373,7 @@ struct ParamTraits WriteParam(aMsg, aParam.mFirCount); WriteParam(aMsg, aParam.mNackCount); WriteParam(aMsg, aParam.mPliCount); - WriteRTCRTPStreamStats(aMsg, aParam); + WriteRTCRtpStreamStats(aMsg, aParam); WriteRTCStats(aMsg, aParam); } @@ -387,7 +387,7 @@ struct ParamTraits !ReadParam(aMsg, aIter, &(aResult->mFirCount)) || !ReadParam(aMsg, aIter, &(aResult->mNackCount)) || !ReadParam(aMsg, aIter, &(aResult->mPliCount)) || - !ReadRTCRTPStreamStats(aMsg, aIter, aResult) || + !ReadRTCRtpStreamStats(aMsg, aIter, aResult) || !ReadRTCStats(aMsg, aIter, aResult)) { return false; } From 033b8142cfe230938e7ea63888a3bdfb749e74b3 Mon Sep 17 00:00:00 2001 From: Michael Kaply Date: Mon, 6 Aug 2018 21:40:03 +0000 Subject: [PATCH 06/28] Bug 1476088 - Additional search submission telemetry. r=florian Differential Revision: https://phabricator.services.mozilla.com/D2165 --HG-- extra : moz-landing-system : lando --- toolkit/components/search/nsSearchService.js | 30 +++++++++- .../tests/xpcshell/test_sendSubmissionURL.js | 58 +++++++++++++++++++ .../search/tests/xpcshell/xpcshell.ini | 1 + .../telemetry/docs/data/environment.rst | 2 +- 4 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 toolkit/components/search/tests/xpcshell/test_sendSubmissionURL.js diff --git a/toolkit/components/search/nsSearchService.js b/toolkit/components/search/nsSearchService.js index 29c891965845..91879751bcd0 100644 --- a/toolkit/components/search/nsSearchService.js +++ b/toolkit/components/search/nsSearchService.js @@ -989,9 +989,10 @@ function EngineURL(aType, aMethod, aTemplate, aResultDomain) { FAIL("new EngineURL: template uses invalid scheme!", Cr.NS_ERROR_FAILURE); } + this.templateHost = templateURI.host; // If no resultDomain was specified in the engine definition file, use the // host from the template. - this.resultDomain = aResultDomain || templateURI.host; + this.resultDomain = aResultDomain || this.templateHost; } EngineURL.prototype = { @@ -4154,6 +4155,33 @@ SearchService.prototype = { } } + if (!sendSubmissionURL) { + // ... or engines that are the same domain as a default engine. + let engineHost = engine._getURLOfType(URLTYPE_SEARCH_HTML).templateHost; + for (let name in this._engines) { + let innerEngine = this._engines[name]; + if (!innerEngine._isDefault) { + continue; + } + + let innerEngineURL = innerEngine._getURLOfType(URLTYPE_SEARCH_HTML); + if (innerEngineURL.templateHost == engineHost) { + sendSubmissionURL = true; + break; + } + } + + if (!sendSubmissionURL) { + // ... or well known search domains. + // + // Starts with: www.google., search.aol., yandex. + // or + // Ends with: search.yahoo.com, .ask.com, .bing.com, .startpage.com, baidu.com, duckduckgo.com + const urlTest = /^(?:www\.google\.|search\.aol\.|yandex\.)|(?:search\.yahoo|\.ask|\.bing|\.startpage|\.baidu|\.duckduckgo)\.com$/; + sendSubmissionURL = urlTest.test(engineHost); + } + } + if (sendSubmissionURL) { let uri = engine._getURLOfType("text/html") .getSubmission("", engine, "searchbar").uri; diff --git a/toolkit/components/search/tests/xpcshell/test_sendSubmissionURL.js b/toolkit/components/search/tests/xpcshell/test_sendSubmissionURL.js new file mode 100644 index 000000000000..8b2418555083 --- /dev/null +++ b/toolkit/components/search/tests/xpcshell/test_sendSubmissionURL.js @@ -0,0 +1,58 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* + * Tests covering sending submission URLs for major engines + */ + +const SUBMISSION_YES = new Map([ + ["Google1 Test", "https://www.google.com/search?q={searchTerms}"], + ["Google2 Test", "https://www.google.co.uk/search?q={searchTerms}"], + ["Yahoo1 Test", "https://search.yahoo.com/search?p={searchTerms}"], + ["Yahoo2 Test", "https://uk.search.yahoo.com/search?p={searchTerms}"], + ["AOL1 Test", "https://search.aol.com/aol/search?q={searchTerms}"], + ["AOL2 Test", "https://search.aol.co.uk/aol/search?q={searchTerms}"], + ["Yandex1 Test", "https://yandex.ru/search/?text={searchTerms}"], + ["Yandex2 Test", "https://yandex.com/search/?text{searchTerms}"], + ["Ask1 Test", "https://www.ask.com/web?q={searchTerms}"], + ["Ask2 Test", "https://fr.ask.com/web?q={searchTerms}"], + ["Bing Test", "https://www.bing.com/search?q={searchTerms}"], + ["Startpage Test", "https://www.startpage.com/do/search?query={searchTerms}"], + ["DuckDuckGo Test", "https://duckduckgo.com/?q={searchTerms}"], + ["Baidu Test", "https://www.baidu.com/s?wd={searchTerms}"], +]); + +const SUBMISSION_NO = new Map([ + ["Other1 Test", "https://example.com?q={searchTerms}"], + ["Other2 Test", "https://googlebutnotgoogle.com?q={searchTerms}"], +]); + +function addAndMakeDefault(name, searchURL) { + Services.search.addEngineWithDetails(name, null, null, null, "GET", searchURL); + let engine = Services.search.getEngineByName(name); + Services.search.currentEngine = engine; + return engine; +} + +add_task(async function test() { + Assert.ok(!Services.search.isInitialized); + + await asyncInit(); + + let engineInfo; + let engine; + + for (let [name, searchURL] of SUBMISSION_YES) { + engine = addAndMakeDefault(name, searchURL); + engineInfo = Services.search.getDefaultEngineInfo(); + Assert.equal(engineInfo.submissionURL, searchURL.replace("{searchTerms}", "")); + Services.search.removeEngine(engine); + } + + for (let [name, searchURL] of SUBMISSION_NO) { + engine = addAndMakeDefault(name, searchURL); + engineInfo = Services.search.getDefaultEngineInfo(); + Assert.equal(engineInfo.submissionURL, null); + Services.search.removeEngine(engine); + } +}); diff --git a/toolkit/components/search/tests/xpcshell/xpcshell.ini b/toolkit/components/search/tests/xpcshell/xpcshell.ini index 667c76322877..d921936bacbe 100644 --- a/toolkit/components/search/tests/xpcshell/xpcshell.ini +++ b/toolkit/components/search/tests/xpcshell/xpcshell.ini @@ -101,3 +101,4 @@ skip-if = (verify && !debug && (os == 'linux')) [test_engineUpdate.js] [test_paramSubstitution.js] [test_migrateWebExtensionEngine.js] +[test_sendSubmissionURL.js] diff --git a/toolkit/components/telemetry/docs/data/environment.rst b/toolkit/components/telemetry/docs/data/environment.rst index a8b88c0bbe80..89b52468209f 100644 --- a/toolkit/components/telemetry/docs/data/environment.rst +++ b/toolkit/components/telemetry/docs/data/environment.rst @@ -42,7 +42,7 @@ Structure: name: , // engine name, e.g. "Yahoo"; or "NONE" if no default loadPath: , // where the engine line is located; missing if no default origin: , // 'default', 'verified', 'unverified', or 'invalid'; based on the presence and validity of the engine's loadPath verification hash. - submissionURL: // missing if no default or for user-installed engines + submissionURL: // set for default engines or well known search domains }, searchCohort: , // optional, contains an identifier for any active search A/B experiments e10sEnabled: , // whether e10s is on, i.e. browser tabs open by default in a different process From 913ae8e3d3710578b3d33ec1800537e805a5b23b Mon Sep 17 00:00:00 2001 From: Nico Grunbaum Date: Mon, 6 Aug 2018 21:44:32 +0000 Subject: [PATCH 07/28] Bug 1480525 - ensure localIdp, remoteIdp exist before closing them r=mjf If PeerConnection initialization terminates early due to an excpetion localIdp, and remoteIdp aren't created. This causes another exception in close(). The patch checks that they each exist in close before attempting to access them. Differential Revision: https://phabricator.services.mozilla.com/D2686 --HG-- extra : moz-landing-system : lando --- dom/media/PeerConnection.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dom/media/PeerConnection.js b/dom/media/PeerConnection.js index da0302db64d9..148b7f6797d8 100644 --- a/dom/media/PeerConnection.js +++ b/dom/media/PeerConnection.js @@ -1419,8 +1419,12 @@ class RTCPeerConnection { } this._closed = true; this.changeIceConnectionState("closed"); - this._localIdp.close(); - this._remoteIdp.close(); + if (this._localIdp) { + this._localIdp.close(); + } + if (this._remoteIdp) { + this._remoteIdp.close(); + } this._impl.close(); this._suppressEvents = true; delete this._pc; From 5ae0e08589b6db914d98ff4eb6f1b406020c35ec Mon Sep 17 00:00:00 2001 From: Chris Manchester Date: Mon, 6 Aug 2018 21:38:43 +0000 Subject: [PATCH 08/28] Bug 1480771 - Take CLOBBER into account when deciding whether to re-run configure. r=gps,firefox-build-system-reviewers Differential Revision: https://phabricator.services.mozilla.com/D2802 --HG-- extra : moz-landing-system : lando --- moz.configure | 1 + 1 file changed, 1 insertion(+) diff --git a/moz.configure b/moz.configure index 3b9269a3ff39..225459044826 100755 --- a/moz.configure +++ b/moz.configure @@ -581,6 +581,7 @@ def config_status_deps(build_env, build_project): extra_deps = [os.path.join(topobjdir[:-7], '.mozconfig.json')] return list(__sandbox__._all_paths) + extra_deps + [ + os.path.join(topsrcdir, 'CLOBBER'), os.path.join(topsrcdir, 'configure'), os.path.join(topsrcdir, 'js', 'src', 'configure'), os.path.join(topsrcdir, 'configure.in'), From 5eb09563bc9882bda5dc1b52543102385e552736 Mon Sep 17 00:00:00 2001 From: Michael Kaply Date: Mon, 6 Aug 2018 22:02:02 +0000 Subject: [PATCH 09/28] Bug 1475571 - Replace follow-on addon with in tree telemetry. r=mikedeboer,florian Differential Revision: https://phabricator.services.mozilla.com/D2125 --HG-- extra : moz-landing-system : lando --- browser/extensions/moz.build | 1 - browser/modules/BrowserUsageTelemetry.jsm | 79 ++++++++++++++++---- toolkit/components/search/nsSearchService.js | 7 +- toolkit/components/telemetry/Histograms.json | 2 +- 4 files changed, 73 insertions(+), 16 deletions(-) diff --git a/browser/extensions/moz.build b/browser/extensions/moz.build index c2b67265febe..66ac545f478c 100644 --- a/browser/extensions/moz.build +++ b/browser/extensions/moz.build @@ -6,7 +6,6 @@ DIRS += [ 'aushelper', - 'followonsearch', 'formautofill', 'onboarding', 'pdfjs', diff --git a/browser/modules/BrowserUsageTelemetry.jsm b/browser/modules/BrowserUsageTelemetry.jsm index a60692631aec..3211c23c9999 100644 --- a/browser/modules/BrowserUsageTelemetry.jsm +++ b/browser/modules/BrowserUsageTelemetry.jsm @@ -13,10 +13,13 @@ var EXPORTED_SYMBOLS = [ ]; ChromeUtils.import("resource://gre/modules/Services.jsm"); +ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm"); +XPCOMUtils.defineLazyGlobalGetters(this, ["URLSearchParams"]); + // The upper bound for the count of the visited unique domain names. const MAX_UNIQUE_VISITED_DOMAINS = 100; @@ -88,7 +91,6 @@ const URLBAR_SELECTED_RESULT_METHODS = { const MINIMUM_TAB_COUNT_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes, in ms - function getOpenTabsAndWinsCounts() { let tabCount = 0; let winCount = 0; @@ -159,6 +161,10 @@ let URICountListener = { return; } + // Don't include URI and domain counts when in private mode. + let shouldCountURI = !PrivateBrowsingUtils.isWindowPrivate(browser.ownerGlobal) || + Services.prefs.getBoolPref("browser.engagement.total_uri_count.pbm", false); + // Track URI loads, even if they're not http(s). let uriSpec = null; try { @@ -166,7 +172,9 @@ let URICountListener = { } catch (e) { // If we have troubles parsing the spec, still count this as // an unfiltered URI. - Services.telemetry.scalarAdd(UNFILTERED_URI_COUNT_SCALAR_NAME, 1); + if (shouldCountURI) { + Services.telemetry.scalarAdd(UNFILTERED_URI_COUNT_SCALAR_NAME, 1); + } return; } @@ -188,12 +196,42 @@ let URICountListener = { // The URI wasn't from a restored tab. Count it among the unfiltered URIs. // If this is an http(s) URI, this also gets counted by the "total_uri_count" // probe. - Services.telemetry.scalarAdd(UNFILTERED_URI_COUNT_SCALAR_NAME, 1); + if (shouldCountURI) { + Services.telemetry.scalarAdd(UNFILTERED_URI_COUNT_SCALAR_NAME, 1); + } if (!this.isHttpURI(uri)) { return; } + let parseURLResult = Services.search.parseSubmissionURL(uriSpec); + if (parseURLResult.engine) { + this._recordSearchTelemetry(uriSpec, parseURLResult); + } else if (this._urlsQueuedForParsing) { + if (Services.search.isInitialized) { + this._urlsQueuedForParsing = null; + } else { + this._urlsQueuedForParsing.push(uriSpec); + if (this._urlsQueuedForParsing.length == 1) { + Services.search.init(rv => { + if (Components.isSuccessCode(rv)) { + for (let url of this._urlsQueuedForParsing) { + let innerParseURLResult = Services.search.parseSubmissionURL(url); + if (innerParseURLResult.engine) { + this._recordSearchTelemetry(url, innerParseURLResult); + } + } + } + this._urlsQueuedForParsing = null; + }); + } + } + } + + if (!shouldCountURI) { + return; + } + // Update the URI counts. Services.telemetry.scalarAdd(TOTAL_URI_COUNT_SCALAR_NAME, 1); @@ -226,6 +264,31 @@ let URICountListener = { this._domainSet.clear(); }, + _urlsQueuedForParsing: [], + + _recordSearchTelemetry(url, parseURLResult) { + switch (parseURLResult.engine.identifier) { + case "google": + case "google-2018": + let type; + let queries = new URLSearchParams(url.split("?")[1]); + let code = queries.get("client"); + if (code) { + // Detecting follow-on searches for sap is a little tricky. + // There are a few parameters that only show up + // with follow-ons, so we look for those. (oq/ved/ei) + type = queries.has("oq") || queries.has("ved") || queries.has("ei") ? "sap-follow-on" : "sap"; + } else { + type = "organic"; + } + let payload = `google.in-content.${type}:${code || "none"}`; + + let histogram = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS"); + histogram.add(payload); + break; + } + }, + QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]), }; @@ -614,11 +677,6 @@ let BrowserUsageTelemetry = { win.addEventListener("unload", this); win.addEventListener("TabOpen", this, true); - // Don't include URI and domain counts when in private mode. - if (PrivateBrowsingUtils.isWindowPrivate(win) && - !Services.prefs.getBoolPref("browser.engagement.total_uri_count.pbm", false)) { - return; - } win.gBrowser.tabContainer.addEventListener(TAB_RESTORING_TOPIC, this); win.gBrowser.addTabsProgressListener(URICountListener); }, @@ -630,11 +688,6 @@ let BrowserUsageTelemetry = { win.removeEventListener("unload", this); win.removeEventListener("TabOpen", this, true); - // Don't include URI and domain counts when in private mode. - if (PrivateBrowsingUtils.isWindowPrivate(win.defaultView) && - !Services.prefs.getBoolPref("browser.engagement.total_uri_count.pbm", false)) { - return; - } win.defaultView.gBrowser.tabContainer.removeEventListener(TAB_RESTORING_TOPIC, this); win.defaultView.gBrowser.removeTabsProgressListener(URICountListener); }, diff --git a/toolkit/components/search/nsSearchService.js b/toolkit/components/search/nsSearchService.js index 91879751bcd0..bc101d213fa0 100644 --- a/toolkit/components/search/nsSearchService.js +++ b/toolkit/components/search/nsSearchService.js @@ -4331,7 +4331,12 @@ SearchService.prototype = { }, parseSubmissionURL: function SRCH_SVC_parseSubmissionURL(aURL) { - this._ensureInitialized(); + if (!gInitialized) { + // If search is not initialized, do nothing. + // This allows us to use this function early in telemetry. + // The only other consumer of this (places) uses it much later. + return gEmptyParseSubmissionResult; + } LOG("parseSubmissionURL: Parsing \"" + aURL + "\"."); if (!this._parseSubmissionMap) { diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index ef0167ce46a6..c86cad1d92b4 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -7827,7 +7827,7 @@ "kind": "count", "keyed": true, "releaseChannelCollection": "opt-out", - "description": "Record the search counts for search engines" + "description": "Records search counts for search access points and in content searches. For search access points, the format is: . For in content searches, the format is .in-content:[sap|sap-follow-on|organic]:[code|none]" }, "SEARCH_RESET_RESULT": { "record_in_processes": ["main", "content"], From 613a40ff153411c254d0dd9810842adf7ddb48eb Mon Sep 17 00:00:00 2001 From: Rob Wu Date: Mon, 6 Aug 2018 11:24:20 +0200 Subject: [PATCH 10/28] Bug 1416103 - Re-enable browser_ext_omnibox.js everywhere r=aswan Likely fixed by the patch for bug 1417052 Ran the test with --repeat=50 on Linux and did not observe any failures. MozReview-Commit-ID: FuMo8jdgJCn --HG-- extra : rebase_source : 2a296cc7817607d352bc56b5b200da81d3e26bf0 --- browser/components/extensions/test/browser/browser-common.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/browser/components/extensions/test/browser/browser-common.ini b/browser/components/extensions/test/browser/browser-common.ini index ccf43aa4ead2..70f52baace6b 100644 --- a/browser/components/extensions/test/browser/browser-common.ini +++ b/browser/components/extensions/test/browser/browser-common.ini @@ -111,7 +111,6 @@ skip-if = (verify && (os == 'linux' || os == 'mac')) [browser_ext_menus_events.js] [browser_ext_menus_refresh.js] [browser_ext_omnibox.js] -skip-if = (debug && (os == 'linux' || os == 'mac')) || (verify && (os == 'linux' || os == 'mac')) # Bug 1416103 (was bug 1417052) [browser_ext_openPanel.js] skip-if = (verify && !debug && (os == 'linux' || os == 'mac')) [browser_ext_optionsPage_browser_style.js] From f22cd9a62c7f036d8c7241d9cc0bc32e25b1d901 Mon Sep 17 00:00:00 2001 From: Kyle Machulis Date: Fri, 3 Aug 2018 19:16:26 +0000 Subject: [PATCH 11/28] Bug 1480641 - Remove nsITextScroll; r=nika Implemented by nsDocShell and nsWebBrowser (which just wraps the docshell functions), but not actually used anywhere. MozReview-Commit-ID: 2YzfsrvOolX Differential Revision: https://phabricator.services.mozilla.com/D2695 --HG-- extra : moz-landing-system : lando --- docshell/base/moz.build | 1 - docshell/base/nsDocShell.cpp | 27 ----------------- docshell/base/nsDocShell.h | 3 -- docshell/base/nsITextScroll.idl | 33 --------------------- toolkit/components/browser/nsWebBrowser.cpp | 27 +---------------- toolkit/components/browser/nsWebBrowser.h | 4 --- 6 files changed, 1 insertion(+), 94 deletions(-) delete mode 100644 docshell/base/nsITextScroll.idl diff --git a/docshell/base/moz.build b/docshell/base/moz.build index ec9baa446ad8..b69ced726ca5 100644 --- a/docshell/base/moz.build +++ b/docshell/base/moz.build @@ -49,7 +49,6 @@ XPIDL_SOURCES += [ 'nsIReflowObserver.idl', 'nsIRefreshURI.idl', 'nsIScrollable.idl', - 'nsITextScroll.idl', 'nsITooltipListener.idl', 'nsITooltipTextProvider.idl', 'nsIURIFixup.idl', diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index ea0c2d3e40d4..095a31af4bfc 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -520,7 +520,6 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDocShell) NS_INTERFACE_MAP_ENTRY(nsIWebNavigation) NS_INTERFACE_MAP_ENTRY(nsIBaseWindow) NS_INTERFACE_MAP_ENTRY(nsIScrollable) - NS_INTERFACE_MAP_ENTRY(nsITextScroll) NS_INTERFACE_MAP_ENTRY(nsIRefreshURI) NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) @@ -6089,32 +6088,6 @@ nsDocShell::GetScrollbarVisibility(bool* aVerticalVisible, return NS_OK; } -//***************************************************************************** -// nsDocShell::nsITextScroll -//***************************************************************************** - -NS_IMETHODIMP -nsDocShell::ScrollByLines(int32_t aNumLines) -{ - nsIScrollableFrame* sf = GetRootScrollFrame(); - NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE); - - sf->ScrollBy(nsIntPoint(0, aNumLines), nsIScrollableFrame::LINES, - nsIScrollableFrame::SMOOTH); - return NS_OK; -} - -NS_IMETHODIMP -nsDocShell::ScrollByPages(int32_t aNumPages) -{ - nsIScrollableFrame* sf = GetRootScrollFrame(); - NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE); - - sf->ScrollBy(nsIntPoint(0, aNumPages), nsIScrollableFrame::PAGES, - nsIScrollableFrame::SMOOTH); - return NS_OK; -} - //***************************************************************************** // nsDocShell::nsIRefreshURI //***************************************************************************** diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index f50d464ba1a6..ff138adf8a78 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -35,7 +35,6 @@ #include "nsIRefreshURI.h" #include "nsIScrollable.h" #include "nsITabParent.h" -#include "nsITextScroll.h" #include "nsIWebNavigation.h" #include "nsIWebPageDescriptor.h" #include "nsIWebProgressListener.h" @@ -122,7 +121,6 @@ class nsDocShell final , public nsIWebNavigation , public nsIBaseWindow , public nsIScrollable - , public nsITextScroll , public nsIRefreshURI , public nsIWebProgressListener , public nsIWebPageDescriptor @@ -173,7 +171,6 @@ public: NS_DECL_NSIWEBNAVIGATION NS_DECL_NSIBASEWINDOW NS_DECL_NSISCROLLABLE - NS_DECL_NSITEXTSCROLL NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSIWEBPROGRESSLISTENER NS_DECL_NSIREFRESHURI diff --git a/docshell/base/nsITextScroll.idl b/docshell/base/nsITextScroll.idl deleted file mode 100644 index 87338c491e2e..000000000000 --- a/docshell/base/nsITextScroll.idl +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -/** - * The nsITextScroll is an interface that can be implemented by a control that - * supports text scrolling. - */ - -[scriptable, uuid(067B28A0-877F-11d3-AF7E-00A024FFC08C)] -interface nsITextScroll : nsISupports -{ - /** - * Scroll the view up or down by aNumLines lines. positive - * values move down in the view. Prevents scrolling off the - * end of the view. - * @param numLines number of lines to scroll the view by - */ - void scrollByLines(in long numLines); - - /** - * Scroll the view up or down by numPages pages. a page - * is considered to be the amount displayed by the clip view. - * positive values move down in the view. Prevents scrolling - * off the end of the view. - * @param numPages number of pages to scroll the view by - */ - void scrollByPages(in long numPages); -}; \ No newline at end of file diff --git a/toolkit/components/browser/nsWebBrowser.cpp b/toolkit/components/browser/nsWebBrowser.cpp index 0f23e2b726c9..3881db40d162 100644 --- a/toolkit/components/browser/nsWebBrowser.cpp +++ b/toolkit/components/browser/nsWebBrowser.cpp @@ -115,7 +115,6 @@ NS_IMPL_CYCLE_COLLECTION(nsWebBrowser, mDocShellAsWin, mDocShellAsNav, mDocShellAsScrollable, - mDocShellAsTextScroll, mWebProgress) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsWebBrowser) @@ -124,7 +123,6 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsWebBrowser) NS_INTERFACE_MAP_ENTRY(nsIWebNavigation) NS_INTERFACE_MAP_ENTRY(nsIBaseWindow) NS_INTERFACE_MAP_ENTRY(nsIScrollable) - NS_INTERFACE_MAP_ENTRY(nsITextScroll) NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem) NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) NS_INTERFACE_MAP_ENTRY(nsIWebBrowserSetup) @@ -1641,26 +1639,6 @@ nsWebBrowser::GetScrollbarVisibility(bool* aVerticalVisible, aHorizontalVisible); } -//***************************************************************************** -// nsWebBrowser::nsITextScroll -//***************************************************************************** - -NS_IMETHODIMP -nsWebBrowser::ScrollByLines(int32_t aNumLines) -{ - NS_ENSURE_STATE(mDocShell); - - return mDocShellAsTextScroll->ScrollByLines(aNumLines); -} - -NS_IMETHODIMP -nsWebBrowser::ScrollByPages(int32_t aNumPages) -{ - NS_ENSURE_STATE(mDocShell); - - return mDocShellAsTextScroll->ScrollByPages(aNumPages); -} - //***************************************************************************** // nsWebBrowser: Listener Helpers //***************************************************************************** @@ -1680,9 +1658,8 @@ nsWebBrowser::SetDocShell(nsIDocShell* aDocShell) nsCOMPtr baseWin(do_QueryInterface(aDocShell)); nsCOMPtr nav(do_QueryInterface(aDocShell)); nsCOMPtr scrollable(do_QueryInterface(aDocShell)); - nsCOMPtr textScroll(do_QueryInterface(aDocShell)); nsCOMPtr progress(do_GetInterface(aDocShell)); - NS_ENSURE_TRUE(req && baseWin && nav && scrollable && textScroll && progress, + NS_ENSURE_TRUE(req && baseWin && nav && scrollable && progress, NS_ERROR_FAILURE); mDocShell = aDocShell; @@ -1690,7 +1667,6 @@ nsWebBrowser::SetDocShell(nsIDocShell* aDocShell) mDocShellAsWin = baseWin; mDocShellAsNav = nav; mDocShellAsScrollable = scrollable; - mDocShellAsTextScroll = textScroll; mWebProgress = progress; // By default, do not allow DNS prefetch, so we don't break our frozen @@ -1715,7 +1691,6 @@ nsWebBrowser::SetDocShell(nsIDocShell* aDocShell) mDocShellAsWin = nullptr; mDocShellAsNav = nullptr; mDocShellAsScrollable = nullptr; - mDocShellAsTextScroll = nullptr; mWebProgress = nullptr; } diff --git a/toolkit/components/browser/nsWebBrowser.h b/toolkit/components/browser/nsWebBrowser.h index a378612d679e..e7593a6c1d66 100644 --- a/toolkit/components/browser/nsWebBrowser.h +++ b/toolkit/components/browser/nsWebBrowser.h @@ -24,7 +24,6 @@ #include "nsIInterfaceRequestorUtils.h" #include "nsIScrollable.h" #include "nsISHistory.h" -#include "nsITextScroll.h" #include "nsIWidget.h" #include "nsIWebProgress.h" #include "nsISecureBrowserUI.h" @@ -76,7 +75,6 @@ class nsWebBrowser final : public nsIWebBrowser, public nsIDocShellTreeItem, public nsIBaseWindow, public nsIScrollable, - public nsITextScroll, public nsIInterfaceRequestor, public nsIWebBrowserPersist, public nsIWebBrowserFocus, @@ -115,7 +113,6 @@ public: NS_DECL_NSIDOCSHELLTREEITEM NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSISCROLLABLE - NS_DECL_NSITEXTSCROLL NS_DECL_NSIWEBBROWSER NS_DECL_NSIWEBNAVIGATION NS_DECL_NSIWEBBROWSERSETUP @@ -148,7 +145,6 @@ protected: nsCOMPtr mDocShellAsWin; nsCOMPtr mDocShellAsNav; nsCOMPtr mDocShellAsScrollable; - nsCOMPtr mDocShellAsTextScroll; mozilla::OriginAttributes mOriginAttributes; nsCOMPtr mInternalWidget; From bb22e8a0feca95dcbce8dbd4417ade86a4b23154 Mon Sep 17 00:00:00 2001 From: Tiberius Oros Date: Tue, 7 Aug 2018 02:45:36 +0300 Subject: [PATCH 12/28] Backed out changeset 8228e57646bf (bug 1480641) for build bustages on a CLOSED TREE --- docshell/base/moz.build | 1 + docshell/base/nsDocShell.cpp | 27 +++++++++++++++++ docshell/base/nsDocShell.h | 3 ++ docshell/base/nsITextScroll.idl | 33 +++++++++++++++++++++ toolkit/components/browser/nsWebBrowser.cpp | 27 ++++++++++++++++- toolkit/components/browser/nsWebBrowser.h | 4 +++ 6 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 docshell/base/nsITextScroll.idl diff --git a/docshell/base/moz.build b/docshell/base/moz.build index b69ced726ca5..ec9baa446ad8 100644 --- a/docshell/base/moz.build +++ b/docshell/base/moz.build @@ -49,6 +49,7 @@ XPIDL_SOURCES += [ 'nsIReflowObserver.idl', 'nsIRefreshURI.idl', 'nsIScrollable.idl', + 'nsITextScroll.idl', 'nsITooltipListener.idl', 'nsITooltipTextProvider.idl', 'nsIURIFixup.idl', diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 095a31af4bfc..ea0c2d3e40d4 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -520,6 +520,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDocShell) NS_INTERFACE_MAP_ENTRY(nsIWebNavigation) NS_INTERFACE_MAP_ENTRY(nsIBaseWindow) NS_INTERFACE_MAP_ENTRY(nsIScrollable) + NS_INTERFACE_MAP_ENTRY(nsITextScroll) NS_INTERFACE_MAP_ENTRY(nsIRefreshURI) NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) @@ -6088,6 +6089,32 @@ nsDocShell::GetScrollbarVisibility(bool* aVerticalVisible, return NS_OK; } +//***************************************************************************** +// nsDocShell::nsITextScroll +//***************************************************************************** + +NS_IMETHODIMP +nsDocShell::ScrollByLines(int32_t aNumLines) +{ + nsIScrollableFrame* sf = GetRootScrollFrame(); + NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE); + + sf->ScrollBy(nsIntPoint(0, aNumLines), nsIScrollableFrame::LINES, + nsIScrollableFrame::SMOOTH); + return NS_OK; +} + +NS_IMETHODIMP +nsDocShell::ScrollByPages(int32_t aNumPages) +{ + nsIScrollableFrame* sf = GetRootScrollFrame(); + NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE); + + sf->ScrollBy(nsIntPoint(0, aNumPages), nsIScrollableFrame::PAGES, + nsIScrollableFrame::SMOOTH); + return NS_OK; +} + //***************************************************************************** // nsDocShell::nsIRefreshURI //***************************************************************************** diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index ff138adf8a78..f50d464ba1a6 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -35,6 +35,7 @@ #include "nsIRefreshURI.h" #include "nsIScrollable.h" #include "nsITabParent.h" +#include "nsITextScroll.h" #include "nsIWebNavigation.h" #include "nsIWebPageDescriptor.h" #include "nsIWebProgressListener.h" @@ -121,6 +122,7 @@ class nsDocShell final , public nsIWebNavigation , public nsIBaseWindow , public nsIScrollable + , public nsITextScroll , public nsIRefreshURI , public nsIWebProgressListener , public nsIWebPageDescriptor @@ -171,6 +173,7 @@ public: NS_DECL_NSIWEBNAVIGATION NS_DECL_NSIBASEWINDOW NS_DECL_NSISCROLLABLE + NS_DECL_NSITEXTSCROLL NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSIWEBPROGRESSLISTENER NS_DECL_NSIREFRESHURI diff --git a/docshell/base/nsITextScroll.idl b/docshell/base/nsITextScroll.idl new file mode 100644 index 000000000000..87338c491e2e --- /dev/null +++ b/docshell/base/nsITextScroll.idl @@ -0,0 +1,33 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +/** + * The nsITextScroll is an interface that can be implemented by a control that + * supports text scrolling. + */ + +[scriptable, uuid(067B28A0-877F-11d3-AF7E-00A024FFC08C)] +interface nsITextScroll : nsISupports +{ + /** + * Scroll the view up or down by aNumLines lines. positive + * values move down in the view. Prevents scrolling off the + * end of the view. + * @param numLines number of lines to scroll the view by + */ + void scrollByLines(in long numLines); + + /** + * Scroll the view up or down by numPages pages. a page + * is considered to be the amount displayed by the clip view. + * positive values move down in the view. Prevents scrolling + * off the end of the view. + * @param numPages number of pages to scroll the view by + */ + void scrollByPages(in long numPages); +}; \ No newline at end of file diff --git a/toolkit/components/browser/nsWebBrowser.cpp b/toolkit/components/browser/nsWebBrowser.cpp index 3881db40d162..0f23e2b726c9 100644 --- a/toolkit/components/browser/nsWebBrowser.cpp +++ b/toolkit/components/browser/nsWebBrowser.cpp @@ -115,6 +115,7 @@ NS_IMPL_CYCLE_COLLECTION(nsWebBrowser, mDocShellAsWin, mDocShellAsNav, mDocShellAsScrollable, + mDocShellAsTextScroll, mWebProgress) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsWebBrowser) @@ -123,6 +124,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsWebBrowser) NS_INTERFACE_MAP_ENTRY(nsIWebNavigation) NS_INTERFACE_MAP_ENTRY(nsIBaseWindow) NS_INTERFACE_MAP_ENTRY(nsIScrollable) + NS_INTERFACE_MAP_ENTRY(nsITextScroll) NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem) NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) NS_INTERFACE_MAP_ENTRY(nsIWebBrowserSetup) @@ -1639,6 +1641,26 @@ nsWebBrowser::GetScrollbarVisibility(bool* aVerticalVisible, aHorizontalVisible); } +//***************************************************************************** +// nsWebBrowser::nsITextScroll +//***************************************************************************** + +NS_IMETHODIMP +nsWebBrowser::ScrollByLines(int32_t aNumLines) +{ + NS_ENSURE_STATE(mDocShell); + + return mDocShellAsTextScroll->ScrollByLines(aNumLines); +} + +NS_IMETHODIMP +nsWebBrowser::ScrollByPages(int32_t aNumPages) +{ + NS_ENSURE_STATE(mDocShell); + + return mDocShellAsTextScroll->ScrollByPages(aNumPages); +} + //***************************************************************************** // nsWebBrowser: Listener Helpers //***************************************************************************** @@ -1658,8 +1680,9 @@ nsWebBrowser::SetDocShell(nsIDocShell* aDocShell) nsCOMPtr baseWin(do_QueryInterface(aDocShell)); nsCOMPtr nav(do_QueryInterface(aDocShell)); nsCOMPtr scrollable(do_QueryInterface(aDocShell)); + nsCOMPtr textScroll(do_QueryInterface(aDocShell)); nsCOMPtr progress(do_GetInterface(aDocShell)); - NS_ENSURE_TRUE(req && baseWin && nav && scrollable && progress, + NS_ENSURE_TRUE(req && baseWin && nav && scrollable && textScroll && progress, NS_ERROR_FAILURE); mDocShell = aDocShell; @@ -1667,6 +1690,7 @@ nsWebBrowser::SetDocShell(nsIDocShell* aDocShell) mDocShellAsWin = baseWin; mDocShellAsNav = nav; mDocShellAsScrollable = scrollable; + mDocShellAsTextScroll = textScroll; mWebProgress = progress; // By default, do not allow DNS prefetch, so we don't break our frozen @@ -1691,6 +1715,7 @@ nsWebBrowser::SetDocShell(nsIDocShell* aDocShell) mDocShellAsWin = nullptr; mDocShellAsNav = nullptr; mDocShellAsScrollable = nullptr; + mDocShellAsTextScroll = nullptr; mWebProgress = nullptr; } diff --git a/toolkit/components/browser/nsWebBrowser.h b/toolkit/components/browser/nsWebBrowser.h index e7593a6c1d66..a378612d679e 100644 --- a/toolkit/components/browser/nsWebBrowser.h +++ b/toolkit/components/browser/nsWebBrowser.h @@ -24,6 +24,7 @@ #include "nsIInterfaceRequestorUtils.h" #include "nsIScrollable.h" #include "nsISHistory.h" +#include "nsITextScroll.h" #include "nsIWidget.h" #include "nsIWebProgress.h" #include "nsISecureBrowserUI.h" @@ -75,6 +76,7 @@ class nsWebBrowser final : public nsIWebBrowser, public nsIDocShellTreeItem, public nsIBaseWindow, public nsIScrollable, + public nsITextScroll, public nsIInterfaceRequestor, public nsIWebBrowserPersist, public nsIWebBrowserFocus, @@ -113,6 +115,7 @@ public: NS_DECL_NSIDOCSHELLTREEITEM NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSISCROLLABLE + NS_DECL_NSITEXTSCROLL NS_DECL_NSIWEBBROWSER NS_DECL_NSIWEBNAVIGATION NS_DECL_NSIWEBBROWSERSETUP @@ -145,6 +148,7 @@ protected: nsCOMPtr mDocShellAsWin; nsCOMPtr mDocShellAsNav; nsCOMPtr mDocShellAsScrollable; + nsCOMPtr mDocShellAsTextScroll; mozilla::OriginAttributes mOriginAttributes; nsCOMPtr mInternalWidget; From 7b8f8f1076c7f1de67199b4f0a0abbfcf5261678 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Mon, 6 Aug 2018 22:11:11 +0000 Subject: [PATCH 13/28] Bug 1458662 - Re-enable regex JIT on aarch64. r=jchen MozReview-Commit-ID: 8d2pO69R2OD Differential Revision: https://phabricator.services.mozilla.com/D2796 --HG-- extra : moz-landing-system : lando --- mobile/android/app/mobile.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mobile/android/app/mobile.js b/mobile/android/app/mobile.js index c6fe4f180267..328fc752ca17 100644 --- a/mobile/android/app/mobile.js +++ b/mobile/android/app/mobile.js @@ -880,10 +880,6 @@ pref("media.openUnsupportedTypeWithExternalApp", true); pref("dom.keyboardevent.dispatch_during_composition", true); -#if CPU_ARCH == aarch64 -pref("javascript.options.native_regexp", false); -#endif - // Ask for permission when enumerating WebRTC devices. pref("media.navigator.permission.device", true); From 6ddc6d1828a30d2c30edf617b5d32501a60379c9 Mon Sep 17 00:00:00 2001 From: Zibi Braniecki Date: Tue, 7 Aug 2018 00:08:29 +0000 Subject: [PATCH 14/28] Bug 1480881 - Upgrade Gecko to Fluent 0.6. r=stas Upgrade Gecko to Fluent 0.6. Differential Revision: https://phabricator.services.mozilla.com/D2740 --HG-- extra : moz-landing-system : lando --- intl/l10n/DOMLocalization.jsm | 6 +- intl/l10n/Localization.jsm | 86 +- intl/l10n/MessageContext.jsm | 207 ++-- intl/l10n/fluent.js.patch | 1013 ++++++++--------- intl/l10n/test/dom/test_domloc.xul | 4 +- .../dom/test_domloc_translateElements.html | 2 +- 6 files changed, 683 insertions(+), 635 deletions(-) diff --git a/intl/l10n/DOMLocalization.jsm b/intl/l10n/DOMLocalization.jsm index 3f2b676fab76..d3fb9b803833 100644 --- a/intl/l10n/DOMLocalization.jsm +++ b/intl/l10n/DOMLocalization.jsm @@ -16,7 +16,7 @@ */ -/* fluent-dom@aa95b1f (July 10, 2018) */ +/* fluent-dom@cab517f (July 31, 2018) */ const { Localization } = ChromeUtils.import("resource://gre/modules/Localization.jsm", {}); @@ -60,10 +60,10 @@ const LOCALIZABLE_ATTRIBUTES = { th: ["abbr"] }, "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul": { - description: ["value"], global: [ "accesskey", "aria-label", "aria-valuetext", "aria-moz-hint", "label" ], + description: ["value"], key: ["key", "keycode"], label: ["value"], textbox: ["placeholder"], @@ -523,7 +523,7 @@ class DOMLocalization extends Localization { if (this.windowElement) { if (this.windowElement !== newRoot.ownerGlobal) { throw new Error(`Cannot connect a root: - DOMLocalization already has a root from a different window`); + DOMLocalization already has a root from a different window.`); } } else { this.windowElement = newRoot.ownerGlobal; diff --git a/intl/l10n/Localization.jsm b/intl/l10n/Localization.jsm index 2a0c0c4ae27e..8aa0722f20d8 100644 --- a/intl/l10n/Localization.jsm +++ b/intl/l10n/Localization.jsm @@ -16,7 +16,7 @@ */ -/* fluent-dom@aa95b1f (July 10, 2018) */ +/* fluent-dom@cab517f (July 31, 2018) */ /* eslint no-console: ["error", { allow: ["warn", "error"] }] */ /* global console */ @@ -25,13 +25,25 @@ const { L10nRegistry } = ChromeUtils.import("resource://gre/modules/L10nRegistry const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {}); const { AppConstants } = ChromeUtils.import("resource://gre/modules/AppConstants.jsm", {}); -/* - * CachedAsyncIterable caches the elements yielded by an iterable. - * - * It can be used to iterate over an iterable many times without depleting the - * iterable. - */ -class CachedAsyncIterable { +class CachedIterable extends Array { + /** + * Create a `CachedIterable` instance from an iterable or, if another + * instance of `CachedIterable` is passed, return it without any + * modifications. + * + * @param {Iterable} iterable + * @returns {CachedIterable} + */ + static from(iterable) { + if (iterable instanceof this) { + return iterable; + } + + return new this(iterable); + } +} + +class CachedAsyncIterable extends CachedIterable { /** * Create an `CachedAsyncIterable` instance. * @@ -39,6 +51,8 @@ class CachedAsyncIterable { * @returns {CachedAsyncIterable} */ constructor(iterable) { + super(); + if (Symbol.asyncIterator in Object(iterable)) { this.iterator = iterable[Symbol.asyncIterator](); } else if (Symbol.iterator in Object(iterable)) { @@ -46,20 +60,46 @@ class CachedAsyncIterable { } else { throw new TypeError("Argument must implement the iteration protocol."); } - - this.seen = []; } + /** + * Synchronous iterator over the cached elements. + * + * Return a generator object implementing the iterator protocol over the + * cached elements of the original (async or sync) iterable. + */ + [Symbol.iterator]() { + const cached = this; + let cur = 0; + + return { + next() { + if (cached.length === cur) { + return {value: undefined, done: true}; + } + return cached[cur++]; + } + }; + } + + /** + * Asynchronous iterator caching the yielded elements. + * + * Elements yielded by the original iterable will be cached and available + * synchronously. Returns an async generator object implementing the + * iterator protocol over the elements of the original (async or sync) + * iterable. + */ [Symbol.asyncIterator]() { - const { seen, iterator } = this; + const cached = this; let cur = 0; return { async next() { - if (seen.length <= cur) { - seen.push(await iterator.next()); + if (cached.length <= cur) { + cached.push(await cached.iterator.next()); } - return seen[cur++]; + return cached[cur++]; } }; } @@ -71,13 +111,17 @@ class CachedAsyncIterable { * @param {number} count - number of elements to consume */ async touchNext(count = 1) { - const { seen, iterator } = this; let idx = 0; while (idx++ < count) { - if (seen.length === 0 || seen[seen.length - 1].done === false) { - seen.push(await iterator.next()); + const last = this[this.length - 1]; + if (last && last.done) { + break; } + this.push(await this.iterator.next()); } + // Return the last cached {value, done} object to allow the calling + // code to decide if it needs to call touchNext again. + return this[this.length - 1]; } } @@ -112,8 +156,8 @@ class Localization { constructor(resourceIds = [], generateMessages = defaultGenerateMessages) { this.resourceIds = resourceIds; this.generateMessages = generateMessages; - this.ctxs = - new CachedAsyncIterable(this.generateMessages(this.resourceIds)); + this.ctxs = CachedAsyncIterable.from( + this.generateMessages(this.resourceIds)); } addResourceIds(resourceIds) { @@ -276,8 +320,8 @@ class Localization { * that language negotiation or available resources changed. */ onChange() { - this.ctxs = - new CachedAsyncIterable(this.generateMessages(this.resourceIds)); + this.ctxs = CachedAsyncIterable.from( + this.generateMessages(this.resourceIds)); this.ctxs.touchNext(2); } } diff --git a/intl/l10n/MessageContext.jsm b/intl/l10n/MessageContext.jsm index 270fe82adae1..71932040660b 100644 --- a/intl/l10n/MessageContext.jsm +++ b/intl/l10n/MessageContext.jsm @@ -16,7 +16,7 @@ */ -/* fluent@aa95b1f (July 10, 2018) */ +/* fluent@0.7.0 */ /* eslint no-magic-numbers: [0] */ @@ -25,6 +25,9 @@ const MAX_PLACEABLES = 100; const entryIdentifierRe = /-?[a-zA-Z][a-zA-Z0-9_-]*/y; const identifierRe = /[a-zA-Z][a-zA-Z0-9_-]*/y; const functionIdentifierRe = /^[A-Z][A-Z_?-]*$/; +const unicodeEscapeRe = /^[a-fA-F0-9]{4}$/; +const trailingWSRe = /[ \t\n\r]+$/; + /** * The `Parser` class is responsible for parsing FTL resources. @@ -94,46 +97,15 @@ class RuntimeParser { const ch = this._source[this._index]; // We don't care about comments or sections at runtime - if (ch === "/" || - (ch === "#" && - [" ", "#", "\n"].includes(this._source[this._index + 1]))) { + if (ch === "#" && + [" ", "#", "\n"].includes(this._source[this._index + 1])) { this.skipComment(); return; } - if (ch === "[") { - this.skipSection(); - return; - } - this.getMessage(); } - /** - * Skip the section entry from the current index. - * - * @private - */ - skipSection() { - this._index += 1; - if (this._source[this._index] !== "[") { - throw this.error('Expected "[[" to open a section'); - } - - this._index += 1; - - this.skipInlineWS(); - this.getVariantName(); - this.skipInlineWS(); - - if (this._source[this._index] !== "]" || - this._source[this._index + 1] !== "]") { - throw this.error('Expected "]]" to close a section'); - } - - this._index += 2; - } - /** * Parse the source string from the current index as an FTL message * and add it to the entries property on the Parser. @@ -147,6 +119,8 @@ class RuntimeParser { if (this._source[this._index] === "=") { this._index++; + } else { + throw this.error("Expected \"=\" after the identifier"); } this.skipInlineWS(); @@ -236,7 +210,7 @@ class RuntimeParser { * Get identifier using the provided regex. * * By default this will get identifiers of public messages, attributes and - * external arguments (without the $). + * variables (without the $). * * @returns {String} * @private @@ -311,21 +285,30 @@ class RuntimeParser { * @private */ getString() { - const start = this._index + 1; + let value = ""; + this._index++; - while (++this._index < this._length) { + while (this._index < this._length) { const ch = this._source[this._index]; if (ch === '"') { + this._index++; break; } if (ch === "\n") { throw this.error("Unterminated string expression"); } + + if (ch === "\\") { + value += this.getEscapedCharacter(["{", "\\", "\""]); + } else { + this._index++; + value += ch; + } } - return this._source.substring(start, this._index++); + return value; } /** @@ -349,10 +332,17 @@ class RuntimeParser { eol = this._length; } - const firstLineContent = start !== eol ? - this._source.slice(start, eol) : null; + // If there's any text between the = and the EOL, store it for now. The next + // non-empty line will decide what to do with it. + const firstLineContent = start !== eol + // Trim the trailing whitespace in case this is a single-line pattern. + // Multiline patterns are parsed anew by getComplexPattern. + ? this._source.slice(start, eol).replace(trailingWSRe, "") + : null; - if (firstLineContent && firstLineContent.includes("{")) { + if (firstLineContent + && (firstLineContent.includes("{") + || firstLineContent.includes("\\"))) { return this.getComplexPattern(); } @@ -439,13 +429,19 @@ class RuntimeParser { } ch = this._source[this._index]; continue; - } else if (ch === "\\") { - const ch2 = this._source[this._index + 1]; - if (ch2 === '"' || ch2 === "{" || ch2 === "\\") { - ch = ch2; - this._index++; - } - } else if (ch === "{") { + } + + if (ch === undefined) { + break; + } + + if (ch === "\\") { + buffer += this.getEscapedCharacter(); + ch = this._source[this._index]; + continue; + } + + if (ch === "{") { // Push the buffer to content array right before placeable if (buffer.length) { content.push(buffer); @@ -457,18 +453,13 @@ class RuntimeParser { buffer = ""; content.push(this.getPlaceable()); - this._index++; - - ch = this._source[this._index]; + ch = this._source[++this._index]; placeables++; continue; } - if (ch) { - buffer += ch; - } - this._index++; - ch = this._source[this._index]; + buffer += ch; + ch = this._source[++this._index]; } if (content.length === 0) { @@ -476,13 +467,42 @@ class RuntimeParser { } if (buffer.length) { - content.push(buffer); + // Trim trailing whitespace, too. + content.push(buffer.replace(trailingWSRe, "")); } return content; } /* eslint-enable complexity */ + /** + * Parse an escape sequence and return the unescaped character. + * + * @returns {string} + * @private + */ + getEscapedCharacter(specials = ["{", "\\"]) { + this._index++; + const next = this._source[this._index]; + + if (specials.includes(next)) { + this._index++; + return next; + } + + if (next === "u") { + const sequence = this._source.slice(this._index + 1, this._index + 5); + if (unicodeEscapeRe.test(sequence)) { + this._index += 5; + return String.fromCodePoint(parseInt(sequence, 16)); + } + + throw this.error(`Invalid Unicode escape sequence: \\u${sequence}`); + } + + throw this.error(`Unknown escape sequence: \\${next}`); + } + /** * Parses a single placeable in a Message pattern and returns its * expression. @@ -519,7 +539,7 @@ class RuntimeParser { const ch = this._source[this._index]; if (ch === "}") { - if (selector.type === "attr" && selector.id.name.startsWith("-")) { + if (selector.type === "getattr" && selector.id.name.startsWith("-")) { throw this.error( "Attributes of private messages cannot be interpolated." ); @@ -536,11 +556,11 @@ class RuntimeParser { throw this.error("Message references cannot be used as selectors."); } - if (selector.type === "var") { + if (selector.type === "getvar") { throw this.error("Variants cannot be used as selectors."); } - if (selector.type === "attr" && !selector.id.name.startsWith("-")) { + if (selector.type === "getattr" && !selector.id.name.startsWith("-")) { throw this.error( "Attributes of public messages cannot be used as selectors." ); @@ -578,6 +598,10 @@ class RuntimeParser { * @private */ getSelectorExpression() { + if (this._source[this._index] === "{") { + return this.getPlaceable(); + } + const literal = this.getLiteral(); if (literal.type !== "ref") { @@ -590,7 +614,7 @@ class RuntimeParser { const name = this.getIdentifier(); this._index++; return { - type: "attr", + type: "getattr", id: literal, name }; @@ -602,7 +626,7 @@ class RuntimeParser { const key = this.getVariantKey(); this._index++; return { - type: "var", + type: "getvar", id: literal, key }; @@ -640,7 +664,7 @@ class RuntimeParser { const args = []; while (this._index < this._length) { - this.skipInlineWS(); + this.skipWS(); if (this._source[this._index] === ")") { return args; @@ -657,7 +681,7 @@ class RuntimeParser { if (this._source[this._index] === ":") { this._index++; - this.skipInlineWS(); + this.skipWS(); const val = this.getSelectorExpression(); @@ -685,7 +709,7 @@ class RuntimeParser { } } - this.skipInlineWS(); + this.skipWS(); if (this._source[this._index] === ")") { break; @@ -885,7 +909,7 @@ class RuntimeParser { if (cc0 === 36) { // $ this._index++; return { - type: "ext", + type: "var", name: this.getIdentifier() }; } @@ -925,12 +949,11 @@ class RuntimeParser { // to parse them properly and skip their content. let eol = this._source.indexOf("\n", this._index); - while (eol !== -1 && - ((this._source[eol + 1] === "/" && this._source[eol + 2] === "/") || - (this._source[eol + 1] === "#" && - [" ", "#"].includes(this._source[eol + 2])))) { - this._index = eol + 3; + while (eol !== -1 + && this._source[eol + 1] === "#" + && [" ", "#"].includes(this._source[eol + 2])) { + this._index = eol + 3; eol = this._source.indexOf("\n", this._index); if (eol === -1) { @@ -972,7 +995,7 @@ class RuntimeParser { if ((cc >= 97 && cc <= 122) || // a-z (cc >= 65 && cc <= 90) || // A-Z - cc === 47 || cc === 91) { // /[ + cc === 45) { // - this._index = start; return; } @@ -1169,11 +1192,11 @@ function values(opts) { * The role of the Fluent resolver is to format a translation object to an * instance of `FluentType` or an array of instances. * - * Translations can contain references to other messages or external arguments, + * Translations can contain references to other messages or variables, * conditional logic in form of select expressions, traits which describe their * grammatical features, and can use Fluent builtins which make use of the * `Intl` formatters to format numbers, dates, lists and more into the - * context's language. See the documentation of the Fluent syntax for more + * context's language. See the documentation of the Fluent syntax for more * information. * * In case of errors the resolver will try to salvage as much of the @@ -1436,8 +1459,8 @@ function Type(env, expr) { return new FluentSymbol(expr.name); case "num": return new FluentNumber(expr.val); - case "ext": - return ExternalArgument(env, expr); + case "var": + return VariableReference(env, expr); case "fun": return FunctionReference(env, expr); case "call": @@ -1446,11 +1469,11 @@ function Type(env, expr) { const message = MessageReference(env, expr); return Type(env, message); } - case "attr": { + case "getattr": { const attr = AttributeExpression(env, expr); return Type(env, attr); } - case "var": { + case "getvar": { const variant = VariantExpression(env, expr); return Type(env, variant); } @@ -1474,7 +1497,7 @@ function Type(env, expr) { } /** - * Resolve a reference to an external argument. + * Resolve a reference to a variable. * * @param {Object} env * Resolver environment object. @@ -1485,11 +1508,11 @@ function Type(env, expr) { * @returns {FluentType} * @private */ -function ExternalArgument(env, {name}) { +function VariableReference(env, {name}) { const { args, errors } = env; if (!args || !args.hasOwnProperty(name)) { - errors.push(new ReferenceError(`Unknown external: ${name}`)); + errors.push(new ReferenceError(`Unknown variable: ${name}`)); return new FluentNone(name); } @@ -1512,7 +1535,7 @@ function ExternalArgument(env, {name}) { } default: errors.push( - new TypeError(`Unsupported external type: ${name}, ${typeof arg}`) + new TypeError(`Unsupported variable type: ${name}, ${typeof arg}`) ); return new FluentNone(name); } @@ -1691,13 +1714,13 @@ class FluentResource extends Map { * responsible for parsing translation resources in the Fluent syntax and can * format translation units (entities) to strings. * - * Always use `MessageContext.format` to retrieve translation units from - * a context. Translations can contain references to other entities or - * external arguments, conditional logic in form of select expressions, traits - * which describe their grammatical features, and can use Fluent builtins which - * make use of the `Intl` formatters to format numbers, dates, lists and more - * into the context's language. See the documentation of the Fluent syntax for - * more information. + * Always use `MessageContext.format` to retrieve translation units from a + * context. Translations can contain references to other entities or variables, + * conditional logic in form of select expressions, traits which describe their + * grammatical features, and can use Fluent builtins which make use of the + * `Intl` formatters to format numbers, dates, lists and more into the + * context's language. See the documentation of the Fluent syntax for more + * information. */ class MessageContext { @@ -1849,8 +1872,8 @@ class MessageContext { * Format a message to a string or null. * * Format a raw `message` from the context into a string (or a null if it has - * a null value). `args` will be used to resolve references to external - * arguments inside of the translation. + * a null value). `args` will be used to resolve references to variables + * passed as arguments to the translation. * * In case of errors `format` will try to salvage as much of the translation * as possible and will still return a string. For performance reasons, the @@ -1868,7 +1891,7 @@ class MessageContext { * * // Returns 'Hello, name!' and `errors` is now: * - * [] + * [] * * @param {Object | string} message * @param {Object | undefined} args diff --git a/intl/l10n/fluent.js.patch b/intl/l10n/fluent.js.patch index f4dbe98ea136..f6072c69e831 100644 --- a/intl/l10n/fluent.js.patch +++ b/intl/l10n/fluent.js.patch @@ -1,481 +1,360 @@ -diff -uNr ./dist/DOMLocalization.jsm /home/zbraniecki/projects/mozilla-unified/intl/l10n/DOMLocalization.jsm ---- ./dist/DOMLocalization.jsm 2018-04-13 08:25:21.143138950 -0700 -+++ /home/zbraniecki/projects/mozilla-unified/intl/l10n/DOMLocalization.jsm 2018-04-13 08:27:11.658083766 -0700 -@@ -18,10 +18,8 @@ +diff -uN -x README -x moz.build -x L10nRegistry.jsm -x jar.mn -x fluent.js.patch ./intl/l10n/DOMLocalization.jsm /home/zbraniecki/projects/fluent/fluent.js/fluent-gecko/dist/DOMLocalization.jsm +--- ./intl/l10n/DOMLocalization.jsm 2018-08-03 13:25:20.275840905 -0700 ++++ /home/zbraniecki/projects/fluent/fluent.js/fluent-gecko/dist/DOMLocalization.jsm 2018-08-01 09:15:58.916763182 -0700 +@@ -16,10 +16,12 @@ + */ - /* fluent-dom@0.2.0 */ --import Localization from '../../fluent-dom/src/localization.js'; -- --/* eslint no-console: ["error", {allow: ["warn"]}] */ --/* global console */ -+const { Localization } = -+ ChromeUtils.import("resource://gre/modules/Localization.jsm", {}); +-/* fluent-dom@cab517f (July 31, 2018) */ ++/* fluent-dom@0.3.0 */ + +-const { Localization } = +- ChromeUtils.import("resource://gre/modules/Localization.jsm", {}); ++import Localization from '../../fluent-dom/src/localization.js'; ++ ++/* eslint no-console: ["error", {allow: ["warn"]}] */ ++/* global console */ // Match the opening angle bracket (<) in HTML tags, and HTML entities like // &, &, &. -@@ -96,6 +94,7 @@ +@@ -61,9 +63,7 @@ + global: [ + "accesskey", "aria-label", "aria-valuetext", "aria-moz-hint", "label" + ], +- description: ["value"], + key: ["key", "keycode"], +- label: ["value"], + textbox: ["placeholder"], + toolbarbutton: ["tooltiptext"], + } +@@ -96,7 +96,6 @@ const templateElement = element.ownerDocument.createElementNS( "http://www.w3.org/1999/xhtml", "template" ); -+ // eslint-disable-next-line no-unsanitized/property +- // eslint-disable-next-line no-unsanitized/property templateElement.innerHTML = value; overlayChildNodes(templateElement.content, element); } -@@ -323,6 +322,46 @@ +@@ -350,46 +349,6 @@ return toElement; } -+/** -+ * Sanitizes a translation before passing them to Node.localize API. -+ * -+ * It returns `false` if the translation contains DOM Overlays and should -+ * not go into Node.localize. -+ * -+ * Note: There's a third item of work that JS DOM Overlays do - removal -+ * of attributes from the previous translation. -+ * This is not trivial to implement for Node.localize scenario, so -+ * at the moment it is not supported. -+ * -+ * @param {{ -+ * localName: string, -+ * namespaceURI: string, -+ * type: string || null -+ * l10nId: string, -+ * l10nArgs: Array || null, -+ * l10nAttrs: string ||null, -+ * }} l10nItems -+ * @param {{value: string, attrs: Object}} translations -+ * @returns boolean -+ * @private -+ */ -+function sanitizeTranslationForNodeLocalize(l10nItem, translation) { -+ if (reOverlay.test(translation.value)) { -+ return false; -+ } -+ -+ if (translation.attributes) { -+ const explicitlyAllowed = l10nItem.l10nAttrs === null ? null : -+ l10nItem.l10nAttrs.split(",").map(i => i.trim()); -+ for (const [j, {name}] of translation.attributes.entries()) { -+ if (!isAttrNameLocalizable(name, l10nItem, explicitlyAllowed)) { -+ translation.attributes.splice(j, 1); -+ } -+ } -+ } -+ return true; -+} -+ +-/** +- * Sanitizes a translation before passing them to Node.localize API. +- * +- * It returns `false` if the translation contains DOM Overlays and should +- * not go into Node.localize. +- * +- * Note: There's a third item of work that JS DOM Overlays do - removal +- * of attributes from the previous translation. +- * This is not trivial to implement for Node.localize scenario, so +- * at the moment it is not supported. +- * +- * @param {{ +- * localName: string, +- * namespaceURI: string, +- * type: string || null +- * l10nId: string, +- * l10nArgs: Array || null, +- * l10nAttrs: string ||null, +- * }} l10nItems +- * @param {{value: string, attrs: Object}} translations +- * @returns boolean +- * @private +- */ +-function sanitizeTranslationForNodeLocalize(l10nItem, translation) { +- if (reOverlay.test(translation.value)) { +- return false; +- } +- +- if (translation.attributes) { +- const explicitlyAllowed = l10nItem.l10nAttrs === null ? null : +- l10nItem.l10nAttrs.split(",").map(i => i.trim()); +- for (const [j, {name}] of translation.attributes.entries()) { +- if (!isAttrNameLocalizable(name, l10nItem, explicitlyAllowed)) { +- translation.attributes.splice(j, 1); +- } +- } +- } +- return true; +-} +- const L10NID_ATTR_NAME = "data-l10n-id"; const L10NARGS_ATTR_NAME = "data-l10n-args"; -@@ -568,6 +607,59 @@ +@@ -530,6 +489,7 @@ + ); + } + ++ + this.roots.add(newRoot); + this.mutationObserver.observe(newRoot, this.observerConfig); + } +@@ -639,10 +599,7 @@ + if (this.pendingElements.size > 0) { + if (this.pendingrAF === null) { + this.pendingrAF = this.windowElement.requestAnimationFrame(() => { +- // We need to filter for elements that lost their l10n-id while +- // waiting for the animation frame. +- this.translateElements(Array.from(this.pendingElements) +- .filter(elem => elem.hasAttribute("data-l10n-id"))); ++ this.translateElements(Array.from(this.pendingElements)); + this.pendingElements.clear(); + this.pendingrAF = null; + }); +@@ -664,63 +621,6 @@ * @returns {Promise} */ translateFragment(frag) { -+ if (frag.localize) { -+ // This is a temporary fast-path offered by Gecko to workaround performance -+ // issues coming from Fluent and XBL+Stylo performing unnecesary -+ // operations during startup. -+ // For details see bug 1441037, bug 1442262, and bug 1363862. -+ -+ // A sparse array which will store translations separated out from -+ // all translations that is needed for DOM Overlay. -+ const overlayTranslations = []; -+ -+ const getTranslationsForItems = async l10nItems => { -+ const keys = l10nItems.map(l10nItem => [l10nItem.l10nId, l10nItem.l10nArgs]); -+ const translations = await this.formatMessages(keys); -+ -+ // Here we want to separate out elements that require DOM Overlays. -+ // Those elements will have to be translated using our JS -+ // implementation, while everything else is going to use the fast-path. -+ for (const [i, translation] of translations.entries()) { -+ if (translation === undefined) { -+ continue; -+ } -+ -+ const hasOnlyText = -+ sanitizeTranslationForNodeLocalize(l10nItems[i], translation); -+ if (!hasOnlyText) { -+ // Removing from translations to make Node.localize skip it. -+ // We will translate it below using JS DOM Overlays. -+ overlayTranslations[i] = translations[i]; -+ translations[i] = undefined; -+ } -+ } -+ -+ // We pause translation observing here because Node.localize -+ // will translate the whole DOM next, using the `translations`. -+ // -+ // The observer will be resumed after DOM Overlays are localized -+ // in the next microtask. -+ this.pauseObserving(); -+ return translations; -+ }; -+ -+ return frag.localize(getTranslationsForItems.bind(this)) -+ .then(untranslatedElements => { -+ for (let i = 0; i < overlayTranslations.length; i++) { -+ if (overlayTranslations[i] !== undefined && -+ untranslatedElements[i] !== undefined) { -+ translateElement(untranslatedElements[i], overlayTranslations[i]); -+ } -+ } -+ this.resumeObserving(); -+ }) -+ .catch(() => this.resumeObserving()); -+ } +- if (frag.localize) { +- // This is a temporary fast-path offered by Gecko to workaround performance +- // issues coming from Fluent and XBL+Stylo performing unnecesary +- // operations during startup. +- // For details see bug 1441037, bug 1442262, and bug 1363862. +- +- // A sparse array which will store translations separated out from +- // all translations that is needed for DOM Overlay. +- const overlayTranslations = []; +- +- const getTranslationsForItems = async l10nItems => { +- const keys = l10nItems.map( +- l10nItem => ({id: l10nItem.l10nId, args: l10nItem.l10nArgs})); +- const translations = await this.formatMessages(keys); +- +- // Here we want to separate out elements that require DOM Overlays. +- // Those elements will have to be translated using our JS +- // implementation, while everything else is going to use the fast-path. +- for (const [i, translation] of translations.entries()) { +- if (translation === undefined) { +- continue; +- } +- +- const hasOnlyText = +- sanitizeTranslationForNodeLocalize(l10nItems[i], translation); +- if (!hasOnlyText) { +- // Removing from translations to make Node.localize skip it. +- // We will translate it below using JS DOM Overlays. +- overlayTranslations[i] = translations[i]; +- translations[i] = undefined; +- } +- } +- +- // We pause translation observing here because Node.localize +- // will translate the whole DOM next, using the `translations`. +- // +- // The observer will be resumed after DOM Overlays are localized +- // in the next microtask. +- this.pauseObserving(); +- return translations; +- }; +- +- return frag.localize(getTranslationsForItems.bind(this)) +- .then(untranslatedElements => { +- for (let i = 0; i < overlayTranslations.length; i++) { +- if (overlayTranslations[i] !== undefined && +- untranslatedElements[i] !== undefined) { +- translateElement(untranslatedElements[i], overlayTranslations[i]); +- } +- } +- this.resumeObserving(); +- }) +- .catch(e => { +- this.resumeObserving(); +- throw e; +- }); +- } return this.translateElements(this.getTranslatables(frag)); } -@@ -647,37 +739,5 @@ +@@ -800,5 +700,37 @@ } } --/* global L10nRegistry, Services */ -- --/** -- * The default localization strategy for Gecko. It comabines locales -- * available in L10nRegistry, with locales requested by the user to -- * generate the iterator over MessageContexts. -- * -- * In the future, we may want to allow certain modules to override this -- * with a different negotitation strategy to allow for the module to -- * be localized into a different language - for example DevTools. -- */ --function defaultGenerateMessages(resourceIds) { -- const requestedLocales = Services.locale.getRequestedLocales(); -- const availableLocales = L10nRegistry.getAvailableLocales(); -- const defaultLocale = Services.locale.defaultLocale; -- const locales = Services.locale.negotiateLanguages( -- requestedLocales, availableLocales, defaultLocale, -- ); -- return L10nRegistry.generateContexts(locales, resourceIds); --} -- -- --class GeckoDOMLocalization extends DOMLocalization { -- constructor( -- windowElement, -- resourceIds, -- generateMessages = defaultGenerateMessages -- ) { -- super(windowElement, resourceIds, generateMessages); -- } --} -- --this.DOMLocalization = GeckoDOMLocalization; --this.EXPORTED_SYMBOLS = ["DOMLocalization"]; -+this.DOMLocalization = DOMLocalization; -+var EXPORTED_SYMBOLS = ["DOMLocalization"]; -diff -uNr ./dist/l10n.js /home/zbraniecki/projects/mozilla-unified/intl/l10n/l10n.js ---- ./dist/l10n.js 2018-04-13 08:25:21.307139138 -0700 -+++ /home/zbraniecki/projects/mozilla-unified/intl/l10n/l10n.js 2018-04-13 08:27:25.230296529 -0700 -@@ -1,20 +1,26 @@ --/* global Components, document, window */ - { - const { DOMLocalization } = -- Components.utils.import("resource://gre/modules/DOMLocalization.jsm"); -+ ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm", {}); - - /** - * Polyfill for document.ready polyfill. - * See: https://github.com/whatwg/html/issues/127 for details. - * -+ * XXX: The callback is a temporary workaround for bug 1193394. Once Promises in Gecko -+ * start beeing a microtask and stop pushing translation post-layout, we can -+ * remove it and start using the returned Promise again. -+ * -+ * @param {Function} callback - function to be called when the document is ready. - * @returns {Promise} - */ -- function documentReady() { -+ function documentReady(callback) { - if (document.contentType === "application/vnd.mozilla.xul+xml") { - // XUL - return new Promise( - resolve => document.addEventListener( -- "MozBeforeInitialXULLayout", resolve, { once: true } -+ "MozBeforeInitialXULLayout", () => { -+ resolve(callback()); -+ }, { once: true } - ) - ); - } -@@ -22,11 +28,13 @@ - // HTML - const rs = document.readyState; - if (rs === "interactive" || rs === "completed") { -- return Promise.resolve(); -+ return Promise.resolve(callback); - } - return new Promise( - resolve => document.addEventListener( -- "readystatechange", resolve, { once: true } -+ "readystatechange", () => { -+ resolve(callback()); -+ }, { once: true } - ) - ); - } -@@ -50,11 +58,8 @@ - // trigger first context to be fetched eagerly - document.l10n.ctxs.touchNext(); - -- document.l10n.ready = documentReady().then(() => { -+ document.l10n.ready = documentReady(() => { - document.l10n.registerObservers(); -- window.addEventListener("unload", () => { -- document.l10n.unregisterObservers(); -- }); - document.l10n.connectRoot(document.documentElement); - return document.l10n.translateRoots(); - }); -diff -uNr ./dist/Localization.jsm /home/zbraniecki/projects/mozilla-unified/intl/l10n/Localization.jsm ---- ./dist/Localization.jsm 2018-04-13 08:25:20.946138732 -0700 -+++ /home/zbraniecki/projects/mozilla-unified/intl/l10n/Localization.jsm 2018-04-13 08:27:16.396155987 -0700 -@@ -18,70 +18,13 @@ - - /* fluent-dom@0.2.0 */ - --/* eslint no-magic-numbers: [0] */ -- --/* global Intl */ -- --/** -- * @overview -- * -- * The FTL resolver ships with a number of functions built-in. -- * -- * Each function take two arguments: -- * - args - an array of positional args -- * - opts - an object of key-value args -- * -- * Arguments to functions are guaranteed to already be instances of -- * `FluentType`. Functions must return `FluentType` objects as well. -- */ -+/* eslint no-console: ["error", { allow: ["warn", "error"] }] */ -+/* global console */ - --/** -- * @overview -- * -- * The role of the Fluent resolver is to format a translation object to an -- * instance of `FluentType` or an array of instances. -- * -- * Translations can contain references to other messages or external arguments, -- * conditional logic in form of select expressions, traits which describe their -- * grammatical features, and can use Fluent builtins which make use of the -- * `Intl` formatters to format numbers, dates, lists and more into the -- * context's language. See the documentation of the Fluent syntax for more -- * information. -- * -- * In case of errors the resolver will try to salvage as much of the -- * translation as possible. In rare situations where the resolver didn't know -- * how to recover from an error it will return an instance of `FluentNone`. -- * -- * `MessageReference`, `VariantExpression`, `AttributeExpression` and -- * `SelectExpression` resolve to raw Runtime Entries objects and the result of -- * the resolution needs to be passed into `Type` to get their real value. -- * This is useful for composing expressions. Consider: -- * -- * brand-name[nominative] -- * -- * which is a `VariantExpression` with properties `id: MessageReference` and -- * `key: Keyword`. If `MessageReference` was resolved eagerly, it would -- * instantly resolve to the value of the `brand-name` message. Instead, we -- * want to get the message object and look for its `nominative` variant. -- * -- * All other expressions (except for `FunctionReference` which is only used in -- * `CallExpression`) resolve to an instance of `FluentType`. The caller should -- * use the `toString` method to convert the instance to a native value. -- * -- * -- * All functions in this file pass around a special object called `env`. -- * This object stores a set of elements used by all resolve functions: -- * -- * * {MessageContext} ctx -- * context for which the given resolution is happening -- * * {Object} args -- * list of developer provided arguments that can be used -- * * {Array} errors -- * list of errors collected while resolving -- * * {WeakSet} dirty -- * Set of patterns already encountered during this resolution. -- * This is used to prevent cyclic resolutions. -- */ -+const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", {}); -+const { L10nRegistry } = ChromeUtils.import("resource://gre/modules/L10nRegistry.jsm", {}); -+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {}); -+const { AppConstants } = ChromeUtils.import("resource://gre/modules/AppConstants.jsm", {}); - - /* - * CachedIterable caches the elements yielded by an iterable. -@@ -148,58 +91,19 @@ - } - } - --/* -- * @overview -- * -- * Functions for managing ordered sequences of MessageContexts. -- * -- * An ordered iterable of MessageContext instances can represent the current -- * negotiated fallback chain of languages. This iterable can be used to find -- * the best existing translation for a given identifier. -- * -- * The mapContext* methods can be used to find the first MessageContext in the -- * given iterable which contains the translation with the given identifier. If -- * the iterable is ordered according to the result of a language negotiation -- * the returned MessageContext contains the best available translation. -- * -- * A simple function which formats translations based on the identifier might -- * be implemented as follows: -- * -- * formatString(id, args) { -- * const ctx = mapContextSync(contexts, id); -- * -- * if (ctx === null) { -- * return id; -- * } -- * -- * const msg = ctx.getMessage(id); -- * return ctx.format(msg, args); -- * } -- * -- * In order to pass an iterator to mapContext*, wrap it in CachedIterable. -- * This allows multiple calls to mapContext* without advancing and eventually -- * depleting the iterator. -- * -- * function *generateMessages() { -- * // Some lazy logic for yielding MessageContexts. -- * yield *[ctx1, ctx2]; -- * } -- * -- * const contexts = new CachedIterable(generateMessages()); -- * const ctx = mapContextSync(contexts, id); -- * -- */ -- --/* -- * @module fluent -- * @overview -- * -- * `fluent` is a JavaScript implementation of Project Fluent, a localization -- * framework designed to unleash the expressive power of the natural language. +-this.DOMLocalization = DOMLocalization; +-var EXPORTED_SYMBOLS = ["DOMLocalization"]; ++/* global L10nRegistry, Services */ ++ +/** + * The default localization strategy for Gecko. It comabines locales + * available in L10nRegistry, with locales requested by the user to + * generate the iterator over MessageContexts. - * ++ * + * In the future, we may want to allow certain modules to override this + * with a different negotitation strategy to allow for the module to + * be localized into a different language - for example DevTools. - */ -- --/* eslint no-console: ["error", { allow: ["warn", "error"] }] */ ++ */ +function defaultGenerateMessages(resourceIds) { -+ const appLocales = Services.locale.getAppLocalesAsLangTags(); -+ return L10nRegistry.generateContexts(appLocales, resourceIds); ++ const requestedLocales = Services.locale.getRequestedLocales(); ++ const availableLocales = L10nRegistry.getAvailableLocales(); ++ const defaultLocale = Services.locale.defaultLocale; ++ const locales = Services.locale.negotiateLanguages( ++ requestedLocales, availableLocales, defaultLocale, ++ ); ++ return L10nRegistry.generateContexts(locales, resourceIds); +} - - /** - * The `Localization` class is a central high-level API for vanilla -@@ -215,7 +119,7 @@ - * - * @returns {Localization} - */ -- constructor(resourceIds, generateMessages) { -+ constructor(resourceIds, generateMessages = defaultGenerateMessages) { - this.resourceIds = resourceIds; - this.generateMessages = generateMessages; - this.ctxs = new CachedIterable(this.generateMessages(this.resourceIds)); -@@ -236,7 +140,7 @@ - async formatWithFallback(keys, method) { - const translations = []; - -- for (let ctx of this.ctxs) { -+ for await (let ctx of this.ctxs) { - // This can operate on synchronous and asynchronous - // contexts coming from the iterator. - if (typeof ctx.then === "function") { -@@ -248,7 +152,7 @@ - break; - } - -- if (typeof console !== "undefined") { -+ if (AppConstants.NIGHTLY_BUILD) { - const locale = ctx.locales[0]; - const ids = Array.from(missingIds).join(", "); - console.warn(`Missing translations in ${locale}: ${ids}`); -@@ -335,8 +239,28 @@ - return val; - } - -- handleEvent() { -- this.onLanguageChange(); -+ /** -+ * Register weak observers on events that will trigger cache invalidation -+ */ -+ registerObservers() { -+ Services.obs.addObserver(this, "intl:app-locales-changed", true); -+ } + -+ /** -+ * Default observer handler method. -+ * -+ * @param {String} subject -+ * @param {String} topic -+ * @param {Object} data -+ */ -+ observe(subject, topic, data) { -+ switch (topic) { -+ case "intl:app-locales-changed": -+ this.onLanguageChange(); -+ break; -+ default: -+ break; -+ } - } ++ ++class GeckoDOMLocalization extends DOMLocalization { ++ constructor( ++ windowElement, ++ resourceIds, ++ generateMessages = defaultGenerateMessages ++ ) { ++ super(windowElement, resourceIds, generateMessages); ++ } ++} ++ ++this.DOMLocalization = GeckoDOMLocalization; ++this.EXPORTED_SYMBOLS = ["DOMLocalization"]; +diff -uN -x README -x moz.build -x L10nRegistry.jsm -x jar.mn -x fluent.js.patch ./intl/l10n/l10n.js /home/zbraniecki/projects/fluent/fluent.js/fluent-gecko/dist/l10n.js +--- ./intl/l10n/l10n.js 2018-08-03 13:26:42.691527746 -0700 ++++ /home/zbraniecki/projects/fluent/fluent.js/fluent-gecko/dist/l10n.js 2018-08-01 09:15:59.253432348 -0700 +@@ -1,6 +1,7 @@ ++/* global Components, document, window */ + { + const { DOMLocalization } = +- ChromeUtils.import("resource://gre/modules/DOMLocalization.jsm", {}); ++ Components.utils.import("resource://gre/modules/DOMLocalization.jsm"); /** -@@ -348,6 +272,10 @@ - } - } + * Polyfill for document.ready polyfill. +@@ -44,13 +45,16 @@ -+Localization.prototype.QueryInterface = XPCOMUtils.generateQI([ -+ Ci.nsISupportsWeakReference -+]); -+ - /** - * Format the value of a message into a string. - * -@@ -368,6 +296,7 @@ + const resourceIds = getResourceLinks(document.head || document); + +- document.l10n = new DOMLocalization(resourceIds); ++ document.l10n = new DOMLocalization(window, resourceIds); + +- // Trigger the first two contexts to be loaded eagerly. +- document.l10n.ctxs.touchNext(2); ++ // trigger first context to be fetched eagerly ++ document.l10n.ctxs.touchNext(); + + document.l10n.ready = documentReady().then(() => { + document.l10n.registerObservers(); ++ window.addEventListener("unload", () => { ++ document.l10n.unregisterObservers(); ++ }); + document.l10n.connectRoot(document.documentElement); + return document.l10n.translateRoots(); + }); +diff -uN -x README -x moz.build -x L10nRegistry.jsm -x jar.mn -x fluent.js.patch ./intl/l10n/Localization.jsm /home/zbraniecki/projects/fluent/fluent.js/fluent-gecko/dist/Localization.jsm +--- ./intl/l10n/Localization.jsm 2018-08-03 13:20:57.417703171 -0700 ++++ /home/zbraniecki/projects/fluent/fluent.js/fluent-gecko/dist/Localization.jsm 2018-08-01 09:15:58.546760435 -0700 +@@ -16,128 +16,11 @@ */ - function valueFromContext(ctx, errors, id, args) { - const msg = ctx.getMessage(id); -+ - return ctx.format(msg, args, errors); - } -@@ -467,44 +396,5 @@ - return missingIds; - } --/* global Components */ --/* eslint no-unused-vars: 0 */ +-/* fluent-dom@cab517f (July 31, 2018) */ ++/* fluent-dom@0.3.0 */ + +-/* eslint no-console: ["error", { allow: ["warn", "error"] }] */ +-/* global console */ - --const Cu = Components.utils; --const Cc = Components.classes; --const Ci = Components.interfaces; +-const { L10nRegistry } = ChromeUtils.import("resource://gre/modules/L10nRegistry.jsm", {}); +-const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {}); +-const { AppConstants } = ChromeUtils.import("resource://gre/modules/AppConstants.jsm", {}); ++import { CachedAsyncIterable } from 'cached-iterable'; + +-class CachedIterable extends Array { +- /** +- * Create a `CachedIterable` instance from an iterable or, if another +- * instance of `CachedIterable` is passed, return it without any +- * modifications. +- * +- * @param {Iterable} iterable +- * @returns {CachedIterable} +- */ +- static from(iterable) { +- if (iterable instanceof this) { +- return iterable; +- } - --const { L10nRegistry } = -- Cu.import("resource://gre/modules/L10nRegistry.jsm", {}); --const ObserverService = -- Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService); --const { Services } = -- Cu.import("resource://gre/modules/Services.jsm", {}); +- return new this(iterable); +- } +-} +- +-class CachedAsyncIterable extends CachedIterable { +- /** +- * Create an `CachedAsyncIterable` instance. +- * +- * @param {Iterable} iterable +- * @returns {CachedAsyncIterable} +- */ +- constructor(iterable) { +- super(); +- +- if (Symbol.asyncIterator in Object(iterable)) { +- this.iterator = iterable[Symbol.asyncIterator](); +- } else if (Symbol.iterator in Object(iterable)) { +- this.iterator = iterable[Symbol.iterator](); +- } else { +- throw new TypeError("Argument must implement the iteration protocol."); +- } +- } +- +- /** +- * Synchronous iterator over the cached elements. +- * +- * Return a generator object implementing the iterator protocol over the +- * cached elements of the original (async or sync) iterable. +- */ +- [Symbol.iterator]() { +- const cached = this; +- let cur = 0; +- +- return { +- next() { +- if (cached.length === cur) { +- return {value: undefined, done: true}; +- } +- return cached[cur++]; +- } +- }; +- } +- +- /** +- * Asynchronous iterator caching the yielded elements. +- * +- * Elements yielded by the original iterable will be cached and available +- * synchronously. Returns an async generator object implementing the +- * iterator protocol over the elements of the original (async or sync) +- * iterable. +- */ +- [Symbol.asyncIterator]() { +- const cached = this; +- let cur = 0; +- +- return { +- async next() { +- if (cached.length <= cur) { +- cached.push(await cached.iterator.next()); +- } +- return cached[cur++]; +- } +- }; +- } +- +- /** +- * This method allows user to consume the next element from the iterator +- * into the cache. +- * +- * @param {number} count - number of elements to consume +- */ +- async touchNext(count = 1) { +- let idx = 0; +- while (idx++ < count) { +- const last = this[this.length - 1]; +- if (last && last.done) { +- break; +- } +- this.push(await this.iterator.next()); +- } +- // Return the last cached {value, done} object to allow the calling +- // code to decide if it needs to call touchNext again. +- return this[this.length - 1]; +- } +-} - -/** - * The default localization strategy for Gecko. It comabines locales @@ -487,99 +366,201 @@ diff -uNr ./dist/Localization.jsm /home/zbraniecki/projects/mozilla-unified/intl - * be localized into a different language - for example DevTools. - */ -function defaultGenerateMessages(resourceIds) { -- const requestedLocales = Services.locale.getRequestedLocales(); -- const availableLocales = L10nRegistry.getAvailableLocales(); -- const defaultLocale = Services.locale.defaultLocale; -- const locales = Services.locale.negotiateLanguages( -- requestedLocales, availableLocales, defaultLocale, -- ); -- return L10nRegistry.generateContexts(locales, resourceIds); +- const appLocales = Services.locale.getAppLocalesAsBCP47(); +- return L10nRegistry.generateContexts(appLocales, resourceIds); -} -- --class GeckoLocalization extends Localization { -- constructor(resourceIds, generateMessages = defaultGenerateMessages) { -- super(resourceIds, generateMessages); ++/* eslint no-console: ["error", { allow: ["warn", "error"] }] */ + + /** + * The `Localization` class is a central high-level API for vanilla +@@ -153,7 +36,7 @@ + * + * @returns {Localization} + */ +- constructor(resourceIds = [], generateMessages = defaultGenerateMessages) { ++ constructor(resourceIds = [], generateMessages) { + this.resourceIds = resourceIds; + this.generateMessages = generateMessages; + this.ctxs = CachedAsyncIterable.from( +@@ -194,12 +77,9 @@ + break; + } + +- if (AppConstants.NIGHTLY_BUILD || Cu.isInAutomation) { ++ if (typeof console !== "undefined") { + const locale = ctx.locales[0]; + const ids = Array.from(missingIds).join(", "); +- if (Cu.isInAutomation) { +- throw new Error(`Missing translations in ${locale}: ${ids}`); +- } + console.warn(`Missing translations in ${locale}: ${ids}`); + } + } +@@ -284,35 +164,8 @@ + return val; + } + +- /** +- * Register weak observers on events that will trigger cache invalidation +- */ +- registerObservers() { +- Services.obs.addObserver(this, "intl:app-locales-changed", true); +- Services.prefs.addObserver("intl.l10n.pseudo", this, true); - } --} - --this.Localization = GeckoLocalization; --this.EXPORTED_SYMBOLS = ["Localization"]; -+this.Localization = Localization; -+var EXPORTED_SYMBOLS = ["Localization"]; -diff -uNr ./dist/MessageContext.jsm /home/zbraniecki/projects/mozilla-unified/intl/l10n/MessageContext.jsm ---- ./dist/MessageContext.jsm 2018-04-13 08:25:20.698138486 -0700 -+++ /home/zbraniecki/projects/mozilla-unified/intl/l10n/MessageContext.jsm 2018-04-13 08:27:20.944227388 -0700 +- /** +- * Default observer handler method. +- * +- * @param {String} subject +- * @param {String} topic +- * @param {Object} data +- */ +- observe(subject, topic, data) { +- switch (topic) { +- case "intl:app-locales-changed": +- this.onChange(); +- break; +- case "nsPref:changed": +- switch (data) { +- case "intl.l10n.pseudo": +- this.onChange(); +- } +- break; +- default: +- break; +- } ++ handleEvent() { ++ this.onChange(); + } + + /** +@@ -326,10 +179,6 @@ + } + } + +-Localization.prototype.QueryInterface = ChromeUtils.generateQI([ +- Ci.nsISupportsWeakReference +-]); +- + /** + * Format the value of a message into a string. + * +@@ -449,5 +298,44 @@ + return missingIds; + } + +-this.Localization = Localization; +-var EXPORTED_SYMBOLS = ["Localization"]; ++/* global Components */ ++/* eslint no-unused-vars: 0 */ ++ ++const Cu = Components.utils; ++const Cc = Components.classes; ++const Ci = Components.interfaces; ++ ++const { L10nRegistry } = ++ Cu.import("resource://gre/modules/L10nRegistry.jsm", {}); ++const ObserverService = ++ Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService); ++const { Services } = ++ Cu.import("resource://gre/modules/Services.jsm", {}); ++ ++/** ++ * The default localization strategy for Gecko. It comabines locales ++ * available in L10nRegistry, with locales requested by the user to ++ * generate the iterator over MessageContexts. ++ * ++ * In the future, we may want to allow certain modules to override this ++ * with a different negotitation strategy to allow for the module to ++ * be localized into a different language - for example DevTools. ++ */ ++function defaultGenerateMessages(resourceIds) { ++ const requestedLocales = Services.locale.getRequestedLocales(); ++ const availableLocales = L10nRegistry.getAvailableLocales(); ++ const defaultLocale = Services.locale.defaultLocale; ++ const locales = Services.locale.negotiateLanguages( ++ requestedLocales, availableLocales, defaultLocale, ++ ); ++ return L10nRegistry.generateContexts(locales, resourceIds); ++} ++ ++class GeckoLocalization extends Localization { ++ constructor(resourceIds, generateMessages = defaultGenerateMessages) { ++ super(resourceIds, generateMessages); ++ } ++} ++ ++this.Localization = GeckoLocalization; ++this.EXPORTED_SYMBOLS = ["Localization"]; +diff -uN -x README -x moz.build -x L10nRegistry.jsm -x jar.mn -x fluent.js.patch ./intl/l10n/MessageContext.jsm /home/zbraniecki/projects/fluent/fluent.js/fluent-gecko/dist/MessageContext.jsm +--- ./intl/l10n/MessageContext.jsm 2018-08-03 13:11:36.949029757 -0700 ++++ /home/zbraniecki/projects/fluent/fluent.js/fluent-gecko/dist/MessageContext.jsm 2018-08-01 09:15:58.176757688 -0700 @@ -16,7 +16,7 @@ */ --/* fluent-dom@0.2.0 */ -+/* fluent@0.6.3 */ +-/* fluent@0.6.0 */ ++/* fluent-dom@0.3.0 */ /* eslint no-magic-numbers: [0] */ -@@ -1858,63 +1858,5 @@ +@@ -1930,6 +1930,57 @@ } } --/* -- * CachedIterable caches the elements yielded by an iterable. -- * -- * It can be used to iterate over an iterable many times without depleting the -- * iterable. -- */ -- --/* -- * @overview -- * -- * Functions for managing ordered sequences of MessageContexts. -- * -- * An ordered iterable of MessageContext instances can represent the current -- * negotiated fallback chain of languages. This iterable can be used to find -- * the best existing translation for a given identifier. -- * -- * The mapContext* methods can be used to find the first MessageContext in the -- * given iterable which contains the translation with the given identifier. If -- * the iterable is ordered according to the result of a language negotiation -- * the returned MessageContext contains the best available translation. -- * -- * A simple function which formats translations based on the identifier might -- * be implemented as follows: -- * -- * formatString(id, args) { -- * const ctx = mapContextSync(contexts, id); -- * -- * if (ctx === null) { -- * return id; -- * } -- * -- * const msg = ctx.getMessage(id); -- * return ctx.format(msg, args); -- * } -- * -- * In order to pass an iterator to mapContext*, wrap it in CachedIterable. -- * This allows multiple calls to mapContext* without advancing and eventually -- * depleting the iterator. -- * -- * function *generateMessages() { -- * // Some lazy logic for yielding MessageContexts. -- * yield *[ctx1, ctx2]; -- * } -- * -- * const contexts = new CachedIterable(generateMessages()); -- * const ctx = mapContextSync(contexts, id); -- * -- */ -- --/* -- * @module fluent -- * @overview -- * -- * `fluent` is a JavaScript implementation of Project Fluent, a localization -- * framework designed to unleash the expressive power of the natural language. -- * -- */ -- ++/* ++ * @overview ++ * ++ * Functions for managing ordered sequences of MessageContexts. ++ * ++ * An ordered iterable of MessageContext instances can represent the current ++ * negotiated fallback chain of languages. This iterable can be used to find ++ * the best existing translation for a given identifier. ++ * ++ * The mapContext* methods can be used to find the first MessageContext in the ++ * given iterable which contains the translation with the given identifier. If ++ * the iterable is ordered according to the result of a language negotiation ++ * the returned MessageContext contains the best available translation. ++ * ++ * A simple function which formats translations based on the identifier might ++ * be implemented as follows: ++ * ++ * formatString(id, args) { ++ * const ctx = mapContextSync(contexts, id); ++ * ++ * if (ctx === null) { ++ * return id; ++ * } ++ * ++ * const msg = ctx.getMessage(id); ++ * return ctx.format(msg, args); ++ * } ++ * ++ * In order to pass an iterator to mapContext*, wrap it in ++ * Cached{Sync|Async}Iterable. ++ * This allows multiple calls to mapContext* without advancing and eventually ++ * depleting the iterator. ++ * ++ * function *generateMessages() { ++ * // Some lazy logic for yielding MessageContexts. ++ * yield *[ctx1, ctx2]; ++ * } ++ * ++ * const contexts = new CachedSyncIterable(generateMessages()); ++ * const ctx = mapContextSync(contexts, id); ++ * ++ */ ++ ++/* ++ * @module fluent ++ * @overview ++ * ++ * `fluent` is a JavaScript implementation of Project Fluent, a localization ++ * framework designed to unleash the expressive power of the natural language. ++ * ++ */ ++ this.MessageContext = MessageContext; --this.EXPORTED_SYMBOLS = ["MessageContext"]; -+var EXPORTED_SYMBOLS = ["MessageContext"]; +-this.FluentResource = FluentResource; +-var EXPORTED_SYMBOLS = ["MessageContext", "FluentResource"]; ++this.EXPORTED_SYMBOLS = ["MessageContext"]; diff --git a/intl/l10n/test/dom/test_domloc.xul b/intl/l10n/test/dom/test_domloc.xul index fcdbefc7254f..215e608754ff 100644 --- a/intl/l10n/test/dom/test_domloc.xul +++ b/intl/l10n/test/dom/test_domloc.xul @@ -19,10 +19,10 @@ async function * generateMessages(locales, resourceIds) { const mc = new MessageContext(locales); mc.addMessages(` -file-menu +file-menu = .label = File .accesskey = F -new-tab +new-tab = .label = New Tab .accesskey = N `); diff --git a/intl/l10n/test/dom/test_domloc_translateElements.html b/intl/l10n/test/dom/test_domloc_translateElements.html index 5e76c1a50beb..e82f03cf40dc 100644 --- a/intl/l10n/test/dom/test_domloc_translateElements.html +++ b/intl/l10n/test/dom/test_domloc_translateElements.html @@ -15,7 +15,7 @@ async function* mockGenerateMessages(locales, resourceIds) { const mc = new MessageContext(locales); mc.addMessages("title = Hello World"); - mc.addMessages("link\n .title = Click me"); + mc.addMessages("link =\n .title = Click me"); yield mc; } From d55fec160ec6f4c6306b7f6d7d16a522f894873a Mon Sep 17 00:00:00 2001 From: Chris Manchester Date: Tue, 7 Aug 2018 00:21:47 +0000 Subject: [PATCH 15/28] Bug 1481328 - Explicitly disable CARGO_INCREMENTAL when building with tup. r=firefox-build-system-reviewers,froydnj Differential Revision: https://phabricator.services.mozilla.com/D2810 --HG-- extra : moz-landing-system : lando --- python/mozbuild/mozbuild/backend/tup.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/python/mozbuild/mozbuild/backend/tup.py b/python/mozbuild/mozbuild/backend/tup.py index 6aa5a2c20dd5..d358a2c17eae 100644 --- a/python/mozbuild/mozbuild/backend/tup.py +++ b/python/mozbuild/mozbuild/backend/tup.py @@ -711,11 +711,9 @@ class TupBackend(CommonBackend): 'PYTHON': self.environment.substs['PYTHON'], 'PYTHONDONTWRITEBYTECODE': '1', } - cargo_incremental = self.environment.substs.get('CARGO_INCREMENTAL') - if cargo_incremental is not None: - # TODO (bug 1468527): CARGO_INCREMENTAL produces outputs that Tup - # doesn't know about, disable it unconditionally for now. - pass # env['CARGO_INCREMENTAL'] = cargo_incremental + # TODO (bug 1468527): CARGO_INCREMENTAL produces outputs that Tup + # doesn't know about, disable it unconditionally for now. + env['CARGO_INCREMENTAL'] = '0' rust_simd = self.environment.substs.get('MOZ_RUST_SIMD') if rust_simd is not None: From 96d35f35bdc93b71f20e21c4fcb4a4e5d8d14766 Mon Sep 17 00:00:00 2001 From: Jeremy Lempereur Date: Sun, 22 Jul 2018 21:49:38 +0200 Subject: [PATCH 16/28] Bug 1471708 - Rename the "scroll-position clamping scroll port size" to "visual viewport size". r=botond MozReview-Commit-ID: IWPzXSF5jfR --HG-- extra : rebase_source : f67d64ef18a643077d5019048399e68acc722337 --- dom/base/nsDOMWindowUtils.cpp | 4 +- dom/base/nsGlobalWindowOuter.cpp | 4 +- dom/base/test/test_innersize_scrollport.html | 6 +-- dom/events/EventStateManager.cpp | 2 +- dom/interfaces/base/nsIDOMWindowUtils.idl | 4 +- layout/base/MobileViewportManager.cpp | 4 +- layout/base/PresShell.cpp | 20 +++++----- layout/base/nsIPresShell.h | 16 ++++---- layout/base/nsLayoutUtils.cpp | 4 +- layout/base/nsLayoutUtils.h | 6 +-- layout/generic/ViewportFrame.cpp | 6 +-- layout/generic/ViewportFrame.h | 2 +- layout/generic/nsGfxScrollFrame.cpp | 40 +++++++++---------- layout/generic/nsGfxScrollFrame.h | 12 +++--- layout/generic/nsIScrollableFrame.h | 4 +- layout/painting/nsDisplayList.cpp | 8 ++-- layout/painting/nsDisplayList.h | 7 ++-- layout/tools/reftest/reftest-content.js | 4 +- .../PerformanceTests/Speedometer/index.html | 2 +- .../PerformanceTests/StyleBench/index.html | 2 +- 20 files changed, 78 insertions(+), 79 deletions(-) diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 2e0d5ab9d72c..65e5dfcb6ac8 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -3240,7 +3240,7 @@ nsDOMWindowUtils::GetPlugins(JSContext* cx, JS::MutableHandle aPlugin } NS_IMETHODIMP -nsDOMWindowUtils::SetScrollPositionClampingScrollPortSize(float aWidth, float aHeight) +nsDOMWindowUtils::SetVisualViewportSize(float aWidth, float aHeight) { if (!(aWidth >= 0.0 && aHeight >= 0.0)) { return NS_ERROR_ILLEGAL_VALUE; @@ -3251,7 +3251,7 @@ nsDOMWindowUtils::SetScrollPositionClampingScrollPortSize(float aWidth, float aH return NS_ERROR_FAILURE; } - nsLayoutUtils::SetScrollPositionClampingScrollPortSize(presShell, CSSSize(aWidth, aHeight)); + nsLayoutUtils::SetVisualViewportSize(presShell, CSSSize(aWidth, aHeight)); return NS_OK; } diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp index d43c45460575..7bc1d6a02657 100644 --- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp @@ -3137,9 +3137,9 @@ nsGlobalWindowOuter::GetInnerSize(CSSIntSize& aSize) * be the visual viewport, but we fall back to the CSS viewport * if it is not set. */ - if (presShell->IsScrollPositionClampingScrollPortSizeSet()) { + if (presShell->IsVisualViewportSizeSet()) { aSize = CSSIntRect::FromAppUnitsRounded( - presShell->GetScrollPositionClampingScrollPortSize()); + presShell->GetVisualViewportSize()); } else { RefPtr viewManager = presShell->GetViewManager(); if (viewManager) { diff --git a/dom/base/test/test_innersize_scrollport.html b/dom/base/test/test_innersize_scrollport.html index 33b614825914..f28e8f4925c4 100644 --- a/dom/base/test/test_innersize_scrollport.html +++ b/dom/base/test/test_innersize_scrollport.html @@ -23,9 +23,9 @@ function run() var newHeight = oldHeight / 2; var utils = SpecialPowers.getDOMWindowUtils(window); - utils.setScrollPositionClampingScrollPortSize(newWidth, newHeight); - is(window.innerWidth, newWidth, "innerWidth not updated to scroll port width"); - is(window.innerHeight, newHeight, "innerHeight not updated to scroll port height"); + utils.setVisualViewportSize(newWidth, newHeight); + is(window.innerWidth, newWidth, "innerWidth not updated to viewport width"); + is(window.innerHeight, newHeight, "innerHeight not updated to viewport height"); var innerWidthGetter = Object.getOwnPropertyDescriptor(window, "innerWidth").get; var innerHeightGetter = Object.getOwnPropertyDescriptor(window, "innerHeight").get; diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index a0b62046d403..857cbfce0047 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -2753,7 +2753,7 @@ EventStateManager::GetScrollAmount(nsPresContext* aPresContext, aScrollableFrame->GetLineScrollAmount(); } - // If there is no scrollable frame and page scrolling, use view port size. + // If there is no scrollable frame and page scrolling, use viewport size. if (isPage) { return aPresContext->GetVisibleArea().Size(); } diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl index 0752d1e5eaf9..6788cc4fac7b 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl @@ -1591,12 +1591,12 @@ interface nsIDOMWindowUtils : nsISupports { readonly attribute jsval plugins; /** - * Set the scrollport size for the purposes of clamping scroll positions for + * Set the viewport size for the purposes of clamping scroll positions for * the root scroll frame of this document to be (aWidth,aHeight) in CSS pixels. * * The caller of this method must have chrome privileges. */ - void setScrollPositionClampingScrollPortSize(in float aWidth, in float aHeight); + void setVisualViewportSize(in float aWidth, in float aHeight); /** * These are used to control whether dialogs (alert, prompt, confirm) are diff --git a/layout/base/MobileViewportManager.cpp b/layout/base/MobileViewportManager.cpp index c069a6410fee..e3122de0116e 100644 --- a/layout/base/MobileViewportManager.cpp +++ b/layout/base/MobileViewportManager.cpp @@ -301,8 +301,8 @@ MobileViewportManager::UpdateSPCSPS(const ScreenIntSize& aDisplaySize, compositionSize.width -= scrollbars.LeftRight(); compositionSize.height -= scrollbars.TopBottom(); CSSSize compSize = compositionSize / aZoom; - MVM_LOG("%p: Setting SPCSPS %s\n", this, Stringify(compSize).c_str()); - nsLayoutUtils::SetScrollPositionClampingScrollPortSize(mPresShell, compSize); + MVM_LOG("%p: Setting VVPS %s\n", this, Stringify(compSize).c_str()); + nsLayoutUtils::SetVisualViewportSize(mPresShell, compSize); } void diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp index 34d56ff431b6..f8863779740c 100644 --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp @@ -777,7 +777,7 @@ nsIPresShell::nsIPresShell() , mIsFirstPaint(false) , mObservesMutationsForPrint(false) , mWasLastReflowInterrupted(false) - , mScrollPositionClampingScrollPortSizeSet(false) + , mVisualViewportSizeSet(false) , mNeedLayoutFlush(true) , mNeedStyleFlush(true) , mObservingStyleFlushes(false) @@ -850,7 +850,7 @@ PresShell::PresShell() mFrozen = false; mRenderFlags = 0; - mScrollPositionClampingScrollPortSizeSet = false; + mVisualViewportSizeSet = false; static bool addedSynthMouseMove = false; if (!addedSynthMouseMove) { @@ -3445,7 +3445,7 @@ static void ScrollToShowRect(nsIScrollableFrame* aFrameAsScrollable, { nsPoint scrollPt = aFrameAsScrollable->GetScrollPosition(); nsRect visibleRect(scrollPt, - aFrameAsScrollable->GetScrollPositionClampingScrollPortSize()); + aFrameAsScrollable->GetVisualViewportSize()); nsSize lineSize; // Don't call GetLineScrollAmount unless we actually need it. Not only @@ -10590,14 +10590,14 @@ nsIPresShell::MarkFixedFramesForReflow(IntrinsicDirty aIntrinsicDirty) } void -nsIPresShell::SetScrollPositionClampingScrollPortSize(nscoord aWidth, nscoord aHeight) +nsIPresShell::SetVisualViewportSize(nscoord aWidth, nscoord aHeight) { - if (!mScrollPositionClampingScrollPortSizeSet || - mScrollPositionClampingScrollPortSize.width != aWidth || - mScrollPositionClampingScrollPortSize.height != aHeight) { - mScrollPositionClampingScrollPortSizeSet = true; - mScrollPositionClampingScrollPortSize.width = aWidth; - mScrollPositionClampingScrollPortSize.height = aHeight; + if (!mVisualViewportSizeSet || + mVisualViewportSize.width != aWidth || + mVisualViewportSize.height != aHeight) { + mVisualViewportSizeSet = true; + mVisualViewportSize.width = aWidth; + mVisualViewportSize.height = aHeight; if (nsIScrollableFrame* rootScrollFrame = GetRootScrollFrameAsScrollable()) { rootScrollFrame->MarkScrollbarsDirtyForReflow(); diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index 2223ab938ef6..aaa261c707fa 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -1660,13 +1660,13 @@ public: // clears that capture. static void ClearMouseCapture(nsIFrame* aFrame); - void SetScrollPositionClampingScrollPortSize(nscoord aWidth, nscoord aHeight); - bool IsScrollPositionClampingScrollPortSizeSet() { - return mScrollPositionClampingScrollPortSizeSet; + void SetVisualViewportSize(nscoord aWidth, nscoord aHeight); + bool IsVisualViewportSizeSet() { + return mVisualViewportSizeSet; } - nsSize GetScrollPositionClampingScrollPortSize() { - NS_ASSERTION(mScrollPositionClampingScrollPortSizeSet, "asking for scroll port when its not set?"); - return mScrollPositionClampingScrollPortSize; + nsSize GetVisualViewportSize() { + NS_ASSERTION(mVisualViewportSizeSet, "asking for visual viewport size when its not set?"); + return mVisualViewportSize; } void SetVisualViewportOffset(const nsPoint& aScrollOffset) { @@ -1753,7 +1753,7 @@ protected: // Count of the number of times this presshell has been painted to a window. uint64_t mPaintCount; - nsSize mScrollPositionClampingScrollPortSize; + nsSize mVisualViewportSize; nsPoint mVisualViewportOffset; @@ -1813,7 +1813,7 @@ protected: // Whether the most recent interruptible reflow was actually interrupted: bool mWasLastReflowInterrupted : 1; - bool mScrollPositionClampingScrollPortSizeSet : 1; + bool mVisualViewportSizeSet : 1; // True if a layout flush might not be a no-op bool mNeedLayoutFlush : 1; diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index a3fe90bd7188..29de8e62c514 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -9040,11 +9040,11 @@ MaybeReflowForInflationScreenSizeChange(nsPresContext *aPresContext) } /* static */ void -nsLayoutUtils::SetScrollPositionClampingScrollPortSize(nsIPresShell* aPresShell, CSSSize aSize) +nsLayoutUtils::SetVisualViewportSize(nsIPresShell* aPresShell, CSSSize aSize) { MOZ_ASSERT(aSize.width >= 0.0 && aSize.height >= 0.0); - aPresShell->SetScrollPositionClampingScrollPortSize( + aPresShell->SetVisualViewportSize( nsPresContext::CSSPixelsToAppUnits(aSize.width), nsPresContext::CSSPixelsToAppUnits(aSize.height)); diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 93cdf41d77b4..3f7715911d3c 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -2852,11 +2852,11 @@ public: static bool HasDocumentLevelListenersForApzAwareEvents(nsIPresShell* aShell); /** - * Set the scroll port size for the purpose of clamping the scroll position + * Set the viewport size for the purpose of clamping the scroll position * for the root scroll frame of this document - * (see nsIDOMWindowUtils.setScrollPositionClampingScrollPortSize). + * (see nsIDOMWindowUtils.setVisualViewportSize). */ - static void SetScrollPositionClampingScrollPortSize(nsIPresShell* aPresShell, + static void SetVisualViewportSize(nsIPresShell* aPresShell, CSSSize aSize); /** diff --git a/layout/generic/ViewportFrame.cpp b/layout/generic/ViewportFrame.cpp index 85f972e81a3c..f669f1491564 100644 --- a/layout/generic/ViewportFrame.cpp +++ b/layout/generic/ViewportFrame.cpp @@ -281,12 +281,12 @@ ViewportFrame::AdjustReflowInputAsContainingBlock(ReflowInput* aReflowInput) con "We don't handle correct positioning of fixed frames with " "scrollbars in odd positions"); - // If a scroll position clamping scroll-port size has been set, layout + // If a scroll position clamping viewport size has been set, layout // fixed position elements to this size instead of the computed size. nsRect rect(0, 0, aReflowInput->ComputedWidth(), aReflowInput->ComputedHeight()); nsIPresShell* ps = PresShell(); - if (ps->IsScrollPositionClampingScrollPortSizeSet()) { - rect.SizeTo(ps->GetScrollPositionClampingScrollPortSize()); + if (ps->IsVisualViewportSizeSet()) { + rect.SizeTo(ps->GetVisualViewportSize()); } return rect; diff --git a/layout/generic/ViewportFrame.h b/layout/generic/ViewportFrame.h index c84766b25941..a402e9651276 100644 --- a/layout/generic/ViewportFrame.h +++ b/layout/generic/ViewportFrame.h @@ -68,7 +68,7 @@ public: /** * Adjust aReflowInput to account for scrollbars and pres shell - * GetScrollPositionClampingScrollPortSizeSet and + * GetVisualViewportSizeSet and * GetContentDocumentFixedPositionMargins adjustments. * @return the rect to use as containing block rect */ diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index dcae45707685..4de9f77a5191 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -384,14 +384,14 @@ nsHTMLScrollFrame::TryLayout(ScrollReflowInput* aState, nsSize scrollPortSize = nsSize(std::max(0, aState->mInsideBorderSize.width - vScrollbarDesiredWidth), std::max(0, aState->mInsideBorderSize.height - hScrollbarDesiredHeight)); - nsSize visualScrollPortSize = scrollPortSize; + nsSize visualViewportSize = scrollPortSize; nsIPresShell* presShell = PresShell(); - if (mHelper.mIsRoot && presShell->IsScrollPositionClampingScrollPortSizeSet()) { + if (mHelper.mIsRoot && presShell->IsVisualViewportSizeSet()) { nsSize compositionSize = nsLayoutUtils::CalculateCompositionSizeForFrame(this, false); float resolution = presShell->GetResolution(); compositionSize.width /= resolution; compositionSize.height /= resolution; - visualScrollPortSize = nsSize(std::max(0, compositionSize.width - vScrollbarDesiredWidth), + visualViewportSize = nsSize(std::max(0, compositionSize.width - vScrollbarDesiredWidth), std::max(0, compositionSize.height - hScrollbarDesiredHeight)); } @@ -405,7 +405,7 @@ nsHTMLScrollFrame::TryLayout(ScrollReflowInput* aState, if (aState->mStyles.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN) { bool wantHScrollbar = aState->mStyles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL || - scrolledRect.XMost() >= visualScrollPortSize.width + oneDevPixel || + scrolledRect.XMost() >= visualViewportSize.width + oneDevPixel || scrolledRect.x <= -oneDevPixel; if (scrollPortSize.width < hScrollbarMinSize.width) wantHScrollbar = false; @@ -417,7 +417,7 @@ nsHTMLScrollFrame::TryLayout(ScrollReflowInput* aState, if (aState->mStyles.mVertical != NS_STYLE_OVERFLOW_HIDDEN) { bool wantVScrollbar = aState->mStyles.mVertical == NS_STYLE_OVERFLOW_SCROLL || - scrolledRect.YMost() >= visualScrollPortSize.height + oneDevPixel || + scrolledRect.YMost() >= visualViewportSize.height + oneDevPixel || scrolledRect.y <= -oneDevPixel; if (scrollPortSize.height < vScrollbarMinSize.height) wantVScrollbar = false; @@ -2860,10 +2860,10 @@ ScrollFrameHelper::ScrollToImpl(nsPoint aPt, const nsRect& aRange, nsAtom* aOrig nsPoint dist(std::abs(pt.x - mLastUpdateFramesPos.x), std::abs(pt.y - mLastUpdateFramesPos.y)); - nsSize scrollPortSize = GetScrollPositionClampingScrollPortSize(); - nscoord horzAllowance = std::max(scrollPortSize.width / std::max(sHorzScrollFraction, 1), + nsSize visualViewportSize = GetVisualViewportSize(); + nscoord horzAllowance = std::max(visualViewportSize.width / std::max(sHorzScrollFraction, 1), nsPresContext::AppUnitsPerCSSPixel()); - nscoord vertAllowance = std::max(scrollPortSize.height / std::max(sVertScrollFraction, 1), + nscoord vertAllowance = std::max(visualViewportSize.height / std::max(sVertScrollFraction, 1), nsPresContext::AppUnitsPerCSSPixel()); if (dist.x >= horzAllowance || dist.y >= vertAllowance) { needFrameVisibilityUpdate = true; @@ -3491,7 +3491,7 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsStyleDisplay* disp = mOuter->StyleDisplay(); if (disp && (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_SCROLL)) { - aBuilder->AddToWillChangeBudget(mOuter, GetScrollPositionClampingScrollPortSize()); + aBuilder->AddToWillChangeBudget(mOuter, GetVisualViewportSize()); } mScrollParentID = aBuilder->GetCurrentScrollParentId(); @@ -4056,16 +4056,16 @@ ScrollFrameHelper::GetScrollRangeForClamping() const return nsRect(nscoord_MIN/2, nscoord_MIN/2, nscoord_MAX - nscoord_MIN/2, nscoord_MAX - nscoord_MIN/2); } - nsSize scrollPortSize = GetScrollPositionClampingScrollPortSize(); - return GetScrollRange(scrollPortSize.width, scrollPortSize.height); + nsSize visualViewportSize = GetVisualViewportSize(); + return GetScrollRange(visualViewportSize.width, visualViewportSize.height); } nsSize -ScrollFrameHelper::GetScrollPositionClampingScrollPortSize() const +ScrollFrameHelper::GetVisualViewportSize() const { nsIPresShell* presShell = mOuter->PresShell(); - if (mIsRoot && presShell->IsScrollPositionClampingScrollPortSizeSet()) { - return presShell->GetScrollPositionClampingScrollPortSize(); + if (mIsRoot && presShell->IsVisualViewportSizeSet()) { + return presShell->GetVisualViewportSize(); } return mScrollPort.Size(); } @@ -5296,7 +5296,7 @@ ScrollFrameHelper::IsScrollingActive(nsDisplayListBuilder* aBuilder) const { const nsStyleDisplay* disp = mOuter->StyleDisplay(); if (disp && (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_SCROLL) && - aBuilder->IsInWillChangeBudget(mOuter, GetScrollPositionClampingScrollPortSize())) { + aBuilder->IsInWillChangeBudget(mOuter, GetVisualViewportSize())) { return true; } @@ -5604,7 +5604,7 @@ ScrollFrameHelper::ReflowFinished() } nsRect scrolledContentRect = GetScrolledRect(); - nsSize scrollClampingScrollPort = GetScrollPositionClampingScrollPortSize(); + nsSize scrollClampingScrollPort = GetVisualViewportSize(); nscoord minX = scrolledContentRect.x; nscoord maxX = scrolledContentRect.XMost() - scrollClampingScrollPort.width; nscoord minY = scrolledContentRect.y; @@ -5824,12 +5824,12 @@ ScrollFrameHelper::LayoutScrollbars(nsBoxLayoutState& aState, bool scrollbarOnLeft = !IsScrollbarOnRight(); bool overlayScrollBarsWithZoom = mIsRoot && LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) && - presShell->IsScrollPositionClampingScrollPortSizeSet(); + presShell->IsVisualViewportSizeSet(); nsSize scrollPortClampingSize = mScrollPort.Size(); double res = 1.0; if (overlayScrollBarsWithZoom) { - scrollPortClampingSize = presShell->GetScrollPositionClampingScrollPortSize(); + scrollPortClampingSize = presShell->GetVisualViewportSize(); res = presShell->GetCumulativeResolution(); } @@ -6109,11 +6109,11 @@ ScrollFrameHelper::GetScrolledRect() const // For that, we first convert the scroll port and the scrolled rect to rects // relative to the reference frame, since that's the space where painting does // snapping. - nsSize scrollPortSize = GetScrollPositionClampingScrollPortSize(); + nsSize visualViewportSize = GetVisualViewportSize(); const nsIFrame* referenceFrame = mReferenceFrameDuringPainting ? mReferenceFrameDuringPainting : nsLayoutUtils::GetReferenceFrame(mOuter); nsPoint toReferenceFrame = mOuter->GetOffsetToCrossDoc(referenceFrame); - nsRect scrollPort(mScrollPort.TopLeft() + toReferenceFrame, scrollPortSize); + nsRect scrollPort(mScrollPort.TopLeft() + toReferenceFrame, visualViewportSize); nsRect scrolledRect = result + scrollPort.TopLeft(); if (scrollPort.Overflows() || scrolledRect.Overflows()) { diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h index 614206830cd6..96db6c43038d 100644 --- a/layout/generic/nsGfxScrollFrame.h +++ b/layout/generic/nsGfxScrollFrame.h @@ -214,9 +214,9 @@ public: return pt; } nsRect GetScrollRange() const; - // Get the scroll range assuming the scrollport has size (aWidth, aHeight). + // Get the scroll range assuming the viewport has size (aWidth, aHeight). nsRect GetScrollRange(nscoord aWidth, nscoord aHeight) const; - nsSize GetScrollPositionClampingScrollPortSize() const; + nsSize GetVisualViewportSize() const; void ScrollSnap(nsIScrollableFrame::ScrollMode aMode = nsIScrollableFrame::SMOOTH_MSD); void ScrollSnap(const nsPoint &aDestination, nsIScrollableFrame::ScrollMode aMode = nsIScrollableFrame::SMOOTH_MSD); @@ -852,8 +852,8 @@ public: virtual nsRect GetScrollRange() const override { return mHelper.GetScrollRange(); } - virtual nsSize GetScrollPositionClampingScrollPortSize() const override { - return mHelper.GetScrollPositionClampingScrollPortSize(); + virtual nsSize GetVisualViewportSize() const override { + return mHelper.GetVisualViewportSize(); } virtual nsSize GetLineScrollAmount() const override { return mHelper.GetLineScrollAmount(); @@ -1304,8 +1304,8 @@ public: virtual nsRect GetScrollRange() const override { return mHelper.GetScrollRange(); } - virtual nsSize GetScrollPositionClampingScrollPortSize() const override { - return mHelper.GetScrollPositionClampingScrollPortSize(); + virtual nsSize GetVisualViewportSize() const override { + return mHelper.GetVisualViewportSize(); } virtual nsSize GetLineScrollAmount() const override { return mHelper.GetLineScrollAmount(); diff --git a/layout/generic/nsIScrollableFrame.h b/layout/generic/nsIScrollableFrame.h index 3fa2d4b88479..65e01b0582e9 100644 --- a/layout/generic/nsIScrollableFrame.h +++ b/layout/generic/nsIScrollableFrame.h @@ -148,10 +148,10 @@ public: */ virtual nsRect GetScrollRange() const = 0; /** - * Get the size of the scroll port to use when clamping the scroll + * Get the size of the view port to use when clamping the scroll * position. */ - virtual nsSize GetScrollPositionClampingScrollPortSize() const = 0; + virtual nsSize GetVisualViewportSize() const = 0; /** * Return how much we would try to scroll by in each direction if * asked to scroll by one "line" vertically and horizontally. diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp index d51c23e8a0b1..af058cd9026f 100644 --- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -7017,8 +7017,8 @@ nsDisplayFixedPosition::BuildLayer(nsDisplayListBuilder* aBuilder, if (viewportFrame) { // Fixed position frames are reflowed into the scroll-port size if one has // been set. - if (presContext->PresShell()->IsScrollPositionClampingScrollPortSizeSet()) { - anchorRect.SizeTo(presContext->PresShell()->GetScrollPositionClampingScrollPortSize()); + if (presContext->PresShell()->IsVisualViewportSizeSet()) { + anchorRect.SizeTo(presContext->PresShell()->GetVisualViewportSize()); } else { anchorRect.SizeTo(viewportFrame->GetSize()); } @@ -7193,9 +7193,9 @@ nsDisplayStickyPosition::BuildLayer(nsDisplayListBuilder* aBuilder, // reflowed into the scroll-port size if one has been set. nsSize scrollFrameSize = scrollFrame->GetSize(); if (scrollFrame == presContext->PresShell()->GetRootScrollFrame() && - presContext->PresShell()->IsScrollPositionClampingScrollPortSizeSet()) { + presContext->PresShell()->IsVisualViewportSizeSet()) { scrollFrameSize = presContext->PresShell()-> - GetScrollPositionClampingScrollPortSize(); + GetVisualViewportSize(); } nsLayoutUtils::SetFixedPositionLayerData(layer, scrollFrame, diff --git a/layout/painting/nsDisplayList.h b/layout/painting/nsDisplayList.h index 711b5a3bb72d..f868147d5a05 100644 --- a/layout/painting/nsDisplayList.h +++ b/layout/painting/nsDisplayList.h @@ -1465,12 +1465,11 @@ public: if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame) && aBuilder->IsPaintingToWindow()) { // position: fixed items are reflowed into and only drawn inside the - // viewport, or the scroll position clamping scrollport size, if one is - // set. + // viewport, or the visual viewport size, if one is set. nsIPresShell* ps = aFrame->PresShell(); - if (ps->IsScrollPositionClampingScrollPortSizeSet()) { + if (ps->IsVisualViewportSizeSet()) { dirtyRectRelativeToDirtyFrame = - nsRect(nsPoint(0, 0), ps->GetScrollPositionClampingScrollPortSize()); + nsRect(nsPoint(0, 0), ps->GetVisualViewportSize()); visible = dirtyRectRelativeToDirtyFrame; #ifdef MOZ_WIDGET_ANDROID } else { diff --git a/layout/tools/reftest/reftest-content.js b/layout/tools/reftest/reftest-content.js index 933140473955..f7656d1ae029 100644 --- a/layout/tools/reftest/reftest-content.js +++ b/layout/tools/reftest/reftest-content.js @@ -292,8 +292,8 @@ function setupViewport(contentRootElement) { var sw = attrOrDefault(contentRootElement, "reftest-scrollport-w", 0); var sh = attrOrDefault(contentRootElement, "reftest-scrollport-h", 0); if (sw !== 0 || sh !== 0) { - LogInfo("Setting scrollport to "); - windowUtils().setScrollPositionClampingScrollPortSize(sw, sh); + LogInfo("Setting viewport to "); + windowUtils().setVisualViewportSize(sw, sh); } // XXX support resolution when needed diff --git a/third_party/webkit/PerformanceTests/Speedometer/index.html b/third_party/webkit/PerformanceTests/Speedometer/index.html index b6cb9c2844cf..010605225ea3 100644 --- a/third_party/webkit/PerformanceTests/Speedometer/index.html +++ b/third_party/webkit/PerformanceTests/Speedometer/index.html @@ -20,7 +20,7 @@ It uses demo web applications to simulate user actions such as adding to-do items.

- Your browser window is too small. For most accurate results, please make the view port size at least 850px by 650px.
+ Your browser window is too small. For most accurate results, please make the viewport size at least 850px by 650px.
It's currently .

diff --git a/third_party/webkit/PerformanceTests/StyleBench/index.html b/third_party/webkit/PerformanceTests/StyleBench/index.html index 5e57bbb27a17..ed2c6cacb2e8 100644 --- a/third_party/webkit/PerformanceTests/StyleBench/index.html +++ b/third_party/webkit/PerformanceTests/StyleBench/index.html @@ -29,7 +29,7 @@ StyleBench is a browser benchmark that measures the performance of the style resolution mechanism.

- Your browser window is too small. For most accurate results, please make the view port size at least 850px by 650px.
+ Your browser window is too small. For most accurate results, please make the viewport size at least 850px by 650px.
It's currently .

From 37669b3f4a931bcba8333cd75d50aec4a550ca84 Mon Sep 17 00:00:00 2001 From: Kyle Machulis Date: Tue, 7 Aug 2018 00:53:58 +0000 Subject: [PATCH 17/28] Bug 1473833 - Skip object loading when given unrecognized mime type; r=bzbarsky At the moment, a tag that has document type capabilities will try to load tag content with invalid MIME types as a document. This patch will cause the load to fail silently instead. This will cause failures in certain WPTs that expect plugins to be present to fill in MIME type requirements, which we currently don't have available on CI. These WPTs have been disabled for the moment. MozReview-Commit-ID: 9JGR4LClE5x Differential Revision: https://phabricator.services.mozilla.com/D2542 --HG-- extra : moz-landing-system : lando --- devtools/client/inspector/test/doc_inspector_embed.html | 2 +- dom/base/nsObjectLoadingContent.cpp | 9 ++++++--- .../svg/object-in-svg-foreignobject.sub.html.ini | 2 ++ 3 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 testing/web-platform/meta/content-security-policy/svg/object-in-svg-foreignobject.sub.html.ini diff --git a/devtools/client/inspector/test/doc_inspector_embed.html b/devtools/client/inspector/test/doc_inspector_embed.html index af84dd31c2a2..8262fc2934a9 100644 --- a/devtools/client/inspector/test/doc_inspector_embed.html +++ b/devtools/client/inspector/test/doc_inspector_embed.html @@ -1,6 +1,6 @@ - diff --git a/dom/base/nsObjectLoadingContent.cpp b/dom/base/nsObjectLoadingContent.cpp index 4c335886a4eb..c61d270f46dc 100644 --- a/dom/base/nsObjectLoadingContent.cpp +++ b/dom/base/nsObjectLoadingContent.cpp @@ -1810,12 +1810,15 @@ nsObjectLoadingContent::UpdateObjectParameters() IsPluginType(newMime_Type)) { newType = newMime_Type; LOG(("OBJLC [%p]: Plugin type with no URI, skipping channel load", this)); - } else if (newURI) { + } else if (newURI && (mOriginalContentType.IsEmpty() || newMime_Type != eType_Null)) { // We could potentially load this if we opened a channel on mURI, indicate - // This by leaving type as loading + // this by leaving type as loading. + // + // If a MIME type was requested in the tag, but we have decided to set load + // type to null, ignore (otherwise we'll default to document type loading). newType = eType_Loading; } else { - // Unloadable - no URI, and no plugin type. Non-plugin types (images, + // Unloadable - no URI, and no plugin/MIME type. Non-plugin types (images, // documents) always load with a channel. newType = eType_Null; } diff --git a/testing/web-platform/meta/content-security-policy/svg/object-in-svg-foreignobject.sub.html.ini b/testing/web-platform/meta/content-security-policy/svg/object-in-svg-foreignobject.sub.html.ini new file mode 100644 index 000000000000..f387e7d52268 --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/svg/object-in-svg-foreignobject.sub.html.ini @@ -0,0 +1,2 @@ +[object-in-svg-foreignobject.sub.html] + disabled: https://github.com/web-platform-tests/wpt/issues/12282 From 7a58a577d54d87ef5608832e754a0da527c3e0b4 Mon Sep 17 00:00:00 2001 From: alwu Date: Fri, 3 Aug 2018 11:28:30 -0700 Subject: [PATCH 18/28] Bug 1480738 - part1 : only allow top-level video document to autoplay. r=cpearce Only allow top-level video document to autoplay in order to avoid autoplay from video document which is in the iframe. MozReview-Commit-ID: BbyjviK1BRK --HG-- extra : rebase_source : f84421e27c6029dd3733f3c5a5d329b1755a0ee3 --- dom/media/AutoplayPolicy.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dom/media/AutoplayPolicy.cpp b/dom/media/AutoplayPolicy.cpp index afc1fae0a232..5204a33bde04 100644 --- a/dom/media/AutoplayPolicy.cpp +++ b/dom/media/AutoplayPolicy.cpp @@ -140,7 +140,9 @@ IsMediaElementAllowedToPlay(const HTMLMediaElement& aElement) return true; } - if (aElement.OwnerDoc()->MediaDocumentKind() == nsIDocument::MediaDocumentKind::Video) { + nsIDocument* topDocument = ApproverDocOf(*aElement.OwnerDoc()); + if (topDocument && + topDocument->MediaDocumentKind() == nsIDocument::MediaDocumentKind::Video) { AUTOPLAY_LOG("Allow video document %p to autoplay\n", &aElement); return true; } From c9a517ec966aae6189f234bc1886ec5f12f91210 Mon Sep 17 00:00:00 2001 From: alwu Date: Fri, 3 Aug 2018 12:57:38 -0700 Subject: [PATCH 19/28] Bug 1480738 - part2 : add test. r=cpearce MozReview-Commit-ID: 8GwifOpAQNf --HG-- extra : rebase_source : 8f21f469894deb5ae815582dcb7c50625c7b50b8 --- .../browser/browser_autoplay_videoDocument.js | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/toolkit/content/tests/browser/browser_autoplay_videoDocument.js b/toolkit/content/tests/browser/browser_autoplay_videoDocument.js index 421fc6a11bd5..8f75b38b4560 100644 --- a/toolkit/content/tests/browser/browser_autoplay_videoDocument.js +++ b/toolkit/content/tests/browser/browser_autoplay_videoDocument.js @@ -12,12 +12,33 @@ function setup_test_preference() { function checkIsVideoDocumentAutoplay(browser) { return ContentTask.spawn(browser, null, async () => { - let video = content.document.getElementsByTagName("video")[0]; - let played = video && await video.play().then(() => true, () => false); + const video = content.document.getElementsByTagName("video")[0]; + const played = video && await video.play().then(() => true, () => false); ok(played, "Should be able to play in video document."); }); } +async function checkIsIframeVideoDocumentAutoplay(browser) { + info("- create iframe video document -"); + await ContentTask.spawn(browser, PAGE, async (pageURL) => { + const iframe = content.document.createElement("iframe"); + iframe.src = pageURL; + content.document.body.appendChild(iframe); + const iframeLoaded = new Promise((resolve, reject) => { + iframe.addEventListener("load", e => resolve(), {once: true}); + }); + await iframeLoaded; + }); + + info("- check whether iframe video document starts playing -"); + await ContentTask.spawn(browser, null, async () => { + const iframe = content.document.querySelector("iframe"); + const video = iframe.contentDocument.querySelector("video"); + ok(video.paused, "Subdoc video should not have played"); + is(video.played.length, 0, "Should have empty played ranges"); + }); +} + add_task(async () => { await BrowserTestUtils.withNewTab({ gBrowser, @@ -31,3 +52,16 @@ add_task(async () => { }); }); +add_task(async () => { + await BrowserTestUtils.withNewTab({ + gBrowser, + url: "about:blank", + }, async (browser) => { + info("- setup test preference -"); + await setup_test_preference(); + + info(`- check whether video document in iframe is autoplay -`); + await checkIsIframeVideoDocumentAutoplay(browser); + }); +}); + From a6e0ebd8ef25d0b0b0331819c56bfe8a6385f04e Mon Sep 17 00:00:00 2001 From: Tiberius Oros Date: Tue, 7 Aug 2018 04:46:22 +0300 Subject: [PATCH 20/28] Backed out changeset 502893089232 (bug 1475571) for browser_preferences_usage.js on a CLOSED TREE --- browser/extensions/moz.build | 1 + browser/modules/BrowserUsageTelemetry.jsm | 79 ++++---------------- toolkit/components/search/nsSearchService.js | 7 +- toolkit/components/telemetry/Histograms.json | 2 +- 4 files changed, 16 insertions(+), 73 deletions(-) diff --git a/browser/extensions/moz.build b/browser/extensions/moz.build index 66ac545f478c..c2b67265febe 100644 --- a/browser/extensions/moz.build +++ b/browser/extensions/moz.build @@ -6,6 +6,7 @@ DIRS += [ 'aushelper', + 'followonsearch', 'formautofill', 'onboarding', 'pdfjs', diff --git a/browser/modules/BrowserUsageTelemetry.jsm b/browser/modules/BrowserUsageTelemetry.jsm index 3211c23c9999..a60692631aec 100644 --- a/browser/modules/BrowserUsageTelemetry.jsm +++ b/browser/modules/BrowserUsageTelemetry.jsm @@ -13,13 +13,10 @@ var EXPORTED_SYMBOLS = [ ]; ChromeUtils.import("resource://gre/modules/Services.jsm"); -ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm"); -XPCOMUtils.defineLazyGlobalGetters(this, ["URLSearchParams"]); - // The upper bound for the count of the visited unique domain names. const MAX_UNIQUE_VISITED_DOMAINS = 100; @@ -91,6 +88,7 @@ const URLBAR_SELECTED_RESULT_METHODS = { const MINIMUM_TAB_COUNT_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes, in ms + function getOpenTabsAndWinsCounts() { let tabCount = 0; let winCount = 0; @@ -161,10 +159,6 @@ let URICountListener = { return; } - // Don't include URI and domain counts when in private mode. - let shouldCountURI = !PrivateBrowsingUtils.isWindowPrivate(browser.ownerGlobal) || - Services.prefs.getBoolPref("browser.engagement.total_uri_count.pbm", false); - // Track URI loads, even if they're not http(s). let uriSpec = null; try { @@ -172,9 +166,7 @@ let URICountListener = { } catch (e) { // If we have troubles parsing the spec, still count this as // an unfiltered URI. - if (shouldCountURI) { - Services.telemetry.scalarAdd(UNFILTERED_URI_COUNT_SCALAR_NAME, 1); - } + Services.telemetry.scalarAdd(UNFILTERED_URI_COUNT_SCALAR_NAME, 1); return; } @@ -196,42 +188,12 @@ let URICountListener = { // The URI wasn't from a restored tab. Count it among the unfiltered URIs. // If this is an http(s) URI, this also gets counted by the "total_uri_count" // probe. - if (shouldCountURI) { - Services.telemetry.scalarAdd(UNFILTERED_URI_COUNT_SCALAR_NAME, 1); - } + Services.telemetry.scalarAdd(UNFILTERED_URI_COUNT_SCALAR_NAME, 1); if (!this.isHttpURI(uri)) { return; } - let parseURLResult = Services.search.parseSubmissionURL(uriSpec); - if (parseURLResult.engine) { - this._recordSearchTelemetry(uriSpec, parseURLResult); - } else if (this._urlsQueuedForParsing) { - if (Services.search.isInitialized) { - this._urlsQueuedForParsing = null; - } else { - this._urlsQueuedForParsing.push(uriSpec); - if (this._urlsQueuedForParsing.length == 1) { - Services.search.init(rv => { - if (Components.isSuccessCode(rv)) { - for (let url of this._urlsQueuedForParsing) { - let innerParseURLResult = Services.search.parseSubmissionURL(url); - if (innerParseURLResult.engine) { - this._recordSearchTelemetry(url, innerParseURLResult); - } - } - } - this._urlsQueuedForParsing = null; - }); - } - } - } - - if (!shouldCountURI) { - return; - } - // Update the URI counts. Services.telemetry.scalarAdd(TOTAL_URI_COUNT_SCALAR_NAME, 1); @@ -264,31 +226,6 @@ let URICountListener = { this._domainSet.clear(); }, - _urlsQueuedForParsing: [], - - _recordSearchTelemetry(url, parseURLResult) { - switch (parseURLResult.engine.identifier) { - case "google": - case "google-2018": - let type; - let queries = new URLSearchParams(url.split("?")[1]); - let code = queries.get("client"); - if (code) { - // Detecting follow-on searches for sap is a little tricky. - // There are a few parameters that only show up - // with follow-ons, so we look for those. (oq/ved/ei) - type = queries.has("oq") || queries.has("ved") || queries.has("ei") ? "sap-follow-on" : "sap"; - } else { - type = "organic"; - } - let payload = `google.in-content.${type}:${code || "none"}`; - - let histogram = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS"); - histogram.add(payload); - break; - } - }, - QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]), }; @@ -677,6 +614,11 @@ let BrowserUsageTelemetry = { win.addEventListener("unload", this); win.addEventListener("TabOpen", this, true); + // Don't include URI and domain counts when in private mode. + if (PrivateBrowsingUtils.isWindowPrivate(win) && + !Services.prefs.getBoolPref("browser.engagement.total_uri_count.pbm", false)) { + return; + } win.gBrowser.tabContainer.addEventListener(TAB_RESTORING_TOPIC, this); win.gBrowser.addTabsProgressListener(URICountListener); }, @@ -688,6 +630,11 @@ let BrowserUsageTelemetry = { win.removeEventListener("unload", this); win.removeEventListener("TabOpen", this, true); + // Don't include URI and domain counts when in private mode. + if (PrivateBrowsingUtils.isWindowPrivate(win.defaultView) && + !Services.prefs.getBoolPref("browser.engagement.total_uri_count.pbm", false)) { + return; + } win.defaultView.gBrowser.tabContainer.removeEventListener(TAB_RESTORING_TOPIC, this); win.defaultView.gBrowser.removeTabsProgressListener(URICountListener); }, diff --git a/toolkit/components/search/nsSearchService.js b/toolkit/components/search/nsSearchService.js index bc101d213fa0..91879751bcd0 100644 --- a/toolkit/components/search/nsSearchService.js +++ b/toolkit/components/search/nsSearchService.js @@ -4331,12 +4331,7 @@ SearchService.prototype = { }, parseSubmissionURL: function SRCH_SVC_parseSubmissionURL(aURL) { - if (!gInitialized) { - // If search is not initialized, do nothing. - // This allows us to use this function early in telemetry. - // The only other consumer of this (places) uses it much later. - return gEmptyParseSubmissionResult; - } + this._ensureInitialized(); LOG("parseSubmissionURL: Parsing \"" + aURL + "\"."); if (!this._parseSubmissionMap) { diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index c86cad1d92b4..ef0167ce46a6 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -7827,7 +7827,7 @@ "kind": "count", "keyed": true, "releaseChannelCollection": "opt-out", - "description": "Records search counts for search access points and in content searches. For search access points, the format is: . For in content searches, the format is .in-content:[sap|sap-follow-on|organic]:[code|none]" + "description": "Record the search counts for search engines" }, "SEARCH_RESET_RESULT": { "record_in_processes": ["main", "content"], From 04b50a312d1e433ad8b2ef3f35411f984b5e88fb Mon Sep 17 00:00:00 2001 From: Kyle Machulis Date: Tue, 7 Aug 2018 01:10:31 +0000 Subject: [PATCH 21/28] Bug 1480607 - Remove nsCWebBrowser and nsCWebBrowserPersist; r=nika It doesn't appear these IDL files have had interfaces in them since before the Netscape import, and were mostly just hanging around because they contained some IDs needed elsewhere. Move the IDs somewhere more appropriate and remove files. MozReview-Commit-ID: AINtTerqHu1 Differential Revision: https://phabricator.services.mozilla.com/D2688 --HG-- extra : moz-landing-system : lando --- dom/webbrowserpersist/moz.build | 1 - .../nsCWebBrowserPersist.idl | 15 -------- .../nsIWebBrowserPersist.idl | 13 +++++++ dom/webbrowserpersist/nsWebBrowserPersist.h | 3 +- toolkit/components/browser/moz.build | 1 - toolkit/components/browser/nsCWebBrowser.idl | 34 ------------------- toolkit/components/browser/nsEmbedCID.h | 11 ------ toolkit/components/browser/nsWebBrowser.cpp | 1 - toolkit/components/browser/nsWebBrowser.h | 1 - widget/windows/nsDragService.cpp | 1 - 10 files changed, 14 insertions(+), 67 deletions(-) delete mode 100644 dom/webbrowserpersist/nsCWebBrowserPersist.idl delete mode 100644 toolkit/components/browser/nsCWebBrowser.idl diff --git a/dom/webbrowserpersist/moz.build b/dom/webbrowserpersist/moz.build index 6270b9d578f6..459f999c9537 100644 --- a/dom/webbrowserpersist/moz.build +++ b/dom/webbrowserpersist/moz.build @@ -9,7 +9,6 @@ with Files("**"): BUG_COMPONENT = ("Core", "DOM") XPIDL_SOURCES += [ - 'nsCWebBrowserPersist.idl', 'nsIWebBrowserPersist.idl', 'nsIWebBrowserPersistDocument.idl', ] diff --git a/dom/webbrowserpersist/nsCWebBrowserPersist.idl b/dom/webbrowserpersist/nsCWebBrowserPersist.idl deleted file mode 100644 index 69f2db7caa90..000000000000 --- a/dom/webbrowserpersist/nsCWebBrowserPersist.idl +++ /dev/null @@ -1,15 +0,0 @@ -/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsIWebBrowserPersist.idl" - -%{ C++ -// {7E677795-C582-4cd1-9E8D-8271B3474D2A} -#define NS_WEBBROWSERPERSIST_CID \ -{ 0x7e677795, 0xc582, 0x4cd1, { 0x9e, 0x8d, 0x82, 0x71, 0xb3, 0x47, 0x4d, 0x2a } } -#define NS_WEBBROWSERPERSIST_CONTRACTID \ -"@mozilla.org/embedding/browser/nsWebBrowserPersist;1" -%} diff --git a/dom/webbrowserpersist/nsIWebBrowserPersist.idl b/dom/webbrowserpersist/nsIWebBrowserPersist.idl index 3b3e4adcc065..ed5b907adef0 100644 --- a/dom/webbrowserpersist/nsIWebBrowserPersist.idl +++ b/dom/webbrowserpersist/nsIWebBrowserPersist.idl @@ -261,3 +261,16 @@ interface nsIWebBrowserPersist : nsICancelable */ void cancelSave(); }; + +/** + * We don't export nsWebBrowserPersist.h as a public header, so we need a place + * to put the CID/ContractID. All places uses the WebBrowserPersist include + * nsIWebBrowserPersist.h, so we define our contract IDs here for now. + */ +%{ C++ +// {7E677795-C582-4cd1-9E8D-8271B3474D2A} +#define NS_WEBBROWSERPERSIST_CID \ + { 0x7e677795, 0xc582, 0x4cd1, { 0x9e, 0x8d, 0x82, 0x71, 0xb3, 0x47, 0x4d, 0x2a } } +#define NS_WEBBROWSERPERSIST_CONTRACTID \ + "@mozilla.org/embedding/browser/nsWebBrowserPersist;1" +%} diff --git a/dom/webbrowserpersist/nsWebBrowserPersist.h b/dom/webbrowserpersist/nsWebBrowserPersist.h index 3eb55f0fcd52..9df8647e9dbe 100644 --- a/dom/webbrowserpersist/nsWebBrowserPersist.h +++ b/dom/webbrowserpersist/nsWebBrowserPersist.h @@ -21,6 +21,7 @@ #include "nsIProgressEventSink.h" #include "nsIFile.h" #include "nsIWebProgressListener2.h" +#include "nsIWebBrowserPersist.h" #include "nsIWebBrowserPersistDocument.h" #include "mozilla/UniquePtr.h" @@ -28,8 +29,6 @@ #include "nsHashKeys.h" #include "nsTArray.h" -#include "nsCWebBrowserPersist.h" - class nsIStorageStream; class nsIWebBrowserPersistDocument; diff --git a/toolkit/components/browser/moz.build b/toolkit/components/browser/moz.build index 92ab3fd903d9..bb659a4a9d1e 100644 --- a/toolkit/components/browser/moz.build +++ b/toolkit/components/browser/moz.build @@ -10,7 +10,6 @@ with Files('**'): DIRS += ['build'] XPIDL_SOURCES += [ - 'nsCWebBrowser.idl', 'nsIEmbeddingSiteWindow.idl', 'nsIWebBrowser.idl', 'nsIWebBrowserChrome.idl', diff --git a/toolkit/components/browser/nsCWebBrowser.idl b/toolkit/components/browser/nsCWebBrowser.idl deleted file mode 100644 index 21927f7c7ef8..000000000000 --- a/toolkit/components/browser/nsCWebBrowser.idl +++ /dev/null @@ -1,34 +0,0 @@ -/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsIWebBrowser.idl" -#include "nsIBaseWindow.idl" -#include "nsIScrollable.idl" -#include "nsITextScroll.idl" - -/* -nsCWebBrowser implements: -------------------------- -nsIWebBrowser -nsIDocShellTreeItem -nsIWebNavigation -nsIWebProgress -nsIBaseWindow -nsIScrollable -nsITextScroll -nsIInterfaceRequestor - - -Outwardly communicates with: ----------------------------- -nsIWebBrowserChrome -nsIBaseWindow -nsIInterfaceRequestor -*/ - -%{ C++ -#include "nsEmbedCID.h" -%} diff --git a/toolkit/components/browser/nsEmbedCID.h b/toolkit/components/browser/nsEmbedCID.h index 82fe237631a4..ab182a033f72 100644 --- a/toolkit/components/browser/nsEmbedCID.h +++ b/toolkit/components/browser/nsEmbedCID.h @@ -43,15 +43,4 @@ #define NS_PROMPTSERVICE_CONTRACTID \ "@mozilla.org/embedcomp/prompt-service;1" -/** - * This contract ID should be implemented by password managers to be able to - * override the standard implementation of nsIAuthPrompt2. It will be used as - * a service. - * - * This contract implements the following interfaces: - * nsIPromptFactory - */ -#define NS_PWMGR_AUTHPROMPTFACTORY \ - "@mozilla.org/passwordmanager/authpromptfactory;1" - #endif // NSEMBEDCID_H diff --git a/toolkit/components/browser/nsWebBrowser.cpp b/toolkit/components/browser/nsWebBrowser.cpp index 0f23e2b726c9..ac7630f3fdec 100644 --- a/toolkit/components/browser/nsWebBrowser.cpp +++ b/toolkit/components/browser/nsWebBrowser.cpp @@ -31,7 +31,6 @@ #include "nsISHistoryListener.h" #include "nsIURI.h" #include "nsIWebBrowserPersist.h" -#include "nsCWebBrowserPersist.h" #include "nsIServiceManager.h" #include "nsFocusManager.h" #include "Layers.h" diff --git a/toolkit/components/browser/nsWebBrowser.h b/toolkit/components/browser/nsWebBrowser.h index a378612d679e..c9784a5d8123 100644 --- a/toolkit/components/browser/nsWebBrowser.h +++ b/toolkit/components/browser/nsWebBrowser.h @@ -16,7 +16,6 @@ #include "nsCycleCollectionParticipant.h" // Interfaces needed -#include "nsCWebBrowser.h" #include "nsIBaseWindow.h" #include "nsIDocShell.h" #include "nsIDocShellTreeItem.h" diff --git a/widget/windows/nsDragService.cpp b/widget/windows/nsDragService.cpp index c6d711126a8c..9b5c2be26b36 100644 --- a/widget/windows/nsDragService.cpp +++ b/widget/windows/nsDragService.cpp @@ -29,7 +29,6 @@ #include "nsIScreenManager.h" #include "nsISupportsPrimitives.h" #include "nsIURL.h" -#include "nsCWebBrowserPersist.h" #include "nsToolkit.h" #include "nsCRT.h" #include "nsDirectoryServiceDefs.h" From f3ef96fcc07a3fe51b55021b25935cca285d3a89 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Wed, 1 Aug 2018 22:46:17 -0400 Subject: [PATCH 22/28] Bug 1480306: Fix unused variable variable 'hasLineOfContext' in TokenStream.cpp. r=Waldo MozReview-Commit-ID: EK1IAvCZFwv --HG-- extra : rebase_source : 8ed430ca01927142f77814a81364c6645c3a2581 --- js/src/frontend/TokenStream.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 0157e48bf64c..aa53509bdb2f 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -626,7 +626,8 @@ TokenStreamChars::internalEncodingError(uint8_t releva TokenStreamAnyChars& anyChars = anyCharsAccess(); - if (bool hasLineOfContext = anyChars.fillExcludingContext(&err, offset)) { + bool hasLineOfContext = anyChars.fillExcludingContext(&err, offset); + if (hasLineOfContext) { if (!internalComputeLineOfContext(&err, offset)) break; From 809d66a5587aedaf7c142df716e95bb8bccfdcd8 Mon Sep 17 00:00:00 2001 From: Julian Descottes Date: Tue, 7 Aug 2018 04:47:56 +0000 Subject: [PATCH 23/28] Bug 1480743 - Update styles in aboutdebugging-new to match other about:pages;r=daisuke This duplicates some of the styles from other about:pages, reusing existing variables when possible. Differential Revision: https://phabricator.services.mozilla.com/D2717 --HG-- extra : moz-landing-system : lando --- .../aboutdebugging-new/aboutdebugging.css | 8 +++++- devtools/client/aboutdebugging-new/index.html | 1 + .../aboutdebugging-new/src/components/App.css | 1 + .../src/components/SidebarItem.css | 28 ++++++++++++------- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/devtools/client/aboutdebugging-new/aboutdebugging.css b/devtools/client/aboutdebugging-new/aboutdebugging.css index 4e9d1b88014d..43d02c97fdc9 100644 --- a/devtools/client/aboutdebugging-new/aboutdebugging.css +++ b/devtools/client/aboutdebugging-new/aboutdebugging.css @@ -2,16 +2,22 @@ * 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/. */ -@import "resource://devtools/client/themes/variables.css"; +@import "chrome://global/skin/in-content/common.css"; @import "resource://devtools/client/aboutdebugging-new/src/components/App.css"; @import "resource://devtools/client/aboutdebugging-new/src/components/RuntimeInfo.css"; @import "resource://devtools/client/aboutdebugging-new/src/components/RuntimePage.css"; @import "resource://devtools/client/aboutdebugging-new/src/components/Sidebar.css"; @import "resource://devtools/client/aboutdebugging-new/src/components/SidebarItem.css"; +:root { + /* Import css variables from common.css */ + --text-color: var(--in-content-page-color); +} + html, body { margin: 0; padding: 0; + color: var(--text-color); } ul { diff --git a/devtools/client/aboutdebugging-new/index.html b/devtools/client/aboutdebugging-new/index.html index 1420da8d533f..d0196bfa402f 100644 --- a/devtools/client/aboutdebugging-new/index.html +++ b/devtools/client/aboutdebugging-new/index.html @@ -5,6 +5,7 @@ + diff --git a/devtools/client/aboutdebugging-new/src/components/App.css b/devtools/client/aboutdebugging-new/src/components/App.css index 7eca3c724fc3..b46e423ab94f 100644 --- a/devtools/client/aboutdebugging-new/src/components/App.css +++ b/devtools/client/aboutdebugging-new/src/components/App.css @@ -14,6 +14,7 @@ .app { display: grid; font-size: 15px; + grid-column-gap: 40px; grid-template-columns: 240px auto; height: 100vh; overflow: hidden; diff --git a/devtools/client/aboutdebugging-new/src/components/SidebarItem.css b/devtools/client/aboutdebugging-new/src/components/SidebarItem.css index a2a0dd7bc7f9..1140cc15be39 100644 --- a/devtools/client/aboutdebugging-new/src/components/SidebarItem.css +++ b/devtools/client/aboutdebugging-new/src/components/SidebarItem.css @@ -3,20 +3,32 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ .sidebar-item { - --sidebar-item-color: var(--grey-50); - --sidebar-item-selected-color: var(--blue-55); + /* Import css variables from common.css */ + --sidebar-text-color: var(--in-content-category-text); + --sidebar-selected-color: var(--in-content-category-text-selected); + --sidebar-background-hover: var(--in-content-category-background-hover); } .sidebar-item { - color: var(--sidebar-item-color); align-items: center; + border-radius: 2px; + color: var(--sidebar-text-color); display: flex; - font-size: 20px; + font-size: 16px; + height: 48px; margin-inline-start: 24px; + padding-inline-end: 10px; + padding-inline-start: 10px; + transition: background-color 150ms; + -moz-user-select: none; +} + +.sidebar-item:hover { + background-color: var(--sidebar-background-hover); } .sidebar-item__icon { - fill: var(--sidebar-item-color); + fill: currentColor; height: 24px; margin-inline-end: 9px; width: 24px; @@ -24,9 +36,5 @@ } .sidebar-item--selected { - color: var(--sidebar-item-selected-color); -} - -.sidebar-item__icon--selected { - fill: var(--sidebar-item-selected-color); + color: var(--sidebar-selected-color); } From d1f26ef91d405184ea98edbedb5c33160dd67efd Mon Sep 17 00:00:00 2001 From: Julian Descottes Date: Tue, 7 Aug 2018 04:56:56 +0000 Subject: [PATCH 24/28] Bug 1480789 - Add Connect page to new aboutdebugging;r=daisuke Differential Revision: https://phabricator.services.mozilla.com/D2724 --HG-- extra : moz-landing-system : lando --- .../aboutdebugging-new/aboutdebugging.css | 4 +- .../aboutdebugging-new/src/components/App.css | 8 +- .../aboutdebugging-new/src/components/App.js | 3 + .../src/components/ConnectPage.css | 24 +++++ .../src/components/ConnectPage.js | 92 +++++++++++++++++++ .../src/components/RuntimePage.css | 7 -- .../src/components/RuntimePage.js | 2 +- .../src/components/moz.build | 3 +- 8 files changed, 130 insertions(+), 13 deletions(-) create mode 100644 devtools/client/aboutdebugging-new/src/components/ConnectPage.css create mode 100644 devtools/client/aboutdebugging-new/src/components/ConnectPage.js delete mode 100644 devtools/client/aboutdebugging-new/src/components/RuntimePage.css diff --git a/devtools/client/aboutdebugging-new/aboutdebugging.css b/devtools/client/aboutdebugging-new/aboutdebugging.css index 43d02c97fdc9..6e00515d7649 100644 --- a/devtools/client/aboutdebugging-new/aboutdebugging.css +++ b/devtools/client/aboutdebugging-new/aboutdebugging.css @@ -4,8 +4,8 @@ @import "chrome://global/skin/in-content/common.css"; @import "resource://devtools/client/aboutdebugging-new/src/components/App.css"; +@import "resource://devtools/client/aboutdebugging-new/src/components/ConnectPage.css"; @import "resource://devtools/client/aboutdebugging-new/src/components/RuntimeInfo.css"; -@import "resource://devtools/client/aboutdebugging-new/src/components/RuntimePage.css"; @import "resource://devtools/client/aboutdebugging-new/src/components/Sidebar.css"; @import "resource://devtools/client/aboutdebugging-new/src/components/SidebarItem.css"; @@ -24,4 +24,4 @@ ul { list-style: none; margin: 0; padding: 0; -} +} \ No newline at end of file diff --git a/devtools/client/aboutdebugging-new/src/components/App.css b/devtools/client/aboutdebugging-new/src/components/App.css index b46e423ab94f..152e21d9688d 100644 --- a/devtools/client/aboutdebugging-new/src/components/App.css +++ b/devtools/client/aboutdebugging-new/src/components/App.css @@ -3,10 +3,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* - * The current layout of the about:debugging is + * The current layout of about:debugging is * * +-------------+-------------------------------+ - * | Sidebar | RuntimePage | + * | Sidebar | Page (Runtime or Connect) | * | (240px) | | * | | | * +-------------+-------------------------------+ @@ -20,3 +20,7 @@ overflow: hidden; width: 100vw; } + +.page { + padding-block-start: 60px; +} diff --git a/devtools/client/aboutdebugging-new/src/components/App.js b/devtools/client/aboutdebugging-new/src/components/App.js index 88f528e50fe3..753250395f06 100644 --- a/devtools/client/aboutdebugging-new/src/components/App.js +++ b/devtools/client/aboutdebugging-new/src/components/App.js @@ -11,6 +11,7 @@ const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); const { PAGES } = require("../constants"); +const ConnectPage = createFactory(require("./ConnectPage")); const RuntimePage = createFactory(require("./RuntimePage")); const Sidebar = createFactory(require("./Sidebar")); @@ -29,6 +30,8 @@ class App extends PureComponent { switch (this.props.selectedPage) { case PAGES.THIS_FIREFOX: return RuntimePage(); + case PAGES.CONNECT: + return ConnectPage(); default: // Invalid page, blank. return null; diff --git a/devtools/client/aboutdebugging-new/src/components/ConnectPage.css b/devtools/client/aboutdebugging-new/src/components/ConnectPage.css new file mode 100644 index 000000000000..569b6ce3ad30 --- /dev/null +++ b/devtools/client/aboutdebugging-new/src/components/ConnectPage.css @@ -0,0 +1,24 @@ +/* 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/. */ + +.connect-page__steps { + list-style-type: decimal; + margin-inline-start: 40px; + line-height: 1.5em; + margin-block-end: 20px; +} + +.connect-page__step { + padding-inline-start: 20px; +} + +.connect-page__section__title { + display: flex; +} + +.connect-page__section__icon { + width: 32px; + height: 32px; + margin-inline-end: 5px; +} diff --git a/devtools/client/aboutdebugging-new/src/components/ConnectPage.js b/devtools/client/aboutdebugging-new/src/components/ConnectPage.js new file mode 100644 index 000000000000..00cb5024978d --- /dev/null +++ b/devtools/client/aboutdebugging-new/src/components/ConnectPage.js @@ -0,0 +1,92 @@ +/* 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"; + +const { PureComponent } = require("devtools/client/shared/vendor/react"); +const dom = require("devtools/client/shared/vendor/react-dom-factories"); + +const USB_ICON_SRC = "chrome://devtools/skin/images/aboutdebugging-connect-icon.svg"; +const WIFI_ICON_SRC = "chrome://devtools/skin/images/aboutdebugging-connect-icon.svg"; + +class RuntimePage extends PureComponent { + renderSteps(steps) { + return dom.ul( + { + className: "connect-page__steps" + }, + steps.map(step => dom.li( + { + className: "connect-page__step" + }, + step) + ) + ); + } + + renderWifi() { + return dom.section( + {}, + dom.h2( + { + className: "connect-page__section__title" + }, + dom.img( + { + className: "connect-page__section__icon", + src: WIFI_ICON_SRC + } + ), + "Via WiFi (Recommended)" + ), + this.renderSteps([ + "Ensure that your browser and device are on the same network", + "Open Firefox for Android", + "Go to Options -> Settings -> Advanced", + "Enable Remote Debugging via WiFi in the Developer Tools section", + ]) + ); + } + + renderUsb() { + return dom.section( + {}, + dom.h2( + { + className: "connect-page__section__title" + }, + dom.img( + { + className: "connect-page__section__icon", + src: USB_ICON_SRC + } + ), + "Via USB" + ), + this.renderSteps([ + "Enable Developer menu on your Android device", + "Enable USB Debugging on the Android Developer Menu", + "Connect the USB Device to your computer", + ]) + ); + } + + render() { + return dom.article( + { + className: "page connect-page", + }, + dom.h1( + { + className: "connect-page__title" + }, + "Connect a Device" + ), + this.renderWifi(), + this.renderUsb(), + ); + } +} + +module.exports = RuntimePage; diff --git a/devtools/client/aboutdebugging-new/src/components/RuntimePage.css b/devtools/client/aboutdebugging-new/src/components/RuntimePage.css deleted file mode 100644 index de6d07513150..000000000000 --- a/devtools/client/aboutdebugging-new/src/components/RuntimePage.css +++ /dev/null @@ -1,7 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -.runtime-page { - padding-block-start: 60px; -} diff --git a/devtools/client/aboutdebugging-new/src/components/RuntimePage.js b/devtools/client/aboutdebugging-new/src/components/RuntimePage.js index 08575538d005..b465bcb64b9f 100644 --- a/devtools/client/aboutdebugging-new/src/components/RuntimePage.js +++ b/devtools/client/aboutdebugging-new/src/components/RuntimePage.js @@ -15,7 +15,7 @@ class RuntimePage extends PureComponent { render() { return dom.article( { - className: "runtime-page", + className: "page", }, RuntimeInfo({ icon: "chrome://branding/content/icon64.png", diff --git a/devtools/client/aboutdebugging-new/src/components/moz.build b/devtools/client/aboutdebugging-new/src/components/moz.build index f61c9fc7ba88..e11f957d9df9 100644 --- a/devtools/client/aboutdebugging-new/src/components/moz.build +++ b/devtools/client/aboutdebugging-new/src/components/moz.build @@ -5,9 +5,10 @@ DevToolsModules( 'App.css', 'App.js', + 'ConnectPage.css', + 'ConnectPage.js', 'RuntimeInfo.css', 'RuntimeInfo.js', - 'RuntimePage.css', 'RuntimePage.js', 'Sidebar.css', 'Sidebar.js', From e3cf7e35dd41a38bb8855657f3a4a036611cb42a Mon Sep 17 00:00:00 2001 From: Nicolas Chevobbe Date: Tue, 7 Aug 2018 05:07:31 +0000 Subject: [PATCH 25/28] Bug 1478252 - Enable client/shared/test/browser_outputparser.js in e10s; r=jdescottes. The test was disabled for intermittent failure, but I did not managed to make it fail with --verify. There was a fixed needed in the test for the angle since the property used there was deprecated. Differential Revision: https://phabricator.services.mozilla.com/D2784 --HG-- extra : moz-landing-system : lando --- devtools/client/shared/test/browser.ini | 1 - devtools/client/shared/test/browser_outputparser.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/devtools/client/shared/test/browser.ini b/devtools/client/shared/test/browser.ini index a79c7efaa575..9b0a4ddcfccc 100644 --- a/devtools/client/shared/test/browser.ini +++ b/devtools/client/shared/test/browser.ini @@ -170,7 +170,6 @@ skip-if = verify [browser_num-l10n.js] [browser_options-view-01.js] [browser_outputparser.js] -skip-if = e10s # Test intermittently fails with e10s. Bug 1124162. [browser_poller.js] [browser_prefs-01.js] [browser_prefs-02.js] diff --git a/devtools/client/shared/test/browser_outputparser.js b/devtools/client/shared/test/browser_outputparser.js index f3a34639f68d..67f65b0acbcf 100644 --- a/devtools/client/shared/test/browser_outputparser.js +++ b/devtools/client/shared/test/browser_outputparser.js @@ -283,7 +283,7 @@ function testParseFilter(doc, parser) { } function testParseAngle(doc, parser) { - let frag = parser.parseCssProperty("image-orientation", "90deg", { + let frag = parser.parseCssProperty("rotate", "90deg", { angleSwatchClass: "test-angleswatch" }); From 6647aa6cc004caf24808a46c40af0b6a11f9c19d Mon Sep 17 00:00:00 2001 From: James Teh Date: Thu, 2 Aug 2018 16:25:09 +1000 Subject: [PATCH 26/28] Bug 1480058 part 1: Expose states for aria-selected/aria-multiselectable on XUL tab/tabs. r=surkov MozReview-Commit-ID: JeV5vBffQIq --HG-- extra : rebase_source : 3e6979e1e1995e62951250937d0c28f1128dcbac --- .../tests/mochitest/states/test_aria.xul | 16 ++++++++++++++ accessible/xul/XULTabAccessible.cpp | 22 +++++++++++++++++++ accessible/xul/XULTabAccessible.h | 2 ++ 3 files changed, 40 insertions(+) diff --git a/accessible/tests/mochitest/states/test_aria.xul b/accessible/tests/mochitest/states/test_aria.xul index b15cc7781569..f642ab1cf4a2 100644 --- a/accessible/tests/mochitest/states/test_aria.xul +++ b/accessible/tests/mochitest/states/test_aria.xul @@ -24,6 +24,14 @@ testStates("pressed_button", STATE_PRESSED, 0, STATE_CHECKABLE); testStates("pressed_menu_button", STATE_PRESSED | STATE_HASPOPUP, 0, STATE_CHECKABLE); + testStates("tabs", STATE_MULTISELECTABLE); + // Make sure XUL selection works, since aria-selected defaults to false. + testStates("tab1", STATE_SELECTED); + // aria-selected="true". + testStates("tab2", STATE_SELECTED); + // Neither. + testStates("tab3", 0, 0, STATE_SELECTED); + SimpleTest.finish() } @@ -53,6 +61,14 @@ + + + + + + + + diff --git a/accessible/xul/XULTabAccessible.cpp b/accessible/xul/XULTabAccessible.cpp index 5c2b099f939e..16ac5068a7d3 100644 --- a/accessible/xul/XULTabAccessible.cpp +++ b/accessible/xul/XULTabAccessible.cpp @@ -5,6 +5,7 @@ #include "XULTabAccessible.h" +#include "ARIAMap.h" #include "nsAccUtils.h" #include "Relation.h" #include "Role.h" @@ -123,6 +124,17 @@ XULTabAccessible::RelationByType(RelationType aType) const return rel; } +void +XULTabAccessible::ApplyARIAState(uint64_t* aState) const +{ + HyperTextAccessibleWrap::ApplyARIAState(aState); + // XUL tab has an implicit ARIA role of tab, so support aria-selected. + // Don't use aria::MapToState because that will set the SELECTABLE state + // even if the tab is disabled. + if (nsAccUtils::IsARIASelected(this)) { + *aState |= states::SELECTED; + } +} //////////////////////////////////////////////////////////////////////////////// // XULTabsAccessible @@ -159,6 +171,16 @@ XULTabsAccessible::NativeName(nsString& aName) const return eNameOK; } +void +XULTabsAccessible::ApplyARIAState(uint64_t* aState) const +{ + XULSelectControlAccessible::ApplyARIAState(aState); + // XUL tabs has an implicit ARIA role of tablist, so support + // aria-multiselectable. + MOZ_ASSERT(Elm()); + aria::MapToState(aria::eARIAMultiSelectable, Elm(), aState); +} + //////////////////////////////////////////////////////////////////////////////// // XULTabpanelsAccessible diff --git a/accessible/xul/XULTabAccessible.h b/accessible/xul/XULTabAccessible.h index 7ee132e7a9c4..b84035002af8 100644 --- a/accessible/xul/XULTabAccessible.h +++ b/accessible/xul/XULTabAccessible.h @@ -29,6 +29,7 @@ public: virtual uint64_t NativeState() const override; virtual uint64_t NativeInteractiveState() const override; virtual Relation RelationByType(RelationType aType) const override; + virtual void ApplyARIAState(uint64_t* aState) const override; // ActionAccessible virtual uint8_t ActionCount() const override; @@ -48,6 +49,7 @@ public: // Accessible virtual void Value(nsString& aValue) const override; virtual a11y::role NativeRole() const override; + virtual void ApplyARIAState(uint64_t* aState) const override; // ActionAccessible virtual uint8_t ActionCount() const override; From 46ba6df24976b5d78dca73ad16e832cf30961c88 Mon Sep 17 00:00:00 2001 From: James Teh Date: Thu, 2 Aug 2018 16:27:18 +1000 Subject: [PATCH 27/28] Bug 1480058 part 2: Add nsAccUtils::IsARIAMultiSelectable and make nsAccUtils::ISARIASelected const. r=surkov We need to be able to call these methods from const methods, so they must take a const Accessible*. MozReview-Commit-ID: CDsWZG1ik31 --HG-- extra : rebase_source : 4721669afcd9101cb017361bd8f87fb8a860664a --- accessible/base/nsAccUtils.cpp | 10 ++++------ accessible/base/nsAccUtils.h | 18 +++++++++++++++++- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/accessible/base/nsAccUtils.cpp b/accessible/base/nsAccUtils.cpp index 275f88300266..78fd8bd7ee7f 100644 --- a/accessible/base/nsAccUtils.cpp +++ b/accessible/base/nsAccUtils.cpp @@ -244,13 +244,11 @@ nsAccUtils::GetSelectableContainer(Accessible* aAccessible, uint64_t aState) } bool -nsAccUtils::IsARIASelected(Accessible* aAccessible) +nsAccUtils::IsDOMAttrTrue(const Accessible* aAccessible, nsAtom* aAttr) { - if (!aAccessible->GetContent()->IsElement()) - return false; - return aAccessible->GetContent()->AsElement()-> - AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_selected, - nsGkAtoms::_true, eCaseMatters); + dom::Element* el = aAccessible->Elm(); + return el && el->AttrValueIs(kNameSpaceID_None, aAttr, nsGkAtoms::_true, + eCaseMatters); } Accessible* diff --git a/accessible/base/nsAccUtils.h b/accessible/base/nsAccUtils.h index da80fc8a4724..bacbb5127e20 100644 --- a/accessible/base/nsAccUtils.h +++ b/accessible/base/nsAccUtils.h @@ -137,11 +137,27 @@ public: static Accessible* TableFor(Accessible* aRow); + /** + * Return true if the DOM node of a given accessible has a given attribute + * with a value of "true". + */ + static bool IsDOMAttrTrue(const Accessible* aAccessible, nsAtom* aAttr); + /** * Return true if the DOM node of given accessible has aria-selected="true" * attribute. */ - static bool IsARIASelected(Accessible* aAccessible); + static inline bool IsARIASelected(const Accessible* aAccessible) { + return IsDOMAttrTrue(aAccessible, nsGkAtoms::aria_selected); + } + + /** + * Return true if the DOM node of given accessible has + * aria-multiselectable="true" attribute. + */ + static inline bool IsARIAMultiSelectable(const Accessible* aAccessible) { + return IsDOMAttrTrue(aAccessible, nsGkAtoms::aria_multiselectable); + } /** * Converts the given coordinates to coordinates relative screen. From 5a83999558459adf11d3f814de194d8db2b6017e Mon Sep 17 00:00:00 2001 From: James Teh Date: Fri, 3 Aug 2018 13:31:43 +1000 Subject: [PATCH 28/28] Bug 1480058 part 3: Support accessible selection retrieval methods for XUL tabs with aria-multiselectable. r=surkov The XULSelectControlAccessible selection methods don't handle ARIA selection. Therefore, if aria-multiselectable is set, use the base implementation of the selection retrieval methods. We don't bother overriding the selection setting methods because implementations (e.g. browser tabs) don't support setting of aria-selected by the a11y engine and we still want to be able to set the primary selected item according to XUL. Being able to retrieve multiple selection programmatically is far more important than being able to set it. MozReview-Commit-ID: CmVp9KyieMY --HG-- extra : rebase_source : e3fa93aad4726b322956babb5422dceebfa0fbb2 --- .../tests/mochitest/selectable/a11y.ini | 1 + .../tests/mochitest/selectable/test_tabs.xul | 94 +++++++++++++++++++ accessible/xul/XULTabAccessible.cpp | 50 ++++++++++ accessible/xul/XULTabAccessible.h | 6 ++ 4 files changed, 151 insertions(+) create mode 100644 accessible/tests/mochitest/selectable/test_tabs.xul diff --git a/accessible/tests/mochitest/selectable/a11y.ini b/accessible/tests/mochitest/selectable/a11y.ini index 4fc11fee84fa..fcdd5b67a613 100644 --- a/accessible/tests/mochitest/selectable/a11y.ini +++ b/accessible/tests/mochitest/selectable/a11y.ini @@ -8,4 +8,5 @@ support-files = [test_menu.xul] [test_menulist.xul] [test_select.html] +[test_tabs.xul] [test_tree.xul] diff --git a/accessible/tests/mochitest/selectable/test_tabs.xul b/accessible/tests/mochitest/selectable/test_tabs.xul new file mode 100644 index 000000000000..76820c98fddc --- /dev/null +++ b/accessible/tests/mochitest/selectable/test_tabs.xul @@ -0,0 +1,94 @@ + + + + + + + + + + + + Mozilla Bug 1480058 +
+

+ +
+      
+ + + + + + + + + + + + + + + + + + +
+ +
diff --git a/accessible/xul/XULTabAccessible.cpp b/accessible/xul/XULTabAccessible.cpp index 16ac5068a7d3..68f4d7ae97d9 100644 --- a/accessible/xul/XULTabAccessible.cpp +++ b/accessible/xul/XULTabAccessible.cpp @@ -181,6 +181,56 @@ XULTabsAccessible::ApplyARIAState(uint64_t* aState) const aria::MapToState(aria::eARIAMultiSelectable, Elm(), aState); } +// XUL tabs is a single selection control and doesn't allow ARIA selection. +// However, if aria-multiselectable is used, it becomes a multiselectable +// control, where both native and ARIA markup are used to set selection. +// Therefore, if aria-multiselectable is set, use the base implementation of +// the selection retrieval methods in order to support ARIA selection. +// We don't bother overriding the selection setting methods because +// current front-end code using XUL tabs doesn't support setting of +// aria-selected by the a11y engine and we still want to be able to set the +// primary selected item according to XUL. + +void +XULTabsAccessible::SelectedItems(nsTArray* aItems) +{ + if (nsAccUtils::IsARIAMultiSelectable(this)) { + AccessibleWrap::SelectedItems(aItems); + } else { + XULSelectControlAccessible::SelectedItems(aItems); + } +} + +Accessible* +XULTabsAccessible::GetSelectedItem(uint32_t aIndex) +{ + if (nsAccUtils::IsARIAMultiSelectable(this)) { + return AccessibleWrap::GetSelectedItem(aIndex); + } + + return XULSelectControlAccessible::GetSelectedItem(aIndex); +} + +uint32_t +XULTabsAccessible::SelectedItemCount() +{ + if (nsAccUtils::IsARIAMultiSelectable(this)) { + return AccessibleWrap::SelectedItemCount(); + } + + return XULSelectControlAccessible::SelectedItemCount(); +} + +bool +XULTabsAccessible::IsItemSelected(uint32_t aIndex) +{ + if (nsAccUtils::IsARIAMultiSelectable(this)) { + return AccessibleWrap::IsItemSelected(aIndex); + } + + return XULSelectControlAccessible::IsItemSelected(aIndex); +} + //////////////////////////////////////////////////////////////////////////////// // XULTabpanelsAccessible diff --git a/accessible/xul/XULTabAccessible.h b/accessible/xul/XULTabAccessible.h index b84035002af8..db68b9502c79 100644 --- a/accessible/xul/XULTabAccessible.h +++ b/accessible/xul/XULTabAccessible.h @@ -54,6 +54,12 @@ public: // ActionAccessible virtual uint8_t ActionCount() const override; + // SelectAccessible + virtual void SelectedItems(nsTArray* aItems) override; + virtual uint32_t SelectedItemCount() override; + virtual Accessible* GetSelectedItem(uint32_t aIndex) override; + virtual bool IsItemSelected(uint32_t aIndex) override; + protected: // Accessible virtual ENameValueFlag NativeName(nsString& aName) const override;