зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-central to mozilla-inbound
This commit is contained in:
Коммит
118e03a936
1
.hgtags
1
.hgtags
|
@ -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 browser’s 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;
|
||||
}
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче