merge mozilla-central to mozilla-inbound

This commit is contained in:
Sebastian Hengst 2018-03-01 20:32:20 +02:00
Родитель eba2944a35 61d400da1c
Коммит 118e03a936
267 изменённых файлов: 6403 добавлений и 3331 удалений

Просмотреть файл

@ -139,3 +139,4 @@ f7e9777221a34f9f23c2e4933307eb38b621b679 FIREFOX_NIGHTLY_57_END
40a14ca1cf04499f398e4cb8ba359b39eae4e216 FIREFOX_BETA_58_BASE
1f91961bb79ad06fd4caef9e5dfd546afd5bf42c FIREFOX_NIGHTLY_58_END
5faab9e619901b1513fd4ca137747231be550def FIREFOX_NIGHTLY_59_END
e33efdb3e1517d521deb949de3fcd6d9946ea440 FIREFOX_BETA_60_BASE

Просмотреть файл

@ -2,10 +2,14 @@
* 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/. */
XULMAP_TYPE(browser, OuterDocAccessible)
XULMAP_TYPE(button, XULButtonAccessible)
XULMAP_TYPE(checkbox, XULCheckboxAccessible)
XULMAP_TYPE(dropMarker, XULDropmarkerAccessible)
XULMAP_TYPE(editor, OuterDocAccessible)
XULMAP_TYPE(findbar, XULToolbarAccessible)
XULMAP_TYPE(groupbox, XULGroupboxAccessible)
XULMAP_TYPE(iframe, OuterDocAccessible)
XULMAP_TYPE(listbox, XULListboxAccessibleWrap)
XULMAP_TYPE(listhead, XULColumAccessible)
XULMAP_TYPE(listheader, XULColumnItemAccessible)
@ -22,6 +26,7 @@ XULMAP_TYPE(radio, XULRadioButtonAccessible)
XULMAP_TYPE(radiogroup, XULRadioGroupAccessible)
XULMAP_TYPE(richlistbox, XULListboxAccessibleWrap)
XULMAP_TYPE(richlistitem, XULListitemAccessible)
XULMAP_TYPE(scale, XULSliderAccessible)
XULMAP_TYPE(statusbar, XULStatusBarAccessible)
XULMAP_TYPE(tab, XULTabAccessible)
XULMAP_TYPE(tabpanels, XULTabpanelsAccessible)
@ -33,6 +38,7 @@ XULMAP_TYPE(treecol, XULColumnItemAccessible)
XULMAP_TYPE(treecolpicker, XULButtonAccessible)
XULMAP_TYPE(treecols, XULTreeColumAccessible)
XULMAP_TYPE(toolbar, XULToolbarAccessible)
XULMAP_TYPE(toolbarbutton, XULToolbarButtonAccessible)
XULMAP_TYPE(tooltip, XULTooltipAccessible)
XULMAP(
@ -73,6 +79,44 @@ XULMAP(
}
)
XULMAP(
menupopup,
[](nsIContent* aContent, Accessible* aContext) {
return CreateMenupopupAccessible(aContent, aContext);
}
)
XULMAP(
popup,
[](nsIContent* aContent, Accessible* aContext) {
return CreateMenupopupAccessible(aContent, aContext);
}
)
XULMAP(
textbox,
[](nsIContent* aContent, Accessible* aContext) -> Accessible* {
if (aContent->IsElement() &&
aContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
nsGkAtoms::autocomplete, eIgnoreCase)) {
return new XULComboboxAccessible(aContent, aContext->Document());
}
return new EnumRoleAccessible<roles::SECTION>(aContent, aContext->Document());
}
)
XULMAP(
thumb,
[](nsIContent* aContent, Accessible* aContext) -> Accessible* {
if (aContent->IsElement() &&
aContent->AsElement()->ClassList()->Contains(NS_LITERAL_STRING("scale-thumb"))) {
return new XULThumbAccessible(aContent, aContext->Document());
}
return nullptr;
}
)
XULMAP(
tree,
[](nsIContent* aContent, Accessible* aContext) -> Accessible* {

Просмотреть файл

@ -23,6 +23,7 @@
#include "nsAccUtils.h"
#include "nsArrayUtils.h"
#include "nsAttrName.h"
#include "nsDOMTokenList.h"
#include "nsEventShell.h"
#include "nsIURI.h"
#include "nsTextFormatter.h"
@ -143,6 +144,28 @@ MustBeAccessible(nsIContent* aContent, DocAccessible* aDocument)
return false;
}
/**
* Used by XULMap.h to map both menupopup and popup elements
*/
#ifdef MOZ_XUL
Accessible*
CreateMenupopupAccessible(nsIContent* aContent, Accessible* aContext)
{
#ifdef MOZ_ACCESSIBILITY_ATK
// ATK considers this node to be redundant when within menubars, and it makes menu
// navigation with assistive technologies more difficult
// XXX In the future we will should this for consistency across the nsIAccessible
// implementations on each platform for a consistent scripting environment, but
// then strip out redundant accessibles in the AccessibleWrap class for each platform.
nsIContent *parent = aContent->GetParent();
if (parent && parent->IsXULElement(nsGkAtoms::menu))
return nullptr;
#endif
return new XULMenupopupAccessible(aContent, aContext->Document());
}
#endif
////////////////////////////////////////////////////////////////////////////////
// Accessible constructors
@ -1449,46 +1472,21 @@ nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
{
nsAutoString role;
nsCoreUtils::XBLBindingRole(aContent, role);
if (role.IsEmpty() || role.EqualsLiteral("none"))
if (role.IsEmpty())
return nullptr;
if (role.EqualsLiteral("outerdoc")) {
RefPtr<Accessible> accessible = new OuterDocAccessible(aContent, aDoc);
return accessible.forget();
}
RefPtr<Accessible> accessible;
#ifdef MOZ_XUL
// XUL controls
if (role.EqualsLiteral("xul:button")) {
accessible = new XULButtonAccessible(aContent, aDoc);
} else if (role.EqualsLiteral("xul:colorpicker")) {
if (role.EqualsLiteral("xul:colorpicker")) {
accessible = new XULColorPickerAccessible(aContent, aDoc);
} else if (role.EqualsLiteral("xul:colorpickertile")) {
accessible = new XULColorPickerTileAccessible(aContent, aDoc);
} else if (role.EqualsLiteral("xul:combobox")) {
accessible = new XULComboboxAccessible(aContent, aDoc);
} else if (role.EqualsLiteral("xul:link")) {
accessible = new XULLinkAccessible(aContent, aDoc);
} else if (role.EqualsLiteral("xul:menupopup")) {
#ifdef MOZ_ACCESSIBILITY_ATK
// ATK considers this node to be redundant when within menubars, and it makes menu
// navigation with assistive technologies more difficult
// XXX In the future we will should this for consistency across the nsIAccessible
// implementations on each platform for a consistent scripting environment, but
// then strip out redundant accessibles in the AccessibleWrap class for each platform.
nsIContent *parent = aContent->GetParent();
if (parent && parent->IsXULElement(nsGkAtoms::menu))
return nullptr;
#endif
accessible = new XULMenupopupAccessible(aContent, aDoc);
} else if(role.EqualsLiteral("xul:pane")) {
accessible = new EnumRoleAccessible<roles::PANE>(aContent, aDoc);
@ -1501,21 +1499,9 @@ nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
else
accessible = new EnumRoleAccessible<roles::PANE>(aContent, aDoc);
} else if (role.EqualsLiteral("xul:scale")) {
accessible = new XULSliderAccessible(aContent, aDoc);
} else if (role.EqualsLiteral("xul:text")) {
accessible = new XULLabelAccessible(aContent, aDoc);
} else if (role.EqualsLiteral("xul:textbox")) {
accessible = new EnumRoleAccessible<roles::SECTION>(aContent, aDoc);
} else if (role.EqualsLiteral("xul:thumb")) {
accessible = new XULThumbAccessible(aContent, aDoc);
} else if (role.EqualsLiteral("xul:toolbarbutton")) {
accessible = new XULToolbarButtonAccessible(aContent, aDoc);
}
#endif // MOZ_XUL

Просмотреть файл

@ -464,6 +464,13 @@ HandlerProvider::MarshalAs(REFIID aIid)
return aIid;
}
HRESULT
HandlerProvider::DisconnectHandlerRemotes()
{
IUnknown* unk = static_cast<IGeckoBackChannel*>(this);
return ::CoDisconnectObject(unk, 0);
}
REFIID
HandlerProvider::GetEffectiveOutParamIid(REFIID aCallIid,
ULONG aCallMethod)

Просмотреть файл

@ -47,6 +47,7 @@ public:
STDMETHODIMP WriteHandlerPayload(NotNull<mscom::IInterceptor*> aInterceptor,
NotNull<IStream*> aStream) override;
STDMETHODIMP_(REFIID) MarshalAs(REFIID aIid) override;
STDMETHODIMP DisconnectHandlerRemotes() override;
STDMETHODIMP_(REFIID) GetEffectiveOutParamIid(REFIID aCallIid,
ULONG aCallMethod) override;
STDMETHODIMP NewInstance(REFIID aIid,

Просмотреть файл

@ -46,6 +46,7 @@
#include "mozilla/ReverseIterator.h"
#include "nsIXULRuntime.h"
#include "mozilla/mscom/AsyncInvoker.h"
#include "mozilla/mscom/Interceptor.h"
#include "oleacc.h"
@ -103,6 +104,24 @@ AccessibleWrap::Shutdown()
}
}
if (XRE_IsContentProcess()) {
// Bug 1434822: To improve performance for cross-process COM, we disable COM
// garbage collection. However, this means we never receive Release calls
// from clients, so defunct accessibles can never be deleted. Since we
// know when an accessible is shutting down, we can work around this by
// forcing COM to disconnect this object from all of its remote clients,
// which will cause associated references to be released.
IUnknown* unk = static_cast<IAccessible*>(this);
mscom::Interceptor::DisconnectRemotesForTarget(unk);
// If an accessible was retrieved via IAccessibleHypertext::hyperlink*,
// it will have a different Interceptor that won't be matched by the above
// call, even though it's the same object. Therefore, call it again with
// the IAccessibleHyperlink pointer. We can remove this horrible hack once
// bug 1440267 is fixed.
unk = static_cast<IAccessibleHyperlink*>(this);
mscom::Interceptor::DisconnectRemotesForTarget(unk);
}
Accessible::Shutdown();
}

Просмотреть файл

@ -169,20 +169,16 @@ XULButtonAccessible::IsAcceptableChild(nsIContent* aEl) const
// buttons can have button (@type="menu-button") and popup accessibles
// (@type="menu-button", @type="menu" or columnpicker.
// XXX: no children until the button is menu button. Probably it's not
// totally correct but in general AT wants to have leaf buttons.
nsAutoString role;
nsCoreUtils::XBLBindingRole(aEl, role);
// Get an accessible for menupopup or panel elements.
if (role.EqualsLiteral("xul:menupopup")) {
// Get an accessible for menupopup or popup elements.
if (aEl->IsXULElement(nsGkAtoms::menupopup) ||
aEl->IsXULElement(nsGkAtoms::popup)) {
return true;
}
// Button type="menu-button" contains a real button. Get an accessible
// Button and toolbarbutton are real buttons. Get an accessible
// for it. Ignore dropmarker button which is placed as a last child.
if ((!role.EqualsLiteral("xul:button") &&
!role.EqualsLiteral("xul:toolbarbutton")) ||
if ((!aEl->IsXULElement(nsGkAtoms::button) &&
!aEl->IsXULElement(nsGkAtoms::toolbarbutton)) ||
aEl->IsXULElement(nsGkAtoms::dropMarker)) {
return false;
}

Просмотреть файл

@ -212,6 +212,7 @@
observes="viewHistorySidebar"
label="&historyButton.label;"/>
<menuitem id="menu_tabsSidebar"
class="sync-ui-item"
observes="viewTabsSidebar"
label="&syncedTabs.sidebar.label;"/>
</menupopup>

Просмотреть файл

@ -298,7 +298,7 @@
</toolbarbutton>
<toolbarbutton id="sidebar-switcher-tabs"
label="&syncedTabs.sidebar.label;"
class="subviewbutton subviewbutton-iconic"
class="subviewbutton subviewbutton-iconic sync-ui-item"
observes="viewTabsSidebar"
oncommand="SidebarUI.show('viewTabsSidebar');">
<observes element="viewTabsSidebar" attribute="checked"/>

Просмотреть файл

@ -201,7 +201,7 @@ class TabBrowser {
this.mCurrentBrowser.droppedLinkHandler = handleDroppedLink;
// Hook up the event listeners to the first browser
var tabListener = this.mTabProgressListener(this.mCurrentTab, this.mCurrentBrowser, true, false);
var tabListener = new TabProgressListener(this.mCurrentTab, this.mCurrentBrowser, true, false);
const nsIWebProgress = Ci.nsIWebProgress;
const filter = Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
.createInstance(nsIWebProgress);
@ -764,437 +764,6 @@ class TabBrowser {
}
}
/**
* A web progress listener object definition for a given tab.
*/
mTabProgressListener(aTab, aBrowser, aStartsBlank, aWasPreloadedBrowser, aOrigStateFlags) {
let stateFlags = aOrigStateFlags || 0;
// Initialize mStateFlags to non-zero e.g. when creating a progress
// listener for preloaded browsers as there was no progress listener
// around when the content started loading. If the content didn't
// quite finish loading yet, mStateFlags will very soon be overridden
// with the correct value and end up at STATE_STOP again.
if (aWasPreloadedBrowser) {
stateFlags = Ci.nsIWebProgressListener.STATE_STOP |
Ci.nsIWebProgressListener.STATE_IS_REQUEST;
}
return ({
mTabBrowser: this,
mTab: aTab,
mBrowser: aBrowser,
mBlank: aStartsBlank,
// cache flags for correct status UI update after tab switching
mStateFlags: stateFlags,
mStatus: 0,
mMessage: "",
mTotalProgress: 0,
// count of open requests (should always be 0 or 1)
mRequestCount: 0,
destroy() {
delete this.mTab;
delete this.mBrowser;
delete this.mTabBrowser;
},
_callProgressListeners() {
Array.unshift(arguments, this.mBrowser);
return this.mTabBrowser._callProgressListeners.apply(this.mTabBrowser, arguments);
},
_shouldShowProgress(aRequest) {
if (this.mBlank)
return false;
// Don't show progress indicators in tabs for about: URIs
// pointing to local resources.
if ((aRequest instanceof Ci.nsIChannel) &&
this.mTabBrowser._isLocalAboutURI(aRequest.originalURI, aRequest.URI)) {
return false;
}
return true;
},
_isForInitialAboutBlank(aWebProgress, aStateFlags, aLocation) {
if (!this.mBlank || !aWebProgress.isTopLevel) {
return false;
}
// If the state has STATE_STOP, and no requests were in flight, then this
// must be the initial "stop" for the initial about:blank document.
const nsIWebProgressListener = Ci.nsIWebProgressListener;
if (aStateFlags & nsIWebProgressListener.STATE_STOP &&
this.mRequestCount == 0 &&
!aLocation) {
return true;
}
let location = aLocation ? aLocation.spec : "";
return location == "about:blank";
},
onProgressChange(aWebProgress, aRequest,
aCurSelfProgress, aMaxSelfProgress,
aCurTotalProgress, aMaxTotalProgress) {
this.mTotalProgress = aMaxTotalProgress ? aCurTotalProgress / aMaxTotalProgress : 0;
if (!this._shouldShowProgress(aRequest))
return;
if (this.mTotalProgress && this.mTab.hasAttribute("busy"))
this.mTab.setAttribute("progress", "true");
this._callProgressListeners("onProgressChange",
[aWebProgress, aRequest,
aCurSelfProgress, aMaxSelfProgress,
aCurTotalProgress, aMaxTotalProgress]);
},
onProgressChange64(aWebProgress, aRequest,
aCurSelfProgress, aMaxSelfProgress,
aCurTotalProgress, aMaxTotalProgress) {
return this.onProgressChange(aWebProgress, aRequest,
aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress,
aMaxTotalProgress);
},
/* eslint-disable complexity */
onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
if (!aRequest)
return;
const nsIWebProgressListener = Ci.nsIWebProgressListener;
const nsIChannel = Ci.nsIChannel;
let location, originalLocation;
try {
aRequest.QueryInterface(nsIChannel);
location = aRequest.URI;
originalLocation = aRequest.originalURI;
} catch (ex) {}
let ignoreBlank = this._isForInitialAboutBlank(aWebProgress, aStateFlags,
location);
// If we were ignoring some messages about the initial about:blank, and we
// got the STATE_STOP for it, we'll want to pay attention to those messages
// from here forward. Similarly, if we conclude that this state change
// is one that we shouldn't be ignoring, then stop ignoring.
if ((ignoreBlank &&
aStateFlags & nsIWebProgressListener.STATE_STOP &&
aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) ||
!ignoreBlank && this.mBlank) {
this.mBlank = false;
}
if (aStateFlags & nsIWebProgressListener.STATE_START) {
this.mRequestCount++;
} else if (aStateFlags & nsIWebProgressListener.STATE_STOP) {
const NS_ERROR_UNKNOWN_HOST = 2152398878;
if (--this.mRequestCount > 0 && aStatus == NS_ERROR_UNKNOWN_HOST) {
// to prevent bug 235825: wait for the request handled
// by the automatic keyword resolver
return;
}
// since we (try to) only handle STATE_STOP of the last request,
// the count of open requests should now be 0
this.mRequestCount = 0;
}
if (aStateFlags & nsIWebProgressListener.STATE_START &&
aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) {
if (aWebProgress.isTopLevel) {
// Need to use originalLocation rather than location because things
// like about:home and about:privatebrowsing arrive with nsIRequest
// pointing to their resolved jar: or file: URIs.
if (!(originalLocation && gInitialPages.includes(originalLocation.spec) &&
originalLocation != "about:blank" &&
this.mBrowser.initialPageLoadedFromURLBar != originalLocation.spec &&
this.mBrowser.currentURI && this.mBrowser.currentURI.spec == "about:blank")) {
// Indicating that we started a load will allow the location
// bar to be cleared when the load finishes.
// In order to not overwrite user-typed content, we avoid it
// (see if condition above) in a very specific case:
// If the load is of an 'initial' page (e.g. about:privatebrowsing,
// about:newtab, etc.), was not explicitly typed in the location
// bar by the user, is not about:blank (because about:blank can be
// loaded by websites under their principal), and the current
// page in the browser is about:blank (indicating it is a newly
// created or re-created browser, e.g. because it just switched
// remoteness or is a new tab/window).
this.mBrowser.urlbarChangeTracker.startedLoad();
}
delete this.mBrowser.initialPageLoadedFromURLBar;
// If the browser is loading it must not be crashed anymore
this.mTab.removeAttribute("crashed");
}
if (this._shouldShowProgress(aRequest)) {
if (!(aStateFlags & nsIWebProgressListener.STATE_RESTORING) &&
aWebProgress && aWebProgress.isTopLevel) {
this.mTab.setAttribute("busy", "true");
this.mTab._notselectedsinceload = !this.mTab.selected;
SchedulePressure.startMonitoring(window, {
highPressureFn() {
// Only switch back to the SVG loading indicator after getting
// three consecutive low pressure callbacks. Used to prevent
// switching quickly between the SVG and APNG loading indicators.
gBrowser.tabContainer._schedulePressureCount = gBrowser.schedulePressureDefaultCount;
gBrowser.tabContainer.setAttribute("schedulepressure", "true");
},
lowPressureFn() {
if (!gBrowser.tabContainer._schedulePressureCount ||
--gBrowser.tabContainer._schedulePressureCount <= 0) {
gBrowser.tabContainer.removeAttribute("schedulepressure");
}
// If tabs are closed while they are loading we need to
// stop monitoring schedule pressure. We don't stop monitoring
// during high pressure times because we want to eventually
// return to the SVG tab loading animations.
let continueMonitoring = true;
if (!document.querySelector(".tabbrowser-tab[busy]")) {
SchedulePressure.stopMonitoring(window);
continueMonitoring = false;
}
return { continueMonitoring };
},
});
this.mTabBrowser.syncThrobberAnimations(this.mTab);
}
if (this.mTab.selected) {
this.mTabBrowser.mIsBusy = true;
}
}
} else if (aStateFlags & nsIWebProgressListener.STATE_STOP &&
aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) {
if (this.mTab.hasAttribute("busy")) {
this.mTab.removeAttribute("busy");
if (!document.querySelector(".tabbrowser-tab[busy]")) {
SchedulePressure.stopMonitoring(window);
this.mTabBrowser.tabContainer.removeAttribute("schedulepressure");
}
// Only animate the "burst" indicating the page has loaded if
// the top-level page is the one that finished loading.
if (aWebProgress.isTopLevel && !aWebProgress.isLoadingDocument &&
Components.isSuccessCode(aStatus) &&
!this.mTabBrowser.tabAnimationsInProgress &&
Services.prefs.getBoolPref("toolkit.cosmeticAnimations.enabled")) {
if (this.mTab._notselectedsinceload) {
this.mTab.setAttribute("notselectedsinceload", "true");
} else {
this.mTab.removeAttribute("notselectedsinceload");
}
this.mTab.setAttribute("bursting", "true");
}
this.mTabBrowser._tabAttrModified(this.mTab, ["busy"]);
if (!this.mTab.selected)
this.mTab.setAttribute("unread", "true");
}
this.mTab.removeAttribute("progress");
if (aWebProgress.isTopLevel) {
let isSuccessful = Components.isSuccessCode(aStatus);
if (!isSuccessful && !isTabEmpty(this.mTab)) {
// Restore the current document's location in case the
// request was stopped (possibly from a content script)
// before the location changed.
this.mBrowser.userTypedValue = null;
let inLoadURI = this.mBrowser.inLoadURI;
if (this.mTab.selected && gURLBar && !inLoadURI) {
URLBarSetURI();
}
} else if (isSuccessful) {
this.mBrowser.urlbarChangeTracker.finishedLoad();
}
// Ignore initial about:blank to prevent flickering.
if (!this.mBrowser.mIconURL && !ignoreBlank) {
// Don't switch to the default icon on about:home or about:newtab,
// since these pages get their favicon set in browser code to
// improve perceived performance.
let isNewTab = originalLocation &&
(originalLocation.spec == "about:newtab" ||
originalLocation.spec == "about:privatebrowsing" ||
originalLocation.spec == "about:home");
if (!isNewTab) {
this.mTabBrowser.useDefaultIcon(this.mTab);
}
}
}
// For keyword URIs clear the user typed value since they will be changed into real URIs
if (location.scheme == "keyword")
this.mBrowser.userTypedValue = null;
if (this.mTab.selected)
this.mTabBrowser.mIsBusy = false;
}
if (ignoreBlank) {
this._callProgressListeners("onUpdateCurrentBrowser",
[aStateFlags, aStatus, "", 0],
true, false);
} else {
this._callProgressListeners("onStateChange",
[aWebProgress, aRequest, aStateFlags, aStatus],
true, false);
}
this._callProgressListeners("onStateChange",
[aWebProgress, aRequest, aStateFlags, aStatus],
false);
if (aStateFlags & (nsIWebProgressListener.STATE_START |
nsIWebProgressListener.STATE_STOP)) {
// reset cached temporary values at beginning and end
this.mMessage = "";
this.mTotalProgress = 0;
}
this.mStateFlags = aStateFlags;
this.mStatus = aStatus;
},
/* eslint-enable complexity */
onLocationChange(aWebProgress, aRequest, aLocation,
aFlags) {
// OnLocationChange is called for both the top-level content
// and the subframes.
let topLevel = aWebProgress.isTopLevel;
if (topLevel) {
let isSameDocument = !!(aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT);
// We need to clear the typed value
// if the document failed to load, to make sure the urlbar reflects the
// failed URI (particularly for SSL errors). However, don't clear the value
// if the error page's URI is about:blank, because that causes complete
// loss of urlbar contents for invalid URI errors (see bug 867957).
// Another reason to clear the userTypedValue is if this was an anchor
// navigation initiated by the user.
if (this.mBrowser.didStartLoadSinceLastUserTyping() ||
((aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) &&
aLocation.spec != "about:blank") ||
(isSameDocument && this.mBrowser.inLoadURI)) {
this.mBrowser.userTypedValue = null;
}
// If the tab has been set to "busy" outside the stateChange
// handler below (e.g. by sessionStore.navigateAndRestore), and
// the load results in an error page, it's possible that there
// isn't any (STATE_IS_NETWORK & STATE_STOP) state to cause busy
// attribute being removed. In this case we should remove the
// attribute here.
if ((aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) &&
this.mTab.hasAttribute("busy")) {
this.mTab.removeAttribute("busy");
this.mTabBrowser._tabAttrModified(this.mTab, ["busy"]);
}
// If the browser was playing audio, we should remove the playing state.
if (this.mTab.hasAttribute("soundplaying") && !isSameDocument) {
clearTimeout(this.mTab._soundPlayingAttrRemovalTimer);
this.mTab._soundPlayingAttrRemovalTimer = 0;
this.mTab.removeAttribute("soundplaying");
this.mTabBrowser._tabAttrModified(this.mTab, ["soundplaying"]);
}
// If the browser was previously muted, we should restore the muted state.
if (this.mTab.hasAttribute("muted")) {
this.mTab.linkedBrowser.mute();
}
if (this.mTabBrowser.isFindBarInitialized(this.mTab)) {
let findBar = this.mTabBrowser.getFindBar(this.mTab);
// Close the Find toolbar if we're in old-style TAF mode
if (findBar.findMode != findBar.FIND_NORMAL) {
findBar.close();
}
}
this.mTabBrowser.setTabTitle(this.mTab);
// Don't clear the favicon if this tab is in the pending
// state, as SessionStore will have set the icon for us even
// though we're pointed at an about:blank. Also don't clear it
// if onLocationChange was triggered by a pushState or a
// replaceState (bug 550565) or a hash change (bug 408415).
if (!this.mTab.hasAttribute("pending") &&
aWebProgress.isLoadingDocument &&
!isSameDocument) {
this.mBrowser.mIconURL = null;
}
let userContextId = this.mBrowser.getAttribute("usercontextid") || 0;
if (this.mBrowser.registeredOpenURI) {
this.mTabBrowser._unifiedComplete
.unregisterOpenPage(this.mBrowser.registeredOpenURI,
userContextId);
delete this.mBrowser.registeredOpenURI;
}
// Tabs in private windows aren't registered as "Open" so
// that they don't appear as switch-to-tab candidates.
if (!isBlankPageURL(aLocation.spec) &&
(!PrivateBrowsingUtils.isWindowPrivate(window) ||
PrivateBrowsingUtils.permanentPrivateBrowsing)) {
this.mTabBrowser._unifiedComplete
.registerOpenPage(aLocation, userContextId);
this.mBrowser.registeredOpenURI = aLocation;
}
}
if (!this.mBlank) {
this._callProgressListeners("onLocationChange",
[aWebProgress, aRequest, aLocation, aFlags]);
}
if (topLevel) {
this.mBrowser.lastURI = aLocation;
this.mBrowser.lastLocationChange = Date.now();
}
},
onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {
if (this.mBlank)
return;
this._callProgressListeners("onStatusChange",
[aWebProgress, aRequest, aStatus, aMessage]);
this.mMessage = aMessage;
},
onSecurityChange(aWebProgress, aRequest, aState) {
this._callProgressListeners("onSecurityChange",
[aWebProgress, aRequest, aState]);
},
onRefreshAttempted(aWebProgress, aURI, aDelay, aSameURI) {
return this._callProgressListeners("onRefreshAttempted",
[aWebProgress, aURI, aDelay, aSameURI]);
},
QueryInterface(aIID) {
if (aIID.equals(Ci.nsIWebProgressListener) ||
aIID.equals(Ci.nsIWebProgressListener2) ||
aIID.equals(Ci.nsISupportsWeakReference) ||
aIID.equals(Ci.nsISupports))
return this;
throw Cr.NS_NOINTERFACE;
}
});
}
storeIcon(aBrowser, aURI, aLoadingPrincipal, aRequestContextID) {
try {
if (!(aURI instanceof Ci.nsIURI)) {
@ -2115,7 +1684,7 @@ class TabBrowser {
// Create a new tab progress listener for the new browser we just injected,
// since tab progress listeners have logic for handling the initial about:blank
// load
listener = this.mTabProgressListener(tab, aBrowser, true, false);
listener = new TabProgressListener(tab, aBrowser, true, false);
this._tabListeners.set(tab, listener);
filter.addProgressListener(listener, Ci.nsIWebProgress.NOTIFY_ALL);
@ -2516,7 +2085,7 @@ class TabBrowser {
}
// wire up a progress listener for the new browser object.
let tabListener = this.mTabProgressListener(aTab, browser, uriIsAboutBlank, usingPreloadedContent);
let tabListener = new TabProgressListener(aTab, browser, uriIsAboutBlank, usingPreloadedContent);
const filter = Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
.createInstance(Ci.nsIWebProgress);
filter.addProgressListener(tabListener, Ci.nsIWebProgress.NOTIFY_ALL);
@ -3601,7 +3170,7 @@ class TabBrowser {
this._swapBrowserDocShells(aOurTab, otherBrowser, aFlags);
// Restore the listeners for the swapped in tab.
tabListener = otherTabBrowser.mTabProgressListener(aOtherTab, otherBrowser, false, false);
tabListener = new otherTabBrowser.ownerGlobal.TabProgressListener(aOtherTab, otherBrowser, false, false);
otherTabBrowser._tabListeners.set(aOtherTab, tabListener);
const notifyAll = Ci.nsIWebProgress.NOTIFY_ALL;
@ -3667,8 +3236,7 @@ class TabBrowser {
}
// Restore the progress listener
tabListener = this.mTabProgressListener(aOurTab, ourBrowser, false, false,
aStateFlags);
tabListener = new TabProgressListener(aOurTab, ourBrowser, false, false, aStateFlags);
this._tabListeners.set(aOurTab, tabListener);
const notifyAll = Ci.nsIWebProgress.NOTIFY_ALL;
@ -5735,3 +5303,428 @@ class TabBrowser {
});
}
}
/**
* A web progress listener object definition for a given tab.
*/
class TabProgressListener {
constructor(aTab, aBrowser, aStartsBlank, aWasPreloadedBrowser, aOrigStateFlags) {
let stateFlags = aOrigStateFlags || 0;
// Initialize mStateFlags to non-zero e.g. when creating a progress
// listener for preloaded browsers as there was no progress listener
// around when the content started loading. If the content didn't
// quite finish loading yet, mStateFlags will very soon be overridden
// with the correct value and end up at STATE_STOP again.
if (aWasPreloadedBrowser) {
stateFlags = Ci.nsIWebProgressListener.STATE_STOP |
Ci.nsIWebProgressListener.STATE_IS_REQUEST;
}
this.mTab = aTab;
this.mBrowser = aBrowser;
this.mBlank = aStartsBlank;
// cache flags for correct status UI update after tab switching
this.mStateFlags = stateFlags;
this.mStatus = 0;
this.mMessage = "";
this.mTotalProgress = 0;
// count of open requests (should always be 0 or 1)
this.mRequestCount = 0;
}
destroy() {
delete this.mTab;
delete this.mBrowser;
}
_callProgressListeners() {
Array.unshift(arguments, this.mBrowser);
return gBrowser._callProgressListeners.apply(gBrowser, arguments);
}
_shouldShowProgress(aRequest) {
if (this.mBlank)
return false;
// Don't show progress indicators in tabs for about: URIs
// pointing to local resources.
if ((aRequest instanceof Ci.nsIChannel) &&
gBrowser._isLocalAboutURI(aRequest.originalURI, aRequest.URI)) {
return false;
}
return true;
}
_isForInitialAboutBlank(aWebProgress, aStateFlags, aLocation) {
if (!this.mBlank || !aWebProgress.isTopLevel) {
return false;
}
// If the state has STATE_STOP, and no requests were in flight, then this
// must be the initial "stop" for the initial about:blank document.
const nsIWebProgressListener = Ci.nsIWebProgressListener;
if (aStateFlags & nsIWebProgressListener.STATE_STOP &&
this.mRequestCount == 0 &&
!aLocation) {
return true;
}
let location = aLocation ? aLocation.spec : "";
return location == "about:blank";
}
onProgressChange(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress,
aCurTotalProgress, aMaxTotalProgress) {
this.mTotalProgress = aMaxTotalProgress ? aCurTotalProgress / aMaxTotalProgress : 0;
if (!this._shouldShowProgress(aRequest))
return;
if (this.mTotalProgress && this.mTab.hasAttribute("busy"))
this.mTab.setAttribute("progress", "true");
this._callProgressListeners("onProgressChange",
[aWebProgress, aRequest,
aCurSelfProgress, aMaxSelfProgress,
aCurTotalProgress, aMaxTotalProgress]);
}
onProgressChange64(aWebProgress, aRequest, aCurSelfProgress,
aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) {
return this.onProgressChange(aWebProgress, aRequest,
aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress,
aMaxTotalProgress);
}
/* eslint-disable complexity */
onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
if (!aRequest)
return;
const nsIWebProgressListener = Ci.nsIWebProgressListener;
const nsIChannel = Ci.nsIChannel;
let location, originalLocation;
try {
aRequest.QueryInterface(nsIChannel);
location = aRequest.URI;
originalLocation = aRequest.originalURI;
} catch (ex) {}
let ignoreBlank = this._isForInitialAboutBlank(aWebProgress, aStateFlags,
location);
// If we were ignoring some messages about the initial about:blank, and we
// got the STATE_STOP for it, we'll want to pay attention to those messages
// from here forward. Similarly, if we conclude that this state change
// is one that we shouldn't be ignoring, then stop ignoring.
if ((ignoreBlank &&
aStateFlags & nsIWebProgressListener.STATE_STOP &&
aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) ||
!ignoreBlank && this.mBlank) {
this.mBlank = false;
}
if (aStateFlags & nsIWebProgressListener.STATE_START) {
this.mRequestCount++;
} else if (aStateFlags & nsIWebProgressListener.STATE_STOP) {
const NS_ERROR_UNKNOWN_HOST = 2152398878;
if (--this.mRequestCount > 0 && aStatus == NS_ERROR_UNKNOWN_HOST) {
// to prevent bug 235825: wait for the request handled
// by the automatic keyword resolver
return;
}
// since we (try to) only handle STATE_STOP of the last request,
// the count of open requests should now be 0
this.mRequestCount = 0;
}
if (aStateFlags & nsIWebProgressListener.STATE_START &&
aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) {
if (aWebProgress.isTopLevel) {
// Need to use originalLocation rather than location because things
// like about:home and about:privatebrowsing arrive with nsIRequest
// pointing to their resolved jar: or file: URIs.
if (!(originalLocation && gInitialPages.includes(originalLocation.spec) &&
originalLocation != "about:blank" &&
this.mBrowser.initialPageLoadedFromURLBar != originalLocation.spec &&
this.mBrowser.currentURI && this.mBrowser.currentURI.spec == "about:blank")) {
// Indicating that we started a load will allow the location
// bar to be cleared when the load finishes.
// In order to not overwrite user-typed content, we avoid it
// (see if condition above) in a very specific case:
// If the load is of an 'initial' page (e.g. about:privatebrowsing,
// about:newtab, etc.), was not explicitly typed in the location
// bar by the user, is not about:blank (because about:blank can be
// loaded by websites under their principal), and the current
// page in the browser is about:blank (indicating it is a newly
// created or re-created browser, e.g. because it just switched
// remoteness or is a new tab/window).
this.mBrowser.urlbarChangeTracker.startedLoad();
}
delete this.mBrowser.initialPageLoadedFromURLBar;
// If the browser is loading it must not be crashed anymore
this.mTab.removeAttribute("crashed");
}
if (this._shouldShowProgress(aRequest)) {
if (!(aStateFlags & nsIWebProgressListener.STATE_RESTORING) &&
aWebProgress && aWebProgress.isTopLevel) {
this.mTab.setAttribute("busy", "true");
this.mTab._notselectedsinceload = !this.mTab.selected;
SchedulePressure.startMonitoring(window, {
highPressureFn() {
// Only switch back to the SVG loading indicator after getting
// three consecutive low pressure callbacks. Used to prevent
// switching quickly between the SVG and APNG loading indicators.
gBrowser.tabContainer._schedulePressureCount = gBrowser.schedulePressureDefaultCount;
gBrowser.tabContainer.setAttribute("schedulepressure", "true");
},
lowPressureFn() {
if (!gBrowser.tabContainer._schedulePressureCount ||
--gBrowser.tabContainer._schedulePressureCount <= 0) {
gBrowser.tabContainer.removeAttribute("schedulepressure");
}
// If tabs are closed while they are loading we need to
// stop monitoring schedule pressure. We don't stop monitoring
// during high pressure times because we want to eventually
// return to the SVG tab loading animations.
let continueMonitoring = true;
if (!document.querySelector(".tabbrowser-tab[busy]")) {
SchedulePressure.stopMonitoring(window);
continueMonitoring = false;
}
return { continueMonitoring };
},
});
gBrowser.syncThrobberAnimations(this.mTab);
}
if (this.mTab.selected) {
gBrowser.mIsBusy = true;
}
}
} else if (aStateFlags & nsIWebProgressListener.STATE_STOP &&
aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) {
if (this.mTab.hasAttribute("busy")) {
this.mTab.removeAttribute("busy");
if (!document.querySelector(".tabbrowser-tab[busy]")) {
SchedulePressure.stopMonitoring(window);
gBrowser.tabContainer.removeAttribute("schedulepressure");
}
// Only animate the "burst" indicating the page has loaded if
// the top-level page is the one that finished loading.
if (aWebProgress.isTopLevel && !aWebProgress.isLoadingDocument &&
Components.isSuccessCode(aStatus) &&
!gBrowser.tabAnimationsInProgress &&
Services.prefs.getBoolPref("toolkit.cosmeticAnimations.enabled")) {
if (this.mTab._notselectedsinceload) {
this.mTab.setAttribute("notselectedsinceload", "true");
} else {
this.mTab.removeAttribute("notselectedsinceload");
}
this.mTab.setAttribute("bursting", "true");
}
gBrowser._tabAttrModified(this.mTab, ["busy"]);
if (!this.mTab.selected)
this.mTab.setAttribute("unread", "true");
}
this.mTab.removeAttribute("progress");
if (aWebProgress.isTopLevel) {
let isSuccessful = Components.isSuccessCode(aStatus);
if (!isSuccessful && !isTabEmpty(this.mTab)) {
// Restore the current document's location in case the
// request was stopped (possibly from a content script)
// before the location changed.
this.mBrowser.userTypedValue = null;
let inLoadURI = this.mBrowser.inLoadURI;
if (this.mTab.selected && gURLBar && !inLoadURI) {
URLBarSetURI();
}
} else if (isSuccessful) {
this.mBrowser.urlbarChangeTracker.finishedLoad();
}
// Ignore initial about:blank to prevent flickering.
if (!this.mBrowser.mIconURL && !ignoreBlank) {
// Don't switch to the default icon on about:home or about:newtab,
// since these pages get their favicon set in browser code to
// improve perceived performance.
let isNewTab = originalLocation &&
(originalLocation.spec == "about:newtab" ||
originalLocation.spec == "about:privatebrowsing" ||
originalLocation.spec == "about:home");
if (!isNewTab) {
gBrowser.useDefaultIcon(this.mTab);
}
}
}
// For keyword URIs clear the user typed value since they will be changed into real URIs
if (location.scheme == "keyword")
this.mBrowser.userTypedValue = null;
if (this.mTab.selected)
gBrowser.mIsBusy = false;
}
if (ignoreBlank) {
this._callProgressListeners("onUpdateCurrentBrowser",
[aStateFlags, aStatus, "", 0],
true, false);
} else {
this._callProgressListeners("onStateChange",
[aWebProgress, aRequest, aStateFlags, aStatus],
true, false);
}
this._callProgressListeners("onStateChange",
[aWebProgress, aRequest, aStateFlags, aStatus],
false);
if (aStateFlags & (nsIWebProgressListener.STATE_START |
nsIWebProgressListener.STATE_STOP)) {
// reset cached temporary values at beginning and end
this.mMessage = "";
this.mTotalProgress = 0;
}
this.mStateFlags = aStateFlags;
this.mStatus = aStatus;
}
/* eslint-enable complexity */
onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
// OnLocationChange is called for both the top-level content
// and the subframes.
let topLevel = aWebProgress.isTopLevel;
if (topLevel) {
let isSameDocument = !!(aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT);
// We need to clear the typed value
// if the document failed to load, to make sure the urlbar reflects the
// failed URI (particularly for SSL errors). However, don't clear the value
// if the error page's URI is about:blank, because that causes complete
// loss of urlbar contents for invalid URI errors (see bug 867957).
// Another reason to clear the userTypedValue is if this was an anchor
// navigation initiated by the user.
if (this.mBrowser.didStartLoadSinceLastUserTyping() ||
((aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) &&
aLocation.spec != "about:blank") ||
(isSameDocument && this.mBrowser.inLoadURI)) {
this.mBrowser.userTypedValue = null;
}
// If the tab has been set to "busy" outside the stateChange
// handler below (e.g. by sessionStore.navigateAndRestore), and
// the load results in an error page, it's possible that there
// isn't any (STATE_IS_NETWORK & STATE_STOP) state to cause busy
// attribute being removed. In this case we should remove the
// attribute here.
if ((aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) &&
this.mTab.hasAttribute("busy")) {
this.mTab.removeAttribute("busy");
gBrowser._tabAttrModified(this.mTab, ["busy"]);
}
// If the browser was playing audio, we should remove the playing state.
if (this.mTab.hasAttribute("soundplaying") && !isSameDocument) {
clearTimeout(this.mTab._soundPlayingAttrRemovalTimer);
this.mTab._soundPlayingAttrRemovalTimer = 0;
this.mTab.removeAttribute("soundplaying");
gBrowser._tabAttrModified(this.mTab, ["soundplaying"]);
}
// If the browser was previously muted, we should restore the muted state.
if (this.mTab.hasAttribute("muted")) {
this.mTab.linkedBrowser.mute();
}
if (gBrowser.isFindBarInitialized(this.mTab)) {
let findBar = gBrowser.getFindBar(this.mTab);
// Close the Find toolbar if we're in old-style TAF mode
if (findBar.findMode != findBar.FIND_NORMAL) {
findBar.close();
}
}
gBrowser.setTabTitle(this.mTab);
// Don't clear the favicon if this tab is in the pending
// state, as SessionStore will have set the icon for us even
// though we're pointed at an about:blank. Also don't clear it
// if onLocationChange was triggered by a pushState or a
// replaceState (bug 550565) or a hash change (bug 408415).
if (!this.mTab.hasAttribute("pending") &&
aWebProgress.isLoadingDocument &&
!isSameDocument) {
this.mBrowser.mIconURL = null;
}
let userContextId = this.mBrowser.getAttribute("usercontextid") || 0;
if (this.mBrowser.registeredOpenURI) {
gBrowser._unifiedComplete
.unregisterOpenPage(this.mBrowser.registeredOpenURI, userContextId);
delete this.mBrowser.registeredOpenURI;
}
// Tabs in private windows aren't registered as "Open" so
// that they don't appear as switch-to-tab candidates.
if (!isBlankPageURL(aLocation.spec) &&
(!PrivateBrowsingUtils.isWindowPrivate(window) ||
PrivateBrowsingUtils.permanentPrivateBrowsing)) {
gBrowser._unifiedComplete.registerOpenPage(aLocation, userContextId);
this.mBrowser.registeredOpenURI = aLocation;
}
}
if (!this.mBlank) {
this._callProgressListeners("onLocationChange",
[aWebProgress, aRequest, aLocation, aFlags]);
}
if (topLevel) {
this.mBrowser.lastURI = aLocation;
this.mBrowser.lastLocationChange = Date.now();
}
}
onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {
if (this.mBlank)
return;
this._callProgressListeners("onStatusChange",
[aWebProgress, aRequest, aStatus, aMessage]);
this.mMessage = aMessage;
}
onSecurityChange(aWebProgress, aRequest, aState) {
this._callProgressListeners("onSecurityChange",
[aWebProgress, aRequest, aState]);
}
onRefreshAttempted(aWebProgress, aURI, aDelay, aSameURI) {
return this._callProgressListeners("onRefreshAttempted",
[aWebProgress, aURI, aDelay, aSameURI]);
}
QueryInterface(aIID) {
if (aIID.equals(Ci.nsIWebProgressListener) ||
aIID.equals(Ci.nsIWebProgressListener2) ||
aIID.equals(Ci.nsISupportsWeakReference) ||
aIID.equals(Ci.nsISupports))
return this;
throw Cr.NS_NOINTERFACE;
}
}

Просмотреть файл

@ -19,6 +19,8 @@ skip-if = (os == 'win' && ccov) # Bug 1423667
skip-if = (os == 'win' && ccov) # Bug 1423667
[browser_bookmark_folder_moveability.js]
skip-if = (os == 'win' && ccov) # Bug 1423667
[browser_bookmark_load_in_sidebar.js]
skip-if = (os == 'win' && ccov) # Bug 1423667
[browser_bookmark_private_window.js]
skip-if = (os == 'win' && ccov) # Bug 1423667
[browser_bookmark_remove_tags.js]

Просмотреть файл

@ -0,0 +1,72 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/**
* Test that a bookmark can be loaded inside the Bookmarks sidebar.
*/
"use strict";
const TEST_URL = "about:buildconfig";
// Cleanup.
registerCleanupFunction(async () => {
await PlacesUtils.bookmarks.eraseEverything();
});
add_task(async function test_load_in_sidebar() {
let bm = await PlacesUtils.bookmarks.insert({
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
url: TEST_URL,
title: TEST_URL,
});
await withSidebarTree("bookmarks", async function(tree) {
tree.selectItems([bm.guid]);
await withBookmarksDialog(
false,
function openPropertiesDialog() {
tree.controller.doCommand("placesCmd_show:info");
},
// Check the "Load this bookmark in the sidebar" option.
async function test(dialogWin) {
let loadInSidebar = dialogWin.document.getElementById("editBMPanel_loadInSidebarCheckbox");
let promiseCheckboxChanged = PlacesTestUtils.waitForNotification(
"onItemChanged",
(id, parentId, checked) => checked === true
);
loadInSidebar.click();
EventUtils.synthesizeKey("VK_RETURN", {}, dialogWin);
await promiseCheckboxChanged;
}
);
let sidebar = document.getElementById("sidebar");
let sidebarLoadedPromise = new Promise(resolve => {
sidebar.addEventListener("load", function() {
executeSoon(resolve);
}, {capture: true, once: true});
});
// Select and open the bookmark in the sidebar.
tree.selectItems([bm.guid]);
tree.controller.doCommand("placesCmd_open");
await sidebarLoadedPromise;
let sidebarTitle = document.getElementById("sidebar-title");
let sidebarBrowser = sidebar.contentDocument.getElementById("web-panels-browser");
await BrowserTestUtils.browserLoaded(sidebarBrowser, false, TEST_URL);
let h1Elem = sidebarBrowser.contentDocument.getElementsByTagName("h1")[0];
// Check that the title and the content of the page are loaded successfully.
Assert.equal(sidebarTitle.value, TEST_URL, "The sidebar title is successfully loaded.");
Assert.equal(h1Elem.textContent, TEST_URL, "The sidebar content is successfully loaded.");
});
});

Просмотреть файл

@ -261,6 +261,9 @@ var gConnectionsDialog = {
for (let element of gConnectionsDialog.getProxyControls()) {
element.disabled = disabled;
}
if (!isControlled) {
gConnectionsDialog.proxyTypeChanged();
}
}
if (isLocked) {

Просмотреть файл

@ -91,6 +91,7 @@
data-l10n-attrs="title">
<link rel="localization" href="branding/brand.ftl"/>
<link rel="localization" href="browser/branding/sync-brand.ftl"/>
<link rel="localization" href="browser/preferences/preferences.ftl"/>
<script type="text/javascript" src="chrome://global/content/l10n.js"></script>

Просмотреть файл

@ -57,6 +57,10 @@ function runConnectionTests(win) {
is(networkProxyNone.getAttribute("rows"), "2",
"networkProxyNone textbox has two rows");
// make sure manual proxy controls are disabled when the window is opened
let networkProxyHTTP = doc.getElementById("networkProxyHTTP");
is(networkProxyHTTP.disabled, true, "networkProxyHTTP textbox is disabled");
// check if sanitizing the given input for the no_proxies_on pref results in
// expected string
function testSanitize(input, expected, errorMessage) {

Просмотреть файл

@ -673,17 +673,30 @@ add_task(async function testExtensionControlledProxyConfig() {
}
function getProxyControls() {
let controlGroup = doc.getElementById("networkProxyType");
return [
...controlGroup.querySelectorAll(":scope > radio"),
...controlGroup.querySelectorAll("label"),
...controlGroup.querySelectorAll("textbox"),
...controlGroup.querySelectorAll("checkbox"),
...doc.querySelectorAll("#networkProxySOCKSVersion > radio"),
...doc.querySelectorAll("#ConnectionsDialogPane > checkbox"),
];
let manualControlContainer = controlGroup.querySelector("grid");
return {
manualControls: [
...manualControlContainer.querySelectorAll("label"),
...manualControlContainer.querySelectorAll("textbox"),
...manualControlContainer.querySelectorAll("checkbox"),
...doc.querySelectorAll("#networkProxySOCKSVersion > radio")],
pacControls: [doc.getElementById("networkProxyAutoconfigURL")],
otherControls: [
...controlGroup.querySelectorAll(":scope > radio"),
...doc.querySelectorAll("#ConnectionsDialogPane > checkbox")],
};
}
let controlState = isControlled ? "disabled" : "enabled";
for (let element of getProxyControls()) {
let controls = getProxyControls();
for (let element of controls.manualControls) {
let disabled = isControlled || proxyType !== proxySvc.PROXYCONFIG_MANUAL;
is(element.disabled, disabled, `Proxy controls are ${controlState}.`);
}
for (let element of controls.pacControls) {
let disabled = isControlled || proxyType !== proxySvc.PROXYCONFIG_PAC;
is(element.disabled, disabled, `Proxy controls are ${controlState}.`);
}
for (let element of controls.otherControls) {
is(element.disabled, isControlled, `Proxy controls are ${controlState}.`);
}
} else {
@ -750,7 +763,7 @@ add_task(async function testExtensionControlledProxyConfig() {
verifyState(mainDoc, false);
// Install an extension that sets Tracking Protection.
// Install an extension that controls proxy settings.
let extension = ExtensionTestUtils.loadExtension({
useAddonManager: "permanent",
manifest: {

Просмотреть файл

@ -622,7 +622,7 @@ var pktApi = (function() {
function retrieve(data = {}, options = {}) {
const requestData = Object.assign({}, data, {access_token: getAccessToken()});
return apiRequest({
path: "/get",
path: "/firefox/get",
data: requestData,
success: options.success,
error: options.error

Просмотреть файл

@ -101,6 +101,7 @@ webextPerms.description.browsingData=Clear recent browsing history, cookies, and
webextPerms.description.clipboardRead=Get data from the clipboard
webextPerms.description.clipboardWrite=Input data to the clipboard
webextPerms.description.devtools=Extend developer tools to access your data in open tabs
webextPerms.description.dns=Access IP address and hostname information
webextPerms.description.downloads=Download files and read and modify the browsers download history
webextPerms.description.downloads.open=Open files downloaded to your computer
webextPerms.description.find=Read the text of all open tabs

Просмотреть файл

@ -161,6 +161,12 @@
margin-inline-start: -3px;
position: relative;
}
@media (-moz-os-version: windows-win7) {
#detailsDeck {
border-top-color: #A9B7C9;
}
}
}
@media (-moz-windows-glass) {
@ -168,25 +174,3 @@
border-top: none;
}
}
@media (-moz-windows-default-theme) and (-moz-os-version: windows-win7) {
#placesView,
#infoPane,
#placesList,
#placeContent {
background-color: #EEF3FA;
}
#detailsDeck {
border-top-color: #A9B7C9;
}
#searchFilter {
-moz-appearance: none;
padding: 2px;
padding-inline-start: 4px;
background-clip: padding-box;
border: 1px solid rgba(0,0,0,.32);
border-radius: 2px;
}
}

Просмотреть файл

@ -67,7 +67,7 @@ def rust_compiler(rustc_info, cargo_info):
You can install rust by running './mach bootstrap'
or by directly running the installer from https://rustup.rs/
'''))
rustc_min_version = Version('1.23.0')
rustc_min_version = Version('1.24.0')
cargo_min_version = Version('0.{}'.format(rustc_min_version.minor + 1))
version = rustc_info.version

Просмотреть файл

@ -26,11 +26,9 @@ class Font extends PureComponent {
super(props);
this.state = {
isFontExpanded: false,
isFontFaceRuleExpanded: false,
};
this.onFontToggle = this.onFontToggle.bind(this);
this.onFontFaceRuleToggle = this.onFontFaceRuleToggle.bind(this);
}
@ -40,18 +38,10 @@ class Font extends PureComponent {
}
this.setState({
isFontExpanded: false,
isFontFaceRuleExpanded: false,
});
}
onFontToggle(event) {
this.setState({
isFontExpanded: !this.state.isFontExpanded
});
event.stopPropagation();
}
onFontFaceRuleToggle(event) {
this.setState({
isFontFaceRuleExpanded: !this.state.isFontFaceRuleExpanded
@ -59,15 +49,6 @@ class Font extends PureComponent {
event.stopPropagation();
}
renderFontCSS(cssFamilyName) {
return dom.p(
{
className: "font-css-name"
},
`${getStr("fontinspector.usedAs")} "${cssFamilyName}"`
);
}
renderFontCSSCode(rule, ruleText) {
if (!rule) {
return null;
@ -89,14 +70,13 @@ class Font extends PureComponent {
this.renderFontCSSCodeTwisty(),
leading,
isFontFaceRuleExpanded ?
null
:
body :
dom.span(
{
className: "font-css-code-expander"
className: "font-css-code-expander",
onClick: this.onFontFaceRuleToggle,
}
),
isFontFaceRuleExpanded ? body : null,
trailing
);
}
@ -129,29 +109,20 @@ class Font extends PureComponent {
renderFontName(name) {
return dom.h1(
{
className: "font-name",
onClick: this.onFontToggle,
className: "font-name"
},
name
);
}
renderFontTwisty() {
let { isFontExpanded } = this.state;
return this.renderTwisty(isFontExpanded, this.onFontToggle);
}
renderFontCSSCodeTwisty() {
let { isFontFaceRuleExpanded } = this.state;
return this.renderTwisty(isFontFaceRuleExpanded, this.onFontFaceRuleToggle);
}
renderTwisty(isExpanded, onClick) {
let attributes = {
className: "theme-twisty",
onClick,
onClick: this.onFontFaceRuleToggle,
};
if (isExpanded) {
if (isFontFaceRuleExpanded) {
attributes.open = "true";
}
@ -168,7 +139,6 @@ class Font extends PureComponent {
let { previewText } = fontOptions;
let {
CSSFamilyName,
format,
name,
previewUrl,
@ -177,23 +147,14 @@ class Font extends PureComponent {
URI,
} = font;
let { isFontExpanded } = this.state;
return dom.li(
{
className: "font" + (isFontExpanded ? " expanded" : ""),
className: "font",
},
this.renderFontTwisty(),
this.renderFontName(name),
FontPreview({ previewText, previewUrl, onPreviewFonts }),
dom.div(
{
className: "font-details"
},
this.renderFontTypeAndURL(URI, format),
this.renderFontCSSCode(rule, ruleText),
this.renderFontCSS(CSSFamilyName)
)
this.renderFontTypeAndURL(URI, format),
this.renderFontCSSCode(rule, ruleText)
);
}
}

Просмотреть файл

@ -9,6 +9,7 @@ const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const Types = require("../types");
const { getStr } = require("../utils/l10n");
class FontPreview extends PureComponent {
static get propTypes() {
@ -85,6 +86,7 @@ class FontPreview extends PureComponent {
className: "font-preview",
src: previewUrl,
onClick: this.onClick,
title: !isFocused ? getStr("fontinspector.editPreview") : "",
}
)
);

Просмотреть файл

@ -17,7 +17,6 @@ support-files =
[browser_fontinspector.js]
[browser_fontinspector_edit-previews.js]
[browser_fontinspector_expand-css-code.js]
[browser_fontinspector_expand-details.js]
[browser_fontinspector_other-fonts.js]
[browser_fontinspector_text-node.js]
[browser_fontinspector_theme-change.js]

Просмотреть файл

@ -55,12 +55,6 @@ function getFormat(fontLi) {
return link.textContent;
}
function getCSSName(fontLi) {
let text = fontLi.querySelector(".font-css-name").textContent;
return text.substring(text.indexOf('"') + 1, text.lastIndexOf('"'));
}
function* testBodyFonts(inspector, viewDoc) {
let lis = getUsedFontsEls(viewDoc);
is(lis.length, 5, "Found 5 fonts");
@ -73,7 +67,6 @@ function* testBodyFonts(inspector, viewDoc) {
is(isRemote(li), font.remote, "font " + i + " remote value correct");
is(li.querySelector(".font-url").href, font.url, "font " + i + " url correct");
is(getFormat(li), font.format, "font " + i + " format correct");
is(getCSSName(li), font.cssName, "font " + i + " css name correct");
}
// test that the bold and regular fonts have different previews
@ -83,15 +76,12 @@ function* testBodyFonts(inspector, viewDoc) {
// test system font
let localFontName = getName(lis[4]);
let localFontCSSName = getCSSName(lis[4]);
// On Linux test machines, the Arial font doesn't exist.
// The fallback is "Liberation Sans"
ok((localFontName == "Arial") || (localFontName == "Liberation Sans"),
"local font right font name");
ok(!isRemote(lis[4]), "local font is local");
ok((localFontCSSName == "Arial") || (localFontCSSName == "Liberation Sans"),
"Arial", "local font has right css name");
}
function* testDivFonts(inspector, viewDoc) {

Просмотреть файл

@ -12,11 +12,8 @@ add_task(function* () {
let { view } = yield openFontInspectorForURL(TEST_URI);
let viewDoc = view.document;
info("Expanding the details section of the first font");
let fontEl = getUsedFontsEls(viewDoc)[0];
yield expandFontDetails(fontEl);
info("Checking that the css font-face rule is collapsed by default");
let fontEl = getUsedFontsEls(viewDoc)[0];
let codeEl = fontEl.querySelector(".font-css-code");
is(codeEl.textContent, "@font-face {}", "The font-face rule is collapsed");
@ -33,4 +30,22 @@ add_task(function* () {
yield onExpanded;
ok(true, "Font-face rule is now expanded");
info("Expanding another rule by clicking on the [...] icon instead");
fontEl = getUsedFontsEls(viewDoc)[1];
codeEl = fontEl.querySelector(".font-css-code");
onExpanded = BrowserTestUtils.waitForCondition(() => {
return codeEl.textContent === `@font-face {
font-family: "bar";
font-weight: bold;
src: url("ostrich-black.ttf");
}`;
}, "Waiting for the font-face rule");
expander = fontEl.querySelector(".font-css-code .font-css-code-expander");
expander.click();
yield onExpanded;
ok(true, "Font-face rule is now expanded too");
});

Просмотреть файл

@ -1,38 +0,0 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that fonts are collapsed by default, and can be expanded.
const TEST_URI = URL_ROOT + "browser_fontinspector.html";
add_task(function* () {
let { inspector, view } = yield openFontInspectorForURL(TEST_URI);
let viewDoc = view.document;
info("Checking all font are collapsed by default");
let fonts = getUsedFontsEls(viewDoc);
checkAllFontsCollapsed(fonts);
info("Clicking on the first one to expand the font details");
yield expandFontDetails(fonts[0]);
ok(fonts[0].querySelector(".theme-twisty").hasAttribute("open"), `Twisty is open`);
ok(isFontDetailsVisible(fonts[0]), `Font details is shown`);
info("Selecting a node with different fonts and checking that all fonts are collapsed");
yield selectNode(".black-text", inspector);
fonts = getUsedFontsEls(viewDoc);
checkAllFontsCollapsed(fonts);
});
function checkAllFontsCollapsed(fonts) {
fonts.forEach((el, i) => {
let twisty = el.querySelector(".theme-twisty");
ok(twisty, `Twisty ${i} exists`);
ok(!twisty.hasAttribute("open"), `Twisty ${i} is closed`);
ok(!isFontDetailsVisible(el), `Font details ${i} is hidden`);
});
}

Просмотреть файл

@ -88,21 +88,6 @@ function* updatePreviewText(view, text) {
is(input.value, text, "The input now contains the correct text.");
}
async function expandFontDetails(fontEl) {
info("Expanding a font details section");
let onExpanded = BrowserTestUtils.waitForCondition(() => isFontDetailsVisible(fontEl),
"Waiting for font details");
let twisty = fontEl.querySelector(".theme-twisty");
twisty.click();
await onExpanded;
}
function isFontDetailsVisible(fontEl) {
return [...fontEl.querySelectorAll(".font-css-name, .font-css-code, .font-format-url")]
.every(el => el.getBoxQuads().length);
}
/**
* Get all of the <li> elements for the fonts used on the currently selected element.
*

Просмотреть файл

@ -10,9 +10,6 @@ const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
* A single font.
*/
const font = exports.font = {
// The name of the font family
CSSFamilyName: PropTypes.string,
// The format of the font
format: PropTypes.string,

Просмотреть файл

@ -708,10 +708,14 @@ Inspector.prototype = {
await this.addRuleView(defaultTab);
this.sidebar.addExistingTab(
"computedview",
INSPECTOR_L10N.getStr("inspector.sidebar.computedViewTitle"),
defaultTab == "computedview");
// If the 3 Pane Inspector feature is disabled, use the old order:
// Rules, Computed, Layout, etc.
if (!this.showSplitSidebarToggle) {
this.sidebar.addExistingTab(
"computedview",
INSPECTOR_L10N.getStr("inspector.sidebar.computedViewTitle"),
defaultTab == "computedview");
}
// Inject a lazy loaded react tab by exposing a fake React object
// with a lazy defined Tab thanks to `panel` being a function
@ -737,6 +741,15 @@ Inspector.prototype = {
},
defaultTab == layoutId);
// If the 3 Pane Inspector feature is enabled, use the new order:
// Rules, Layout, Computed, etc.
if (this.showSplitSidebarToggle) {
this.sidebar.addExistingTab(
"computedview",
INSPECTOR_L10N.getStr("inspector.sidebar.computedViewTitle"),
defaultTab == "computedview");
}
if (Services.prefs.getBoolPref("devtools.changesview.enabled")) {
// Inject a lazy loaded react tab by exposing a fake React object
// with a lazy defined Tab thanks to `panel` being a function

Просмотреть файл

@ -5,10 +5,6 @@
# LOCALIZATION NOTE This file contains the Font Inspector strings.
# The Font Inspector is a panel accessible in the Inspector sidebar.
# LOCALIZATION NOTE (fontinspector.usedAs) This label introduces the name used to refer to
# the font in a stylesheet.
fontinspector.usedAs=Used as:
# LOCALIZATION NOTE (fontinspector.system) This label indicates that the font is a local
# system font.
fontinspector.system=system
@ -23,4 +19,9 @@ fontinspector.noFontsOnSelectedElement=No fonts were found for the current eleme
# LOCALIZATION NOTE (fontinspector.otherFontsInPageHeader): This is the text for the
# header of a collapsible section containing other fonts used in the page.
fontinspector.otherFontsInPageHeader=Other fonts in page
fontinspector.otherFontsInPageHeader=Other fonts in page
# LOCALIZATION NOTE (fontinspector.editPreview): This is the text that appears in a
# tooltip on hover of a font preview string. Clicking on the string opens a text input
# where users can type to change the preview text.
fontinspector.editPreview=Click to edit preview

Просмотреть файл

@ -22,7 +22,7 @@ const { render, unmountComponentAtNode } = require("devtools/client/shared/vendo
const Provider = createFactory(require("devtools/client/shared/vendor/react-redux").Provider);
const { bindActionCreators } = require("devtools/client/shared/vendor/redux");
const { Connector } = require("./src/connector/index");
const { configureStore } = require("./src/utils/create-store");
const { configureStore } = require("./src/create-store");
const App = createFactory(require("./src/components/App"));
const { EVENTS } = require("./src/constants");
const {

Просмотреть файл

@ -43,7 +43,7 @@ require("./src/assets/styles/netmonitor.css");
const EventEmitter = require("devtools-modules/src/utils/event-emitter");
EventEmitter.decorate(window);
const { configureStore } = require("./src/utils/create-store");
const { configureStore } = require("./src/create-store");
const App = require("./src/components/App");
const { Connector } = require("./src/connector/index");
const connector = new Connector();

Просмотреть файл

@ -7,7 +7,7 @@
const { Component, createFactory } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { connect } = require("../utils/redux-connect");
// Components
loader.lazyGetter(this, "MonitorPanel", function () {

Просмотреть файл

@ -7,7 +7,7 @@
const { Component } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { connect } = require("../utils/redux-connect");
const { L10N } = require("../utils/l10n");
const { fetchNetworkUpdatePacket } = require("../utils/request-utils");
const Actions = require("../actions/index");

Просмотреть файл

@ -9,7 +9,7 @@ const { Component, createFactory } = require("devtools/client/shared/vendor/reac
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const { div } = dom;
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { connect } = require("../utils/redux-connect");
const { findDOMNode } = require("devtools/client/shared/vendor/react-dom");
const Actions = require("../actions/index");
const { updateFormDataSections } = require("../utils/request-utils");

Просмотреть файл

@ -7,7 +7,7 @@
const { createFactory } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { connect } = require("../utils/redux-connect");
const Actions = require("../actions/index");
const { getSelectedRequest } = require("../selectors/index");

Просмотреть файл

@ -7,7 +7,7 @@
const { Component, createFactory } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { connect } = require("../utils/redux-connect");
const { L10N } = require("../utils/l10n");
const {
fetchNetworkUpdatePacket,

Просмотреть файл

@ -7,7 +7,7 @@
const { Component, createFactory } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { connect } = require("../utils/redux-connect");
const { HTMLTooltip } = require("devtools/client/shared/widgets/tooltip/HTMLTooltip");
const Actions = require("../actions/index");

Просмотреть файл

@ -7,7 +7,7 @@
const { Component, createFactory } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { connect } = require("../utils/redux-connect");
const Actions = require("../actions/index");
const { ACTIVITY_TYPE } = require("../constants");
const { L10N } = require("../utils/l10n");

Просмотреть файл

@ -7,7 +7,7 @@
const { Component } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { connect } = require("../utils/redux-connect");
const { getTheme, addThemeObserver, removeThemeObserver } =
require("devtools/client/shared/theme");
const Actions = require("../actions/index");

Просмотреть файл

@ -9,7 +9,7 @@ const { FILTER_TAGS } = require("../constants");
const { Component, createFactory } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { connect } = require("../utils/redux-connect");
const { Chart } = require("devtools/client/shared/widgets/Chart");
const { PluralForm } = require("devtools/shared/plural-form");
const Actions = require("../actions/index");

Просмотреть файл

@ -6,7 +6,7 @@
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { connect } = require("../utils/redux-connect");
const { PluralForm } = require("devtools/shared/plural-form");
const Actions = require("../actions/index");
const {

Просмотреть файл

@ -8,7 +8,7 @@ const Services = require("Services");
const { Component, createFactory } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { connect } = require("../utils/redux-connect");
const Actions = require("../actions/index");
const { FILTER_SEARCH_DELAY, FILTER_TAGS } = require("../constants");

Просмотреть файл

@ -8,18 +8,18 @@ const Services = require("Services");
const { applyMiddleware, createStore } = require("devtools/client/shared/vendor/redux");
// Middleware
const batching = require("../middleware/batching");
const prefs = require("../middleware/prefs");
const thunk = require("../middleware/thunk");
const recording = require("../middleware/recording");
const batching = require("./middleware/batching");
const prefs = require("./middleware/prefs");
const thunk = require("./middleware/thunk");
const recording = require("./middleware/recording");
// Reducers
const rootReducer = require("../reducers/index");
const { FilterTypes, Filters } = require("../reducers/filters");
const { Requests } = require("../reducers/requests");
const { Sort } = require("../reducers/sort");
const { TimingMarkers } = require("../reducers/timing-markers");
const { UI, Columns } = require("../reducers/ui");
const rootReducer = require("./reducers/index");
const { FilterTypes, Filters } = require("./reducers/filters");
const { Requests } = require("./reducers/requests");
const { Sort } = require("./reducers/sort");
const { TimingMarkers } = require("./reducers/timing-markers");
const { UI, Columns } = require("./reducers/ui");
/**
* Configure state and middleware for the Network monitor tool.

Просмотреть файл

@ -16,4 +16,5 @@ DIRS += [
DevToolsModules(
'constants.js',
'create-store.js',
)

Просмотреть файл

@ -8,7 +8,6 @@ DIRS += [
]
DevToolsModules(
'create-store.js',
'filter-autocomplete-provider.js',
'filter-predicates.js',
'filter-text-utils.js',
@ -19,6 +18,7 @@ DevToolsModules(
'menu.js',
'open-request-in-tab.js',
'prefs.js',
'redux-connect.js',
'request-utils.js',
'sort-predicates.js',
'sort-utils.js'

Просмотреть файл

@ -0,0 +1,28 @@
/* 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 { createFactory, createElement } = require("devtools/client/shared/vendor/react");
const VisibilityHandler = createFactory(require("devtools/client/shared/components/VisibilityHandler"));
const { connect } = require("devtools/client/shared/vendor/react-redux");
/**
* This helper is wrapping Redux's connect() method and applying
* HOC (VisibilityHandler component) on whatever component is
* originally passed in. The HOC is responsible for not causing
* rendering if the owner panel runs in the background.
*/
function connectWrapper() {
let args = [].slice.call(arguments);
return component => {
return connect(...args)(props => {
return VisibilityHandler(null, createElement(component, props));
});
};
}
module.exports = {
connect: connectWrapper
};

Просмотреть файл

@ -60,6 +60,7 @@ support-files =
[browser_net_accessibility-01.js]
[browser_net_accessibility-02.js]
[browser_net_api-calls.js]
[browser_net_background_update.js]
[browser_net_autoscroll.js]
[browser_net_cached-status.js]
[browser_net_cause.js]

Просмотреть файл

@ -0,0 +1,56 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Check that network logs created when the Net panel is not visible
* are displayed when the user shows the panel again.
*/
add_task(async () => {
let { tab, monitor, toolbox } = await initNetMonitor(CUSTOM_GET_URL);
info("Starting test... ");
let { document, store, windowRequire } = monitor.panelWin;
let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
store.dispatch(Actions.batchEnable(false));
// Execute two requests
await performRequests(monitor, tab, 2);
// Wait for two logs
await waitUntil(() => document.querySelectorAll(".request-list-item").length == 2);
info("Select the inspector");
await toolbox.selectTool("inspector");
info("Wait for Net panel to be hidden");
await waitUntil(() => (document.visibilityState == "hidden"));
// Execute another two requests
await performRequests(monitor, tab, 2);
// The number of rendered requests should be the same since
// requests shouldn't be rendered while the net panel is in
// background
is(document.querySelectorAll(".request-list-item").length, 2,
"There should be expected number of requests");
info("Select the Net panel again");
await toolbox.selectTool("netmonitor");
// Wait for another two logs to be rendered since the panel
// is selected now.
await waitUntil(() => document.querySelectorAll(".request-list-item").length == 4);
return teardown(monitor);
});
async function performRequests(monitor, tab, count) {
let wait = waitForNetworkEvents(monitor, count);
await ContentTask.spawn(tab.linkedBrowser, count, requestCount => {
content.wrappedJSObject.performRequests(requestCount);
});
await wait;
}

Просмотреть файл

@ -19,6 +19,7 @@ const BROWSER_BASED_DIRS = [
"resource://devtools/client/inspector/grids",
"resource://devtools/client/inspector/layout",
"resource://devtools/client/jsonview",
"resource://devtools/client/netmonitor/src/utils",
"resource://devtools/client/shared/source-map",
"resource://devtools/client/shared/redux",
"resource://devtools/client/shared/vendor",

Просмотреть файл

@ -44,6 +44,7 @@ class SidebarToggle extends Component {
// Events
onClick(event) {
event.stopPropagation();
this.props.onClick(event);
}

Просмотреть файл

@ -1,12 +1,10 @@
:root {
--breakpoint-background: url("chrome://devtools/skin/images/breakpoint.svg#light");
--breakpoint-hover-background: url("chrome://devtools/skin/images/breakpoint.svg#light-hover");
--breakpoint-conditional-background: url("chrome://devtools/skin/images/breakpoint.svg#light-conditional");
}
.theme-dark:root {
--breakpoint-background: url("chrome://devtools/skin/images/breakpoint.svg#dark");
--breakpoint-hover-background: url("chrome://devtools/skin/images/breakpoint.svg#dark-hover");
--breakpoint-conditional-background: url("chrome://devtools/skin/images/breakpoint.svg#dark-conditional");
}

Просмотреть файл

@ -25,22 +25,19 @@
border: 1px solid var(--theme-splitter-color);
border-width: 0 1px 1px 0;
display: grid;
grid-template-columns: 14px auto 1fr;
grid-template-rows: 50px;
grid-column-gap: 10px;
padding: 0 10px 0 5px;
grid-template-columns: 1fr auto;
padding: 10px 20px;
}
#font-container .theme-twisty {
display: inline-block;
cursor: pointer;
place-self: center;
vertical-align: text-top;
vertical-align: bottom;
}
.font-preview-container {
grid-column: 3 / -1;
grid-row: 1;
grid-column: 2;
grid-row: 1 / span 2;
overflow: hidden;
display: grid;
place-items: center end;
@ -61,14 +58,16 @@
background-position-y: 45px;
}
.font-preview-input {
#font-container .font-preview-input {
position: absolute;
top: 0;
top: 5px;
left: 0;
width: calc(100% - 5px);
height: calc(100% - 2px);
height: calc(100% - 10px);
background: transparent;
color: transparent;
border-radius: 0;
padding: 0;
}
.font-preview-input::-moz-selection {
@ -78,27 +77,20 @@
.font-name {
margin: 0;
font-size: 1em;
font-size: 1.2em;
font-weight: normal;
white-space: nowrap;
grid-column: 2;
place-self: center start;
}
.font-details {
grid-column: 2 / 4;
padding-inline-end: 14px;
width: 100%;
}
.font-css-code {
direction: ltr;
padding: 5px;
margin: 0;
border: 1px solid var(--theme-splitter-color);
border-radius: 3px;
overflow: hidden;
text-overflow: ellipsis;
color: var(--theme-toolbar-color);
grid-column: span 2;
position: relative;
offset-inline-start: -4px;
}
.font-css-code-expander::before {
@ -118,12 +110,12 @@
.font-format-url {
text-transform: capitalize;
margin-block-start: 0;
margin-top: .2em;
color: var(--grey-50);
}
.font-url {
margin-inline-start: 1em;
text-transform: uppercase;
margin-inline-start: .5em;
text-decoration: underline;
color: var(--theme-highlight-blue);
background: transparent;
@ -145,9 +137,6 @@
fill: var(--blue-60);
}
.font:not(.expanded) .font-css-name,
.font:not(.expanded) .font-css-code,
.font:not(.expanded) .font-format-url {
display: none;
#font-container .devtools-sidepanel-no-result + .accordion {
border-block-start: 1px solid var(--theme-splitter-color);
}

Просмотреть файл

@ -761,7 +761,6 @@ a.learn-more-link.webconsole-learn-more-link {
height: 100%;
-moz-user-focus: normal;
color: var(--console-output-color);
--console-output-indent-width: 1rem;
--console-output-indent-border-color: var(--theme-selection-background);
--icon-top-margin: 3px;
--object-inspector-hover-background: transparent;
@ -937,7 +936,7 @@ a.learn-more-link.webconsole-learn-more-link {
}
.theme-dark .webconsole-output-wrapper .message.error .tree.object-inspector,
.theme-dark .webconsole-output-wrapper .message.warn .tree.object-inspector {
--tree-indent-border-color: var(--theme-body-color);
--console-output-indent-border-color: var(--theme-body-color);
}
.webconsole-output-wrapper .message-flex-body > .message-body {

Просмотреть файл

@ -176,7 +176,6 @@ skip-if = true # Bug 1437844
[browser_console_dead_objects.js]
skip-if = true # Bug 1437845
[browser_console_error_source_click.js]
skip-if = true # Bug 1437847
[browser_console_filters.js]
[browser_console_nsiconsolemessage.js]
[browser_console_open_or_focus.js]

Просмотреть файл

@ -3,26 +3,27 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from head.js */
// Check that JS errors and CSS warnings open view source when their source link
// is clicked in the Browser Console. See bug 877778.
// is clicked in the Browser Console.
"use strict";
const TEST_URI = "data:text/html;charset=utf8,<p>hello world from bug 877778 " +
const TEST_URI = "data:text/html;charset=utf8,<p>hello world" +
"<button onclick='foobar.explode()' " +
"style='test-color: green-please'>click!</button>";
add_task(function* () {
yield new Promise(resolve => {
SpecialPowers.pushPrefEnv({"set": [
["devtools.browserconsole.filter.cssparser", true]
]}, resolve);
});
yield loadTab(TEST_URI);
let hud = yield HUDService.toggleBrowserConsole();
add_task(async function () {
await addTab(TEST_URI);
let hud = await HUDService.toggleBrowserConsole();
ok(hud, "browser console opened");
// Enable CSS warnings and errors.
await setFilterState(hud, {
css: true
});
// On e10s, the exception is triggered in child process
// and is ignored by test harness
if (!Services.appinfo.browserTabsRemoteAutostart) {
@ -30,50 +31,28 @@ add_task(function* () {
}
info("generate exception and wait for the message");
ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
ContentTask.spawn(gBrowser.selectedBrowser, {}, () => {
let button = content.document.querySelector("button");
button.click();
});
let results = yield waitForMessages({
webconsole: hud,
messages: [
{
text: "ReferenceError: foobar is not defined",
category: CATEGORY_JS,
severity: SEVERITY_ERROR,
},
{
text: "Unknown property \u2018test-color\u2019",
category: CATEGORY_CSS,
severity: SEVERITY_WARNING,
},
],
});
let viewSourceCalled = false;
let viewSource = hud.viewSource;
hud.viewSource = () => {
viewSourceCalled = true;
};
for (let result of results) {
viewSourceCalled = false;
let msg = [...result.matched][0];
ok(msg, "message element found for: " + result.text);
ok(!msg.classList.contains("filtered-by-type"), "message element is not filtered");
let selector = ".message .message-location .frame-link-source";
let locationNode = msg.querySelector(selector);
ok(locationNode, "message location element found");
locationNode.click();
ok(viewSourceCalled, "view source opened");
}
hud.viewSource = viewSource;
yield finishTest();
await waitForMessageAndViewSource(hud,
"ReferenceError: foobar is not defined");
await waitForMessageAndViewSource(hud,
"Unknown property \u2018test-color\u2019.");
await resetFilters(hud);
});
async function waitForMessageAndViewSource(hud, message) {
let msg = await waitFor(() => findMessage(hud, message));
ok(msg, `Message found: "${message}"`);
let locationNode = msg.querySelector(".message-location .frame-link-source");
ok(locationNode, "Message location link element found");
let onTabOpen = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
locationNode.click();
let newTab = await onTabOpen;
ok(true, "The view source tab was opened in response to clicking the link");
await BrowserTestUtils.removeTab(newTab);
}

Просмотреть файл

@ -124,6 +124,7 @@ void
FlattenedChildIterator::Init(bool aIgnoreXBL)
{
if (aIgnoreXBL) {
mXBLInvolved = Some(false);
return;
}
@ -132,7 +133,7 @@ FlattenedChildIterator::Init(bool aIgnoreXBL)
if (mParent->IsElement()) {
if (ShadowRoot* shadow = mParent->AsElement()->GetShadowRoot()) {
mParent = shadow;
mXBLInvolved = true;
mXBLInvolved = Some(true);
return;
}
}
@ -143,25 +144,31 @@ FlattenedChildIterator::Init(bool aIgnoreXBL)
if (binding) {
MOZ_ASSERT(binding->GetAnonymousContent());
mParent = binding->GetAnonymousContent();
mXBLInvolved = true;
mXBLInvolved = Some(true);
}
}
bool
FlattenedChildIterator::ComputeWhetherXBLIsInvolved() const
{
MOZ_ASSERT(mXBLInvolved.isNothing());
// We set mXBLInvolved to true if either the node we're iterating has a
// binding with content attached to it (in which case it is handled in Init),
// or the node is generated XBL content and has an <xbl:children> child.
if (!mParent->GetBindingParent()) {
return false;
}
// We set mXBLInvolved to true if either:
// - The node we're iterating has a binding with content attached to it.
// - The node is generated XBL content and has an <xbl:children> child.
//
// FIXME(emilio): This is very slow :(
if (!mXBLInvolved && mParent->GetBindingParent()) {
for (nsIContent* child = mParent->GetFirstChild();
child;
child = child->GetNextSibling()) {
if (child->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
MOZ_ASSERT(child->GetBindingParent());
mXBLInvolved = true;
break;
}
for (nsIContent* child = mParent->GetFirstChild();
child;
child = child->GetNextSibling()) {
if (child->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
MOZ_ASSERT(child->GetBindingParent());
return true;
}
}
return false;
}
bool

Просмотреть файл

@ -134,7 +134,6 @@ public:
explicit FlattenedChildIterator(const nsIContent* aParent,
bool aStartAtBeginning = true)
: ExplicitChildIterator(aParent, aStartAtBeginning)
, mXBLInvolved(false)
, mOriginalContent(aParent)
{
Init(false);
@ -142,20 +141,30 @@ public:
FlattenedChildIterator(FlattenedChildIterator&& aOther)
: ExplicitChildIterator(Move(aOther))
, mXBLInvolved(aOther.mXBLInvolved)
, mOriginalContent(aOther.mOriginalContent)
, mXBLInvolved(aOther.mXBLInvolved)
{}
FlattenedChildIterator(const FlattenedChildIterator& aOther)
: ExplicitChildIterator(aOther)
, mXBLInvolved(aOther.mXBLInvolved)
, mOriginalContent(aOther.mOriginalContent)
, mXBLInvolved(aOther.mXBLInvolved)
{}
bool XBLInvolved() { return mXBLInvolved; }
bool XBLInvolved() {
if (mXBLInvolved.isNothing()) {
mXBLInvolved = Some(ComputeWhetherXBLIsInvolved());
}
return *mXBLInvolved;
}
const nsIContent* Parent() const { return mOriginalContent; }
private:
bool ComputeWhetherXBLIsInvolved() const;
void Init(bool aIgnoreXBL);
protected:
/**
* This constructor is a hack to help AllChildrenIterator which sometimes
@ -164,20 +173,20 @@ protected:
FlattenedChildIterator(const nsIContent* aParent, uint32_t aFlags,
bool aStartAtBeginning = true)
: ExplicitChildIterator(aParent, aStartAtBeginning)
, mXBLInvolved(false)
, mOriginalContent(aParent)
{
bool ignoreXBL = aFlags & nsIContent::eAllButXBL;
Init(ignoreXBL);
}
void Init(bool aIgnoreXBL);
// For certain optimizations, nsCSSFrameConstructor needs to know if the
// child list of the element that we're iterating matches its .childNodes.
bool mXBLInvolved;
const nsIContent* mOriginalContent;
private:
// For certain optimizations, nsCSSFrameConstructor needs to know if the child
// list of the element that we're iterating matches its .childNodes.
//
// This is lazily computed when asked for it.
Maybe<bool> mXBLInvolved;
};
/**

Просмотреть файл

@ -42,3 +42,8 @@ DEPRECATED_OPERATION(URLCreateObjectURL_MediaStream)
DEPRECATED_OPERATION(XMLBaseAttribute)
DEPRECATED_OPERATION(WindowContentUntrusted)
DEPRECATED_OPERATION(RegisterProtocolHandlerInsecure)
DEPRECATED_OPERATION(MixedDisplayObjectSubrequest)
DEPRECATED_OPERATION(MotionEvent)
DEPRECATED_OPERATION(OrientationEvent)
DEPRECATED_OPERATION(ProximityEvent)
DEPRECATED_OPERATION(AmbientLightEvent)

Просмотреть файл

@ -911,6 +911,10 @@ nsGenericDOMDataNode::ThreadSafeTextIsOnlyWhitespace() const
if (mText.Is2b()) {
// The fragment contains non-8bit characters and such characters
// are never considered whitespace.
//
// FIXME(emilio): This is not quite true in presence of the
// NS_MAYBE_MODIFIED_FREQUENTLY flag... But looks like we only set that on
// anonymous nodes, so should be fine...
return false;
}
@ -924,6 +928,8 @@ nsGenericDOMDataNode::ThreadSafeTextIsOnlyWhitespace() const
while (cp < end) {
char ch = *cp;
// NOTE(emilio): If you ever change the definition of "whitespace" here, you
// need to change it too in RestyleManager::CharacterDataChanged.
if (!dom::IsSpaceCharacter(ch)) {
return false;
}

Просмотреть файл

@ -3032,6 +3032,12 @@ nsGlobalWindowInner::RegisterProtocolHandlerAllowedForContext(JSContext* aCx, JS
Preferences::GetBool("dom.registerProtocolHandler.insecure.enabled");
}
/* static */ bool
nsGlobalWindowInner::DeviceSensorsEnabled(JSContext* aCx, JSObject* aObj)
{
return Preferences::GetBool("device.sensors.enabled");
}
nsIDOMOfflineResourceList*
nsGlobalWindowInner::GetApplicationCache(ErrorResult& aError)
{

Просмотреть файл

@ -402,6 +402,8 @@ public:
static bool RegisterProtocolHandlerAllowedForContext(JSContext* /* unused */, JSObject* aObj);
static bool DeviceSensorsEnabled(JSContext* /* unused */, JSObject* aObj);
bool DoResolve(JSContext* aCx, JS::Handle<JSObject*> aObj,
JS::Handle<jsid> aId,
JS::MutableHandle<JS::PropertyDescriptor> aDesc);

Просмотреть файл

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html class="reftest-wait">
<iframe id="iframe" src="about:blank"></iframe>
<script>
iframe.onload = function() {
let doc = iframe.contentDocument;
let canvas = doc.createElement('canvas');
doc.body.appendChild(canvas);
let ctx = canvas.getContext('2d');
document.body.offsetTop;
iframe.style.display = 'none';
try {
ctx.font = '10px serif';
} finally {
document.documentElement.className = "";
}
};
</script>
</html>

Просмотреть файл

@ -50,3 +50,4 @@ load 1334647-1.html
load 1349067.html
pref(gfx.offscreencanvas.enabled,true) load 1348976-1.html
load 1357092.html
load 1441613.html

Просмотреть файл

@ -117,7 +117,7 @@ skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
[test_bug704423.html]
[test_bug741666.html]
[test_bug742376.html]
[test_deviceSensor.html]
[test_bug812744.html]
[test_bug822898.html]
[test_bug855741.html]
@ -167,6 +167,8 @@ skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
skip-if = toolkit == 'android' #TIMED_OUT
[test_eventctors.html]
skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
[test_eventctors_sensors.html]
[test_disabled_events.html]
[test_eventhandler_scoping.html]
[test_eventTimeStamp.html]
[test_focus_disabled.html]

Просмотреть файл

@ -1,74 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=402089
-->
<head>
<title>Test for Bug 742376</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=742376">Mozilla Bug 742376</a>
<script class="testbody" type="text/javascript">
/** Test for Bug 742376 **/
function hasListeners() {
var Cc = SpecialPowers.Cc;
var Ci = SpecialPowers.Ci;
var dss = Cc["@mozilla.org/devicesensors;1"].getService(Ci.nsIDeviceSensors);
return dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_ORIENTATION, window) ||
dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_ROTATION_VECTOR, window) ||
dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_GAME_ROTATION_VECTOR, window);
}
is(hasListeners(), false, "Must not have listeners before tests start");
function dumbListener(event) {}
function dumbListener2(event) {}
function dumbListener3(event) {}
window.addEventListener("deviceorientation", dumbListener);
window.addEventListener("random_event_name", function() {});
window.addEventListener("deviceorientation", dumbListener2);
is(hasListeners(), true, "Listeners should have been added");
window.setTimeout(function() {
window.removeEventListener("deviceorientation", dumbListener);
is(hasListeners(), true, "Only some listeners should have been removed");
window.setTimeout(function() {
window.removeEventListener("deviceorientation", dumbListener2);
window.setTimeout(function() {
is(hasListeners(), false, "Listeners should have been removed");
testEventHandler();
}, 0);
}, 0);
}, 0);
function testEventHandler() {
window.ondeviceorientation = function() {}
window.setTimeout(function() {
is(hasListeners(), true, "Handler should have been added");
window.ondeviceorientation = null;
window.setTimeout(function() {
is(hasListeners(), false, "Handler should have been removed");
SimpleTest.finish();
}, 0);
}, 0)
}
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,136 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=402089
-->
<head>
<title>Test for Bug 742376</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=742376">Mozilla Bug 742376</a>
<script class="testbody" type="text/javascript">
/** Test for Bug 742376 **/
let Cc = SpecialPowers.Cc;
let Ci = SpecialPowers.Ci;
let dss = Cc["@mozilla.org/devicesensors;1"].getService(Ci.nsIDeviceSensors);
function hasLightListeners() {
return dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_LIGHT, window);
}
function hasOrientationListeners() {
return dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_ORIENTATION, window) ||
dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_ROTATION_VECTOR, window) ||
dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_GAME_ROTATION_VECTOR, window);
}
function hasProximityListeners() {
return dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_PROXIMITY, window);
}
function hasMotionListeners() {
return dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_ACCELERATION, window) ||
dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_LINEAR_ACCELERATION, window) ||
dss.hasWindowListener(Ci.nsIDeviceSensorData.TYPE_GYROSCOPE, window);
}
async function test_event_presence(prefName, eventCheck, eventName) {
function dumbListener(event) {}
function dumbListener2(event) {}
function dumbListener3(event) {}
await SpecialPowers.pushPrefEnv({"set": [
[prefName, true]
]});
is(eventCheck(), false, "Must not have listeners before tests start");
window.addEventListener(eventName, dumbListener);
window.addEventListener("random_event_name", function() {});
window.addEventListener(eventName, dumbListener2);
is(eventCheck(), true, `Should have listeners when ${eventName} sensor is enabled`);
window.removeEventListener(eventName, dumbListener);
window.removeEventListener(eventName, dumbListener2);
is(eventCheck(), false, "Must not have listeners when removed");
await SpecialPowers.pushPrefEnv({"set": [
[prefName, false]
]});
window.addEventListener(eventName, dumbListener);
window.addEventListener("random_event_name", function() {});
window.addEventListener(eventName, dumbListener2);
is(eventCheck(), false, "Must not have listeners when sensor is disabled");
}
async function start() {
await SpecialPowers.pushPrefEnv({"set": [
["device.sensors.enabled", true],
["device.sensors.orientation.enabled", true]
]});
is(hasOrientationListeners(), false, "Must not have listeners before tests start");
function dumbListener(event) {}
function dumbListener2(event) {}
function dumbListener3(event) {}
window.addEventListener("deviceorientation", dumbListener);
window.addEventListener("random_event_name", function() {});
window.addEventListener("deviceorientation", dumbListener2);
is(hasOrientationListeners(), true, "Listeners should have been added");
await new Promise(resolve => {
window.setTimeout(function() {
window.removeEventListener("deviceorientation", dumbListener);
is(hasOrientationListeners(), true, "Only some listeners should have been removed");
window.setTimeout(function() {
window.removeEventListener("deviceorientation", dumbListener2);
window.setTimeout(function() {
is(hasOrientationListeners(), false, "Listeners should have been removed");
resolve();
}, 0);
}, 0);
}, 0);
});
await new Promise(resolve => {
window.ondeviceorientation = function() {}
window.setTimeout(function() {
is(hasOrientationListeners(), true, "Handler should have been added");
window.ondeviceorientation = null;
window.setTimeout(function() {
is(hasOrientationListeners(), false, "Handler should have been removed");
resolve();
}, 0);
}, 0);
});
await test_event_presence("device.sensors.ambientLight.enabled", hasLightListeners, "devicelight");
await test_event_presence("device.sensors.proximity.enabled", hasProximityListeners, "deviceproximity");
await test_event_presence("device.sensors.motion.enabled", hasMotionListeners, "devicemotion");
await test_event_presence("device.sensors.orientation.enabled", hasOrientationListeners, "deviceorientation");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
start();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,40 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1359076
-->
<head>
<title>Test for Bug 675884</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1359076">Mozilla Bug 1359076</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [
["device.sensors.orientation.enabled", false],
["device.sensors.motion.enabled", false],
["device.sensors.proximity.enabled", false],
["device.sensors.ambientLight.enabled", false],
["dom.w3c_pointer_events.enabled", false]
]}, () => {
is("DeviceProximityEvent" in window, false, "DeviceProximityEvent does not exist");
is("UserProximityEvent" in window, false, "UserProximityEvent does not exist");
is("DeviceLightEvent" in window, false, "DeviceLightEvent does not exist");
is("DeviceOrientationEvent" in window, false, "DeviceOrientationEvent does not exist");
is("DeviceMotionEvent" in window, false, "DeviceMotionEvent does not exist");
SimpleTest.finish();
});
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -624,61 +624,6 @@ is(e.storageArea, localStorage, "Wrong value");
document.dispatchEvent(e);
is(receivedEvent, e, "Wrong event!");
// DeviceProximityEvent
e = new DeviceProximityEvent("hello", {min: 0, value: 1, max: 2});
is(e.type, "hello", "Wrong event type!");
ok(!e.isTrusted, "Event should not be trusted");
is(e.value, 1, "value should be 1");
is(e.min, 0, "min should be 0");
is(e.max, 2, "max should be 2");
document.dispatchEvent(e);
is(receivedEvent, e, "Wrong event!");
e = new DeviceProximityEvent("hello");
is(e.value, Infinity, "Uninitialized value should be infinity");
is(e.min, -Infinity, "Uninitialized min should be -infinity");
is(e.max, Infinity, "Uninitialized max should be infinity");
// UserProximityEvent
e = new UserProximityEvent("hello", {near: true});
is(e.type, "hello", "Wrong event type!");
ok(!e.isTrusted, "Event should not be trusted");
is(e.near, true, "near should be true");
document.dispatchEvent(e);
is(receivedEvent, e, "Wrong event!");
// DeviceLightEvent
e = new DeviceLightEvent("hello", {value: 1} );
is(e.type, "hello", "Wrong event type!");
ok(!e.isTrusted, "Event should not be trusted");
is(e.value, 1, "value should be 1");
document.dispatchEvent(e);
is(receivedEvent, e, "Wrong event!");
e = new DeviceLightEvent("hello", {value: Infinity} );
is(e.value, Infinity, "value should be positive infinity");
e = new DeviceLightEvent("hello", {value: -Infinity} );
is(e.value, -Infinity, "value should be negative infinity");
e = new DeviceLightEvent("hello");
is(e.value, Infinity, "Uninitialized value should be positive infinity");
// DeviceOrientationEvent
e = new DeviceOrientationEvent("hello");
is(e.type, "hello", "Wrong event type!");
ok(!e.isTrusted, "Event should not be trusted");
is(e.alpha, null);
is(e.beta, null);
is(e.gamma, null);
is(e.absolute, false);
e = new DeviceOrientationEvent("hello", { alpha: 1, beta: 2, gamma: 3, absolute: true } );
is(e.type, "hello", "Wrong event type!");
ok(!e.isTrusted, "Event should not be trusted");
is(e.alpha, 1);
is(e.beta, 2);
is(e.gamma, 3);
is(e.absolute, true);
document.dispatchEvent(e);
is(receivedEvent, e, "Wrong event!");
// MouseEvent
try {

Просмотреть файл

@ -0,0 +1,110 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=675884
-->
<head>
<title>Test for Bug 675884</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=675884">Mozilla Bug 675884</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [
["device.sensors.enabled", true],
["device.sensors.orientation.enabled", true],
["device.sensors.motion.enabled", true],
["device.sensors.proximity.enabled", true],
["device.sensors.ambientLight.enabled", true]
]}, () => {
let receivedEvent;
document.addEventListener("hello", function(e) { receivedEvent = e; }, true);
// DeviceProximityEvent
let e = new DeviceProximityEvent("hello", {min: 0, value: 1, max: 2});
is(e.type, "hello", "Wrong event type!");
ok(!e.isTrusted, "Event should not be trusted");
is(e.value, 1, "value should be 1");
is(e.min, 0, "min should be 0");
is(e.max, 2, "max should be 2");
document.dispatchEvent(e);
is(receivedEvent, e, "Wrong event!");
e = new DeviceProximityEvent("hello");
is(e.value, Infinity, "Uninitialized value should be infinity");
is(e.min, -Infinity, "Uninitialized min should be -infinity");
is(e.max, Infinity, "Uninitialized max should be infinity");
// UserProximityEvent
e = new UserProximityEvent("hello", {near: true});
is(e.type, "hello", "Wrong event type!");
ok(!e.isTrusted, "Event should not be trusted");
is(e.near, true, "near should be true");
document.dispatchEvent(e);
is(receivedEvent, e, "Wrong event!");
// DeviceLightEvent
e = new DeviceLightEvent("hello", {value: 1} );
is(e.type, "hello", "Wrong event type!");
ok(!e.isTrusted, "Event should not be trusted");
is(e.value, 1, "value should be 1");
document.dispatchEvent(e);
is(receivedEvent, e, "Wrong event!");
e = new DeviceLightEvent("hello", {value: Infinity} );
is(e.value, Infinity, "value should be positive infinity");
e = new DeviceLightEvent("hello", {value: -Infinity} );
is(e.value, -Infinity, "value should be negative infinity");
e = new DeviceLightEvent("hello");
is(e.value, Infinity, "Uninitialized value should be positive infinity");
// DeviceOrientationEvent
e = new DeviceOrientationEvent("hello");
is(e.type, "hello", "Wrong event type!");
ok(!e.isTrusted, "Event should not be trusted");
is(e.alpha, null);
is(e.beta, null);
is(e.gamma, null);
is(e.absolute, false);
e = new DeviceOrientationEvent("hello", { alpha: 1, beta: 2, gamma: 3, absolute: true } );
is(e.type, "hello", "Wrong event type!");
ok(!e.isTrusted, "Event should not be trusted");
is(e.alpha, 1);
is(e.beta, 2);
is(e.gamma, 3);
is(e.absolute, true);
document.dispatchEvent(e);
is(receivedEvent, e, "Wrong event!");
// DeviceMotionEvent
e = new DeviceMotionEvent("hello");
is(e.type, "hello", "Wrong event type!");
ok(!e.isTrusted, "Event should not be trusted");
is(typeof e.acceleration, "object");
is(e.acceleration.x, null);
is(e.acceleration.y, null);
is(e.acceleration.z, null);
is(typeof e.accelerationIncludingGravity, "object");
is(e.accelerationIncludingGravity.x, null);
is(e.accelerationIncludingGravity.y, null);
is(e.accelerationIncludingGravity.z, null);
is(typeof e.rotationRate, "object");
is(e.rotationRate.alpha, null);
is(e.rotationRate.beta, null);
is(e.rotationRate.gamma, null);
is(e.interval, null);
SimpleTest.finish();
});
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1645,11 +1645,10 @@ HTMLMediaElement::MozDumpDebugInfo()
void
HTMLMediaElement::SetVisible(bool aVisible)
{
if (!mDecoder) {
return;
mForcedHidden = !aVisible;
if (mDecoder) {
mDecoder->SetForcedHidden(!aVisible);
}
mDecoder->SetForcedHidden(!aVisible);
}
already_AddRefed<layers::Image>
@ -3880,6 +3879,7 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
mFirstFrameLoaded(false),
mDefaultPlaybackStartPosition(0.0),
mHasSuspendTaint(false),
mForcedHidden(false),
mMediaTracksConstructed(false),
mVisibilityState(Visibility::UNTRACKED),
mErrorSink(new ErrorSink(this)),
@ -7331,6 +7331,9 @@ HTMLMediaElement::SetDecoder(MediaDecoder* aDecoder)
}
mDecoder = aDecoder;
DDLINKCHILD("decoder", mDecoder.get());
if (mDecoder && mForcedHidden) {
mDecoder->SetForcedHidden(mForcedHidden);
}
}
float

Просмотреть файл

@ -1821,6 +1821,10 @@ private:
// participate in video decoder suspending.
bool mHasSuspendTaint;
// True if media element has been forced into being considered 'hidden'.
// For use by mochitests. Enabling pref "media.test.video-suspend"
bool mForcedHidden;
// True if audio tracks and video tracks are constructed and added into the
// track list, false if all tracks are removed from the track list.
bool mMediaTracksConstructed;

Просмотреть файл

@ -2969,11 +2969,11 @@ nsGenericHTMLElement::NewURIFromString(const nsAString& aURISpec,
static bool
IsOrHasAncestorWithDisplayNone(Element* aElement, nsIPresShell* aPresShell)
{
// FIXME(emilio): In the servo case it should suffice to do something like:
//
// return !aElement->HasServoData() || Servo_Element_IsDisplayNone(aElement);
//
// at least in the case the element is part of the flattened tree...
if (aPresShell->StyleSet()->IsServo()) {
return !aElement->HasServoData() || Servo_Element_IsDisplayNone(aElement);
}
#ifdef MOZ_OLD_STYLE
AutoTArray<Element*, 10> elementsToCheck;
// Style and layout work on the flattened tree, so this is what we need to
// check in order to figure out whether we're in a display: none subtree.
@ -2990,26 +2990,22 @@ IsOrHasAncestorWithDisplayNone(Element* aElement, nsIPresShell* aPresShell)
return false;
}
StyleSetHandle styleSet = aPresShell->StyleSet();
RefPtr<nsStyleContext> sc;
nsStyleSet* styleSet = aPresShell->StyleSet()->AsGecko();
RefPtr<GeckoStyleContext> sc;
for (auto* element : Reversed(elementsToCheck)) {
if (sc) {
if (styleSet->IsGecko()) {
sc = styleSet->ResolveStyleFor(element, sc,
LazyComputeBehavior::Assert);
} else {
// Call ResolveStyleLazily to protect against stale element data in
// the tree when styled by Servo.
sc = styleSet->AsServo()->ResolveStyleLazily(
element, CSSPseudoElementType::NotPseudo);
}
sc = styleSet->ResolveStyleFor(element, sc, LazyComputeBehavior::Assert);
} else {
sc = nsComputedDOMStyle::GetStyleContextNoFlush(element, nullptr);
sc = nsComputedDOMStyle::GetStyleContextNoFlush(element, nullptr)
.downcast<GeckoStyleContext>();
}
if (sc->StyleDisplay()->mDisplay == StyleDisplay::None) {
return true;
}
}
#else
MOZ_CRASH("Old style system disabled");
#endif
return false;
}

Просмотреть файл

@ -30,6 +30,7 @@ interface nsIPaymentItem : nsISupports
readonly attribute AString label;
readonly attribute nsIPaymentCurrencyAmount amount;
readonly attribute boolean pending;
readonly attribute AString type;
};
[scriptable, builtinclass, uuid(74259861-c318-40e8-b3d5-518e701bed80)]

Просмотреть файл

@ -354,3 +354,8 @@ InvalidKeyframePropertyValue=Keyframe property value “%1$S” is invalid accor
ReadableStreamReadingFailed=Failed to read data from the ReadableStream: “%S”.
# LOCALIZATION NOTE: Do not translate "registerProtocolHandler".
RegisterProtocolHandlerInsecureWarning=Use of the registerProtocolHandler for insecure connections will be removed in version 62.
MixedDisplayObjectSubrequestWarning=Loading insecure content within a plugin embedded in a secure connection is going to be removed.
MotionEventWarning=Use of the motion sensor is deprecated.
OrientationEventWarning=Use of the orientation sensor is deprecated.
ProximityEventWarning=Use of the proximity sensor is deprecated.
AmbientLightEventWarning=Use of the ambient light sensor is deprecated.

Просмотреть файл

@ -25,6 +25,9 @@
#include "prdtoa.h"
#include <algorithm>
#include <stdint.h>
#ifdef MOZ_WIDGET_ANDROID
#include "GeneratedJNIWrappers.h"
#endif
#define PREF_VOLUME_SCALE "media.volume_scale"
#define PREF_CUBEB_BACKEND "media.cubeb.backend"
@ -119,8 +122,8 @@ cubeb* sCubebContext;
double sVolumeScale = 1.0;
uint32_t sCubebPlaybackLatencyInMilliseconds = 100;
uint32_t sCubebMSGLatencyInFrames = 512;
bool sCubebPlaybackLatencyPrefSet;
bool sCubebMSGLatencyPrefSet;
bool sCubebPlaybackLatencyPrefSet = false;
bool sCubebMSGLatencyPrefSet = false;
bool sAudioStreamInitEverSucceeded = false;
#ifdef MOZ_CUBEB_REMOTING
bool sCubebSandbox;
@ -305,11 +308,15 @@ bool InitPreferredSampleRate()
if (!context) {
return false;
}
#ifdef MOZ_WIDGET_ANDROID
sPreferredSampleRate = AndroidGetAudioOutputSampleRate();
#else
if (cubeb_get_preferred_sample_rate(context,
&sPreferredSampleRate) != CUBEB_OK) {
return false;
}
#endif
MOZ_ASSERT(sPreferredSampleRate);
return true;
}
@ -527,14 +534,28 @@ bool CubebMSGLatencyPrefSet()
return sCubebMSGLatencyPrefSet;
}
Maybe<uint32_t> GetCubebMSGLatencyInFrames()
uint32_t GetCubebMSGLatencyInFrames(cubeb_stream_params * params)
{
StaticMutexAutoLock lock(sMutex);
if (!sCubebMSGLatencyPrefSet) {
return Maybe<uint32_t>();
if (sCubebMSGLatencyPrefSet) {
MOZ_ASSERT(sCubebMSGLatencyInFrames > 0);
return sCubebMSGLatencyInFrames;
}
MOZ_ASSERT(sCubebMSGLatencyInFrames > 0);
return Some(sCubebMSGLatencyInFrames);
#ifdef MOZ_WIDGET_ANDROID
return AndroidGetAudioOutputFramesPerBuffer();
#else
cubeb* context = GetCubebContextUnlocked();
if (!context) {
return sCubebMSGLatencyInFrames; // default 512
}
uint32_t latency_frames = 0;
if (cubeb_get_min_latency(context, params, &latency_frames) != CUBEB_OK) {
NS_WARNING("Could not get minimal latency from cubeb.");
return sCubebMSGLatencyInFrames; // default 512
}
return latency_frames;
#endif
}
void InitLibrary()
@ -741,5 +762,20 @@ void GetDeviceCollection(nsTArray<RefPtr<AudioDeviceInfo>>& aDeviceInfos,
}
}
#ifdef MOZ_WIDGET_ANDROID
uint32_t AndroidGetAudioOutputSampleRate()
{
int32_t sample_rate = java::GeckoAppShell::GetAudioOutputSampleRate();
MOZ_ASSERT(sample_rate > 0);
return sample_rate;
}
uint32_t AndroidGetAudioOutputFramesPerBuffer()
{
int32_t frames = java::GeckoAppShell::GetAudioOutputFramesPerBuffer();
MOZ_ASSERT(frames > 0);
return frames;
}
#endif
} // namespace CubebUtils
} // namespace mozilla

Просмотреть файл

@ -44,7 +44,7 @@ cubeb* GetCubebContext();
void ReportCubebStreamInitFailure(bool aIsFirstStream);
void ReportCubebBackendUsed();
uint32_t GetCubebPlaybackLatencyInMilliseconds();
Maybe<uint32_t> GetCubebMSGLatencyInFrames();
uint32_t GetCubebMSGLatencyInFrames(cubeb_stream_params * params);
bool CubebLatencyPrefSet();
cubeb_channel_layout ConvertChannelMapToCubebLayout(uint32_t aChannelMap);
void GetCurrentBackend(nsAString& aBackend);
@ -52,6 +52,11 @@ void GetPreferredChannelLayout(nsAString& aLayout);
void GetDeviceCollection(nsTArray<RefPtr<AudioDeviceInfo>>& aDeviceInfos,
Side aSide);
cubeb_channel_layout GetPreferredChannelLayoutOrSMPTE(cubeb* context, uint32_t aChannels);
#ifdef MOZ_WIDGET_ANDROID
uint32_t AndroidGetAudioOutputSampleRate();
uint32_t AndroidGetAudioOutputFramesPerBuffer();
#endif
} // namespace CubebUtils
} // namespace mozilla

Просмотреть файл

@ -599,7 +599,6 @@ AudioCallbackDriver::Init()
cubeb_stream_params output;
cubeb_stream_params input;
uint32_t latency_frames;
bool firstStream = CubebUtils::GetFirstStream();
MOZ_ASSERT(!NS_IsMainThread(),
@ -629,14 +628,7 @@ AudioCallbackDriver::Init()
output.layout = CubebUtils::GetPreferredChannelLayoutOrSMPTE(cubebContext, mOutputChannels);
output.prefs = CUBEB_STREAM_PREF_NONE;
Maybe<uint32_t> latencyPref = CubebUtils::GetCubebMSGLatencyInFrames();
if (latencyPref) {
latency_frames = latencyPref.value();
} else {
if (cubeb_get_min_latency(cubebContext, &output, &latency_frames) != CUBEB_OK) {
NS_WARNING("Could not get minimal latency from cubeb.");
}
}
uint32_t latency_frames = CubebUtils::GetCubebMSGLatencyInFrames(&output);
// Macbook and MacBook air don't have enough CPU to run very low latency
// MediaStreamGraphs, cap the minimal latency to 512 frames int this case.

Просмотреть файл

@ -3080,6 +3080,11 @@ void MediaDecoderStateMachine::SetVideoDecodeModeInternal(VideoDecodeMode aMode)
{
MOZ_ASSERT(OnTaskQueue());
LOG("SetVideoDecodeModeInternal(), VideoDecodeMode=(%s->%s), mVideoDecodeSuspended=%c",
mVideoDecodeMode == VideoDecodeMode::Normal ? "Normal" : "Suspend",
aMode == VideoDecodeMode::Normal ? "Normal" : "Suspend",
mVideoDecodeSuspended ? 'T' : 'F');
// Should not suspend decoding if we don't turn on the pref.
if (!MediaPrefs::MDSMSuspendBackgroundVideoEnabled() &&
aMode == VideoDecodeMode::Suspend) {
@ -3092,11 +3097,6 @@ void MediaDecoderStateMachine::SetVideoDecodeModeInternal(VideoDecodeMode aMode)
return;
}
LOG("SetVideoDecodeModeInternal(), VideoDecodeMode=(%s->%s), mVideoDecodeSuspended=%c",
mVideoDecodeMode == VideoDecodeMode::Normal ? "Normal" : "Suspend",
aMode == VideoDecodeMode::Normal ? "Normal" : "Suspend",
mVideoDecodeSuspended ? 'T' : 'F');
// Set new video decode mode.
mVideoDecodeMode = aMode;

Просмотреть файл

@ -2,7 +2,7 @@
* 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/. */
/* jshint esversion: 6, -W097 */
/* globals SimpleTest, SpecialPowers, info, is, ok */
/* globals SimpleTest, SpecialPowers, document, info, is, manager, ok */
"use strict";
@ -14,6 +14,38 @@ function startTest(test) {
});
}
/**
* @param {HTMLMediaElement} video target of interest.
* @param {string} eventName the event to wait on.
* @returns {Promise} A promise that is resolved when event happens.
*/
function nextEvent(video, eventName) {
return new Promise(function (resolve, reject) {
let f = function (event) {
ok(true, `${video.token} ${eventName}.`);
video.removeEventListener(eventName, f, false);
resolve(event);
};
video.addEventListener(eventName, f, false);
});
}
function nextVideoEnded(video) {
return nextEvent(video, 'ended');
}
function nextVideoPlaying(video) {
return nextEvent(video, 'playing');
}
function nextVideoResumes(video) {
return nextEvent(video, 'mozexitvideosuspend');
}
function nextVideoSuspends(video) {
return nextEvent(video, 'mozentervideosuspend');
}
/**
* @param {string} url video src.
* @returns {HTMLMediaElement} The created video element.
@ -21,14 +53,14 @@ function startTest(test) {
function appendVideoToDoc(url, token, width, height) {
// Default size of (160, 120) is used by other media tests.
if (width === undefined) { width = 160; }
if (height === undefined) { height = 3*width/4; }
if (height === undefined) { height = 3 * width / 4; }
let v = document.createElement('video');
v.token = token;
document.body.appendChild(v);
v.width = width;
v.height = height;
v.src = url;
document.body.appendChild(v);
return v;
}
@ -89,7 +121,7 @@ function testVideoSuspendsWhenHidden(video) {
* @returns {Promise} Promise that is resolved when video decode resumes.
*/
function testVideoResumesWhenShown(video) {
var p = once(video, 'mozexitvideosuspend').then(() => {
var p = once(video, 'mozexitvideosuspend').then(() => {
ok(true, `${video.token} resumes`);
});
Log(video.token, "Set visible");
@ -102,7 +134,7 @@ function testVideoResumesWhenShown(video) {
* @returns {Promise} Promise that is resolved when video decode resumes.
*/
function testVideoOnlySeekCompletedWhenShown(video) {
var p = once(video, 'mozvideoonlyseekcompleted').then(() => {
var p = once(video, 'mozvideoonlyseekcompleted').then(() => {
ok(true, `${video.token} resumes`);
});
Log(video.token, "Set visible");
@ -116,7 +148,7 @@ function testVideoOnlySeekCompletedWhenShown(video) {
*/
function checkVideoDoesntSuspend(video) {
let p = Promise.race([
waitUntilEnded(video).then(() => { ok(true, `${video.token} ended before decode was suspended`)}),
waitUntilEnded(video).then(() => { ok(true, `${video.token} ended before decode was suspended`) }),
once(video, 'mozentervideosuspend', () => { Promise.reject(new Error(`${video.token} suspended`)) })
]);
Log(video.token, "Set hidden.");

Просмотреть файл

@ -4,48 +4,71 @@
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="manifest.js"></script>
<script src="background_video.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" href="/tests/SimpleTest/test.css" />
<script type="text/javascript">
"use strict";
"use strict";
var manager = new MediaTestManager;
var manager = new MediaTestManager;
var MIN_DELAY = 100;
var MIN_DELAY = 100;
function testDelay(v, start, min) {
let end = performance.now();
let delay = end - start;
ok(delay > min, `${v.token} suspended with a delay of ${delay} ms`);
}
function testDelay(v, start, min) {
let end = performance.now();
let delay = end - start;
ok(delay > min, `${v.token} suspended with a delay of ${delay} ms`);
}
startTest({
desc: 'Test Background Video Suspends',
prefs: [
[ "media.test.video-suspend", true ],
[ "media.suspend-bkgnd-video.enabled", true ],
// Use a short delay to ensure video decode suspend happens before end
// of video.
[ "media.suspend-bkgnd-video.delay-ms", MIN_DELAY ],
[ "privacy.reduceTimerPrecision", false ]
],
tests: gDecodeSuspendTests,
runTest: (test, token) => {
let v = appendVideoToDoc(test.name, token);
async function runTest(test, token) {
let video = appendVideoToDoc(test.name, token);
manager.started(token);
let start;
waitUntilPlaying(v)
.then(() => { start = performance.now(); })
.then(() => testVideoSuspendsWhenHidden(v))
.then(() => {
testDelay(v, start, MIN_DELAY);
return testVideoResumesWhenShown(v);
})
.then(() => waitUntilEnded(v))
.then(() => {
removeNodeAndSource(v);
manager.finished(token);
});
let ended = nextVideoEnded(video);
let playing = nextVideoPlaying(video);
let resumes = nextVideoResumes(video);
let suspends = nextVideoSuspends(video);
Log(token, "Start playing");
video.play();
Log(token, "Waiting for video playing");
await playing;
let start = performance.now();
Log(token, "Set hidden");
video.setVisible(false);
Log(token, "Waiting for video suspend");
await suspends;
testDelay(video, start, MIN_DELAY);
Log(token, "Set visible");
video.setVisible(true);
Log(token, "Waiting for video resume");
await resumes;
Log(token, "Waiting for ended");
await ended;
ok(video.currentTime >= video.duration, 'current time approximates duration.');
removeNodeAndSource(video);
manager.finished(token);
}
});
</script>
startTest({
desc: 'Test Background Video Suspends',
prefs: [
["media.test.video-suspend", true],
["media.suspend-bkgnd-video.enabled", true],
// Use a short delay to ensure video decode suspend happens before end
// of video.
["media.suspend-bkgnd-video.delay-ms", MIN_DELAY],
["privacy.reduceTimerPrecision", false]
],
tests: gDecodeSuspendTests,
runTest: runTest
});
</script>

Просмотреть файл

@ -4,36 +4,50 @@
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="manifest.js"></script>
<script src="background_video.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" href="/tests/SimpleTest/test.css" />
<script type="text/javascript">
"use strict";
"use strict";
var manager = new MediaTestManager;
var manager = new MediaTestManager;
startTest({
desc: "Test Background Suspended Video Fires 'ended' Event",
prefs: [
[ "media.test.video-suspend", true ],
[ "media.suspend-bkgnd-video.enabled", true ],
// User a short delay to ensure video decode suspend happens before end
// of video.
[ "media.suspend-bkgnd-video.delay-ms", 1000 ]
],
tests: gDecodeSuspendTests,
runTest: (test, token) => {
let v = appendVideoToDoc(test.name, token);
async function runTest(test, token) {
let video = appendVideoToDoc(test.name, token);
manager.started(token);
// This test checks that 'ended' event is received for videos with
// suspended video decoding. This is important for looping video logic
// handling in HTMLMediaElement.
waitUntilPlaying(v)
.then(() => testVideoSuspendsWhenHidden(v))
.then(() => waitUntilEnded(v))
.then(() => {
ok(v.currentTime >= v.duration, 'current time approximates duration.');
manager.finished(token);
});
let ended = nextVideoEnded(video);
let suspends = nextVideoSuspends(video);
Log(token, "Start playing");
video.play();
Log(token, "Set hidden");
video.setVisible(false);
Log(token, "Waiting for video suspend");
await suspends;
Log(token, "Waiting for ended");
await ended;
ok(video.currentTime >= video.duration, 'current time approximates duration.');
manager.finished(token);
}
});
</script>
startTest({
desc: "Test Background Suspended Video Fires 'ended' Event",
prefs: [
["media.test.video-suspend", true],
["media.suspend-bkgnd-video.enabled", true],
// User a short delay to ensure video decode suspend happens before end
// of video.
["media.suspend-bkgnd-video.delay-ms", 1000]
],
tests: gDecodeSuspendTests,
runTest: runTest
});
</script>

Просмотреть файл

@ -108,10 +108,12 @@ NS_IMPL_ISUPPORTS(PaymentItem,
PaymentItem::PaymentItem(const nsAString& aLabel,
nsIPaymentCurrencyAmount* aAmount,
const bool aPending)
const bool aPending,
const nsAString& aType)
: mLabel(aLabel)
, mAmount(aAmount)
, mPending(aPending)
, mType(aType)
{
}
@ -126,7 +128,7 @@ PaymentItem::Create(const IPCPaymentItem& aIPCItem, nsIPaymentItem** aItem)
return rv;
}
nsCOMPtr<nsIPaymentItem> item =
new PaymentItem(aIPCItem.label(), amount, aIPCItem.pending());
new PaymentItem(aIPCItem.label(), amount, aIPCItem.pending(), aIPCItem.type());
item.forget(aItem);
return NS_OK;
}
@ -156,6 +158,13 @@ PaymentItem::GetPending(bool* aPending)
return NS_OK;
}
NS_IMETHODIMP
PaymentItem::GetType(nsAString& aType)
{
aType = mType;
return NS_OK;
}
/* PaymentDetailsModifier */
NS_IMPL_ISUPPORTS(PaymentDetailsModifier,

Просмотреть файл

@ -65,13 +65,15 @@ public:
private:
PaymentItem(const nsAString& aLabel,
nsIPaymentCurrencyAmount* aAmount,
const bool aPending);
const bool aPending,
const nsAString& aType);
~PaymentItem() = default;
nsString mLabel;
nsCOMPtr<nsIPaymentCurrencyAmount> mAmount;
bool mPending;
nsString mType;
};
class PaymentDetailsModifier final : public nsIPaymentDetailsModifier

Просмотреть файл

@ -51,9 +51,18 @@ ConvertCurrencyAmount(const PaymentCurrencyAmount& aAmount,
void
ConvertItem(const PaymentItem& aItem, IPCPaymentItem& aIPCItem)
{
uint8_t typeIndex = UINT8_MAX;
if (aItem.mType.WasPassed()) {
typeIndex = static_cast<uint8_t>(aItem.mType.Value());
}
nsString type;
if (typeIndex < ArrayLength(PaymentItemTypeValues::strings)) {
type.AssignASCII(
PaymentItemTypeValues::strings[typeIndex].value);
}
IPCPaymentCurrencyAmount amount;
ConvertCurrencyAmount(aItem.mAmount, amount);
aIPCItem = IPCPaymentItem(aItem.mLabel, amount, aItem.mPending);
aIPCItem = IPCPaymentItem(aItem.mLabel, amount, aItem.mPending, type);
}
nsresult

Просмотреть файл

@ -27,6 +27,7 @@ struct IPCPaymentItem
nsString label;
IPCPaymentCurrencyAmount amount;
bool pending;
nsString type;
};
struct IPCPaymentDetailsModifier

Просмотреть файл

@ -141,8 +141,8 @@ function checkComplexRequest(payRequest) {
if (!details.displayItems) {
emitTestFail("details.displayItems should not be undefined.");
}
if (displayItems.length != 2) {
emitTestFail("displayItems' length should be 2.")
if (displayItems.length != 3) {
emitTestFail("displayItems' length should be 3.")
}
let item = displayItems.queryElementAt(0, Ci.nsIPaymentItem);
if (item.label != "First item") {
@ -154,6 +154,9 @@ function checkComplexRequest(payRequest) {
if (item.amount.value != "60.00") {
emitTestFail("1st display item's value should be '60.00'.");
}
if (item.type != "") {
emitTestFail("1st display item's type should be ''.");
}
item = displayItems.queryElementAt(1, Ci.nsIPaymentItem);
if (item.label != "Second item") {
emitTestFail("2nd display item's label should be 'Second item'.");
@ -164,6 +167,22 @@ function checkComplexRequest(payRequest) {
if (item.amount.value != "40.00") {
emitTestFail("2nd display item's value should be '40.00'.");
}
if (item.type != "") {
emitTestFail("2nd display item's type should be ''.");
}
item = displayItems.queryElementAt(2, Ci.nsIPaymentItem);
if (item.label != "Tax") {
emitTestFail("3rd display item's label should be 'Tax'.");
}
if (item.amount.currency != "USD") {
emitTestFail("3rd display item's currency should be 'USD'.");
}
if (item.amount.value != "5.00") {
emitTestFail("3rd display item's value should be '5.00'.");
}
if (item.type != "tax") {
emitTestFail("3rd display item's type should be 'tax'.");
}
const modifiers = details.modifiers;
if (!modifiers) {

Просмотреть файл

@ -75,6 +75,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1345361
currency: "USD",
value: "40.00"
}
},
{
label: "Tax",
amount: {
currency: "USD",
value: "5.00"
},
type: "tax"
}
],
modifiers: [

Просмотреть файл

@ -936,6 +936,9 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
// set hasMixedContentObjectSubrequest on this object if necessary
if (aContentType == TYPE_OBJECT_SUBREQUEST) {
if (!sBlockMixedObjectSubrequest) {
rootDoc->WarnOnceAbout(nsIDocument::eMixedDisplayObjectSubrequest);
}
rootDoc->SetHasMixedContentObjectSubrequest(true);
}

Просмотреть файл

@ -37,6 +37,12 @@ using namespace hal;
#define DEFAULT_SENSOR_POLL 100
static bool gPrefSensorsEnabled = false;
static bool gPrefMotionSensorEnabled = false;
static bool gPrefOrientationSensorEnabled = false;
static bool gPrefProximitySensorEnabled = false;
static bool gPrefAmbientLightSensorEnabled = false;
static const nsTArray<nsIDOMWindow*>::index_type NoIndex =
nsTArray<nsIDOMWindow*>::NoIndex;
@ -106,7 +112,21 @@ nsDeviceSensors::nsDeviceSensors()
{
mIsUserProximityNear = false;
mLastDOMMotionEventTime = TimeStamp::Now();
mEnabled = Preferences::GetBool("device.sensors.enabled", true);
Preferences::AddBoolVarCache(&gPrefSensorsEnabled,
"device.sensors.enabled",
true);
Preferences::AddBoolVarCache(&gPrefMotionSensorEnabled,
"device.sensors.motion.enabled",
true);
Preferences::AddBoolVarCache(&gPrefOrientationSensorEnabled,
"device.sensors.orientation.enabled",
true);
Preferences::AddBoolVarCache(&gPrefProximitySensorEnabled,
"device.sensors.proximity.enabled",
false);
Preferences::AddBoolVarCache(&gPrefAmbientLightSensorEnabled,
"device.sensors.ambientLight.enabled",
false);
for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
nsTArray<nsIDOMWindow*> *windows = new nsTArray<nsIDOMWindow*>();
@ -130,7 +150,7 @@ nsDeviceSensors::~nsDeviceSensors()
NS_IMETHODIMP nsDeviceSensors::HasWindowListener(uint32_t aType, nsIDOMWindow *aWindow, bool *aRetVal)
{
if (AreSensorEventsDisabled(aWindow))
if (!IsSensorAllowedByPref(aType, aWindow))
*aRetVal = false;
else
*aRetVal = mWindowListeners[aType]->IndexOf(aWindow) != NoIndex;
@ -171,7 +191,7 @@ static bool sTestSensorEvents = false;
NS_IMETHODIMP nsDeviceSensors::AddWindowListener(uint32_t aType, nsIDOMWindow *aWindow)
{
if (AreSensorEventsDisabled(aWindow))
if (!IsSensorAllowedByPref(aType, aWindow))
return NS_OK;
if (mWindowListeners[aType]->IndexOf(aWindow) != NoIndex)
@ -587,17 +607,64 @@ nsDeviceSensors::FireDOMMotionEvent(nsIDocument *doc,
}
bool
nsDeviceSensors::AreSensorEventsDisabled(nsIDOMWindow* aWindow)
nsDeviceSensors::IsSensorAllowedByPref(uint32_t aType, nsIDOMWindow* aWindow)
{
if (!mEnabled) {
return true;
}
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aWindow);
if (!window) {
// checks "device.sensors.enabled" master pref
if (!gPrefSensorsEnabled) {
return false;
}
return nsContentUtils::ShouldResistFingerprinting(window->GetDocShell());
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aWindow);
nsCOMPtr<nsIDocument> doc;
if (window) {
doc = window->GetExtantDoc();
}
switch (aType) {
case nsIDeviceSensorData::TYPE_LINEAR_ACCELERATION:
case nsIDeviceSensorData::TYPE_ACCELERATION:
case nsIDeviceSensorData::TYPE_GYROSCOPE:
// checks "device.sensors.motion.enabled" pref
if (!gPrefMotionSensorEnabled) {
return false;
} else if (doc) {
doc->WarnOnceAbout(nsIDocument::eMotionEvent);
}
break;
case nsIDeviceSensorData::TYPE_GAME_ROTATION_VECTOR:
case nsIDeviceSensorData::TYPE_ORIENTATION:
case nsIDeviceSensorData::TYPE_ROTATION_VECTOR:
// checks "device.sensors.orientation.enabled" pref
if (!gPrefOrientationSensorEnabled) {
return false;
} else if (doc) {
doc->WarnOnceAbout(nsIDocument::eOrientationEvent);
}
break;
case nsIDeviceSensorData::TYPE_PROXIMITY:
// checks "device.sensors.proximity.enabled" pref
if (!gPrefProximitySensorEnabled) {
return false;
} else if (doc) {
doc->WarnOnceAbout(nsIDocument::eProximityEvent, true);
}
break;
case nsIDeviceSensorData::TYPE_LIGHT:
// checks "device.sensors.ambientLight.enabled" pref
if (!gPrefAmbientLightSensorEnabled) {
return false;
} else if (doc) {
doc->WarnOnceAbout(nsIDocument::eAmbientLightEvent, true);
}
break;
default:
MOZ_ASSERT_UNREACHABLE("Device sensor type not recognised");
return false;
}
if (!window) {
return true;
}
return !nsContentUtils::ShouldResistFingerprinting(window->GetDocShell());
}

Просмотреть файл

@ -69,13 +69,11 @@ private:
double y,
double z);
bool mEnabled;
inline bool IsSensorEnabled(uint32_t aType) {
return mWindowListeners[aType]->Length() > 0;
}
bool AreSensorEventsDisabled(nsIDOMWindow* aWindow);
bool IsSensorAllowedByPref(uint32_t aType, nsIDOMWindow* aWindow);
mozilla::TimeStamp mLastDOMMotionEventTime;
bool mIsUserProximityNear;

Просмотреть файл

@ -295,13 +295,13 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "DelayNode", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "DeviceLightEvent", insecureContext: true},
{name: "DeviceLightEvent", insecureContext: true, release: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "DeviceMotionEvent", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "DeviceOrientationEvent", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "DeviceProximityEvent", insecureContext: true},
{name: "DeviceProximityEvent", insecureContext: true, release: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "Directory", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
@ -1165,7 +1165,7 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "URLSearchParams", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "UserProximityEvent", insecureContext: true},
{name: "UserProximityEvent", insecureContext: true, release: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "ValidityState", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!

Просмотреть файл

@ -4,7 +4,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
[Constructor(DOMString type, optional DeviceLightEventInit eventInitDict)]
[Pref="device.sensors.ambientLight.enabled", Func="nsGlobalWindowInner::DeviceSensorsEnabled", Constructor(DOMString type, optional DeviceLightEventInit eventInitDict)]
interface DeviceLightEvent : Event
{
readonly attribute unrestricted double value;

Просмотреть файл

@ -18,7 +18,7 @@ interface DeviceRotationRate {
readonly attribute double? gamma;
};
[Constructor(DOMString type, optional DeviceMotionEventInit eventInitDict)]
[Pref="device.sensors.motion.enabled", Func="nsGlobalWindowInner::DeviceSensorsEnabled", Constructor(DOMString type, optional DeviceMotionEventInit eventInitDict)]
interface DeviceMotionEvent : Event {
readonly attribute DeviceAcceleration? acceleration;
readonly attribute DeviceAcceleration? accelerationIncludingGravity;

Просмотреть файл

@ -4,7 +4,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
[Constructor(DOMString type, optional DeviceOrientationEventInit eventInitDict), LegacyEventInit]
[Pref="device.sensors.orientation.enabled", Func="nsGlobalWindowInner::DeviceSensorsEnabled", Constructor(DOMString type, optional DeviceOrientationEventInit eventInitDict), LegacyEventInit]
interface DeviceOrientationEvent : Event
{
readonly attribute double? alpha;

Просмотреть файл

@ -4,7 +4,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
[Constructor(DOMString type, optional DeviceProximityEventInit eventInitDict)]
[Pref="device.sensors.proximity.enabled", Func="nsGlobalWindowInner::DeviceSensorsEnabled", Constructor(DOMString type, optional DeviceProximityEventInit eventInitDict)]
interface DeviceProximityEvent : Event
{
readonly attribute double value;

Просмотреть файл

@ -18,10 +18,15 @@ dictionary PaymentCurrencyAmount {
DOMString currencySystem = "urn:iso:std:iso:4217";
};
enum PaymentItemType {
"tax"
};
dictionary PaymentItem {
required DOMString label;
required PaymentCurrencyAmount amount;
boolean pending = false;
PaymentItemType type;
};
dictionary PaymentShippingOption {

Просмотреть файл

@ -4,7 +4,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
[Constructor(DOMString type, optional UserProximityEventInit eventInitDict)]
[Pref="device.sensors.proximity.enabled", Func="nsGlobalWindowInner::DeviceSensorsEnabled", Constructor(DOMString type, optional UserProximityEventInit eventInitDict)]
interface UserProximityEvent : Event
{
readonly attribute boolean near;

Просмотреть файл

@ -1073,11 +1073,11 @@ XULDocument::GetElementsByAttribute(const nsAString& aAttribute,
const nsAString& aValue)
{
RefPtr<nsAtom> attrAtom(NS_Atomize(aAttribute));
void* attrValue = new nsString(aValue);
nsAutoPtr<nsString> attrValue(new nsString(aValue));
RefPtr<nsContentList> list = new nsContentList(this,
MatchAttribute,
nsContentUtils::DestroyMatchString,
attrValue,
attrValue.forget(),
true,
attrAtom,
kNameSpaceID_Unknown);
@ -1092,7 +1092,7 @@ XULDocument::GetElementsByAttributeNS(const nsAString& aNamespaceURI,
ErrorResult& aRv)
{
RefPtr<nsAtom> attrAtom(NS_Atomize(aAttribute));
void* attrValue = new nsString(aValue);
nsAutoPtr<nsString> attrValue(new nsString(aValue));
int32_t nameSpaceId = kNameSpaceID_Wildcard;
if (!aNamespaceURI.EqualsLiteral("*")) {
@ -1108,7 +1108,7 @@ XULDocument::GetElementsByAttributeNS(const nsAString& aNamespaceURI,
RefPtr<nsContentList> list = new nsContentList(this,
MatchAttribute,
nsContentUtils::DestroyMatchString,
attrValue,
attrValue.forget(),
true,
attrAtom,
nameSpaceId);

Просмотреть файл

@ -103,7 +103,7 @@ FastMarshaler::GetMarshalFlags(DWORD aDestContext, DWORD aMshlFlags)
return aMshlFlags;
}
if (!IsCallerExternalProcess()) {
if (IsCallerExternalProcess()) {
return aMshlFlags;
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше