зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to b2ginbound a=merge
This commit is contained in:
Коммит
c3a8e32831
|
@ -10,6 +10,7 @@
|
|||
#include "AccessibleWrap.h"
|
||||
#include "DocAccessible.h"
|
||||
#include "nsMai.h"
|
||||
#include "ProxyAccessible.h"
|
||||
#include "mozilla/Likely.h"
|
||||
|
||||
using namespace mozilla::a11y;
|
||||
|
@ -46,12 +47,14 @@ documentInterfaceInitCB(AtkDocumentIface *aIface)
|
|||
const gchar *
|
||||
getDocumentLocaleCB(AtkDocument *aDocument)
|
||||
{
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aDocument));
|
||||
if (!accWrap)
|
||||
return nullptr;
|
||||
|
||||
nsAutoString locale;
|
||||
accWrap->Language(locale);
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aDocument));
|
||||
if (accWrap) {
|
||||
accWrap->Language(locale);
|
||||
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aDocument))) {
|
||||
proxy->Language(locale);
|
||||
}
|
||||
|
||||
return locale.IsEmpty() ? nullptr : AccessibleWrap::ReturnString(locale);
|
||||
}
|
||||
|
||||
|
@ -71,24 +74,30 @@ prependToList(GSList *aList, const char *const aName, const nsAutoString &aValue
|
|||
AtkAttributeSet *
|
||||
getDocumentAttributesCB(AtkDocument *aDocument)
|
||||
{
|
||||
nsAutoString url;
|
||||
nsAutoString w3cDocType;
|
||||
nsAutoString mimeType;
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aDocument));
|
||||
if (!accWrap || !accWrap->IsDoc())
|
||||
if (accWrap) {
|
||||
if (!accWrap->IsDoc()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DocAccessible* document = accWrap->AsDoc();
|
||||
document->URL(url);
|
||||
document->DocType(w3cDocType);
|
||||
document->MimeType(mimeType);
|
||||
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aDocument))) {
|
||||
proxy->URLDocTypeMimeType(url, w3cDocType, mimeType);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// according to atkobject.h, AtkAttributeSet is a GSList
|
||||
GSList* attributes = nullptr;
|
||||
DocAccessible* document = accWrap->AsDoc();
|
||||
nsAutoString aURL;
|
||||
document->URL(aURL);
|
||||
attributes = prependToList(attributes, kDocUrlName, aURL);
|
||||
|
||||
nsAutoString aW3CDocType;
|
||||
document->DocType(aW3CDocType);
|
||||
attributes = prependToList(attributes, kDocTypeName, aW3CDocType);
|
||||
|
||||
nsAutoString aMimeType;
|
||||
document->MimeType(aMimeType);
|
||||
attributes = prependToList(attributes, kMimeTypeName, aMimeType);
|
||||
attributes = prependToList(attributes, kDocUrlName, url);
|
||||
attributes = prependToList(attributes, kDocTypeName, w3cDocType);
|
||||
attributes = prependToList(attributes, kMimeTypeName, mimeType);
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
@ -97,20 +106,44 @@ const gchar *
|
|||
getDocumentAttributeValueCB(AtkDocument *aDocument,
|
||||
const gchar *aAttrName)
|
||||
{
|
||||
ProxyAccessible* proxy = nullptr;
|
||||
DocAccessible* document = nullptr;
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aDocument));
|
||||
if (!accWrap || !accWrap->IsDoc())
|
||||
return nullptr;
|
||||
if (accWrap) {
|
||||
if (!accWrap->IsDoc()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
document = accWrap->AsDoc();
|
||||
} else {
|
||||
proxy = GetProxy(ATK_OBJECT(aDocument));
|
||||
if (!proxy) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
DocAccessible* document = accWrap->AsDoc();
|
||||
nsAutoString attrValue;
|
||||
if (!strcasecmp(aAttrName, kDocTypeName))
|
||||
document->DocType(attrValue);
|
||||
else if (!strcasecmp(aAttrName, kDocUrlName))
|
||||
document->URL(attrValue);
|
||||
else if (!strcasecmp(aAttrName, kMimeTypeName))
|
||||
document->MimeType(attrValue);
|
||||
else
|
||||
if (!strcasecmp(aAttrName, kDocTypeName)) {
|
||||
if (document) {
|
||||
document->DocType(attrValue);
|
||||
} else {
|
||||
proxy->DocType(attrValue);
|
||||
}
|
||||
} else if (!strcasecmp(aAttrName, kDocUrlName)) {
|
||||
if (document) {
|
||||
document->URL(attrValue);
|
||||
} else {
|
||||
proxy->URL(attrValue);
|
||||
}
|
||||
} else if (!strcasecmp(aAttrName, kMimeTypeName)) {
|
||||
if (document) {
|
||||
document->MimeType(attrValue);
|
||||
} else {
|
||||
proxy->MimeType(attrValue);
|
||||
}
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return attrValue.IsEmpty() ? nullptr : AccessibleWrap::ReturnString(attrValue);
|
||||
}
|
||||
|
|
|
@ -1631,5 +1631,70 @@ DocAccessibleChild::RecvBounds(const uint64_t& aID,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvLanguage(const uint64_t& aID,
|
||||
nsString* aLocale)
|
||||
{
|
||||
Accessible* acc = IdToAccessible(aID);
|
||||
if (acc) {
|
||||
acc->Language(*aLocale);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvDocType(const uint64_t& aID,
|
||||
nsString* aType)
|
||||
{
|
||||
Accessible* acc = IdToAccessible(aID);
|
||||
if (acc && acc->IsDoc()) {
|
||||
acc->AsDoc()->DocType(*aType);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvURL(const uint64_t& aID,
|
||||
nsString* aURL)
|
||||
{
|
||||
Accessible* acc = IdToAccessible(aID);
|
||||
if (acc && acc->IsDoc()) {
|
||||
acc->AsDoc()->URL(*aURL);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvMimeType(const uint64_t& aID,
|
||||
nsString* aMime)
|
||||
{
|
||||
Accessible* acc = IdToAccessible(aID);
|
||||
if (acc && acc->IsDoc()) {
|
||||
acc->AsDoc()->MimeType(*aMime);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvURLDocTypeMimeType(const uint64_t& aID,
|
||||
nsString* aURL,
|
||||
nsString* aDocType,
|
||||
nsString* aMimeType)
|
||||
{
|
||||
Accessible* acc = IdToAccessible(aID);
|
||||
if (acc && acc->IsDoc()) {
|
||||
DocAccessible* doc = acc->AsDoc();
|
||||
doc->URL(*aURL);
|
||||
doc->DocType(*aDocType);
|
||||
doc->MimeType(*aMimeType);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -401,6 +401,15 @@ public:
|
|||
bool* aOk) override;
|
||||
|
||||
virtual bool RecvBounds(const uint64_t& aID, nsIntRect* aRect) override;
|
||||
|
||||
virtual bool RecvLanguage(const uint64_t& aID, nsString* aLocale) override;
|
||||
virtual bool RecvDocType(const uint64_t& aID, nsString* aType) override;
|
||||
virtual bool RecvURL(const uint64_t& aID, nsString* aURL) override;
|
||||
virtual bool RecvMimeType(const uint64_t& aID, nsString* aMime) override;
|
||||
virtual bool RecvURLDocTypeMimeType(const uint64_t& aID,
|
||||
nsString* aURL,
|
||||
nsString* aDocType,
|
||||
nsString* aMimeType) override;
|
||||
private:
|
||||
|
||||
Accessible* IdToAccessible(const uint64_t& aID) const;
|
||||
|
|
|
@ -209,6 +209,12 @@ child:
|
|||
prio(high) sync ChildAtPoint(uint64_t aID, int32_t aX, int32_t aY, uint32_t aWhich)
|
||||
returns(uint64_t aChild, bool aOk);
|
||||
prio(high) sync Bounds(uint64_t aID) returns(nsIntRect aRect);
|
||||
|
||||
prio(high) sync Language(uint64_t aID) returns(nsString aLocale);
|
||||
prio(high) sync DocType(uint64_t aID) returns(nsString aType);
|
||||
prio(high) sync URL(uint64_t aID) returns(nsString aURL);
|
||||
prio(high) sync MimeType(uint64_t aID) returns(nsString aMime);
|
||||
prio(high) sync URLDocTypeMimeType(uint64_t aID) returns(nsString aURL, nsString aDocType, nsString aMimeType);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -911,5 +911,36 @@ ProxyAccessible::Bounds()
|
|||
return rect;
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::Language(nsString& aLocale)
|
||||
{
|
||||
unused << mDoc->SendLanguage(mID, &aLocale);
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::DocType(nsString& aType)
|
||||
{
|
||||
unused << mDoc->SendDocType(mID, &aType);
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::URL(nsString& aURL)
|
||||
{
|
||||
unused << mDoc->SendURL(mID, &aURL);
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::MimeType(nsString aMime)
|
||||
{
|
||||
unused << mDoc->SendMimeType(mID, &aMime);
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::URLDocTypeMimeType(nsString& aURL, nsString& aDocType,
|
||||
nsString& aMimeType)
|
||||
{
|
||||
unused << mDoc->SendURLDocTypeMimeType(mID, &aURL, &aDocType, &aMimeType);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -276,6 +276,13 @@ public:
|
|||
Accessible::EWhichChildAtPoint aWhichChild);
|
||||
nsIntRect Bounds();
|
||||
|
||||
void Language(nsString& aLocale);
|
||||
void DocType(nsString& aType);
|
||||
void URL(nsString& aURL);
|
||||
void MimeType(nsString aMime);
|
||||
void URLDocTypeMimeType(nsString& aURL, nsString& aDocType,
|
||||
nsString& aMimeType);
|
||||
|
||||
/**
|
||||
* Allow the platform to store a pointers worth of data on us.
|
||||
*/
|
||||
|
|
|
@ -540,8 +540,7 @@ struct RoleDescrComparator
|
|||
|
||||
nsAutoString value;
|
||||
mGeckoAccessible->Value(value);
|
||||
return value.IsEmpty() ? nil : [NSString stringWithCharacters:reinterpret_cast<const unichar*>(value.BeginReading())
|
||||
length:value.Length()];
|
||||
return nsCocoaUtils::ToNSString(value);
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
@ -585,8 +584,7 @@ struct RoleDescrComparator
|
|||
|
||||
nsAutoString helpText;
|
||||
mGeckoAccessible->Help(helpText);
|
||||
return helpText.IsEmpty() ? nil : [NSString stringWithCharacters:reinterpret_cast<const unichar*>(helpText.BeginReading())
|
||||
length:helpText.Length()];
|
||||
return nsCocoaUtils::ToNSString(helpText);
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
|
|
@ -46,6 +46,12 @@ searchbar {
|
|||
-moz-binding: url("chrome://browser/content/search/search.xml#searchbar");
|
||||
}
|
||||
|
||||
/* Prevent shrinking the page content to 0 height and width */
|
||||
.browserStack > browser {
|
||||
min-height: 25px;
|
||||
min-width: 25px;
|
||||
}
|
||||
|
||||
.browserStack > browser {
|
||||
-moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-browser");
|
||||
}
|
||||
|
|
|
@ -661,7 +661,7 @@
|
|||
setfocus="false"
|
||||
tooltip="tabbrowser-tab-tooltip"
|
||||
stopwatchid="FX_TAB_CLICK_MS">
|
||||
<tab class="tabbrowser-tab" selected="true" fadein="true"/>
|
||||
<tab class="tabbrowser-tab" selected="true" visuallyselected="true" fadein="true"/>
|
||||
</tabs>
|
||||
|
||||
<toolbarbutton id="new-tab-button"
|
||||
|
|
|
@ -1203,7 +1203,7 @@
|
|||
// We need to explicitly focus the new tab, because
|
||||
// tabbox.xml does this only in some cases.
|
||||
this.mCurrentTab.focus();
|
||||
} else if (gMultiProcessBrowser) {
|
||||
} else if (gMultiProcessBrowser && document.activeElement !== newBrowser) {
|
||||
// Clear focus so that _adjustFocusAfterTabSwitch can detect if
|
||||
// some element has been focused and respect that.
|
||||
document.activeElement.blur();
|
||||
|
@ -1215,6 +1215,14 @@
|
|||
|
||||
this.tabContainer._setPositionalAttributes();
|
||||
|
||||
if (!gMultiProcessBrowser) {
|
||||
let event = new CustomEvent("TabSwitchDone", {
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
});
|
||||
this.dispatchEvent(event);
|
||||
}
|
||||
|
||||
if (!aForceUpdate)
|
||||
TelemetryStopwatch.finish("FX_TAB_SWITCH_UPDATE_MS");
|
||||
]]>
|
||||
|
@ -2760,7 +2768,8 @@
|
|||
let wasFocused = (document.activeElement == this.mCurrentTab);
|
||||
|
||||
aIndex = aIndex < aTab._tPos ? aIndex: aIndex+1;
|
||||
this.mCurrentTab._selected = false;
|
||||
this.mCurrentTab._logicallySelected = false;
|
||||
this.mCurrentTab._visuallySelected = false;
|
||||
|
||||
// invalidate caches
|
||||
this._browsers = null;
|
||||
|
@ -2772,9 +2781,11 @@
|
|||
|
||||
for (let i = 0; i < this.tabs.length; i++) {
|
||||
this.tabs[i]._tPos = i;
|
||||
this.tabs[i]._selected = false;
|
||||
this.tabs[i]._logicallySelected = false;
|
||||
this.tabs[i]._visuallySelected = false;
|
||||
}
|
||||
this.mCurrentTab._selected = true;
|
||||
this.mCurrentTab._logicallySelected = true;
|
||||
this.mCurrentTab._visuallySelected = true;
|
||||
|
||||
if (wasFocused)
|
||||
this.mCurrentTab.focus();
|
||||
|
@ -2866,6 +2877,518 @@
|
|||
</body>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
The tab switcher is responsible for asynchronously switching
|
||||
tabs in e10s. It waits until the new tab is ready (i.e., the
|
||||
layer tree is available) before switching to it. Then it
|
||||
unloads the layer tree for the old tab.
|
||||
|
||||
The tab switcher is a state machine. For each tab, it
|
||||
maintains state about whether the layer tree for the tab is
|
||||
available, being loaded, being unloaded, or unavailable. It
|
||||
also keeps track of the tab currently being displayed, the tab
|
||||
it's trying to load, and the tab the user has asked to switch
|
||||
to. The switcher object is created upon tab switch. It is
|
||||
released when there are no pending tabs to load or unload.
|
||||
|
||||
The following general principles have guided the design:
|
||||
|
||||
1. We only request one layer tree at a time. If the user
|
||||
switches to a different tab while waiting, we don't request
|
||||
the new layer tree until the old tab has loaded or timed out.
|
||||
|
||||
2. If loading the layers for a tab times out, we show the
|
||||
spinner and possibly request the layer tree for another tab if
|
||||
the user has requested one.
|
||||
|
||||
3. We discard layer trees on a delay. This way, if the user is
|
||||
switching among the same tabs frequently, we don't continually
|
||||
load the same tabs.
|
||||
|
||||
It's important that we always show either the spinner or a tab
|
||||
whose layers are available. Otherwise the compositor will draw
|
||||
an entirely black frame, which is very jarring. To ensure this
|
||||
never happens, we do the following:
|
||||
|
||||
1. When switching away from a tab, we assume the old tab might
|
||||
still be drawn until a MozAfterPaint event occurs. Because
|
||||
layout and compositing happen asynchronously, we don't have
|
||||
any other way of knowing when the switch actually takes
|
||||
place. Therefore, we don't unload the old tab until the next
|
||||
MozAfterPaint event.
|
||||
|
||||
2. Suppose that the user switches from tab A to B and then
|
||||
back to A. Suppose that we ask for tab A's layers to be
|
||||
unloaded via message M1 after the first switch and then
|
||||
request them again via message M2 once the second switch
|
||||
happens. Both loading and unloading of layers happens
|
||||
asynchronously, and this can cause problems. It's possible
|
||||
that the content process publishes one last layer tree before
|
||||
M1 is received. The parent process doesn't know that this
|
||||
layer tree was published before M1 and not after M2, so it
|
||||
will display the tab. However, once M1 arrives, the content
|
||||
process will destroy the layer tree for A and now we will
|
||||
display black for it.
|
||||
|
||||
To counter this problem, we keep tab A in a separate
|
||||
"unloading" state until the layer tree is actually dropped in
|
||||
the compositor thread. While the tab is in the "unloading"
|
||||
state, we're not allowed to request layers for it. Once the
|
||||
layers are dropped in the compositor, an event will fire and
|
||||
we will transition the tab to the "unloaded" state. Then we
|
||||
are free to request the tab's layers again.
|
||||
-->
|
||||
<field name="_switcher">null</field>
|
||||
<method name="_getSwitcher">
|
||||
<body><![CDATA[
|
||||
if (this._switcher) {
|
||||
return this._switcher;
|
||||
}
|
||||
|
||||
let switcher = {
|
||||
// How long to wait for a tab's layers to load. After this
|
||||
// time elapses, we're free to put up the spinner and start
|
||||
// trying to load a different tab.
|
||||
TAB_SWITCH_TIMEOUT: 300 /* ms */,
|
||||
|
||||
// When the user hasn't switched tabs for this long, we unload
|
||||
// layers for all tabs that aren't in use.
|
||||
UNLOAD_DELAY: 300 /* ms */,
|
||||
|
||||
// The next three tabs form the principal state variables.
|
||||
// See the assertions in postActions for their invariants.
|
||||
|
||||
// Tab the user requested most recently.
|
||||
requestedTab: this.selectedTab,
|
||||
|
||||
// Tab we're currently trying to load.
|
||||
loadingTab: null,
|
||||
|
||||
// We show this tab in case the requestedTab hasn't loaded yet.
|
||||
lastVisibleTab: this.selectedTab,
|
||||
|
||||
// Auxilliary state variables:
|
||||
|
||||
visibleTab: this.selectedTab, // Tab that's on screen.
|
||||
spinnerTab: null, // Tab showing a spinner.
|
||||
originalTab: this.selectedTab, // Tab that we started on.
|
||||
|
||||
tabbrowser: this, // Reference to gBrowser.
|
||||
loadTimer: null, // TAB_SWITCH_TIMEOUT timer.
|
||||
unloadTimer: null, // UNLOAD_DELAY timer.
|
||||
|
||||
// Map from tabs to STATE_* (below).
|
||||
tabState: new Map(),
|
||||
|
||||
// Set of tabs that might be visible right now. We maintain
|
||||
// this set because we can't be sure when a tab is actually
|
||||
// drawn. A tab is added to this set when we ask to make it
|
||||
// visible. All tabs but the most recently shown tab are
|
||||
// removed from the set upon MozAfterPaint.
|
||||
maybeVisibleTabs: new Set([this.selectedTab]),
|
||||
|
||||
STATE_UNLOADED: 0,
|
||||
STATE_LOADING: 1,
|
||||
STATE_LOADED: 2,
|
||||
STATE_UNLOADING: 3,
|
||||
|
||||
logging: false,
|
||||
|
||||
getTabState: function(tab) {
|
||||
let state = this.tabState.get(tab);
|
||||
if (state === undefined) {
|
||||
return this.STATE_UNLOADED;
|
||||
}
|
||||
return state;
|
||||
},
|
||||
|
||||
setTabState: function(tab, state) {
|
||||
if (state == this.STATE_UNLOADED) {
|
||||
this.tabState.delete(tab);
|
||||
} else {
|
||||
this.tabState.set(tab, state);
|
||||
}
|
||||
|
||||
let browser = tab.linkedBrowser;
|
||||
let fl = browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
|
||||
if (state == this.STATE_LOADING) {
|
||||
// Ask for a MozLayerTreeReady event.
|
||||
fl.requestNotifyLayerTreeReady();
|
||||
browser.docShellIsActive = true;
|
||||
} else if (state == this.STATE_UNLOADING) {
|
||||
// Ask for MozLayerTreeCleared event.
|
||||
fl.requestNotifyLayerTreeCleared();
|
||||
browser.docShellIsActive = false;
|
||||
}
|
||||
},
|
||||
|
||||
init: function() {
|
||||
this.log("START");
|
||||
|
||||
window.addEventListener("MozAfterPaint", this);
|
||||
window.addEventListener("MozLayerTreeReady", this);
|
||||
window.addEventListener("MozLayerTreeCleared", this);
|
||||
window.addEventListener("TabRemotenessChange", this);
|
||||
this.setTabState(this.requestedTab, this.STATE_LOADED);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
clearTimeout(this.unloadTimer);
|
||||
clearTimeout(this.loadTimer);
|
||||
|
||||
window.removeEventListener("MozAfterPaint", this);
|
||||
window.removeEventListener("MozLayerTreeReady", this);
|
||||
window.removeEventListener("MozLayerTreeCleared", this);
|
||||
window.removeEventListener("TabRemotenessChange", this);
|
||||
|
||||
this.tabbrowser._switcher = null;
|
||||
},
|
||||
|
||||
finish: function() {
|
||||
this.log("FINISH");
|
||||
|
||||
this.assert(this.tabbrowser._switcher);
|
||||
this.assert(this.tabbrowser._switcher === this);
|
||||
this.assert(!this.spinnerTab);
|
||||
this.assert(!this.loadTimer);
|
||||
this.assert(!this.loadingTab);
|
||||
this.assert(this.lastVisibleTab === this.requestedTab);
|
||||
this.assert(this.getTabState(this.requestedTab) == this.STATE_LOADED);
|
||||
|
||||
this.destroy();
|
||||
|
||||
let toBrowser = this.requestedTab.linkedBrowser;
|
||||
toBrowser.setAttribute("type", "content-primary");
|
||||
|
||||
this.tabbrowser._adjustFocusAfterTabSwitch(this.requestedTab);
|
||||
|
||||
let fromBrowser = this.originalTab.linkedBrowser;
|
||||
// It's possible that the tab we're switching from closed
|
||||
// before we were able to finalize, in which case, fromBrowser
|
||||
// doesn't exist.
|
||||
if (fromBrowser) {
|
||||
fromBrowser.setAttribute("type", "content-targetable");
|
||||
}
|
||||
|
||||
let event = new CustomEvent("TabSwitchDone", {
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
});
|
||||
this.tabbrowser.dispatchEvent(event);
|
||||
},
|
||||
|
||||
// This function is called after all the main state changes to
|
||||
// make sure we display the right tab.
|
||||
updateDisplay: function() {
|
||||
// Figure out which tab we actually want visible right now.
|
||||
let showTab = null;
|
||||
if (this.getTabState(this.requestedTab) != this.STATE_LOADED &&
|
||||
this.lastVisibleTab && this.loadTimer) {
|
||||
// If we can't show the requestedTab, and lastVisibleTab is
|
||||
// available, show it.
|
||||
showTab = this.lastVisibleTab;
|
||||
} else {
|
||||
// Show the requested tab. If it's not available, we'll show the spinner.
|
||||
showTab = this.requestedTab;
|
||||
}
|
||||
|
||||
// Show or hide the spinner as needed.
|
||||
let needSpinner = this.getTabState(showTab) != this.STATE_LOADED;
|
||||
if (!needSpinner && this.spinnerTab) {
|
||||
this.tabbrowser.removeAttribute("pendingpaint");
|
||||
this.spinnerTab.linkedBrowser.removeAttribute("pendingpaint");
|
||||
this.spinnerTab = null;
|
||||
} else if (needSpinner && this.spinnerTab !== showTab) {
|
||||
if (this.spinnerTab) {
|
||||
this.spinnerTab.linkedBrowser.removeAttribute("pendingpaint");
|
||||
}
|
||||
this.spinnerTab = showTab;
|
||||
this.tabbrowser.setAttribute("pendingpaint", "true");
|
||||
this.spinnerTab.linkedBrowser.setAttribute("pendingpaint", "true");
|
||||
}
|
||||
|
||||
// Switch to the tab we've decided to make visible.
|
||||
if (this.visibleTab !== showTab) {
|
||||
this.visibleTab = showTab;
|
||||
|
||||
this.maybeVisibleTabs.add(showTab);
|
||||
|
||||
let tabs = this.tabbrowser.mTabBox.tabs;
|
||||
let tabPanel = this.tabbrowser.mPanelContainer;
|
||||
let showPanel = tabs.getRelatedElement(showTab);
|
||||
let index = Array.indexOf(tabPanel.childNodes, showPanel);
|
||||
if (index != -1) {
|
||||
this.log(`Switch to tab ${index} - ${this.tinfo(showTab)}`);
|
||||
tabPanel.setAttribute("selectedIndex", index);
|
||||
if (showTab === this.requestedTab) {
|
||||
this.tabbrowser._adjustFocusAfterTabSwitch(showTab);
|
||||
}
|
||||
}
|
||||
|
||||
// This doesn't necessarily exist if we're a new window and haven't switched tabs yet
|
||||
if (this.lastVisibleTab)
|
||||
this.lastVisibleTab._visuallySelected = false;
|
||||
|
||||
this.visibleTab._visuallySelected = true;
|
||||
}
|
||||
|
||||
this.lastVisibleTab = this.visibleTab;
|
||||
|
||||
},
|
||||
|
||||
assert: function(cond) {
|
||||
if (!cond) {
|
||||
dump("Assertion failure\n" + Error().stack);
|
||||
throw new Error("Assertion failure");
|
||||
}
|
||||
},
|
||||
|
||||
// We've decided to try to load requestedTab.
|
||||
loadRequestedTab: function() {
|
||||
this.assert(!this.loadTimer);
|
||||
|
||||
// loadingTab can be non-null here if we timed out loading the current tab.
|
||||
// In that case we just overwrite it with a different tab; it's had its chance.
|
||||
this.loadingTab = this.requestedTab;
|
||||
this.log("Loading tab " + this.tinfo(this.loadingTab));
|
||||
|
||||
this.setTabState(this.requestedTab, this.STATE_LOADING);
|
||||
this.loadTimer = setTimeout(() => this.onLoadTimeout(), this.TAB_SWITCH_TIMEOUT);
|
||||
},
|
||||
|
||||
// This function runs before every event. It fixes up the state
|
||||
// to account for closed tabs.
|
||||
preActions: function() {
|
||||
this.assert(this.tabbrowser._switcher);
|
||||
this.assert(this.tabbrowser._switcher === this);
|
||||
|
||||
for (let [tab, state] of this.tabState) {
|
||||
if (!tab.linkedBrowser) {
|
||||
this.tabState.delete(tab);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.lastVisibleTab && !this.lastVisibleTab.linkedBrowser) {
|
||||
this.lastVisibleTab = null;
|
||||
}
|
||||
if (this.spinnerTab && !this.spinnerTab.linkedBrowser) {
|
||||
this.spinnerTab = null;
|
||||
}
|
||||
if (this.loadingTab && !this.loadingTab.linkedBrowser) {
|
||||
this.loadingTab = null;
|
||||
clearTimeout(this.loadTimer);
|
||||
this.loadTimer = null;
|
||||
}
|
||||
},
|
||||
|
||||
// This code runs after we've responded to an event or requested a new
|
||||
// tab. It's expected that we've already updated all the principal
|
||||
// state variables. This function takes care of updating any auxilliary
|
||||
// state.
|
||||
postActions: function() {
|
||||
// Once we finish loading loadingTab, we null it out. So the state should
|
||||
// always be LOADING.
|
||||
this.assert(!this.loadingTab ||
|
||||
this.getTabState(this.loadingTab) == this.STATE_LOADING);
|
||||
|
||||
// We guarantee that loadingTab is non-null iff loadTimer is non-null. So
|
||||
// the timer is set only when we're loading something.
|
||||
this.assert(!this.loadTimer || this.loadingTab);
|
||||
this.assert(!this.loadingTab || this.loadTimer);
|
||||
|
||||
// If we're not loading anything, try loading the requested tab.
|
||||
if (!this.loadTimer && this.getTabState(this.requestedTab) == this.STATE_UNLOADED) {
|
||||
this.loadRequestedTab();
|
||||
}
|
||||
|
||||
// See how many tabs still have work to do.
|
||||
let numPending = 0;
|
||||
for (let [tab, state] of this.tabState) {
|
||||
if (state == this.STATE_LOADED && tab !== this.requestedTab) {
|
||||
numPending++;
|
||||
}
|
||||
if (state == this.STATE_LOADING || state == this.STATE_UNLOADING) {
|
||||
numPending++;
|
||||
}
|
||||
}
|
||||
|
||||
this.updateDisplay();
|
||||
|
||||
// It's possible for updateDisplay to trigger one of our own event
|
||||
// handlers, which might cause finish() to already have been called.
|
||||
// Check for that before calling finish() again.
|
||||
if (!this.tabbrowser._switcher) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (numPending == 0) {
|
||||
this.finish();
|
||||
}
|
||||
|
||||
this.logState("done");
|
||||
},
|
||||
|
||||
// Fires when we're ready to unload unused tabs.
|
||||
onUnloadTimeout: function() {
|
||||
this.logState("onUnloadTimeout");
|
||||
this.preActions();
|
||||
|
||||
let numPending = 0;
|
||||
|
||||
// Unload any tabs that can be unloaded.
|
||||
for (let [tab, state] of this.tabState) {
|
||||
if (state == this.STATE_LOADED &&
|
||||
!this.maybeVisibleTabs.has(tab) &&
|
||||
tab !== this.lastVisibleTab &&
|
||||
tab !== this.loadingTab &&
|
||||
tab !== this.requestedTab)
|
||||
{
|
||||
this.setTabState(tab, this.STATE_UNLOADING);
|
||||
}
|
||||
|
||||
if (state != this.STATE_UNLOADED && tab !== this.requestedTab) {
|
||||
numPending++;
|
||||
}
|
||||
}
|
||||
|
||||
if (numPending) {
|
||||
// Keep the timer going since there may be more tabs to unload.
|
||||
this.unloadTimer = setTimeout(() => this.onUnloadTimeout(), this.UNLOAD_DELAY);
|
||||
}
|
||||
|
||||
this.postActions();
|
||||
},
|
||||
|
||||
// Fires when an ongoing load has taken too long.
|
||||
onLoadTimeout: function() {
|
||||
this.logState("onLoadTimeout");
|
||||
this.preActions();
|
||||
this.loadTimer = null;
|
||||
this.loadingTab = null;
|
||||
this.postActions();
|
||||
},
|
||||
|
||||
// Fires when the layers become available for a tab.
|
||||
onLayersReady: function(browser) {
|
||||
this.logState("onLayersReady");
|
||||
|
||||
let tab = this.tabbrowser.getTabForBrowser(browser);
|
||||
this.setTabState(tab, this.STATE_LOADED);
|
||||
|
||||
if (this.loadingTab === tab) {
|
||||
clearTimeout(this.loadTimer);
|
||||
this.loadTimer = null;
|
||||
this.loadingTab = null;
|
||||
}
|
||||
},
|
||||
|
||||
// Fires when we paint the screen. Any tab switches we initiated
|
||||
// previously are done, so there's no need to keep the old layers
|
||||
// around.
|
||||
onPaint: function() {
|
||||
this.maybeVisibleTabs.clear();
|
||||
},
|
||||
|
||||
// Called when we're done clearing the layers for a tab.
|
||||
onLayersCleared: function(browser) {
|
||||
this.logState("onLayersCleared");
|
||||
|
||||
let tab = this.tabbrowser.getTabForBrowser(browser);
|
||||
if (tab) {
|
||||
this.setTabState(tab, this.STATE_UNLOADED);
|
||||
}
|
||||
},
|
||||
|
||||
// Called when a tab switches from remote to non-remote. In this case
|
||||
// a MozLayerTreeReady notification that we requested may never fire,
|
||||
// so we need to simulate it.
|
||||
onRemotenessChange: function(tab) {
|
||||
this.logState("onRemotenessChange");
|
||||
if (!tab.linkedBrowser.isRemoteBrowser) {
|
||||
if (this.getTabState(tab) == this.STATE_LOADING) {
|
||||
this.onLayersReady(tab.linkedBrowser);
|
||||
} else if (this.getTabState(tab) == this.STATE_UNLOADING) {
|
||||
this.onLayersCleared(tab.linkedBrowser);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Called when the user asks to switch to a given tab.
|
||||
requestTab: function(tab) {
|
||||
if (tab === this.requestedTab) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.logState("requestTab " + this.tinfo(tab));
|
||||
|
||||
this.requestedTab = tab;
|
||||
|
||||
this.preActions();
|
||||
|
||||
clearTimeout(this.unloadTimer);
|
||||
this.unloadTimer = setTimeout(() => this.onUnloadTimeout(), this.UNLOAD_DELAY);
|
||||
|
||||
this.postActions();
|
||||
},
|
||||
|
||||
handleEvent: function(event) {
|
||||
this.preActions();
|
||||
|
||||
if (event.type == "MozLayerTreeReady") {
|
||||
this.onLayersReady(event.originalTarget);
|
||||
} if (event.type == "MozAfterPaint") {
|
||||
this.onPaint();
|
||||
} else if (event.type == "MozLayerTreeCleared") {
|
||||
this.onLayersCleared(event.originalTarget);
|
||||
} else if (event.type == "TabRemotenessChange") {
|
||||
this.onRemotenessChange(event.target);
|
||||
}
|
||||
|
||||
this.postActions();
|
||||
},
|
||||
|
||||
tinfo: function(tab) {
|
||||
if (tab) {
|
||||
return tab._tPos + "(" + tab.linkedBrowser.currentURI.spec + ")";
|
||||
} else {
|
||||
return "null";
|
||||
}
|
||||
},
|
||||
|
||||
log: function(s) {
|
||||
if (!this.logging)
|
||||
return;
|
||||
dump(s + "\n");
|
||||
},
|
||||
|
||||
logState: function(prefix) {
|
||||
if (!this.logging)
|
||||
return;
|
||||
|
||||
dump(prefix + " ");
|
||||
for (let i = 0; i < this.tabbrowser.tabs.length; i++) {
|
||||
let tab = this.tabbrowser.tabs[i];
|
||||
let state = this.getTabState(tab);
|
||||
|
||||
dump(i + ":");
|
||||
if (tab === this.lastVisibleTab) dump("V");
|
||||
if (tab === this.loadingTab) dump("L");
|
||||
if (tab === this.requestedTab) dump("R");
|
||||
if (state == this.STATE_LOADED) dump("(+)");
|
||||
if (state == this.STATE_LOADING) dump("(+?)");
|
||||
if (state == this.STATE_UNLOADED) dump("(-)");
|
||||
if (state == this.STATE_UNLOADING) dump("(-?)");
|
||||
dump(" ");
|
||||
}
|
||||
dump("\n");
|
||||
},
|
||||
};
|
||||
this._switcher = switcher;
|
||||
switcher.init();
|
||||
return switcher;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- BEGIN FORWARDED BROWSER PROPERTIES. IF YOU ADD A PROPERTY TO THE BROWSER ELEMENT
|
||||
MAKE SURE TO ADD IT HERE AS WELL. -->
|
||||
<property name="canGoBack"
|
||||
|
@ -3380,6 +3903,10 @@
|
|||
if (gMultiProcessBrowser) {
|
||||
messageManager.removeMessageListener("DOMTitleChanged", this);
|
||||
messageManager.removeMessageListener("contextmenu", this);
|
||||
|
||||
if (this._switcher) {
|
||||
this._switcher.destroy();
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</destructor>
|
||||
|
@ -3404,154 +3931,6 @@
|
|||
</body>
|
||||
</method>
|
||||
|
||||
<method name="_showBusySpinnerRemoteBrowser">
|
||||
<parameter name="aBrowser"/>
|
||||
<body><![CDATA[
|
||||
aBrowser.setAttribute("pendingpaint", "true");
|
||||
if (this._contentWaitingCount <= 0) {
|
||||
// We are not currently spinning
|
||||
this.setAttribute("pendingpaint", "true");
|
||||
this._contentWaitingCount = 1;
|
||||
} else {
|
||||
this._contentWaitingCount++;
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_hideBusySpinnerRemoteBrowser">
|
||||
<parameter name="aBrowser"/>
|
||||
<body><![CDATA[
|
||||
aBrowser.removeAttribute("pendingpaint");
|
||||
this._contentWaitingCount--;
|
||||
if (this._contentWaitingCount <= 0) {
|
||||
this.removeAttribute("pendingpaint");
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_prepareForTabSwitch">
|
||||
<parameter name="toTab"/>
|
||||
<parameter name="fromTab"/>
|
||||
<body><![CDATA[
|
||||
const kTabSwitchTimeout = 300;
|
||||
let toBrowser = this.getBrowserForTab(toTab);
|
||||
let fromBrowser = fromTab ? this.getBrowserForTab(fromTab)
|
||||
: null;
|
||||
|
||||
// We only want to wait for the MozAfterRemotePaint event if
|
||||
// the tab we're switching to is a remote tab, and if the tab
|
||||
// we're switching to isn't the one we've already got. The latter
|
||||
// case can occur when closing tabs before the currently selected
|
||||
// one.
|
||||
let shouldWait = toBrowser.getAttribute("remote") == "true" &&
|
||||
toBrowser != fromBrowser;
|
||||
|
||||
let switchPromise;
|
||||
|
||||
if (shouldWait) {
|
||||
let timeoutId;
|
||||
let panels = this.mPanelContainer;
|
||||
|
||||
// Both the timeout and MozAfterPaint promises use this same
|
||||
// logic to determine whether they should carry out the tab
|
||||
// switch, or reject it outright.
|
||||
let attemptTabSwitch = (aResolve, aReject) => {
|
||||
if (this.selectedBrowser == toBrowser) {
|
||||
aResolve();
|
||||
} else {
|
||||
// We switched away or closed the browser before we timed
|
||||
// out. We reject, which will cancel the tab switch.
|
||||
aReject();
|
||||
}
|
||||
};
|
||||
|
||||
let timeoutPromise = new Promise((aResolve, aReject) => {
|
||||
timeoutId = setTimeout(() => {
|
||||
if (toBrowser.isRemoteBrowser) {
|
||||
// The browser's remoteness could have changed since we
|
||||
// setTimeout so only show the spinner if it's still remote.
|
||||
this._showBusySpinnerRemoteBrowser(toBrowser);
|
||||
}
|
||||
attemptTabSwitch(aResolve, aReject);
|
||||
}, kTabSwitchTimeout);
|
||||
});
|
||||
|
||||
let paintPromise = new Promise((aResolve, aReject) => {
|
||||
let onRemotePaint = () => {
|
||||
toBrowser.removeEventListener("MozAfterRemotePaint", onRemotePaint);
|
||||
this._hideBusySpinnerRemoteBrowser(toBrowser);
|
||||
clearTimeout(timeoutId);
|
||||
attemptTabSwitch(aResolve, aReject);
|
||||
};
|
||||
toBrowser.addEventListener("MozAfterRemotePaint", onRemotePaint);
|
||||
toBrowser.QueryInterface(Ci.nsIFrameLoaderOwner)
|
||||
.frameLoader
|
||||
.requestNotifyAfterRemotePaint();
|
||||
// We need to activate the docShell on the tab we're switching
|
||||
// to - otherwise, we won't initiate a remote paint request and
|
||||
// therefore we won't get the MozAfterRemotePaint event that we're
|
||||
// waiting for.
|
||||
// Note that this happens, as we require, even if the timeout in the
|
||||
// timeoutPromise triggers before the paintPromise even runs.
|
||||
toBrowser.docShellIsActive = true;
|
||||
});
|
||||
|
||||
switchPromise = Promise.race([paintPromise, timeoutPromise]);
|
||||
} else {
|
||||
// Activate the docShell on the tab we're switching to.
|
||||
toBrowser.docShellIsActive = true;
|
||||
|
||||
// No need to wait - just resolve immediately to do the switch ASAP.
|
||||
switchPromise = Promise.resolve();
|
||||
}
|
||||
|
||||
return switchPromise;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_deactivateContent">
|
||||
<parameter name="tab"/>
|
||||
<body><![CDATA[
|
||||
// It's unlikely, yet possible, that while we were waiting
|
||||
// to deactivate this tab, that something closed it and wiped
|
||||
// out the browser. For example, during a tab switch, while waiting
|
||||
// for the MozAfterRemotePaint event to fire, something closes the
|
||||
// original tab that the user had selected. If that's the case, then
|
||||
// there's nothing to deactivate.
|
||||
let browser = this.getBrowserForTab(tab);
|
||||
if (browser && this.selectedBrowser != browser) {
|
||||
browser.docShellIsActive = false;
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_finalizeTabSwitch">
|
||||
<parameter name="toTab"/>
|
||||
<parameter name="fromTab"/>
|
||||
<body><![CDATA[
|
||||
this._adjustFocusAfterTabSwitch(toTab);
|
||||
this._deactivateContent(fromTab);
|
||||
|
||||
let toBrowser = this.getBrowserForTab(toTab);
|
||||
toBrowser.setAttribute("type", "content-primary");
|
||||
|
||||
let fromBrowser = this.getBrowserForTab(fromTab);
|
||||
// It's possible that the tab we're switching from closed
|
||||
// before we were able to finalize, in which case, fromBrowser
|
||||
// doesn't exist.
|
||||
if (fromBrowser) {
|
||||
fromBrowser.setAttribute("type", "content-targetable");
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_cancelTabSwitch">
|
||||
<parameter name="toTab"/>
|
||||
<body><![CDATA[
|
||||
this._deactivateContent(toTab);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<property name="mContextTab" readonly="true"
|
||||
onget="return TabContextMenu.contextTab;"/>
|
||||
<property name="mPrefs" readonly="true"
|
||||
|
@ -5042,22 +5421,22 @@
|
|||
|
||||
<content context="tabContextMenu" closetabtext="&closeTab.label;">
|
||||
<xul:stack class="tab-stack" flex="1">
|
||||
<xul:hbox xbl:inherits="pinned,selected,titlechanged,fadein"
|
||||
<xul:hbox xbl:inherits="pinned,selected,visuallyselected,titlechanged,fadein"
|
||||
class="tab-background">
|
||||
<xul:hbox xbl:inherits="pinned,selected,titlechanged"
|
||||
<xul:hbox xbl:inherits="pinned,selected,visuallyselected,titlechanged"
|
||||
class="tab-background-start"/>
|
||||
<xul:hbox xbl:inherits="pinned,selected,titlechanged"
|
||||
<xul:hbox xbl:inherits="pinned,selected,visuallyselected,titlechanged"
|
||||
class="tab-background-middle"/>
|
||||
<xul:hbox xbl:inherits="pinned,selected,titlechanged"
|
||||
<xul:hbox xbl:inherits="pinned,selected,visuallyselected,titlechanged"
|
||||
class="tab-background-end"/>
|
||||
</xul:hbox>
|
||||
<xul:hbox xbl:inherits="pinned,selected,titlechanged"
|
||||
<xul:hbox xbl:inherits="pinned,selected,visuallyselected,titlechanged"
|
||||
class="tab-content" align="center">
|
||||
<xul:image xbl:inherits="fadein,pinned,busy,progress,selected"
|
||||
<xul:image xbl:inherits="fadein,pinned,busy,progress,selected,visuallyselected"
|
||||
class="tab-throbber"
|
||||
role="presentation"
|
||||
layer="true" />
|
||||
<xul:image xbl:inherits="src=image,fadein,pinned,selected,busy,crashed"
|
||||
<xul:image xbl:inherits="src=image,fadein,pinned,selected,visuallyselected,busy,crashed"
|
||||
anonid="tab-icon-image"
|
||||
class="tab-icon-image"
|
||||
validate="never"
|
||||
|
@ -5067,17 +5446,36 @@
|
|||
role="presentation"/>
|
||||
<xul:label flex="1"
|
||||
anonid="tab-label"
|
||||
xbl:inherits="value=visibleLabel,crop,accesskey,fadein,pinned,selected"
|
||||
xbl:inherits="value=visibleLabel,crop,accesskey,fadein,pinned,selected,visuallyselected"
|
||||
class="tab-text tab-label"
|
||||
role="presentation"/>
|
||||
<xul:toolbarbutton anonid="close-button"
|
||||
xbl:inherits="fadein,pinned,selected"
|
||||
xbl:inherits="fadein,pinned,selected,visuallyselected"
|
||||
class="tab-close-button close-icon"/>
|
||||
</xul:hbox>
|
||||
</xul:stack>
|
||||
</content>
|
||||
|
||||
<implementation>
|
||||
|
||||
<property name="_selected">
|
||||
<setter>
|
||||
<![CDATA[
|
||||
// in e10s we want to only pseudo-select a tab before its rendering is done, so that
|
||||
// the rest of the system knows that the tab is selected, but we don't want to update its
|
||||
// visual status to selected until after we receive confirmation that its content has painted.
|
||||
this._logicallySelected = val;
|
||||
|
||||
// If we're non-e10s we should update the visual selection as well at the same time
|
||||
if (!gMultiProcessBrowser) {
|
||||
this._visuallySelected = val;
|
||||
}
|
||||
|
||||
return val;
|
||||
]]>
|
||||
</setter>
|
||||
</property>
|
||||
|
||||
<property name="label">
|
||||
<getter>
|
||||
return this.getAttribute("label");
|
||||
|
@ -5514,7 +5912,7 @@
|
|||
let fromTab = this._selectedPanel ? this.getRelatedElement(this._selectedPanel)
|
||||
: null;
|
||||
|
||||
let switchPromise = gBrowser._prepareForTabSwitch(toTab, fromTab);
|
||||
gBrowser._getSwitcher().requestTab(toTab);
|
||||
|
||||
var panel = this._selectedPanel;
|
||||
var newPanel = this.childNodes[val];
|
||||
|
@ -5525,26 +5923,6 @@
|
|||
this.dispatchEvent(event);
|
||||
|
||||
this._selectedIndex = val;
|
||||
|
||||
switchPromise.then(() => {
|
||||
// If we cannot find the tabpanel that we were trying to switch to, then
|
||||
// it must have been removed before our Promise could be resolved. In
|
||||
// that case, we just cancel the tab switch.
|
||||
var updatedTabIndex = Array.indexOf(this.childNodes, newPanel);
|
||||
if (updatedTabIndex == -1) {
|
||||
gBrowser._cancelTabSwitch(toTab);
|
||||
} else {
|
||||
this.setAttribute("selectedIndex", updatedTabIndex);
|
||||
gBrowser._finalizeTabSwitch(toTab, fromTab);
|
||||
}
|
||||
}, () => {
|
||||
// If the promise rejected, that means we don't want to actually
|
||||
// flip the deck, so we cancel the tab switch.
|
||||
// We need to nullcheck the method we're about to call because
|
||||
// the binding might be dead at this point.
|
||||
if (gBrowser._cancelTabSwitch)
|
||||
gBrowser._cancelTabSwitch(toTab);
|
||||
});
|
||||
}
|
||||
|
||||
return val;
|
||||
|
|
|
@ -4,6 +4,9 @@ function test() {
|
|||
|
||||
var isLinux = navigator.platform.indexOf("Linux") == 0;
|
||||
for (let i = 9; i >= 1; i--) {
|
||||
// Make sure the keystroke goes to chrome.
|
||||
document.activeElement.blur();
|
||||
|
||||
EventUtils.synthesizeKey(i.toString(), { altKey: isLinux, accelKey: !isLinux });
|
||||
|
||||
is(gBrowser.tabContainer.selectedIndex, (i == 9 ? gBrowser.tabs.length : i) - 1,
|
||||
|
|
|
@ -32,6 +32,55 @@ function loadURI(tab, url) {
|
|||
return BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
}
|
||||
|
||||
// Creates a framescript which caches the current object value from the plugin
|
||||
// in the page. checkObjectValue below verifies that the framescript is still
|
||||
// active for the browser and that the cached value matches that from the plugin
|
||||
// in the page which tells us the plugin hasn't been reinitialized.
|
||||
function cacheObjectValue(browser) {
|
||||
let frame_script = function() {
|
||||
let plugin = content.document.wrappedJSObject.body.firstChild;
|
||||
let objectValue = plugin.getObjectValue();
|
||||
|
||||
addMessageListener("Test:CheckObjectValue", () => {
|
||||
try {
|
||||
let plugin = content.document.wrappedJSObject.body.firstChild;
|
||||
sendAsyncMessage("Test:CheckObjectValue", {
|
||||
result: plugin.checkObjectValue(objectValue)
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
sendAsyncMessage("Test:CheckObjectValue", {
|
||||
result: null,
|
||||
exception: e.toString()
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
browser.messageManager.loadFrameScript("data:,(" + frame_script.toString() + ")();", false)
|
||||
}
|
||||
|
||||
// See the notes for cacheObjectValue above.
|
||||
function checkObjectValue(browser) {
|
||||
let mm = browser.messageManager;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let listener = ({ data }) => {
|
||||
mm.removeMessageListener("Test:CheckObjectValue", listener);
|
||||
if (data.result === null) {
|
||||
ok(false, "checkObjectValue threw an exception: " + data.exception);
|
||||
reject(data.exception);
|
||||
}
|
||||
else {
|
||||
resolve(data.result);
|
||||
}
|
||||
};
|
||||
|
||||
mm.addMessageListener("Test:CheckObjectValue", listener);
|
||||
mm.sendAsyncMessage("Test:CheckObjectValue");
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
let embed = '<embed type="application/x-test" allowscriptaccess="always" allowfullscreen="true" wmode="window" width="640" height="480"></embed>'
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
|
||||
|
@ -57,15 +106,12 @@ add_task(function*() {
|
|||
is(gBrowser.tabs[2], tabs[3], "tab3");
|
||||
is(gBrowser.tabs[3], tabs[4], "tab4");
|
||||
|
||||
let plugin = tabs[4].linkedBrowser.contentDocument.wrappedJSObject.body.firstChild;
|
||||
let tab4_plugin_object = plugin.getObjectValue();
|
||||
cacheObjectValue(tabs[4].linkedBrowser);
|
||||
|
||||
swapTabsAndCloseOther(3, 2); // now: 0 1 4
|
||||
gBrowser.selectedTab = gBrowser.tabs[2];
|
||||
|
||||
let doc = gBrowser.tabs[2].linkedBrowser.contentDocument.wrappedJSObject;
|
||||
plugin = doc.body.firstChild;
|
||||
ok(plugin && plugin.checkObjectValue(tab4_plugin_object), "same plugin instance");
|
||||
ok((yield checkObjectValue(gBrowser.tabs[2].linkedBrowser)), "same plugin instance");
|
||||
|
||||
is(gBrowser.tabs[1], tabs[1], "tab1");
|
||||
is(gBrowser.tabs[2], tabs[3], "tab4");
|
||||
|
@ -77,9 +123,7 @@ add_task(function*() {
|
|||
swapTabsAndCloseOther(2, 1); // now: 0 4
|
||||
is(gBrowser.tabs[1], tabs[1], "tab1");
|
||||
|
||||
doc = gBrowser.tabs[1].linkedBrowser.contentDocument.wrappedJSObject;
|
||||
plugin = doc.body.firstChild;
|
||||
ok(plugin && plugin.checkObjectValue(tab4_plugin_object), "same plugin instance");
|
||||
ok((yield checkObjectValue(gBrowser.tabs[1].linkedBrowser)), "same plugin instance");
|
||||
|
||||
yield clickTest(gBrowser.tabs[1]);
|
||||
|
||||
|
|
|
@ -216,14 +216,13 @@ add_task(function*() {
|
|||
"main-window", "tab1", true,
|
||||
"tab change when selected tab element was focused");
|
||||
|
||||
let paintWaiter;
|
||||
let switchWaiter;
|
||||
if (gMultiProcessBrowser) {
|
||||
paintWaiter = new Promise((resolve, reject) => {
|
||||
browser2.addEventListener("MozAfterRemotePaint", function paintListener() {
|
||||
browser2.removeEventListener("MozAfterRemotePaint", paintListener, false);
|
||||
switchWaiter = new Promise((resolve, reject) => {
|
||||
gBrowser.addEventListener("TabSwitchDone", function listener() {
|
||||
gBrowser.removeEventListener("TabSwitchDone", listener);
|
||||
executeSoon(resolve);
|
||||
}, false);
|
||||
browser2.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.requestNotifyAfterRemotePaint();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -236,7 +235,7 @@ add_task(function*() {
|
|||
// Otherwise, the _adjustFocusAfterTabSwitch in tabbrowser gets confused and
|
||||
// isn't sure what tab is really focused.
|
||||
if (gMultiProcessBrowser) {
|
||||
yield paintWaiter;
|
||||
yield switchWaiter;
|
||||
}
|
||||
|
||||
yield expectFocusShift(function () gBrowser.selectedTab.blur(),
|
||||
|
|
|
@ -25,12 +25,12 @@ add_task(function*() {
|
|||
is (nbox.clientWidth, nboxWidth, "Opening the toolbox hasn't changed the width of the nbox");
|
||||
|
||||
let iframe = document.getAnonymousElementByAttribute(nbox, "class", "devtools-toolbox-bottom-iframe");
|
||||
is (iframe.clientHeight, nboxHeight - 10, "The iframe fits within the available space ");
|
||||
is (iframe.clientHeight, nboxHeight - 25, "The iframe fits within the available space");
|
||||
|
||||
yield toolbox.switchHost(devtools.Toolbox.HostType.SIDE);
|
||||
iframe = document.getAnonymousElementByAttribute(nbox, "class", "devtools-toolbox-side-iframe");
|
||||
iframe.style.minWidth = "1px"; // Disable the min width set in css
|
||||
is (iframe.clientWidth, nboxWidth - 10, "The iframe fits within the available space");
|
||||
is (iframe.clientWidth, nboxWidth - 25, "The iframe fits within the available space");
|
||||
|
||||
yield cleanup(toolbox);
|
||||
});
|
||||
|
|
|
@ -10,6 +10,12 @@ const {Promise: promise} = require("resource://gre/modules/Promise.jsm");
|
|||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource:///modules/devtools/DOMHelpers.jsm");
|
||||
|
||||
/* A host should always allow this much space for the page to be displayed.
|
||||
* There is also a min-height on the browser, but we still don't want to set
|
||||
* frame.height to be larger than that, since it can cause problems with
|
||||
* resizing the toolbox and panel layout. */
|
||||
const MIN_PAGE_SIZE = 25;
|
||||
|
||||
/**
|
||||
* A toolbox host represents an object that contains a toolbox (e.g. the
|
||||
* sidebar or a separate window). Any host object should implement the
|
||||
|
@ -57,7 +63,7 @@ BottomHost.prototype = {
|
|||
this.frame.className = "devtools-toolbox-bottom-iframe";
|
||||
this.frame.height = Math.min(
|
||||
Services.prefs.getIntPref(this.heightPref),
|
||||
this._nbox.clientHeight - 10 // Always show at least some page content
|
||||
this._nbox.clientHeight - MIN_PAGE_SIZE
|
||||
);
|
||||
|
||||
this._nbox.appendChild(this._splitter);
|
||||
|
@ -144,7 +150,7 @@ SidebarHost.prototype = {
|
|||
|
||||
this.frame.width = Math.min(
|
||||
Services.prefs.getIntPref(this.widthPref),
|
||||
this._sidebar.clientWidth - 10 // Always show at least some page content
|
||||
this._sidebar.clientWidth - MIN_PAGE_SIZE
|
||||
);
|
||||
|
||||
this._sidebar.appendChild(this._splitter);
|
||||
|
|
|
@ -2328,7 +2328,7 @@ function ElementEditor(aContainer, aNode) {
|
|||
this.template = this.markup.template.bind(this.markup);
|
||||
this.doc = this.markup.doc;
|
||||
|
||||
this.attrs = {};
|
||||
this.attrElements = new Map();
|
||||
this.animationTimers = {};
|
||||
|
||||
// The templates will fill the following properties
|
||||
|
@ -2408,14 +2408,20 @@ ElementEditor.prototype = {
|
|||
* Update the state of the editor from the node.
|
||||
*/
|
||||
update: function() {
|
||||
let attrs = this.node.attributes || [];
|
||||
let attrsToRemove = new Set(this.attrList.querySelectorAll(".attreditor"));
|
||||
let nodeAttributes = this.node.attributes || [];
|
||||
|
||||
// Only loop through the current attributes on the node, anything that's
|
||||
// been removed will be removed from this DOM because it will be part of
|
||||
// the attrsToRemove set.
|
||||
for (let attr of attrs) {
|
||||
let el = this.attrs[attr.name];
|
||||
// Keep the data model in sync with attributes on the node.
|
||||
let currentAttributes = new Set(nodeAttributes.map(a=>a.name));
|
||||
for (let name of this.attrElements.keys()) {
|
||||
if (!currentAttributes.has(name)) {
|
||||
this.removeAttribute(name);
|
||||
}
|
||||
}
|
||||
|
||||
// Only loop through the current attributes on the node. Missing
|
||||
// attributes have already been removed at this point.
|
||||
for (let attr of nodeAttributes) {
|
||||
let el = this.attrElements.get(attr.name);
|
||||
let valueChanged = el && el.querySelector(".attr-value").innerHTML !== attr.value;
|
||||
let isEditing = el && el.querySelector(".editable").inplaceEditor;
|
||||
let canSimplyShowEditor = el && (!valueChanged || isEditing);
|
||||
|
@ -2423,7 +2429,6 @@ ElementEditor.prototype = {
|
|||
if (canSimplyShowEditor) {
|
||||
// Element already exists and doesn't need to be recreated.
|
||||
// Just show it (it's hidden by default due to the template).
|
||||
attrsToRemove.delete(el);
|
||||
el.style.removeProperty("display");
|
||||
} else {
|
||||
// Create a new editor, because the value of an existing attribute
|
||||
|
@ -2439,10 +2444,6 @@ ElementEditor.prototype = {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let el of attrsToRemove) {
|
||||
el.remove();
|
||||
}
|
||||
},
|
||||
|
||||
_startModifyingAttributes: function() {
|
||||
|
@ -2459,6 +2460,18 @@ ElementEditor.prototype = {
|
|||
".attreditor[data-attr=" + attrName + "] .attr-value");
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove an attribute from the attrElements object and the DOM
|
||||
* @param string attrName The name of the attribute to remove
|
||||
*/
|
||||
removeAttribute: function(attrName) {
|
||||
let attr = this.attrElements.get(attrName);
|
||||
if (attr) {
|
||||
this.attrElements.delete(attrName);
|
||||
attr.remove();
|
||||
}
|
||||
},
|
||||
|
||||
_createAttribute: function(aAttr, aBefore = null) {
|
||||
// Create the template editor, which will save some variables here.
|
||||
let data = {
|
||||
|
@ -2541,18 +2554,13 @@ ElementEditor.prototype = {
|
|||
if (aAttr.name == "id") {
|
||||
before = this.attrList.firstChild;
|
||||
} else if (aAttr.name == "class") {
|
||||
let idNode = this.attrs["id"];
|
||||
let idNode = this.attrElements.get("id");
|
||||
before = idNode ? idNode.nextSibling : this.attrList.firstChild;
|
||||
}
|
||||
this.attrList.insertBefore(attr, before);
|
||||
|
||||
// Remove the old version of this attribute from the DOM.
|
||||
let oldAttr = this.attrs[aAttr.name];
|
||||
if (oldAttr && oldAttr.parentNode) {
|
||||
oldAttr.parentNode.removeChild(oldAttr);
|
||||
}
|
||||
|
||||
this.attrs[aAttr.name] = attr;
|
||||
this.removeAttribute(aAttr.name);
|
||||
this.attrElements.set(aAttr.name, attr);
|
||||
|
||||
let collapsedValue;
|
||||
if (aAttr.value.match(COLLAPSE_DATA_URL_REGEX)) {
|
||||
|
|
|
@ -140,7 +140,7 @@ function* checkData(index, editor, inspector) {
|
|||
} else {
|
||||
let nodeFront = yield getNodeFront("#node14", inspector);
|
||||
let editor = getContainerForNodeFront(nodeFront, inspector).editor;
|
||||
let attr = editor.attrs["style"].querySelector(".editable");
|
||||
let attr = editor.attrElements.get("style").querySelector(".editable");
|
||||
is(attr.textContent, completion, "Correct value is persisted after pressing Enter");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,32 @@ const TEST_DATA = [
|
|||
}), "newattr attribute removed");
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Re-adding an attribute",
|
||||
test: () => {
|
||||
let node1 = getNode("#node1");
|
||||
node1.setAttribute("newattr", "newattrval");
|
||||
},
|
||||
check: function*(inspector) {
|
||||
let {editor} = yield getContainerForSelector("#node1", inspector);
|
||||
ok([...editor.attrList.querySelectorAll(".attreditor")].some(attr => {
|
||||
return attr.textContent.trim() === "newattr=\"newattrval\"";
|
||||
}), "newattr attribute found");
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Changing an attribute",
|
||||
test: () => {
|
||||
let node1 = getNode("#node1");
|
||||
node1.setAttribute("newattr", "newattrchanged");
|
||||
},
|
||||
check: function*(inspector) {
|
||||
let {editor} = yield getContainerForSelector("#node1", inspector);
|
||||
ok([...editor.attrList.querySelectorAll(".attreditor")].some(attr => {
|
||||
return attr.textContent.trim() === "newattr=\"newattrchanged\"";
|
||||
}), "newattr attribute found");
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Updating the text-content",
|
||||
test: () => {
|
||||
|
|
|
@ -123,7 +123,7 @@ function* assertNodeFlashing(nodeFront, inspector) {
|
|||
function* assertAttributeFlashing(nodeFront, attribute, inspector) {
|
||||
let container = getContainerForNodeFront(nodeFront, inspector);
|
||||
ok(container, "Markup container for node found");
|
||||
ok(container.editor.attrs[attribute], "Attribute exists on editor");
|
||||
ok(container.editor.attrElements.get(attribute), "Attribute exists on editor");
|
||||
|
||||
let attributeElement = container.editor.getAttributeElement(attribute);
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ add_task(function*() {
|
|||
|
||||
info("Focus the ID attribute and change its content");
|
||||
let {editor} = yield getContainerForSelector("#test-div", inspector);
|
||||
let attr = editor.attrs["id"].querySelector(".editable");
|
||||
let attr = editor.attrElements.get("id").querySelector(".editable");
|
||||
let mutated = inspector.once("markupmutation");
|
||||
setEditableFieldValue(attr,
|
||||
attr.textContent + ' class="newclass" style="color:green"', inspector);
|
||||
|
|
|
@ -47,7 +47,7 @@ let TEST_DATA = [{
|
|||
},
|
||||
validate: (element, container, inspector) => {
|
||||
let editor = container.editor;
|
||||
let visibleAttrText = editor.attrs["style"].querySelector(".attr-value").textContent;
|
||||
let visibleAttrText = editor.attrElements.get("style").querySelector(".attr-value").textContent;
|
||||
is (visibleAttrText, DATA_URL_INLINE_STYLE_COLLAPSED);
|
||||
}
|
||||
}, {
|
||||
|
@ -58,7 +58,7 @@ let TEST_DATA = [{
|
|||
},
|
||||
validate: (element, container, inspector) => {
|
||||
let editor = container.editor;
|
||||
let visibleAttrText = editor.attrs["data-long"].querySelector(".attr-value").textContent;
|
||||
let visibleAttrText = editor.attrElements.get("data-long").querySelector(".attr-value").textContent;
|
||||
is (visibleAttrText, LONG_ATTRIBUTE_COLLAPSED)
|
||||
}
|
||||
}, {
|
||||
|
@ -69,7 +69,7 @@ let TEST_DATA = [{
|
|||
},
|
||||
validate: (element, container, inspector) => {
|
||||
let editor = container.editor;
|
||||
let visibleAttrText = editor.attrs["src"].querySelector(".attr-value").textContent;
|
||||
let visibleAttrText = editor.attrElements.get("src").querySelector(".attr-value").textContent;
|
||||
is (visibleAttrText, DATA_URL_ATTRIBUTE_COLLAPSED);
|
||||
}
|
||||
}];
|
||||
|
|
|
@ -36,7 +36,7 @@ function* testCollapsedLongAttribute(inspector) {
|
|||
});
|
||||
|
||||
let {editor} = yield getContainerForSelector("#node24", inspector);
|
||||
let attr = editor.attrs["data-long"].querySelector(".editable");
|
||||
let attr = editor.attrElements.get("data-long").querySelector(".editable");
|
||||
|
||||
// Check to make sure it has expanded after focus
|
||||
attr.focus();
|
||||
|
@ -48,7 +48,7 @@ function* testCollapsedLongAttribute(inspector) {
|
|||
setEditableFieldValue(attr, input.value + ' data-short="ABC"', inspector);
|
||||
yield inspector.once("markupmutation");
|
||||
|
||||
let visibleAttrText = editor.attrs["data-long"].querySelector(".attr-value").textContent;
|
||||
let visibleAttrText = editor.attrElements.get("data-long").querySelector(".attr-value").textContent;
|
||||
is (visibleAttrText, LONG_ATTRIBUTE_COLLAPSED)
|
||||
|
||||
yield assertAttributes("#node24", {
|
||||
|
@ -69,7 +69,7 @@ function* testModifyInlineStyleWithQuotes(inspector) {
|
|||
|
||||
let onMutated = inspector.once("markupmutation");
|
||||
let {editor} = yield getContainerForSelector("#node26", inspector);
|
||||
let attr = editor.attrs["style"].querySelector(".editable");
|
||||
let attr = editor.attrElements.get("style").querySelector(".editable");
|
||||
|
||||
attr.focus();
|
||||
EventUtils.sendKey("return", inspector.panelWin);
|
||||
|
@ -105,7 +105,7 @@ function* testEditingAttributeWithMixedQuotes(inspector) {
|
|||
|
||||
let onMutated = inspector.once("markupmutation");
|
||||
let {editor} = yield getContainerForSelector("#node27", inspector);
|
||||
let attr = editor.attrs["class"].querySelector(".editable");
|
||||
let attr = editor.attrElements.get("class").querySelector(".editable");
|
||||
|
||||
attr.focus();
|
||||
EventUtils.sendKey("return", inspector.panelWin);
|
||||
|
|
|
@ -27,7 +27,7 @@ function* testWellformedMixedCase(inspector) {
|
|||
|
||||
info("Focusing the viewBox attribute editor");
|
||||
let {editor} = yield getContainerForSelector("svg", inspector);
|
||||
let attr = editor.attrs["viewBox"].querySelector(".editable");
|
||||
let attr = editor.attrElements.get("viewBox").querySelector(".editable");
|
||||
attr.focus();
|
||||
EventUtils.sendKey("return", inspector.panelWin);
|
||||
|
||||
|
@ -53,7 +53,7 @@ function* testMalformedMixedCase(inspector) {
|
|||
|
||||
info("Focusing the viewBox attribute editor");
|
||||
let {editor} = yield getContainerForSelector("svg", inspector);
|
||||
let attr = editor.attrs["viewBox"].querySelector(".editable");
|
||||
let attr = editor.attrElements.get("viewBox").querySelector(".editable");
|
||||
attr.focus();
|
||||
EventUtils.sendKey("return", inspector.panelWin);
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ function* runEditAttributesTest(test, inspector) {
|
|||
|
||||
info("Listening for the markupmutation event");
|
||||
let nodeMutated = inspector.once("markupmutation");
|
||||
let attr = container.editor.attrs[test.name].querySelector(".editable");
|
||||
let attr = container.editor.attrElements.get(test.name).querySelector(".editable");
|
||||
setEditableFieldValue(attr, test.value, inspector);
|
||||
yield nodeMutated;
|
||||
|
||||
|
|
|
@ -57,7 +57,6 @@ skip-if = e10s # Bug 1091596
|
|||
[browser_net_cyrillic-02.js]
|
||||
[browser_net_details-no-duplicated-content.js]
|
||||
[browser_net_filter-01.js]
|
||||
skip-if = e10s # Bug 1091603
|
||||
[browser_net_filter-02.js]
|
||||
[browser_net_filter-03.js]
|
||||
[browser_net_filter-04.js]
|
||||
|
|
|
@ -297,8 +297,10 @@ PerformanceFront.prototype = {
|
|||
return profilerStatus.currentTime;
|
||||
}
|
||||
|
||||
// Extend the profiler options so that protocol.js doesn't modify the original.
|
||||
let profilerOptions = extend({}, this._customProfilerOptions);
|
||||
// If this._customProfilerOptions is defined, use those to pass in
|
||||
// to the profiler actor. The profiler actor handles all the defaults
|
||||
// now, so this should only be used for tests.
|
||||
let profilerOptions = this._customProfilerOptions || {};
|
||||
yield this._request("profiler", "startProfiler", profilerOptions);
|
||||
|
||||
this.emit("profiler-activated");
|
||||
|
@ -400,19 +402,6 @@ PerformanceFront.prototype = {
|
|||
deferred.resolve();
|
||||
}),
|
||||
|
||||
/**
|
||||
* Overrides the options sent to the built-in profiler module when activating,
|
||||
* such as the maximum entries count, the sampling interval etc.
|
||||
*
|
||||
* Used in tests and for older backend implementations.
|
||||
*/
|
||||
_customProfilerOptions: {
|
||||
entries: 1000000,
|
||||
interval: 1,
|
||||
features: ["js"],
|
||||
threadFilters: ["GeckoMain"]
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns an object indicating if mock actors are being used or not.
|
||||
*/
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
*/
|
||||
|
||||
/* Lightweight theme on tabs */
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[selected=true]:-moz-lwtheme::before,
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[selected=true]:-moz-lwtheme::before {
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[visuallyselected=true]:-moz-lwtheme::before,
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[visuallyselected=true]:-moz-lwtheme::before {
|
||||
background-attachment: scroll, fixed;
|
||||
background-color: transparent;
|
||||
background-image: @fgTabTextureLWT@;/*, lwtHeader;*/
|
||||
|
@ -20,7 +20,7 @@
|
|||
background-repeat: repeat-x, no-repeat;
|
||||
}
|
||||
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[visuallyselected=true]:-moz-lwtheme {
|
||||
background-attachment: scroll, scroll, fixed;
|
||||
background-color: transparent;
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
|
||||
|
|
|
@ -1841,15 +1841,15 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
|||
}
|
||||
|
||||
/* Tab close button */
|
||||
.tab-close-button:not([selected]):not(:hover) {
|
||||
.tab-close-button:not([visuallyselected]):not(:hover) {
|
||||
background-image: -moz-image-rect(url("chrome://global/skin/icons/close.svg"), 0, 64, 16, 48);
|
||||
}
|
||||
|
||||
#TabsToolbar[brighttext] .tab-close-button:not([selected]):not(:hover) {
|
||||
#TabsToolbar[brighttext] .tab-close-button:not([visuallyselected]):not(:hover) {
|
||||
background-image: -moz-image-rect(url("chrome://global/skin/icons/close.svg"), 0, 80, 16, 64);
|
||||
}
|
||||
|
||||
.tab-close-button:not([selected]):not(:hover):-moz-lwtheme-darktext {
|
||||
.tab-close-button:not([visuallyselected]):not(:hover):-moz-lwtheme-darktext {
|
||||
background-image: -moz-image-rect(url("chrome://global/skin/icons/close.svg"), 0, 96, 16, 80);
|
||||
}
|
||||
|
||||
|
@ -1924,7 +1924,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
|||
list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
|
||||
}
|
||||
|
||||
.alltabs-item[selected="true"] {
|
||||
.alltabs-item[visuallyselected="true"] {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
*/
|
||||
|
||||
/* Lightweight theme on tabs */
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[selected=true]:-moz-lwtheme::before,
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[selected=true]:-moz-lwtheme::before {
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[visuallyselected=true]:-moz-lwtheme::before,
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[visuallyselected=true]:-moz-lwtheme::before {
|
||||
background-attachment: scroll, fixed;
|
||||
background-color: transparent;
|
||||
background-image: @fgTabTextureLWT@;/*, lwtHeader;*/
|
||||
|
@ -19,7 +19,7 @@
|
|||
background-repeat: repeat-x, no-repeat;
|
||||
}
|
||||
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[visuallyselected=true]:-moz-lwtheme {
|
||||
background-attachment: scroll, scroll, fixed;
|
||||
background-color: transparent;
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
|
||||
|
@ -30,7 +30,7 @@
|
|||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[visuallyselected=true]:-moz-lwtheme {
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle@2x.png),
|
||||
@fgTabTextureLWT@;/*,
|
||||
lwtHeader;*/
|
||||
|
|
|
@ -3045,26 +3045,26 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
|||
url(chrome://browser/skin/tabbrowser/tab-background-start@2x.png);
|
||||
}
|
||||
|
||||
.tabbrowser-tab:hover > .tab-stack > .tab-background:not([selected=true]),
|
||||
.tabbrowser-tab:hover > .tab-stack > .tab-background:not([visuallyselected=true]),
|
||||
.tabs-newtab-button:hover {
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-background-start@2x.png),
|
||||
url(chrome://browser/skin/tabbrowser/tab-background-middle@2x.png),
|
||||
url(chrome://browser/skin/tabbrowser/tab-background-end@2x.png);
|
||||
}
|
||||
|
||||
.tab-background-middle[selected=true] {
|
||||
.tab-background-middle[visuallyselected=true] {
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle@2x.png),
|
||||
@fgTabTexture@,
|
||||
none;
|
||||
}
|
||||
|
||||
.tab-background-start[selected=true]:-moz-locale-dir(ltr)::after,
|
||||
.tab-background-end[selected=true]:-moz-locale-dir(rtl)::after {
|
||||
.tab-background-start[visuallyselected=true]:-moz-locale-dir(ltr)::after,
|
||||
.tab-background-end[visuallyselected=true]:-moz-locale-dir(rtl)::after {
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-stroke-start@2x.png);
|
||||
}
|
||||
|
||||
.tab-background-end[selected=true]:-moz-locale-dir(ltr)::after,
|
||||
.tab-background-start[selected=true]:-moz-locale-dir(rtl)::after {
|
||||
.tab-background-end[visuallyselected=true]:-moz-locale-dir(ltr)::after,
|
||||
.tab-background-start[visuallyselected=true]:-moz-locale-dir(rtl)::after {
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-stroke-end@2x.png);
|
||||
}
|
||||
|
||||
|
@ -3082,13 +3082,13 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
|||
|
||||
/* Background tab separators */
|
||||
#tabbrowser-tabs[movingtab] > .tabbrowser-tab[beforeselected]:not([last-visible-tab])::after,
|
||||
.tabbrowser-tab:not([selected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before,
|
||||
#tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([selected]):not([beforehovered]):not(:hover)::after {
|
||||
.tabbrowser-tab:not([visuallyselected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before,
|
||||
#tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([visuallyselected]):not([beforehovered]):not(:hover)::after {
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-separator@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
.tabbrowser-tab:not(:hover) > .tab-stack > .tab-content > .tab-icon-image:not([selected="true"]) {
|
||||
.tabbrowser-tab:not(:hover) > .tab-stack > .tab-content > .tab-icon-image:not([visuallyselected="true"]) {
|
||||
opacity: .9;
|
||||
}
|
||||
|
||||
|
@ -3100,7 +3100,7 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
|||
opacity: 0.9999;
|
||||
}
|
||||
|
||||
.tab-label:not([selected="true"]) {
|
||||
.tab-label:not([visuallyselected="true"]) {
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
|
@ -3110,12 +3110,12 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
|||
border: none;
|
||||
}
|
||||
|
||||
.tabbrowser-tab[selected=true]:not(:-moz-lwtheme) {
|
||||
.tabbrowser-tab[visuallyselected=true]:not(:-moz-lwtheme) {
|
||||
/* overriding tabbox.css */
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.tabbrowser-tab[selected=true] {
|
||||
.tabbrowser-tab[visuallyselected=true] {
|
||||
/* overriding tabbox.css */
|
||||
text-shadow: inherit;
|
||||
}
|
||||
|
@ -3165,7 +3165,7 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
|||
* of the window (e.g. no menubar, tabs in titlebar, etc.) to make it easier to drag the window by
|
||||
* the titlebar. We don't need this in fullscreen since window dragging is not an issue there.
|
||||
*/
|
||||
#main-window[tabsintitlebar]:not([inFullscreen]) .tab-background-middle:not([selected=true]) {
|
||||
#main-window[tabsintitlebar]:not([inFullscreen]) .tab-background-middle:not([visuallyselected=true]) {
|
||||
clip-path: url(chrome://browser/content/browser.xul#tab-hover-clip-path);
|
||||
}
|
||||
|
||||
|
@ -3201,12 +3201,12 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
|||
cursor: default;
|
||||
}
|
||||
|
||||
#TabsToolbar[brighttext] .tab-close-button.close-icon:not([selected=true]):not(:hover) {
|
||||
#TabsToolbar[brighttext] .tab-close-button.close-icon:not([visuallyselected=true]):not(:hover) {
|
||||
-moz-image-region: rect(0, 64px, 16px, 48px);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#TabsToolbar[brighttext] .tab-close-button.close-icon:not([selected=true]):not(:hover) {
|
||||
#TabsToolbar[brighttext] .tab-close-button.close-icon:not([visuallyselected=true]):not(:hover) {
|
||||
-moz-image-region: rect(0, 128px, 32px, 96px);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,11 +85,11 @@
|
|||
|
||||
/* Tab styling - make sure to use an inverted icon for the selected tab
|
||||
(brighttext only covers the unselected tabs) */
|
||||
.tab-close-button[selected=true]:not(:hover) {
|
||||
.tab-close-button[visuallyselected=true]:not(:hover) {
|
||||
-moz-image-region: rect(0, 64px, 16px, 48px);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.tab-close-button[selected=true]:not(:hover) {
|
||||
.tab-close-button[visuallyselected=true]:not(:hover) {
|
||||
-moz-image-region: rect(0, 128px, 32px, 96px);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,17 +141,17 @@
|
|||
-moz-padding-start: 0;
|
||||
}
|
||||
|
||||
.tab-background-start[selected=true]::after,
|
||||
.tab-background-start[selected=true]::before,
|
||||
.tab-background-start[visuallyselected=true]::after,
|
||||
.tab-background-start[visuallyselected=true]::before,
|
||||
.tab-background-start,
|
||||
.tab-background-end,
|
||||
.tab-background-end[selected=true]::after,
|
||||
.tab-background-end[selected=true]::before {
|
||||
.tab-background-end[visuallyselected=true]::after,
|
||||
.tab-background-end[visuallyselected=true]::before {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.tab-background-start[selected=true]::after,
|
||||
.tab-background-end[selected=true]::after {
|
||||
.tab-background-start[visuallyselected=true]::after,
|
||||
.tab-background-end[visuallyselected=true]::after {
|
||||
-moz-margin-start: 0;
|
||||
}
|
||||
/* End override @tabCurveHalfWidth@ and @tabCurveWidth@ */
|
||||
|
@ -270,8 +270,8 @@ searchbar:not([oneoffui]) .search-go-button {
|
|||
|
||||
/* Make the tab splitter 1px wide with a solid background. */
|
||||
#tabbrowser-tabs[movingtab] > .tabbrowser-tab[beforeselected]:not([last-visible-tab])::after,
|
||||
.tabbrowser-tab:not([selected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before,
|
||||
#tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([selected]):not([beforehovered]):not(:hover)::after {
|
||||
.tabbrowser-tab:not([visuallyselected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before,
|
||||
#tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([visuallyselected]):not([beforehovered]):not(:hover)::after {
|
||||
background: var(--tab-separator-color);
|
||||
width: 1px;
|
||||
-moz-margin-start: 0;
|
||||
|
@ -282,7 +282,7 @@ searchbar:not([oneoffui]) .search-go-button {
|
|||
due to the ::after element causing the width of the tab to extend, which
|
||||
causes an overflow and makes it disappear, which removes the overflow and
|
||||
causes it to reappear, etc, etc. */
|
||||
#tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([selected]):not([beforehovered]):not(:hover)::after {
|
||||
#tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([visuallyselected]):not([beforehovered]):not(:hover)::after {
|
||||
-moz-margin-start: -1px;
|
||||
-moz-margin-end: 0;
|
||||
}
|
||||
|
@ -304,7 +304,7 @@ searchbar:not([oneoffui]) .search-go-button {
|
|||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.tabbrowser-tab[pinned][titlechanged]:not([selected="true"]) > .tab-stack > .tab-content {
|
||||
.tabbrowser-tab[pinned][titlechanged]:not([visuallyselected="true"]) > .tab-stack > .tab-content {
|
||||
background-image: var(--pinned-tab-glow);
|
||||
background-position: center;
|
||||
background-size: 100%;
|
||||
|
@ -316,7 +316,7 @@ searchbar:not([oneoffui]) .search-go-button {
|
|||
background-color: var(--tab-hover-background-color);
|
||||
}
|
||||
|
||||
.tabbrowser-tab[selected] {
|
||||
.tabbrowser-tab[visuallyselected] {
|
||||
color: var(--tab-selection-color) !important; /* Override color: inherit */
|
||||
background-color: var(--tab-selection-background-color);
|
||||
box-shadow: var(--tab-selection-box-shadow);
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
}
|
||||
|
||||
/* The selected tab should appear above adjacent tabs, .tabs-newtab-button and the highlight of #nav-bar */
|
||||
.tabbrowser-tab[selected=true] {
|
||||
.tabbrowser-tab[visuallyselected=true] {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
@ -167,17 +167,17 @@
|
|||
transition: opacity 150ms ease;
|
||||
}
|
||||
|
||||
.tab-background-start[selected=true]::after,
|
||||
.tab-background-start[selected=true]::before,
|
||||
.tab-background-start[visuallyselected=true]::after,
|
||||
.tab-background-start[visuallyselected=true]::before,
|
||||
.tab-background-start,
|
||||
.tab-background-end,
|
||||
.tab-background-end[selected=true]::after,
|
||||
.tab-background-end[selected=true]::before {
|
||||
.tab-background-end[visuallyselected=true]::after,
|
||||
.tab-background-end[visuallyselected=true]::before {
|
||||
min-height: var(--tab-min-height);
|
||||
width: @tabCurveWidth@;
|
||||
}
|
||||
|
||||
.tabbrowser-tab:not([selected=true]),
|
||||
.tabbrowser-tab:not([visuallyselected=true]),
|
||||
.tabbrowser-tab:-moz-lwtheme {
|
||||
color: inherit;
|
||||
}
|
||||
|
@ -193,8 +193,8 @@
|
|||
*/
|
||||
|
||||
|
||||
.tab-background-start[selected=true]::after,
|
||||
.tab-background-end[selected=true]::after {
|
||||
.tab-background-start[visuallyselected=true]::after,
|
||||
.tab-background-end[visuallyselected=true]::after {
|
||||
/* position ::after on top of its parent */
|
||||
-moz-margin-start: -@tabCurveWidth@;
|
||||
background-size: 100% 100%;
|
||||
|
@ -203,47 +203,47 @@
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.tab-background-start[selected=true]::before,
|
||||
.tab-background-end[selected=true]::before {
|
||||
.tab-background-start[visuallyselected=true]::before,
|
||||
.tab-background-end[visuallyselected=true]::before {
|
||||
/* all ::before pseudo elements */
|
||||
content: "";
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
.tab-background-start[selected=true]:-moz-locale-dir(ltr):not(:-moz-lwtheme)::before,
|
||||
.tab-background-end[selected=true]:-moz-locale-dir(rtl):not(:-moz-lwtheme)::before {
|
||||
.tab-background-start[visuallyselected=true]:-moz-locale-dir(ltr):not(:-moz-lwtheme)::before,
|
||||
.tab-background-end[visuallyselected=true]:-moz-locale-dir(rtl):not(:-moz-lwtheme)::before {
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-selected-start.svg);
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.tab-background-end[selected=true]:-moz-locale-dir(ltr):not(:-moz-lwtheme)::before,
|
||||
.tab-background-start[selected=true]:-moz-locale-dir(rtl):not(:-moz-lwtheme)::before {
|
||||
.tab-background-end[visuallyselected=true]:-moz-locale-dir(ltr):not(:-moz-lwtheme)::before,
|
||||
.tab-background-start[visuallyselected=true]:-moz-locale-dir(rtl):not(:-moz-lwtheme)::before {
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-selected-end.svg);
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
/* For lightweight themes, clip the header image on start, middle, and end. */
|
||||
.tab-background-start[selected=true]:-moz-locale-dir(ltr):-moz-lwtheme::before,
|
||||
.tab-background-end[selected=true]:-moz-locale-dir(rtl):-moz-lwtheme::before {
|
||||
.tab-background-start[visuallyselected=true]:-moz-locale-dir(ltr):-moz-lwtheme::before,
|
||||
.tab-background-end[visuallyselected=true]:-moz-locale-dir(rtl):-moz-lwtheme::before {
|
||||
clip-path: url(chrome://browser/content/browser.xul#tab-curve-clip-path-start);
|
||||
}
|
||||
|
||||
.tab-background-end[selected=true]:-moz-locale-dir(ltr):-moz-lwtheme::before,
|
||||
.tab-background-start[selected=true]:-moz-locale-dir(rtl):-moz-lwtheme::before {
|
||||
.tab-background-end[visuallyselected=true]:-moz-locale-dir(ltr):-moz-lwtheme::before,
|
||||
.tab-background-start[visuallyselected=true]:-moz-locale-dir(rtl):-moz-lwtheme::before {
|
||||
clip-path: url(chrome://browser/content/browser.xul#tab-curve-clip-path-end);
|
||||
}
|
||||
|
||||
.tab-background-start[selected=true]:-moz-locale-dir(ltr)::after,
|
||||
.tab-background-end[selected=true]:-moz-locale-dir(rtl)::after {
|
||||
.tab-background-start[visuallyselected=true]:-moz-locale-dir(ltr)::after,
|
||||
.tab-background-end[visuallyselected=true]:-moz-locale-dir(rtl)::after {
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-stroke-start.png);
|
||||
}
|
||||
|
||||
.tab-background-end[selected=true]:-moz-locale-dir(ltr)::after,
|
||||
.tab-background-start[selected=true]:-moz-locale-dir(rtl)::after {
|
||||
.tab-background-end[visuallyselected=true]:-moz-locale-dir(ltr)::after,
|
||||
.tab-background-start[visuallyselected=true]:-moz-locale-dir(rtl)::after {
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-stroke-end.png);
|
||||
}
|
||||
|
||||
.tab-background-middle[selected=true] {
|
||||
.tab-background-middle[visuallyselected=true] {
|
||||
background-clip: padding-box, padding-box, content-box;
|
||||
background-color: @fgTabBackgroundColor@;
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
|
||||
|
@ -258,7 +258,7 @@
|
|||
|
||||
/* Selected tab lightweight theme styles.
|
||||
See browser-lightweightTheme.css for information about run-time changes to LWT styles. */
|
||||
.tab-background-middle[selected=true]:-moz-lwtheme {
|
||||
.tab-background-middle[visuallyselected=true]:-moz-lwtheme {
|
||||
background-color: transparent;
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
|
||||
@fgTabTextureLWT@;/*,
|
||||
|
@ -268,21 +268,21 @@
|
|||
}
|
||||
|
||||
/* These LWT styles are normally overridden by browser-lightweightTheme.css */
|
||||
.tab-background-start[selected=true]:-moz-lwtheme::before,
|
||||
.tab-background-end[selected=true]:-moz-lwtheme::before {
|
||||
.tab-background-start[visuallyselected=true]:-moz-lwtheme::before,
|
||||
.tab-background-end[visuallyselected=true]:-moz-lwtheme::before {
|
||||
background-image: @fgTabTextureLWT@;
|
||||
}
|
||||
|
||||
.tab-background-start[selected=true]:-moz-lwtheme::before,
|
||||
.tab-background-end[selected=true]:-moz-lwtheme::before,
|
||||
.tab-background-middle[selected=true]:-moz-lwtheme {
|
||||
.tab-background-start[visuallyselected=true]:-moz-lwtheme::before,
|
||||
.tab-background-end[visuallyselected=true]:-moz-lwtheme::before,
|
||||
.tab-background-middle[visuallyselected=true]:-moz-lwtheme {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* End selected tab */
|
||||
|
||||
/* new tab button border and gradient on hover */
|
||||
.tabbrowser-tab:hover > .tab-stack > .tab-background:not([selected=true]),
|
||||
.tabbrowser-tab:hover > .tab-stack > .tab-background:not([visuallyselected=true]),
|
||||
.tabs-newtab-button:hover {
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-background-start.png),
|
||||
url(chrome://browser/skin/tabbrowser/tab-background-middle.png),
|
||||
|
@ -311,7 +311,7 @@
|
|||
position: absolute;
|
||||
}
|
||||
|
||||
.tabbrowser-tab[pinned][titlechanged]:not([selected="true"]) > .tab-stack > .tab-content {
|
||||
.tabbrowser-tab[pinned][titlechanged]:not([visuallyselected="true"]) > .tab-stack > .tab-content {
|
||||
background-image: radial-gradient(farthest-corner at center bottom, rgb(255,255,255) 3%, rgba(186,221,251,0.75) 20%, rgba(127,179,255,0.25) 40%, transparent 70%);
|
||||
background-position: center bottom var(--tab-toolbar-navbar-overlap);
|
||||
background-repeat: no-repeat;
|
||||
|
@ -321,8 +321,8 @@
|
|||
/* Background tab separators (3px wide).
|
||||
Also show separators beside the selected tab when dragging it. */
|
||||
#tabbrowser-tabs[movingtab] > .tabbrowser-tab[beforeselected]:not([last-visible-tab])::after,
|
||||
.tabbrowser-tab:not([selected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before,
|
||||
#tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([selected]):not([beforehovered]):not(:hover)::after {
|
||||
.tabbrowser-tab:not([visuallyselected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before,
|
||||
#tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([visuallyselected]):not([beforehovered]):not(:hover)::after {
|
||||
-moz-margin-start: -1.5px;
|
||||
-moz-margin-end: -1.5px;
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-separator.png);
|
||||
|
|
|
@ -83,7 +83,7 @@
|
|||
background-color: @customToolbarColor@;
|
||||
}
|
||||
|
||||
.tab-background-middle[selected=true]:not(:-moz-lwtheme) {
|
||||
.tab-background-middle[visuallyselected=true]:not(:-moz-lwtheme) {
|
||||
background-color: @customToolbarColor@;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
*/
|
||||
|
||||
/* Lightweight theme on tabs */
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[selected=true]:-moz-lwtheme::before,
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[selected=true]:-moz-lwtheme::before {
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[visuallyselected=true]:-moz-lwtheme::before,
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[visuallyselected=true]:-moz-lwtheme::before {
|
||||
background-attachment: scroll, fixed;
|
||||
background-color: transparent;
|
||||
background-image: @fgTabTextureLWT@;/*, lwtHeader;*/
|
||||
|
@ -20,7 +20,7 @@
|
|||
background-repeat: repeat-x, no-repeat;
|
||||
}
|
||||
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[visuallyselected=true]:-moz-lwtheme {
|
||||
background-attachment: scroll, scroll, fixed;
|
||||
background-color: transparent;
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
|
||||
|
@ -31,7 +31,7 @@
|
|||
}
|
||||
|
||||
@media (min-resolution: 1.25dppx) {
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
|
||||
#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[visuallyselected=true]:-moz-lwtheme {
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle@2x.png),
|
||||
@fgTabTextureLWT@;/*,
|
||||
lwtHeader;*/
|
||||
|
|
|
@ -1828,26 +1828,26 @@ toolbarbutton[type="socialmark"] > .toolbarbutton-icon {
|
|||
url(chrome://browser/skin/tabbrowser/tab-background-start@2x.png);
|
||||
}
|
||||
|
||||
.tabbrowser-tab:hover > .tab-stack > .tab-background:not([selected=true]),
|
||||
.tabbrowser-tab:hover > .tab-stack > .tab-background:not([visuallyselected=true]),
|
||||
.tabs-newtab-button:hover {
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-background-start@2x.png),
|
||||
url(chrome://browser/skin/tabbrowser/tab-background-middle@2x.png),
|
||||
url(chrome://browser/skin/tabbrowser/tab-background-end@2x.png);
|
||||
}
|
||||
|
||||
.tab-background-middle[selected=true] {
|
||||
.tab-background-middle[visuallyselected=true] {
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle@2x.png),
|
||||
@fgTabTexture@,
|
||||
none;
|
||||
}
|
||||
|
||||
.tab-background-start[selected=true]:-moz-locale-dir(ltr)::after,
|
||||
.tab-background-end[selected=true]:-moz-locale-dir(rtl)::after {
|
||||
.tab-background-start[visuallyselected=true]:-moz-locale-dir(ltr)::after,
|
||||
.tab-background-end[visuallyselected=true]:-moz-locale-dir(rtl)::after {
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-stroke-start@2x.png);
|
||||
}
|
||||
|
||||
.tab-background-end[selected=true]:-moz-locale-dir(ltr)::after,
|
||||
.tab-background-start[selected=true]:-moz-locale-dir(rtl)::after {
|
||||
.tab-background-end[visuallyselected=true]:-moz-locale-dir(ltr)::after,
|
||||
.tab-background-start[visuallyselected=true]:-moz-locale-dir(rtl)::after {
|
||||
background-image: url(chrome://browser/skin/tabbrowser/tab-stroke-end@2x.png);
|
||||
}
|
||||
}
|
||||
|
@ -1856,14 +1856,14 @@ toolbarbutton[type="socialmark"] > .toolbarbutton-icon {
|
|||
/* Use lighter colors of buttons and text in the titlebar on luna-blue */
|
||||
@media (-moz-windows-theme: luna-blue) {
|
||||
#tabbrowser-tabs[movingtab] > .tabbrowser-tab[beforeselected]:not([last-visible-tab])::after,
|
||||
.tabbrowser-tab:not([selected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before,
|
||||
#tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([selected]):not([beforehovered]):not(:hover)::after {
|
||||
.tabbrowser-tab:not([visuallyselected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before,
|
||||
#tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([visuallyselected]):not([beforehovered]):not(:hover)::after {
|
||||
background-image: url("chrome://browser/skin/tabbrowser/tab-separator-luna-blue.png");
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
#TabsToolbar[brighttext] .tab-close-button:not(:hover):not([selected="true"]) {
|
||||
#TabsToolbar[brighttext] .tab-close-button:not(:hover):not([visuallyselected="true"]) {
|
||||
-moz-image-region: rect(0, 64px, 16px, 48px) !important;
|
||||
}
|
||||
|
||||
|
@ -1878,7 +1878,7 @@ toolbarbutton[type="socialmark"] > .toolbarbutton-icon {
|
|||
* of the window (e.g. no menubar, tabs in titlebar, etc.) to make it easier to drag the window by
|
||||
* the titlebar. We don't need this in fullscreen since window dragging is not an issue there.
|
||||
*/
|
||||
#main-window[tabsintitlebar][sizemode=normal] #toolbar-menubar[autohide="true"][inactive] + #TabsToolbar .tab-background-middle:not([selected=true]) {
|
||||
#main-window[tabsintitlebar][sizemode=normal] #toolbar-menubar[autohide="true"][inactive] + #TabsToolbar .tab-background-middle:not([visuallyselected=true]) {
|
||||
clip-path: url(chrome://browser/content/browser.xul#tab-hover-clip-path);
|
||||
}
|
||||
|
||||
|
|
|
@ -158,6 +158,6 @@
|
|||
|
||||
/* Tab styling - make sure to use an inverted icon for the selected tab
|
||||
(brighttext only covers the unselected tabs) */
|
||||
.tab-close-button[selected=true]:not(:hover) {
|
||||
.tab-close-button[visuallyselected=true]:not(:hover) {
|
||||
-moz-image-region: rect(0, 64px, 16px, 48px);
|
||||
}
|
||||
|
|
|
@ -64,17 +64,25 @@ AC_ARG_WITH(nspr-exec-prefix,
|
|||
|
||||
if test -z "$no_nspr"; then
|
||||
nspr_config_major_version=`echo $NSPR_VERSION_STRING | \
|
||||
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\(\.\([[0-9]]*\)\)\{0,1\}/\1/'`
|
||||
nspr_config_minor_version=`echo $NSPR_VERSION_STRING | \
|
||||
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\(\.\([[0-9]]*\)\)\{0,1\}/\2/'`
|
||||
nspr_config_micro_version=`echo $NSPR_VERSION_STRING | \
|
||||
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\(\.\([[0-9]]*\)\)\{0,1\}/\4/'`
|
||||
if test -z "$nspr_config_micro_version"; then
|
||||
nspr_config_micro_version="0"
|
||||
fi
|
||||
|
||||
min_nspr_major_version=`echo $min_nspr_version | \
|
||||
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\(\.\([[0-9]]*\)\)\{0,1\}/\1/'`
|
||||
min_nspr_minor_version=`echo $min_nspr_version | \
|
||||
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\(\.\([[0-9]]*\)\)\{0,1\}/\2/'`
|
||||
min_nspr_micro_version=`echo $min_nspr_version | \
|
||||
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\(\.\([[0-9]]*\)\)\{0,1\}/\4/'`
|
||||
if test -z "$min_nspr_micro_version"; then
|
||||
min_nspr_micro_version="0"
|
||||
fi
|
||||
|
||||
if test "$nspr_config_major_version" -ne "$min_nspr_major_version"; then
|
||||
no_nspr="yes"
|
||||
elif test "$nspr_config_major_version" -eq "$min_nspr_major_version" &&
|
||||
|
|
|
@ -45,17 +45,25 @@ AC_ARG_WITH(nss-exec-prefix,
|
|||
NSS_LIBS=`$NSS_CONFIG $nss_config_args --libs`
|
||||
|
||||
nss_config_major_version=`$NSS_CONFIG $nss_config_args --version | \
|
||||
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\(\.\([[0-9]]*\)\)\{0,1\}/\1/'`
|
||||
nss_config_minor_version=`$NSS_CONFIG $nss_config_args --version | \
|
||||
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\(\.\([[0-9]]*\)\)\{0,1\}/\2/'`
|
||||
nss_config_micro_version=`$NSS_CONFIG $nss_config_args --version | \
|
||||
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\(\.\([[0-9]]*\)\)\{0,1\}/\4/'`
|
||||
if test -z "$nss_config_micro_version"; then
|
||||
nss_config_micro_version="0"
|
||||
fi
|
||||
|
||||
min_nss_major_version=`echo $min_nss_version | \
|
||||
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\(\.\([[0-9]]*\)\)\{0,1\}/\1/'`
|
||||
min_nss_minor_version=`echo $min_nss_version | \
|
||||
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\(\.\([[0-9]]*\)\)\{0,1\}/\2/'`
|
||||
min_nss_micro_version=`echo $min_nss_version | \
|
||||
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
|
||||
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\(\.\([[0-9]]*\)\)\{0,1\}/\4/'`
|
||||
if test -z "$min_nss_micro_version"; then
|
||||
min_nss_micro_version="0"
|
||||
fi
|
||||
|
||||
if test "$nss_config_major_version" -lt "$min_nss_major_version"; then
|
||||
no_nss="yes"
|
||||
elif test "$nss_config_major_version" -eq "$min_nss_major_version" &&
|
||||
|
|
|
@ -33,9 +33,9 @@ public:
|
|||
// Check whether two markers should be considered the same,
|
||||
// for the purpose of pairing start and end markers. Normally
|
||||
// this definition suffices.
|
||||
virtual bool Equals(const TimelineMarker* aOther)
|
||||
virtual bool Equals(const TimelineMarker& aOther)
|
||||
{
|
||||
return strcmp(mName, aOther->mName) == 0;
|
||||
return strcmp(mName, aOther.mName) == 0;
|
||||
}
|
||||
|
||||
// Add details specific to this marker type to aMarker. The
|
||||
|
|
|
@ -2977,10 +2977,10 @@ nsDocShell::PopProfileTimelineMarkers(
|
|||
// If we see an unpaired START, we keep it around for the next call
|
||||
// to PopProfileTimelineMarkers. We store the kept START objects in
|
||||
// this array.
|
||||
nsTArray<TimelineMarker*> keptMarkers;
|
||||
nsTArray<UniquePtr<TimelineMarker>> keptMarkers;
|
||||
|
||||
for (uint32_t i = 0; i < mProfileTimelineMarkers.Length(); ++i) {
|
||||
TimelineMarker* startPayload = mProfileTimelineMarkers[i];
|
||||
UniquePtr<TimelineMarker>& startPayload = mProfileTimelineMarkers[i];
|
||||
const char* startMarkerName = startPayload->GetName();
|
||||
|
||||
bool hasSeenPaintedLayer = false;
|
||||
|
@ -3002,7 +3002,7 @@ nsDocShell::PopProfileTimelineMarkers(
|
|||
// enough for the amount of markers to always be small enough that the
|
||||
// nested for loop isn't going to be a performance problem.
|
||||
for (uint32_t j = i + 1; j < mProfileTimelineMarkers.Length(); ++j) {
|
||||
TimelineMarker* endPayload = mProfileTimelineMarkers[j];
|
||||
UniquePtr<TimelineMarker>& endPayload = mProfileTimelineMarkers[j];
|
||||
const char* endMarkerName = endPayload->GetName();
|
||||
|
||||
// Look for Layer markers to stream out paint markers.
|
||||
|
@ -3011,7 +3011,7 @@ nsDocShell::PopProfileTimelineMarkers(
|
|||
endPayload->AddLayerRectangles(layerRectangles);
|
||||
}
|
||||
|
||||
if (!startPayload->Equals(endPayload)) {
|
||||
if (!startPayload->Equals(*endPayload)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -3048,14 +3048,13 @@ nsDocShell::PopProfileTimelineMarkers(
|
|||
|
||||
// If we did not see the corresponding END, keep the START.
|
||||
if (!hasSeenEnd) {
|
||||
keptMarkers.AppendElement(mProfileTimelineMarkers[i]);
|
||||
keptMarkers.AppendElement(Move(mProfileTimelineMarkers[i]));
|
||||
mProfileTimelineMarkers.RemoveElementAt(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClearProfileTimelineMarkers();
|
||||
mProfileTimelineMarkers.SwapElements(keptMarkers);
|
||||
|
||||
if (!ToJSValue(aCx, profileTimelineMarkers, aProfileTimelineMarkers)) {
|
||||
|
@ -3086,10 +3085,10 @@ nsDocShell::AddProfileTimelineMarker(const char* aName,
|
|||
}
|
||||
|
||||
void
|
||||
nsDocShell::AddProfileTimelineMarker(UniquePtr<TimelineMarker>& aMarker)
|
||||
nsDocShell::AddProfileTimelineMarker(UniquePtr<TimelineMarker>&& aMarker)
|
||||
{
|
||||
if (mProfileTimelineRecording) {
|
||||
mProfileTimelineMarkers.AppendElement(aMarker.release());
|
||||
mProfileTimelineMarkers.AppendElement(Move(aMarker));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3125,9 +3124,6 @@ nsDocShell::GetWindowDraggingAllowed(bool* aValue)
|
|||
void
|
||||
nsDocShell::ClearProfileTimelineMarkers()
|
||||
{
|
||||
for (uint32_t i = 0; i < mProfileTimelineMarkers.Length(); ++i) {
|
||||
delete mProfileTimelineMarkers[i];
|
||||
}
|
||||
mProfileTimelineMarkers.Clear();
|
||||
}
|
||||
|
||||
|
|
|
@ -272,7 +272,7 @@ public:
|
|||
// See nsIDocShell::recordProfileTimelineMarkers
|
||||
void AddProfileTimelineMarker(const char* aName,
|
||||
TracingMetadata aMetaData);
|
||||
void AddProfileTimelineMarker(mozilla::UniquePtr<TimelineMarker>& aMarker);
|
||||
void AddProfileTimelineMarker(mozilla::UniquePtr<TimelineMarker>&& aMarker);
|
||||
|
||||
// Global counter for how many docShells are currently recording profile
|
||||
// timeline markers
|
||||
|
@ -984,7 +984,7 @@ private:
|
|||
// True if recording profiles.
|
||||
bool mProfileTimelineRecording;
|
||||
|
||||
nsTArray<TimelineMarker*> mProfileTimelineMarkers;
|
||||
nsTArray<mozilla::UniquePtr<TimelineMarker>> mProfileTimelineMarkers;
|
||||
|
||||
// Get rid of all the timeline markers accumulated so far
|
||||
void ClearProfileTimelineMarkers();
|
||||
|
|
|
@ -8,6 +8,8 @@ const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
|||
let { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
|
||||
let { Promise } = Cu.import('resource://gre/modules/Promise.jsm', {});
|
||||
|
||||
Cu.import("resource://gre/modules/Timer.jsm");
|
||||
|
||||
// Functions that look like mochitest functions but forward to the
|
||||
// browser process.
|
||||
|
||||
|
@ -81,8 +83,9 @@ this.timelineContentTest = function(tests) {
|
|||
|
||||
function timelineWaitForMarkers(docshell, searchFor) {
|
||||
if (typeof(searchFor) == "string") {
|
||||
let searchForString = searchFor;
|
||||
let f = function (markers) {
|
||||
return markers.some(m => m.name == searchFor);
|
||||
return markers.some(m => m.name == searchForString);
|
||||
};
|
||||
searchFor = f;
|
||||
}
|
||||
|
@ -92,14 +95,15 @@ function timelineWaitForMarkers(docshell, searchFor) {
|
|||
let maxWaitIterationCount = 10; // Wait for 2sec maximum
|
||||
let markers = [];
|
||||
|
||||
let interval = content.setInterval(() => {
|
||||
setTimeout(function timeoutHandler() {
|
||||
let newMarkers = docshell.popProfileTimelineMarkers();
|
||||
markers = [...markers, ...newMarkers];
|
||||
if (searchFor(markers) || waitIterationCount > maxWaitIterationCount) {
|
||||
content.clearInterval(interval);
|
||||
resolve(markers);
|
||||
} else {
|
||||
setTimeout(timeoutHandler, 200);
|
||||
waitIterationCount++;
|
||||
}
|
||||
waitIterationCount++;
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -39,9 +39,16 @@ function makeTimelineTest(frameScriptName, url) {
|
|||
|
||||
/* Open a URL for a timeline test. */
|
||||
function timelineTestOpenUrl(url) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
window.focus();
|
||||
window.focus();
|
||||
|
||||
let tabSwitchPromise = new Promise((resolve, reject) => {
|
||||
window.gBrowser.addEventListener("TabSwitchDone", function listener() {
|
||||
window.gBrowser.removeEventListener("TabSwitchDone", listener);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
let loadPromise = new Promise(function(resolve, reject) {
|
||||
let tab = window.gBrowser.selectedTab = window.gBrowser.addTab(url);
|
||||
let linkedBrowser = tab.linkedBrowser;
|
||||
|
||||
|
@ -50,4 +57,6 @@ function timelineTestOpenUrl(url) {
|
|||
resolve(tab);
|
||||
}, true);
|
||||
});
|
||||
|
||||
return Promise.all([tabSwitchPromise, loadPromise]).then(([_, tab]) => tab);
|
||||
}
|
||||
|
|
|
@ -934,13 +934,13 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
virtual bool Equals(const TimelineMarker* aOther) override
|
||||
virtual bool Equals(const TimelineMarker& aOther) override
|
||||
{
|
||||
if (!TimelineMarker::Equals(aOther)) {
|
||||
return false;
|
||||
}
|
||||
// Console markers must have matching causes as well.
|
||||
return GetCause() == aOther->GetCause();
|
||||
return GetCause() == aOther.GetCause();
|
||||
}
|
||||
|
||||
virtual void AddDetails(mozilla::dom::ProfileTimelineMarker& aMarker) override
|
||||
|
@ -1057,7 +1057,7 @@ Console::Method(JSContext* aCx, MethodName aMethodName,
|
|||
MakeUnique<ConsoleTimelineMarker>(docShell,
|
||||
aMethodName == MethodTime ? TRACING_INTERVAL_START : TRACING_INTERVAL_END,
|
||||
key);
|
||||
docShell->AddProfileTimelineMarker(marker);
|
||||
docShell->AddProfileTimelineMarker(Move(marker));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -312,7 +312,6 @@ AutoJSAPI::~AutoJSAPI()
|
|||
{
|
||||
if (mOwnErrorReporting) {
|
||||
MOZ_ASSERT(NS_IsMainThread(), "See corresponding assertion in TakeOwnershipOfErrorReporting()");
|
||||
JS::ContextOptionsRef(cx()).setAutoJSAPIOwnsErrorReporting(mOldAutoJSAPIOwnsErrorReporting);
|
||||
|
||||
if (HasException()) {
|
||||
|
||||
|
@ -342,6 +341,13 @@ AutoJSAPI::~AutoJSAPI()
|
|||
NS_WARNING("OOMed while acquiring uncaught exception from JSAPI");
|
||||
}
|
||||
}
|
||||
|
||||
// We need to do this _after_ processing the existing exception, because the
|
||||
// JS engine can throw while doing that, and uses this bit to determine what
|
||||
// to do in that case: squelch the exception if the bit is set, otherwise
|
||||
// call the error reporter. Calling WarningOnlyErrorReporter with a
|
||||
// non-warning will assert, so we need to make sure we do the former.
|
||||
JS::ContextOptionsRef(cx()).setAutoJSAPIOwnsErrorReporting(mOldAutoJSAPIOwnsErrorReporting);
|
||||
}
|
||||
|
||||
if (mOldErrorReporter.isSome()) {
|
||||
|
|
|
@ -2779,6 +2779,10 @@ nsFrameLoader::RequestNotifyLayerTreeReady()
|
|||
return mRemoteBrowser->RequestNotifyLayerTreeReady() ? NS_OK : NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (!mOwnerContent) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsRefPtr<AsyncEventDispatcher> event =
|
||||
new AsyncEventDispatcher(mOwnerContent,
|
||||
NS_LITERAL_STRING("MozLayerTreeReady"),
|
||||
|
@ -2795,6 +2799,10 @@ nsFrameLoader::RequestNotifyLayerTreeCleared()
|
|||
return mRemoteBrowser->RequestNotifyLayerTreeCleared() ? NS_OK : NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (!mOwnerContent) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsRefPtr<AsyncEventDispatcher> event =
|
||||
new AsyncEventDispatcher(mOwnerContent,
|
||||
NS_LITERAL_STRING("MozLayerTreeCleared"),
|
||||
|
|
|
@ -1239,6 +1239,7 @@ GK_ATOM(viewport_minimum_scale, "viewport-minimum-scale")
|
|||
GK_ATOM(viewport_user_scalable, "viewport-user-scalable")
|
||||
GK_ATOM(viewport_width, "viewport-width")
|
||||
GK_ATOM(visibility, "visibility")
|
||||
GK_ATOM(visuallyselected, "visuallyselected")
|
||||
GK_ATOM(vlink, "vlink")
|
||||
GK_ATOM(vspace, "vspace")
|
||||
GK_ATOM(wbr, "wbr")
|
||||
|
|
|
@ -643,9 +643,8 @@ public:
|
|||
JS::Handle<jsid> id,
|
||||
JS::MutableHandle<JS::Value> vp) const override;
|
||||
virtual bool set(JSContext *cx, JS::Handle<JSObject*> proxy,
|
||||
JS::Handle<JSObject*> receiver,
|
||||
JS::Handle<jsid> id,
|
||||
JS::MutableHandle<JS::Value> vp,
|
||||
JS::Handle<jsid> id, JS::Handle<JS::Value> v,
|
||||
JS::Handle<JS::Value> receiver,
|
||||
JS::ObjectOpResult &result) const override;
|
||||
|
||||
// SpiderMonkey extensions
|
||||
|
@ -909,9 +908,9 @@ nsOuterWindowProxy::get(JSContext *cx, JS::Handle<JSObject*> proxy,
|
|||
|
||||
bool
|
||||
nsOuterWindowProxy::set(JSContext *cx, JS::Handle<JSObject*> proxy,
|
||||
JS::Handle<JSObject*> receiver,
|
||||
JS::Handle<jsid> id,
|
||||
JS::MutableHandle<JS::Value> vp,
|
||||
JS::Handle<JS::Value> v,
|
||||
JS::Handle<JS::Value> receiver,
|
||||
JS::ObjectOpResult &result) const
|
||||
{
|
||||
int32_t index = GetArrayIndexFromId(cx, id);
|
||||
|
@ -921,7 +920,7 @@ nsOuterWindowProxy::set(JSContext *cx, JS::Handle<JSObject*> proxy,
|
|||
return result.failReadOnly();
|
||||
}
|
||||
|
||||
return js::Wrapper::set(cx, proxy, receiver, id, vp, result);
|
||||
return js::Wrapper::set(cx, proxy, id, v, receiver, result);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -9807,7 +9807,7 @@ class CGProxySpecialOperation(CGPerSignatureCall):
|
|||
false.
|
||||
"""
|
||||
def __init__(self, descriptor, operation, checkFound=True,
|
||||
argumentMutableValue=None, resultVar=None, foundVar=None):
|
||||
argumentHandleValue=None, resultVar=None, foundVar=None):
|
||||
self.checkFound = checkFound
|
||||
self.foundVar = foundVar or "found"
|
||||
|
||||
|
@ -9832,12 +9832,12 @@ class CGProxySpecialOperation(CGPerSignatureCall):
|
|||
treatNullAs=argument.treatNullAs,
|
||||
sourceDescription=("value being assigned to %s setter" %
|
||||
descriptor.interface.identifier.name))
|
||||
if argumentMutableValue is None:
|
||||
argumentMutableValue = "desc.value()"
|
||||
if argumentHandleValue is None:
|
||||
argumentHandleValue = "desc.value()"
|
||||
templateValues = {
|
||||
"declName": argument.identifier.name,
|
||||
"holderName": argument.identifier.name + "_holder",
|
||||
"val": argumentMutableValue,
|
||||
"val": argumentHandleValue,
|
||||
"obj": "obj",
|
||||
"passedToJSImpl": "false"
|
||||
}
|
||||
|
@ -9882,10 +9882,10 @@ class CGProxyIndexedOperation(CGProxySpecialOperation):
|
|||
foundVar: See the docstring for CGProxySpecialOperation.
|
||||
"""
|
||||
def __init__(self, descriptor, name, doUnwrap=True, checkFound=True,
|
||||
argumentMutableValue=None, resultVar=None, foundVar=None):
|
||||
argumentHandleValue=None, resultVar=None, foundVar=None):
|
||||
self.doUnwrap = doUnwrap
|
||||
CGProxySpecialOperation.__init__(self, descriptor, name, checkFound,
|
||||
argumentMutableValue=argumentMutableValue,
|
||||
argumentHandleValue=argumentHandleValue,
|
||||
resultVar=resultVar,
|
||||
foundVar=foundVar)
|
||||
|
||||
|
@ -9943,9 +9943,9 @@ class CGProxyIndexedSetter(CGProxyIndexedOperation):
|
|||
"""
|
||||
Class to generate a call to an indexed setter.
|
||||
"""
|
||||
def __init__(self, descriptor, argumentMutableValue=None):
|
||||
def __init__(self, descriptor, argumentHandleValue=None):
|
||||
CGProxyIndexedOperation.__init__(self, descriptor, 'IndexedSetter',
|
||||
argumentMutableValue=argumentMutableValue)
|
||||
argumentHandleValue=argumentHandleValue)
|
||||
|
||||
|
||||
class CGProxyIndexedDeleter(CGProxyIndexedOperation):
|
||||
|
@ -9973,10 +9973,10 @@ class CGProxyNamedOperation(CGProxySpecialOperation):
|
|||
|
||||
foundVar: See the docstring for CGProxySpecialOperation.
|
||||
"""
|
||||
def __init__(self, descriptor, name, value=None, argumentMutableValue=None,
|
||||
def __init__(self, descriptor, name, value=None, argumentHandleValue=None,
|
||||
resultVar=None, foundVar=None):
|
||||
CGProxySpecialOperation.__init__(self, descriptor, name,
|
||||
argumentMutableValue=argumentMutableValue,
|
||||
argumentHandleValue=argumentHandleValue,
|
||||
resultVar=resultVar,
|
||||
foundVar=foundVar)
|
||||
self.value = value
|
||||
|
@ -10074,9 +10074,9 @@ class CGProxyNamedSetter(CGProxyNamedOperation):
|
|||
"""
|
||||
Class to generate a call to a named setter.
|
||||
"""
|
||||
def __init__(self, descriptor, argumentMutableValue=None):
|
||||
def __init__(self, descriptor, argumentHandleValue=None):
|
||||
CGProxyNamedOperation.__init__(self, descriptor, 'NamedSetter',
|
||||
argumentMutableValue=argumentMutableValue)
|
||||
argumentHandleValue=argumentHandleValue)
|
||||
|
||||
|
||||
class CGProxyNamedDeleter(CGProxyNamedOperation):
|
||||
|
@ -10693,7 +10693,7 @@ class CGDOMJSProxyHandler_setCustom(ClassMethod):
|
|||
args = [Argument('JSContext*', 'cx'),
|
||||
Argument('JS::Handle<JSObject*>', 'proxy'),
|
||||
Argument('JS::Handle<jsid>', 'id'),
|
||||
Argument('JS::MutableHandle<JS::Value>', 'vp'),
|
||||
Argument('JS::Handle<JS::Value>', 'v'),
|
||||
Argument('bool*', 'done')]
|
||||
ClassMethod.__init__(self, "setCustom", "bool", args, virtual=True, override=True, const=True)
|
||||
self.descriptor = descriptor
|
||||
|
@ -10718,7 +10718,7 @@ class CGDOMJSProxyHandler_setCustom(ClassMethod):
|
|||
raise ValueError("In interface " + self.descriptor.name + ": " +
|
||||
"Can't cope with [OverrideBuiltins] and unforgeable members")
|
||||
|
||||
callSetter = CGProxyNamedSetter(self.descriptor, argumentMutableValue="vp")
|
||||
callSetter = CGProxyNamedSetter(self.descriptor, argumentHandleValue="v")
|
||||
return (assertion +
|
||||
callSetter.define() +
|
||||
"*done = true;\n"
|
||||
|
@ -10743,7 +10743,7 @@ class CGDOMJSProxyHandler_setCustom(ClassMethod):
|
|||
|
||||
""",
|
||||
callSetter=CGProxyIndexedSetter(self.descriptor,
|
||||
argumentMutableValue="vp").define())
|
||||
argumentHandleValue="v").define())
|
||||
else:
|
||||
setIndexed = ""
|
||||
|
||||
|
|
|
@ -219,13 +219,14 @@ DOMProxyHandler::defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::
|
|||
}
|
||||
|
||||
bool
|
||||
DOMProxyHandler::set(JSContext *cx, Handle<JSObject*> proxy, Handle<JSObject*> receiver,
|
||||
Handle<jsid> id, MutableHandle<JS::Value> vp, ObjectOpResult &result) const
|
||||
DOMProxyHandler::set(JSContext *cx, Handle<JSObject*> proxy, Handle<jsid> id,
|
||||
Handle<JS::Value> v, Handle<JS::Value> receiver,
|
||||
ObjectOpResult &result) const
|
||||
{
|
||||
MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
|
||||
"Should not have a XrayWrapper here");
|
||||
bool done;
|
||||
if (!setCustom(cx, proxy, id, vp, &done)) {
|
||||
if (!setCustom(cx, proxy, id, v, &done)) {
|
||||
return false;
|
||||
}
|
||||
if (done) {
|
||||
|
@ -252,7 +253,7 @@ DOMProxyHandler::set(JSContext *cx, Handle<JSObject*> proxy, Handle<JSObject*> r
|
|||
}
|
||||
}
|
||||
|
||||
return js::SetPropertyIgnoringNamedGetter(cx, proxy, id, vp, receiver, desc, result);
|
||||
return js::SetPropertyIgnoringNamedGetter(cx, proxy, id, v, receiver, desc, result);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -350,7 +351,7 @@ IdToInt32(JSContext* cx, JS::Handle<jsid> id)
|
|||
|
||||
bool
|
||||
DOMProxyHandler::setCustom(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
|
||||
JS::MutableHandle<JS::Value> vp, bool *done) const
|
||||
JS::Handle<JS::Value> v, bool *done) const
|
||||
{
|
||||
*done = false;
|
||||
return true;
|
||||
|
|
|
@ -122,8 +122,8 @@ public:
|
|||
const override;
|
||||
bool has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
|
||||
bool* bp) const override;
|
||||
bool set(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<JSObject*> receiver,
|
||||
JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp, JS::ObjectOpResult &result)
|
||||
bool set(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
|
||||
JS::Handle<JS::Value> v, JS::Handle<JS::Value> receiver, JS::ObjectOpResult &result)
|
||||
const override;
|
||||
|
||||
/*
|
||||
|
@ -132,7 +132,7 @@ public:
|
|||
* *done to false.
|
||||
*/
|
||||
virtual bool setCustom(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
|
||||
JS::MutableHandle<JS::Value> vp, bool *done) const;
|
||||
JS::Handle<JS::Value> v, bool *done) const;
|
||||
|
||||
static JSObject* GetExpandoObject(JSObject* obj);
|
||||
|
||||
|
|
|
@ -1094,7 +1094,7 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
|
|||
mozilla::UniquePtr<TimelineMarker> marker =
|
||||
MakeUnique<EventTimelineMarker>(ds, TRACING_INTERVAL_START,
|
||||
phase, typeStr);
|
||||
ds->AddProfileTimelineMarker(marker);
|
||||
ds->AddProfileTimelineMarker(Move(marker));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "mozilla/dom/Response.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/URLSearchParams.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
#include "InternalRequest.h"
|
||||
#include "InternalResponse.h"
|
||||
|
@ -231,6 +232,8 @@ FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
Telemetry::Accumulate(Telemetry::FETCH_IS_MAINTHREAD, 1);
|
||||
|
||||
nsRefPtr<MainThreadFetchResolver> resolver = new MainThreadFetchResolver(p);
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = doc->GetDocumentLoadGroup();
|
||||
nsRefPtr<FetchDriver> fetch =
|
||||
|
@ -244,6 +247,8 @@ FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
|
|||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
|
||||
Telemetry::Accumulate(Telemetry::FETCH_IS_MAINTHREAD, 0);
|
||||
|
||||
if (worker->IsServiceWorker()) {
|
||||
r->SetSkipServiceWorker();
|
||||
}
|
||||
|
|
|
@ -60,6 +60,9 @@ FetchDriver::Fetch(FetchDriverObserver* aObserver)
|
|||
workers::AssertIsOnMainThread();
|
||||
mObserver = aObserver;
|
||||
|
||||
Telemetry::Accumulate(Telemetry::SERVICE_WORKER_REQUEST_PASSTHROUGH,
|
||||
mRequest->WasCreatedByFetchEvent());
|
||||
|
||||
return Fetch(false /* CORS flag */);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ InternalRequest::GetRequestConstructorCopy(nsIGlobalObject* aGlobal, ErrorResult
|
|||
copy->mMode = mMode;
|
||||
copy->mCredentialsMode = mCredentialsMode;
|
||||
copy->mCacheMode = mCacheMode;
|
||||
copy->mCreatedByFetchEvent = mCreatedByFetchEvent;
|
||||
return copy.forget();
|
||||
}
|
||||
|
||||
|
@ -87,6 +88,7 @@ InternalRequest::InternalRequest(const InternalRequest& aOther)
|
|||
, mSynchronous(aOther.mSynchronous)
|
||||
, mUnsafeRequest(aOther.mUnsafeRequest)
|
||||
, mUseURLCredentials(aOther.mUseURLCredentials)
|
||||
, mCreatedByFetchEvent(aOther.mCreatedByFetchEvent)
|
||||
{
|
||||
// NOTE: does not copy body stream... use the fallible Clone() for that
|
||||
}
|
||||
|
|
|
@ -283,6 +283,24 @@ public:
|
|||
already_AddRefed<InternalRequest>
|
||||
GetRequestConstructorCopy(nsIGlobalObject* aGlobal, ErrorResult& aRv) const;
|
||||
|
||||
bool
|
||||
WasCreatedByFetchEvent() const
|
||||
{
|
||||
return mCreatedByFetchEvent;
|
||||
}
|
||||
|
||||
void
|
||||
SetCreatedByFetchEvent()
|
||||
{
|
||||
mCreatedByFetchEvent = true;
|
||||
}
|
||||
|
||||
void
|
||||
ClearCreatedByFetchEvent()
|
||||
{
|
||||
mCreatedByFetchEvent = false;
|
||||
}
|
||||
|
||||
private:
|
||||
// Does not copy mBodyStream. Use fallible Clone() for complete copy.
|
||||
explicit InternalRequest(const InternalRequest& aOther);
|
||||
|
@ -317,6 +335,10 @@ private:
|
|||
bool mSynchronous;
|
||||
bool mUnsafeRequest;
|
||||
bool mUseURLCredentials;
|
||||
// This is only set when a Request object is created by a fetch event. We
|
||||
// use it to check if Service Workers are simply fetching intercepted Request
|
||||
// objects without modifying them.
|
||||
bool mCreatedByFetchEvent = false;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -147,16 +147,19 @@ Request::Constructor(const GlobalObject& aGlobal,
|
|||
: fallbackCredentials;
|
||||
|
||||
if (mode != RequestMode::EndGuard_) {
|
||||
request->ClearCreatedByFetchEvent();
|
||||
request->SetMode(mode);
|
||||
}
|
||||
|
||||
if (credentials != RequestCredentials::EndGuard_) {
|
||||
request->ClearCreatedByFetchEvent();
|
||||
request->SetCredentialsMode(credentials);
|
||||
}
|
||||
|
||||
RequestCache cache = aInit.mCache.WasPassed() ?
|
||||
aInit.mCache.Value() : fallbackCache;
|
||||
if (cache != RequestCache::EndGuard_) {
|
||||
request->ClearCreatedByFetchEvent();
|
||||
request->SetCacheMode(cache);
|
||||
}
|
||||
|
||||
|
@ -185,8 +188,10 @@ Request::Constructor(const GlobalObject& aGlobal,
|
|||
upperCaseMethod.EqualsLiteral("POST") ||
|
||||
upperCaseMethod.EqualsLiteral("PUT") ||
|
||||
upperCaseMethod.EqualsLiteral("OPTIONS")) {
|
||||
request->ClearCreatedByFetchEvent();
|
||||
request->SetMethod(upperCaseMethod);
|
||||
} else {
|
||||
request->ClearCreatedByFetchEvent();
|
||||
request->SetMethod(method);
|
||||
}
|
||||
}
|
||||
|
@ -199,6 +204,7 @@ Request::Constructor(const GlobalObject& aGlobal,
|
|||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
request->ClearCreatedByFetchEvent();
|
||||
headers = h->GetInternalHeaders();
|
||||
} else {
|
||||
headers = new InternalHeaders(*requestHeaders);
|
||||
|
@ -244,6 +250,7 @@ Request::Constructor(const GlobalObject& aGlobal,
|
|||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
request->ClearCreatedByFetchEvent();
|
||||
request->SetBody(stream);
|
||||
|
||||
if (!contentType.IsVoid() &&
|
||||
|
|
|
@ -612,8 +612,7 @@ parent:
|
|||
* This call connects the content process to a plugin process. While this
|
||||
* call runs, a new PluginModuleParent will be created in the ContentChild
|
||||
* via bridging. The corresponding PluginModuleChild will live in the plugin
|
||||
* process. We use intr semantics here to ensure that the PluginModuleParent
|
||||
* allocation message is dispatched before LoadPlugin returns.
|
||||
* process.
|
||||
*/
|
||||
sync LoadPlugin(uint32_t pluginId) returns (nsresult rv);
|
||||
|
||||
|
|
|
@ -277,6 +277,7 @@ TabParent::TabParent(nsIContentParent* aManager,
|
|||
, mInitedByParent(false)
|
||||
, mTabId(aTabId)
|
||||
, mCreatingWindow(false)
|
||||
, mNeedLayerTreeReadyNotification(false)
|
||||
{
|
||||
MOZ_ASSERT(aManager);
|
||||
}
|
||||
|
@ -2389,6 +2390,12 @@ TabParent::RecvGetRenderFrameInfo(PRenderFrameParent* aRenderFrame,
|
|||
RenderFrameParent* renderFrame = static_cast<RenderFrameParent*>(aRenderFrame);
|
||||
renderFrame->GetTextureFactoryIdentifier(aTextureFactoryIdentifier);
|
||||
*aLayersId = renderFrame->GetLayersId();
|
||||
|
||||
if (mNeedLayerTreeReadyNotification) {
|
||||
RequestNotifyLayerTreeReady();
|
||||
mNeedLayerTreeReadyNotification = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2691,11 +2698,11 @@ TabParent::RequestNotifyLayerTreeReady()
|
|||
{
|
||||
RenderFrameParent* frame = GetRenderFrame();
|
||||
if (!frame) {
|
||||
return false;
|
||||
mNeedLayerTreeReadyNotification = true;
|
||||
} else {
|
||||
CompositorParent::RequestNotifyLayerTreeReady(frame->GetLayersId(),
|
||||
new LayerTreeUpdateObserver());
|
||||
}
|
||||
|
||||
CompositorParent::RequestNotifyLayerTreeReady(frame->GetLayersId(),
|
||||
new LayerTreeUpdateObserver());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -520,6 +520,11 @@ private:
|
|||
// CreateWindow response. Then TabChild loads them immediately.
|
||||
nsTArray<FrameScriptInfo> mDelayedFrameScripts;
|
||||
|
||||
// If the user called RequestNotifyLayerTreeReady and the RenderFrameParent
|
||||
// wasn't ready yet, we set this flag and call RequestNotifyLayerTreeReady
|
||||
// again once the RenderFrameParent arrives.
|
||||
bool mNeedLayerTreeReadyNotification;
|
||||
|
||||
private:
|
||||
// This is used when APZ needs to find the TabParent associated with a layer
|
||||
// to dispatch events.
|
||||
|
|
|
@ -1820,7 +1820,7 @@ _popupcontextmenu(NPP instance, NPMenu* menu)
|
|||
if (success) {
|
||||
return mozilla::plugins::PluginUtilsOSX::ShowCocoaContextMenu(menu,
|
||||
screenX, screenY,
|
||||
PluginModuleChild::GetChrome(),
|
||||
InstCast(instance)->Manager(),
|
||||
ProcessBrowserEvents);
|
||||
} else {
|
||||
NS_WARNING("Convertpoint failed, could not created contextmenu.");
|
||||
|
|
|
@ -17,8 +17,8 @@ interface FetchEvent : Event {
|
|||
readonly attribute Client? client; // The window issuing the request.
|
||||
readonly attribute boolean isReload;
|
||||
|
||||
[Throws] void respondWith(Promise<Response> r);
|
||||
[Throws] void respondWith(Response r);
|
||||
[Throws]
|
||||
void respondWith((Response or Promise<Response>) r);
|
||||
};
|
||||
|
||||
dictionary FetchEventInit : EventInit {
|
||||
|
|
|
@ -282,37 +282,32 @@ RespondWithHandler::CancelRequest()
|
|||
} // anonymous namespace
|
||||
|
||||
void
|
||||
FetchEvent::RespondWith(Promise& aPromise, ErrorResult& aRv)
|
||||
FetchEvent::RespondWith(const ResponseOrPromise& aArg, ErrorResult& aRv)
|
||||
{
|
||||
if (mWaitToRespond) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise;
|
||||
|
||||
if (aArg.IsResponse()) {
|
||||
nsRefPtr<Response> res = &aArg.GetAsResponse();
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
worker->AssertIsOnWorkerThread();
|
||||
promise = Promise::Create(worker->GlobalScope(), aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
promise->MaybeResolve(res);
|
||||
} else if (aArg.IsPromise()) {
|
||||
promise = &aArg.GetAsPromise();
|
||||
}
|
||||
mWaitToRespond = true;
|
||||
nsRefPtr<RespondWithHandler> handler =
|
||||
new RespondWithHandler(mChannel, mServiceWorker, mRequest->Mode());
|
||||
aPromise.AppendNativeHandler(handler);
|
||||
}
|
||||
|
||||
void
|
||||
FetchEvent::RespondWith(Response& aResponse, ErrorResult& aRv)
|
||||
{
|
||||
if (mWaitToRespond) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
worker->AssertIsOnWorkerThread();
|
||||
nsRefPtr<Promise> promise = Promise::Create(worker->GlobalScope(), aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
promise->MaybeResolve(&aResponse);
|
||||
|
||||
RespondWith(*promise, aRv);
|
||||
promise->AppendNativeHandler(handler);
|
||||
}
|
||||
|
||||
already_AddRefed<ServiceWorkerClient>
|
||||
|
|
|
@ -19,6 +19,7 @@ class nsIInterceptedChannel;
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Request;
|
||||
class ResponseOrPromise;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -82,10 +83,7 @@ public:
|
|||
}
|
||||
|
||||
void
|
||||
RespondWith(Promise& aPromise, ErrorResult& aRv);
|
||||
|
||||
void
|
||||
RespondWith(Response& aResponse, ErrorResult& aRv);
|
||||
RespondWith(const ResponseOrPromise& aArg, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
ForwardTo(const nsAString& aUrl);
|
||||
|
|
|
@ -2302,6 +2302,10 @@ private:
|
|||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return false;
|
||||
}
|
||||
// For Telemetry, note that this Request object was created by a Fetch event.
|
||||
nsRefPtr<InternalRequest> internalReq = request->GetInternalRequest();
|
||||
MOZ_ASSERT(internalReq);
|
||||
internalReq->SetCreatedByFetchEvent();
|
||||
|
||||
RootedDictionary<FetchEventInit> init(aCx);
|
||||
init.mRequest.Construct();
|
||||
|
|
|
@ -849,9 +849,8 @@ LayerTransactionParent::RecvClearCachedResources()
|
|||
// context, it's just a subtree root. We need to scope the clear
|
||||
// of resources to exactly that subtree, so we specify it here.
|
||||
mLayerManager->ClearCachedResources(mRoot);
|
||||
|
||||
mShadowLayersManager->NotifyClearCachedResources(this);
|
||||
}
|
||||
mShadowLayersManager->NotifyClearCachedResources(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,9 +29,7 @@ namespace layers {
|
|||
* the main thread and the compositor thread context. It's primary
|
||||
* purpose is to manage the PLayerTransaction sub protocol.
|
||||
*/
|
||||
// This should really be 'sync', but we're using 'rpc' as a workaround
|
||||
// for Bug 716631.
|
||||
intr protocol PCompositor
|
||||
sync protocol PCompositor
|
||||
{
|
||||
// A Compositor manages a single Layer Manager (PLayerTransaction)
|
||||
manages PLayerTransaction;
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace layers {
|
|||
* frames directly to the compositor thread/process without relying on the main thread
|
||||
* which might be too busy dealing with content script.
|
||||
*/
|
||||
intr protocol PImageBridge
|
||||
sync protocol PImageBridge
|
||||
{
|
||||
manages PCompositable;
|
||||
manages PTexture;
|
||||
|
|
|
@ -4,10 +4,9 @@
|
|||
<script id="script">
|
||||
var i=0;
|
||||
function doe() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var navigator1 = top.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIWebNavigation);
|
||||
var docShell = navigator1.QueryInterface(Components.interfaces.nsIDocShell);
|
||||
var docviewer = docShell.contentViewer;
|
||||
var navigator1 = SpecialPowers.wrap(top).QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor).getInterface(SpecialPowers.Ci.nsIWebNavigation);
|
||||
var docShell = navigator1.QueryInterface(SpecialPowers.Ci.nsIDocShell);
|
||||
var docviewer = docShell.contentViewer.QueryInterface(SpecialPowers.Ci.nsIMarkupDocumentViewer);
|
||||
docviewer.textZoom=i;
|
||||
i=i+0.2;
|
||||
if (i>10)
|
||||
|
|
|
@ -12,10 +12,9 @@ if (document.getElementById('content')) {
|
|||
|
||||
var docviewer;
|
||||
function do_onload() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var navigator = parent.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIWebNavigation);
|
||||
var docShell = navigator.QueryInterface(Components.interfaces.nsIDocShell);
|
||||
docviewer = docShell.contentViewer;
|
||||
var navigator1 = SpecialPowers.wrap(parent).QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor).getInterface(SpecialPowers.Ci.nsIWebNavigation);
|
||||
var docShell = navigator1.QueryInterface(SpecialPowers.Ci.nsIDocShell);
|
||||
docviewer = docShell.contentViewer.QueryInterface(SpecialPowers.Ci.nsIMarkupDocumentViewer);
|
||||
|
||||
setTimeout(doe,500, 0.2);
|
||||
}
|
||||
|
|
|
@ -71,10 +71,9 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base
|
|||
ReturnStatus *rs, JSVariant *result) {
|
||||
return Answer::RecvGet(ObjectId::deserialize(objId), receiverVar, id, rs, result);
|
||||
}
|
||||
bool RecvSet(const uint64_t &objId, const ObjectVariant &receiverVar,
|
||||
const JSIDVariant &id, const JSVariant &value, ReturnStatus *rs,
|
||||
JSVariant *result) {
|
||||
return Answer::RecvSet(ObjectId::deserialize(objId), receiverVar, id, value, rs, result);
|
||||
bool RecvSet(const uint64_t &objId, const JSIDVariant &id, const JSVariant &value,
|
||||
const JSVariant &receiverVar, ReturnStatus *rs) {
|
||||
return Answer::RecvSet(ObjectId::deserialize(objId), id, value, receiverVar, rs);
|
||||
}
|
||||
|
||||
bool RecvIsExtensible(const uint64_t &objId, ReturnStatus *rs,
|
||||
|
@ -161,10 +160,9 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base
|
|||
ReturnStatus *rs, JSVariant *result) {
|
||||
return Base::SendGet(objId.serialize(), receiverVar, id, rs, result);
|
||||
}
|
||||
bool SendSet(const ObjectId &objId, const ObjectVariant &receiverVar,
|
||||
const JSIDVariant &id, const JSVariant &value, ReturnStatus *rs,
|
||||
JSVariant *result) {
|
||||
return Base::SendSet(objId.serialize(), receiverVar, id, value, rs, result);
|
||||
bool SendSet(const ObjectId &objId, const JSIDVariant &id, const JSVariant &value,
|
||||
const JSVariant &receiverVar, ReturnStatus *rs) {
|
||||
return Base::SendSet(objId.serialize(), id, value, receiverVar, rs);
|
||||
}
|
||||
|
||||
bool SendIsExtensible(const ObjectId &objId, ReturnStatus *rs,
|
||||
|
|
|
@ -33,7 +33,7 @@ both:
|
|||
prio(high) sync Has(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
|
||||
prio(high) sync HasOwn(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
|
||||
prio(high) sync Get(uint64_t objId, ObjectVariant receiver, JSIDVariant id) returns (ReturnStatus rs, JSVariant result);
|
||||
prio(high) sync Set(uint64_t objId, ObjectVariant receiver, JSIDVariant id, JSVariant value) returns (ReturnStatus rs, JSVariant result);
|
||||
prio(high) sync Set(uint64_t objId, JSIDVariant id, JSVariant value, JSVariant receiver) returns (ReturnStatus rs);
|
||||
|
||||
prio(high) sync IsExtensible(uint64_t objId) returns (ReturnStatus rs, bool result);
|
||||
prio(high) sync CallOrConstruct(uint64_t objId, JSParam[] argv, bool construct) returns (ReturnStatus rs, JSVariant result, JSParam[] outparams);
|
||||
|
|
|
@ -308,26 +308,17 @@ WrapperAnswer::RecvGet(const ObjectId &objId, const ObjectVariant &receiverVar,
|
|||
}
|
||||
|
||||
bool
|
||||
WrapperAnswer::RecvSet(const ObjectId &objId, const ObjectVariant &receiverVar,
|
||||
const JSIDVariant &idVar, const JSVariant &value, ReturnStatus *rs,
|
||||
JSVariant *resultValue)
|
||||
WrapperAnswer::RecvSet(const ObjectId &objId, const JSIDVariant &idVar, const JSVariant &value,
|
||||
const JSVariant &receiverVar, ReturnStatus *rs)
|
||||
{
|
||||
// We may run scripted setters.
|
||||
AutoEntryScript aes(xpc::NativeGlobal(scopeForTargetObjects()));
|
||||
JSContext *cx = aes.cx();
|
||||
|
||||
// The outparam will be written to the buffer, so it must be set even if
|
||||
// the parent won't read it.
|
||||
*resultValue = UndefinedVariant();
|
||||
|
||||
RootedObject obj(cx, findObjectById(cx, objId));
|
||||
if (!obj)
|
||||
return fail(cx, rs);
|
||||
|
||||
RootedObject receiver(cx, fromObjectVariant(cx, receiverVar));
|
||||
if (!receiver)
|
||||
return fail(cx, rs);
|
||||
|
||||
LOG("set %s[%s] = %s", ReceiverObj(objId), Identifier(idVar), InVariant(value));
|
||||
|
||||
RootedId id(cx);
|
||||
|
@ -338,12 +329,12 @@ WrapperAnswer::RecvSet(const ObjectId &objId, const ObjectVariant &receiverVar,
|
|||
if (!fromVariant(cx, value, &val))
|
||||
return fail(cx, rs);
|
||||
|
||||
ObjectOpResult result;
|
||||
RootedValue receiverVal(cx, ObjectValue(*receiver));
|
||||
if (!JS_ForwardSetPropertyTo(cx, obj, id, val, receiverVal, result))
|
||||
RootedValue receiver(cx);
|
||||
if (!fromVariant(cx, receiverVar, &receiver))
|
||||
return fail(cx, rs);
|
||||
|
||||
if (!toVariant(cx, val, resultValue))
|
||||
ObjectOpResult result;
|
||||
if (!JS_ForwardSetPropertyTo(cx, obj, id, val, receiver, result))
|
||||
return fail(cx, rs);
|
||||
|
||||
return ok(rs, result);
|
||||
|
|
|
@ -37,9 +37,8 @@ class WrapperAnswer : public virtual JavaScriptShared
|
|||
bool RecvGet(const ObjectId &objId, const ObjectVariant &receiverVar,
|
||||
const JSIDVariant &id,
|
||||
ReturnStatus *rs, JSVariant *result);
|
||||
bool RecvSet(const ObjectId &objId, const ObjectVariant &receiverVar,
|
||||
const JSIDVariant &id, const JSVariant &value, ReturnStatus *rs,
|
||||
JSVariant *result);
|
||||
bool RecvSet(const ObjectId &objId, const JSIDVariant &id, const JSVariant &value,
|
||||
const JSVariant &receiverVar, ReturnStatus *rs);
|
||||
|
||||
bool RecvIsExtensible(const ObjectId &objId, ReturnStatus *rs,
|
||||
bool *result);
|
||||
|
|
|
@ -110,9 +110,8 @@ class CPOWProxyHandler : public BaseProxyHandler
|
|||
virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const override;
|
||||
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
|
||||
HandleId id, MutableHandleValue vp) const override;
|
||||
virtual bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
|
||||
JS::HandleId id, JS::MutableHandleValue vp,
|
||||
JS::ObjectOpResult &result) const override;
|
||||
virtual bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue v,
|
||||
JS::HandleValue receiver, JS::ObjectOpResult &result) const override;
|
||||
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const override;
|
||||
virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const override;
|
||||
|
||||
|
@ -517,41 +516,37 @@ WrapperOwner::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
|
|||
}
|
||||
|
||||
bool
|
||||
CPOWProxyHandler::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
|
||||
JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult &result) const
|
||||
CPOWProxyHandler::set(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue v,
|
||||
JS::HandleValue receiver, JS::ObjectOpResult &result) const
|
||||
{
|
||||
FORWARD(set, (cx, proxy, receiver, id, vp, result));
|
||||
FORWARD(set, (cx, proxy, id, v, receiver, result));
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperOwner::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
|
||||
JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult &result)
|
||||
WrapperOwner::set(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue v,
|
||||
JS::HandleValue receiver, JS::ObjectOpResult &result)
|
||||
{
|
||||
ObjectId objId = idOf(proxy);
|
||||
|
||||
ObjectVariant receiverVar;
|
||||
if (!toObjectVariant(cx, receiver, &receiverVar))
|
||||
return false;
|
||||
|
||||
JSIDVariant idVar;
|
||||
if (!toJSIDVariant(cx, id, &idVar))
|
||||
return false;
|
||||
|
||||
JSVariant val;
|
||||
if (!toVariant(cx, vp, &val))
|
||||
if (!toVariant(cx, v, &val))
|
||||
return false;
|
||||
|
||||
JSVariant receiverVar;
|
||||
if (!toVariant(cx, receiver, &receiverVar))
|
||||
return false;
|
||||
|
||||
ReturnStatus status;
|
||||
JSVariant resultValue;
|
||||
if (!SendSet(objId, receiverVar, idVar, val, &status, &resultValue))
|
||||
if (!SendSet(objId, idVar, val, receiverVar, &status))
|
||||
return ipcfail(cx);
|
||||
|
||||
LOG_STACK();
|
||||
|
||||
if (!ok(cx, status, result))
|
||||
return false;
|
||||
|
||||
return fromVariant(cx, resultValue, vp);
|
||||
return ok(cx, status, result);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -42,8 +42,8 @@ class WrapperOwner : public virtual JavaScriptShared
|
|||
bool has(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
|
||||
bool get(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
|
||||
JS::HandleId id, JS::MutableHandleValue vp);
|
||||
bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
|
||||
JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult &result);
|
||||
bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue v,
|
||||
JS::HandleValue receiver, JS::ObjectOpResult &result);
|
||||
bool callOrConstruct(JSContext *cx, JS::HandleObject proxy, const JS::CallArgs &args,
|
||||
bool construct);
|
||||
|
||||
|
@ -128,9 +128,8 @@ class WrapperOwner : public virtual JavaScriptShared
|
|||
virtual bool SendGet(const ObjectId &objId, const ObjectVariant &receiverVar,
|
||||
const JSIDVariant &id,
|
||||
ReturnStatus *rs, JSVariant *result) = 0;
|
||||
virtual bool SendSet(const ObjectId &objId, const ObjectVariant &receiverVar,
|
||||
const JSIDVariant &id, const JSVariant &value,
|
||||
ReturnStatus *rs, JSVariant *result) = 0;
|
||||
virtual bool SendSet(const ObjectId &objId, const JSIDVariant &id, const JSVariant &value,
|
||||
const JSVariant &receiverVar, ReturnStatus *rs) = 0;
|
||||
|
||||
virtual bool SendIsExtensible(const ObjectId &objId, ReturnStatus *rs,
|
||||
bool *result) = 0;
|
||||
|
|
|
@ -342,8 +342,8 @@ typedef bool
|
|||
(* GetPropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, JS::HandleId id,
|
||||
JS::MutableHandleValue vp);
|
||||
typedef bool
|
||||
(* SetPropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, JS::HandleId id,
|
||||
JS::MutableHandleValue vp, JS::ObjectOpResult &result);
|
||||
(* SetPropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v,
|
||||
JS::HandleValue receiver, JS::ObjectOpResult &result);
|
||||
typedef bool
|
||||
(* GetOwnPropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
|
||||
JS::MutableHandle<JSPropertyDescriptor> desc);
|
||||
|
|
|
@ -295,8 +295,8 @@ class JS_FRIEND_API(BaseProxyHandler)
|
|||
virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const;
|
||||
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
|
||||
HandleId id, MutableHandleValue vp) const;
|
||||
virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver,
|
||||
HandleId id, MutableHandleValue vp, ObjectOpResult &result) const;
|
||||
virtual bool set(JSContext *cx, HandleObject proxy, HandleId id, HandleValue v,
|
||||
HandleValue receiver, ObjectOpResult &result) const;
|
||||
|
||||
/*
|
||||
* [[Call]] and [[Construct]] are standard internal methods but according
|
||||
|
@ -395,9 +395,8 @@ class JS_FRIEND_API(DirectProxyHandler) : public BaseProxyHandler
|
|||
bool *bp) const override;
|
||||
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
|
||||
HandleId id, MutableHandleValue vp) const override;
|
||||
virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver,
|
||||
HandleId id, MutableHandleValue vp,
|
||||
ObjectOpResult &result) const override;
|
||||
virtual bool set(JSContext *cx, HandleObject proxy, HandleId id, HandleValue v,
|
||||
HandleValue receiver, ObjectOpResult &result) const override;
|
||||
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const override;
|
||||
virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const override;
|
||||
|
||||
|
|
|
@ -4443,20 +4443,13 @@ FoldMaskedArrayIndex(FunctionCompiler &f, ParseNode **indexExpr, int32_t *mask,
|
|||
|
||||
uint32_t mask2;
|
||||
if (IsLiteralOrConstInt(f, maskNode, &mask2)) {
|
||||
// Flag the access to skip the bounds check if the mask ensures that an 'out of
|
||||
// bounds' access can not occur based on the current heap length constraint.
|
||||
if (mask2 == 0) {
|
||||
// Flag the access to skip the bounds check if the mask ensures that an
|
||||
// 'out of bounds' access can not occur based on the current heap length
|
||||
// constraint. The unsigned maximum of a masked index is the mask
|
||||
// itself, so check that the mask is not negative and compare the mask
|
||||
// to the known minimum heap length.
|
||||
if (int32_t(mask2) >= 0 && mask2 < f.m().minHeapLength())
|
||||
*needsBoundsCheck = NO_BOUNDS_CHECK;
|
||||
} else {
|
||||
uint32_t minHeap = f.m().minHeapLength();
|
||||
uint32_t minHeapZeroes = CountLeadingZeroes32(minHeap - 1);
|
||||
uint32_t maskZeroes = CountLeadingZeroes32(mask2);
|
||||
if ((minHeapZeroes < maskZeroes) ||
|
||||
(IsPowerOfTwo(minHeap) && minHeapZeroes == maskZeroes))
|
||||
{
|
||||
*needsBoundsCheck = NO_BOUNDS_CHECK;
|
||||
}
|
||||
}
|
||||
*mask &= mask2;
|
||||
*indexExpr = indexNode;
|
||||
return true;
|
||||
|
|
|
@ -1904,8 +1904,8 @@ TypedObject::obj_getArrayElement(JSContext *cx,
|
|||
}
|
||||
|
||||
bool
|
||||
TypedObject::obj_setProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
|
||||
MutableHandleValue vp, ObjectOpResult &result)
|
||||
TypedObject::obj_setProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
|
||||
HandleValue receiver, ObjectOpResult &result)
|
||||
{
|
||||
Rooted<TypedObject *> typedObj(cx, &obj->as<TypedObject>());
|
||||
|
||||
|
@ -1919,7 +1919,7 @@ TypedObject::obj_setProperty(JSContext *cx, HandleObject obj, HandleObject recei
|
|||
|
||||
case type::Array: {
|
||||
if (JSID_IS_ATOM(id, cx->names().length)) {
|
||||
if (obj == receiver) {
|
||||
if (receiver.isObject() && obj == &receiver.toObject()) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage,
|
||||
nullptr, JSMSG_CANT_REDEFINE_ARRAY_LENGTH);
|
||||
return false;
|
||||
|
@ -1929,8 +1929,8 @@ TypedObject::obj_setProperty(JSContext *cx, HandleObject obj, HandleObject recei
|
|||
|
||||
uint32_t index;
|
||||
if (IdIsIndex(id, &index)) {
|
||||
if (obj != receiver)
|
||||
return SetPropertyByDefining(cx, obj, receiver, id, vp, false, result);
|
||||
if (!receiver.isObject() || obj != &receiver.toObject())
|
||||
return SetPropertyByDefining(cx, obj, id, v, receiver, false, result);
|
||||
|
||||
if (index >= uint32_t(typedObj->length())) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage,
|
||||
|
@ -1941,7 +1941,7 @@ TypedObject::obj_setProperty(JSContext *cx, HandleObject obj, HandleObject recei
|
|||
Rooted<TypeDescr*> elementType(cx);
|
||||
elementType = &typedObj->typeDescr().as<ArrayTypeDescr>().elementType();
|
||||
size_t offset = elementType->size() * index;
|
||||
if (!ConvertAndCopyTo(cx, elementType, typedObj, offset, NullPtr(), vp))
|
||||
if (!ConvertAndCopyTo(cx, elementType, typedObj, offset, NullPtr(), v))
|
||||
return false;
|
||||
return result.succeed();
|
||||
}
|
||||
|
@ -1955,19 +1955,19 @@ TypedObject::obj_setProperty(JSContext *cx, HandleObject obj, HandleObject recei
|
|||
if (!descr->fieldIndex(id, &fieldIndex))
|
||||
break;
|
||||
|
||||
if (obj != receiver)
|
||||
return SetPropertyByDefining(cx, obj, receiver, id, vp, false, result);
|
||||
if (!receiver.isObject() || obj != &receiver.toObject())
|
||||
return SetPropertyByDefining(cx, obj, id, v, receiver, false, result);
|
||||
|
||||
size_t offset = descr->fieldOffset(fieldIndex);
|
||||
Rooted<TypeDescr*> fieldType(cx, &descr->fieldDescr(fieldIndex));
|
||||
RootedAtom fieldName(cx, &descr->fieldName(fieldIndex));
|
||||
if (!ConvertAndCopyTo(cx, fieldType, typedObj, offset, fieldName, vp))
|
||||
if (!ConvertAndCopyTo(cx, fieldType, typedObj, offset, fieldName, v))
|
||||
return false;
|
||||
return result.succeed();
|
||||
}
|
||||
}
|
||||
|
||||
return SetPropertyOnProto(cx, obj, receiver, id, vp, result);
|
||||
return SetPropertyOnProto(cx, obj, id, v, receiver, result);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -540,8 +540,8 @@ class TypedObject : public JSObject
|
|||
static bool obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
|
||||
uint32_t index, MutableHandleValue vp);
|
||||
|
||||
static bool obj_setProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
|
||||
HandleId id, MutableHandleValue vp, ObjectOpResult &result);
|
||||
static bool obj_setProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
|
||||
HandleValue receiver, ObjectOpResult &result);
|
||||
|
||||
static bool obj_getOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
|
||||
MutableHandle<JSPropertyDescriptor> desc);
|
||||
|
|
|
@ -154,13 +154,35 @@ function GetIterator(obj, method) {
|
|||
return iterator;
|
||||
}
|
||||
|
||||
// ES6 draft 20150317 7.3.20.
|
||||
function SpeciesConstructor(obj, defaultConstructor) {
|
||||
var C = obj.constructor;
|
||||
if (C === undefined) {
|
||||
// Step 1.
|
||||
assert(IsObject(obj), "not passed an object");
|
||||
|
||||
// Steps 2-3.
|
||||
var ctor = obj.constructor;
|
||||
|
||||
// Step 4.
|
||||
if (ctor === undefined)
|
||||
return defaultConstructor;
|
||||
}
|
||||
if (!IsConstructor(C)) {
|
||||
ThrowError(JSMSG_NOT_CONSTRUCTOR, DecompileArg(1, C));
|
||||
}
|
||||
return C;
|
||||
|
||||
// Step 5.
|
||||
if (!IsObject(ctor))
|
||||
ThrowError(JSMSG_NOT_NONNULL_OBJECT, "object's 'constructor' property");
|
||||
|
||||
// Steps 6-7. We don't yet implement @@species and Symbol.species, so we
|
||||
// don't implement this correctly right now. Somebody fix this!
|
||||
var s = /* ctor[Symbol.species] */ undefined;
|
||||
|
||||
// Step 8.
|
||||
if (s === undefined || s === null)
|
||||
return defaultConstructor;
|
||||
|
||||
// Step 9.
|
||||
if (IsConstructor(s))
|
||||
return s;
|
||||
|
||||
// Step 10.
|
||||
ThrowError(JSMSG_NOT_CONSTRUCTOR,
|
||||
"@@species property of object's constructor");
|
||||
}
|
||||
|
|
|
@ -113,21 +113,39 @@ enum class AllocKind {
|
|||
static_assert(uint8_t(AllocKind::OBJECT0) == 0, "Please check AllocKind iterations and comparisons"
|
||||
" of the form |kind <= AllocKind::OBJECT_LAST| to ensure their range is still valid!");
|
||||
|
||||
// Returns a sequence for use in a range-based for loop,
|
||||
// to iterate over all alloc kinds.
|
||||
inline decltype(mozilla::MakeEnumeratedRange<int>(AllocKind::FIRST, AllocKind::LIMIT))
|
||||
AllAllocKinds()
|
||||
{
|
||||
return mozilla::MakeEnumeratedRange<int>(AllocKind::FIRST, AllocKind::LIMIT);
|
||||
}
|
||||
|
||||
// Returns a sequence for use in a range-based for loop,
|
||||
// to iterate over all object alloc kinds.
|
||||
inline decltype(mozilla::MakeEnumeratedRange<int>(AllocKind::OBJECT0, AllocKind::OBJECT_LIMIT))
|
||||
ObjectAllocKinds()
|
||||
{
|
||||
return mozilla::MakeEnumeratedRange<int>(AllocKind::OBJECT0, AllocKind::OBJECT_LIMIT);
|
||||
}
|
||||
|
||||
// Returns a sequence for use in a range-based for loop,
|
||||
// to iterate over alloc kinds from |first| to |limit|, exclusive.
|
||||
inline decltype(mozilla::MakeEnumeratedRange<int>(AllocKind::FIRST, AllocKind::LIMIT))
|
||||
SomeAllocKinds(AllocKind first = AllocKind::FIRST, AllocKind limit = AllocKind::LIMIT)
|
||||
{
|
||||
MOZ_ASSERT(limit <= AllocKind::LIMIT);
|
||||
MOZ_ASSERT(first <= limit);
|
||||
return mozilla::MakeEnumeratedRange<int>(first, limit);
|
||||
}
|
||||
|
||||
// AllAllocKindArray<ValueType> gives an enumerated array of ValueTypes,
|
||||
// with each index corresponding to a particular alloc kind.
|
||||
template<typename ValueType> using AllAllocKindArray =
|
||||
mozilla::EnumeratedArray<AllocKind, AllocKind::LIMIT, ValueType>;
|
||||
|
||||
// ObjectAllocKindArray<ValueType> gives an enumerated array of ValueTypes,
|
||||
// with each index corresponding to a particular object alloc kind.
|
||||
template<typename ValueType> using ObjectAllocKindArray =
|
||||
mozilla::EnumeratedArray<AllocKind, AllocKind::OBJECT_LIMIT, ValueType>;
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
setJitCompilerOption("ion.warmup.trigger", 30);
|
||||
function bar(i) {
|
||||
if (i >= 40)
|
||||
return;
|
||||
if ("aaa,bbb,ccc".split(",")[0].length != 3)
|
||||
throw "???";
|
||||
bar(i + 1);
|
||||
}
|
||||
bar(0);
|
|
@ -8366,7 +8366,7 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_
|
|||
MOZ_ASSERT(op == JSOP_SETPROP || op == JSOP_STRICTSETPROP);
|
||||
|
||||
RootedValue v(cx, rhs);
|
||||
if (!PutProperty(cx, obj, id, &v, op == JSOP_STRICTSETPROP))
|
||||
if (!PutProperty(cx, obj, id, v, op == JSOP_STRICTSETPROP))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1567,9 +1567,6 @@ EmitCallProxyGet(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &at
|
|||
masm.Push(object);
|
||||
masm.movePtr(StackPointer, argProxyReg);
|
||||
|
||||
// Unused space, to keep the same stack layout as Proxy::set frames.
|
||||
PushObjectOpResult(masm);
|
||||
|
||||
masm.loadJSContext(argJSContextReg);
|
||||
|
||||
if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic))
|
||||
|
@ -2220,6 +2217,15 @@ EmitObjectOpResultCheck(MacroAssembler &masm, Label *failure, bool strict,
|
|||
masm.bind(&noStrictError);
|
||||
}
|
||||
|
||||
static bool
|
||||
ProxySetProperty(JSContext *cx, HandleObject proxy, HandleId id, HandleValue v, bool strict)
|
||||
{
|
||||
RootedValue receiver(cx, ObjectValue(*proxy));
|
||||
ObjectOpResult result;
|
||||
return Proxy::set(cx, proxy, id, v, receiver, result)
|
||||
&& result.checkStrictErrorOrWarning(cx, proxy, id, strict);
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitCallProxySet(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
|
||||
HandleId propId, RegisterSet liveRegs, Register object,
|
||||
|
@ -2237,22 +2243,25 @@ EmitCallProxySet(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &at
|
|||
RegisterSet regSet(RegisterSet::All());
|
||||
regSet.take(AnyRegister(object));
|
||||
|
||||
// Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
|
||||
// MutableHandleValue vp, ObjectOpResult &result)
|
||||
// ProxySetProperty(JSContext *cx, HandleObject proxy, HandleId id, HandleValue v,
|
||||
// bool strict);
|
||||
Register argJSContextReg = regSet.takeGeneral();
|
||||
Register argProxyReg = regSet.takeGeneral();
|
||||
Register argIdReg = regSet.takeGeneral();
|
||||
Register argVpReg = regSet.takeGeneral();
|
||||
Register argResultReg = regSet.takeGeneral();
|
||||
Register argValueReg = regSet.takeGeneral();
|
||||
Register argStrictReg = regSet.takeGeneral();
|
||||
|
||||
Register scratch = regSet.takeGeneral();
|
||||
|
||||
// Push stubCode for marking.
|
||||
attacher.pushStubCodePointer(masm);
|
||||
|
||||
// Push args on stack first so we can take pointers to make handles.
|
||||
// Push args on stack so we can take pointers to make handles.
|
||||
// Push value before touching any other registers (see WARNING above).
|
||||
masm.Push(value);
|
||||
masm.movePtr(StackPointer, argVpReg);
|
||||
masm.movePtr(StackPointer, argValueReg);
|
||||
|
||||
masm.move32(Imm32(strict), argStrictReg);
|
||||
|
||||
masm.Push(propId, scratch);
|
||||
masm.movePtr(StackPointer, argIdReg);
|
||||
|
@ -2263,10 +2272,6 @@ EmitCallProxySet(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &at
|
|||
masm.Push(object);
|
||||
masm.movePtr(StackPointer, argProxyReg);
|
||||
|
||||
// Allocate result out-param.
|
||||
PushObjectOpResult(masm);
|
||||
masm.movePtr(StackPointer, argResultReg);
|
||||
|
||||
masm.loadJSContext(argJSContextReg);
|
||||
|
||||
if (!masm.icBuildOOLFakeExitFrame(returnAddr, aic))
|
||||
|
@ -2274,24 +2279,17 @@ EmitCallProxySet(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &at
|
|||
masm.enterFakeExitFrame(IonOOLProxyExitFrameLayout::Token());
|
||||
|
||||
// Make the call.
|
||||
masm.setupUnalignedABICall(6, scratch);
|
||||
masm.setupUnalignedABICall(5, scratch);
|
||||
masm.passABIArg(argJSContextReg);
|
||||
masm.passABIArg(argProxyReg);
|
||||
masm.passABIArg(argProxyReg);
|
||||
masm.passABIArg(argIdReg);
|
||||
masm.passABIArg(argVpReg);
|
||||
masm.passABIArg(argResultReg);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, Proxy::set));
|
||||
masm.passABIArg(argValueReg);
|
||||
masm.passABIArg(argStrictReg);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ProxySetProperty));
|
||||
|
||||
// Test for error.
|
||||
masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
|
||||
|
||||
// Test for strict failure. We emit the check even in non-strict mode in
|
||||
// order to pick up the warning if extraWarnings is enabled.
|
||||
EmitObjectOpResultCheck<IonOOLProxyExitFrameLayout>(masm, masm.exceptionLabel(), strict,
|
||||
scratch, argJSContextReg, argProxyReg,
|
||||
argIdReg, argVpReg, argResultReg);
|
||||
|
||||
// masm.leaveExitFrame & pop locals
|
||||
masm.adjustStack(IonOOLProxyExitFrameLayout::Size());
|
||||
|
||||
|
@ -2508,8 +2506,9 @@ GenerateCallSetter(JSContext *cx, IonScript *ion, MacroAssembler &masm,
|
|||
|
||||
SetterOp target = shape->setterOp();
|
||||
MOZ_ASSERT(target);
|
||||
|
||||
// JSSetterOp: bool fn(JSContext *cx, HandleObject obj,
|
||||
// HandleId id, MutableHandleValue vp, ObjectOpResult &result);
|
||||
// HandleId id, HandleValue value, ObjectOpResult &result);
|
||||
|
||||
// First, allocate an ObjectOpResult on the stack. We push this before
|
||||
// the stubCode pointer in order to match the layout of
|
||||
|
@ -2530,11 +2529,11 @@ GenerateCallSetter(JSContext *cx, IonScript *ion, MacroAssembler &masm,
|
|||
// OK, now we can grab our remaining registers and grab the pointer to
|
||||
// what we just pushed into one of them.
|
||||
Register argJSContextReg = regSet.takeGeneral();
|
||||
Register argVpReg = regSet.takeGeneral();
|
||||
Register argValueReg = regSet.takeGeneral();
|
||||
// We can just reuse the "object" register for argObjReg
|
||||
Register argObjReg = object;
|
||||
Register argIdReg = regSet.takeGeneral();
|
||||
masm.movePtr(StackPointer, argVpReg);
|
||||
masm.movePtr(StackPointer, argValueReg);
|
||||
|
||||
// push canonical jsid from shape instead of propertyname.
|
||||
masm.Push(shape->propid(), argIdReg);
|
||||
|
@ -2554,18 +2553,20 @@ GenerateCallSetter(JSContext *cx, IonScript *ion, MacroAssembler &masm,
|
|||
masm.passABIArg(argJSContextReg);
|
||||
masm.passABIArg(argObjReg);
|
||||
masm.passABIArg(argIdReg);
|
||||
masm.passABIArg(argVpReg);
|
||||
masm.passABIArg(argValueReg);
|
||||
masm.passABIArg(argResultReg);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, target));
|
||||
|
||||
// Test for error.
|
||||
masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
|
||||
|
||||
// Test for failure.
|
||||
// Test for strict failure. We emit the check even in non-strict mode
|
||||
// in order to pick up the warning if extraWarnings is enabled.
|
||||
EmitObjectOpResultCheck<IonOOLSetterOpExitFrameLayout>(masm, masm.exceptionLabel(),
|
||||
strict, scratchReg,
|
||||
argJSContextReg, argObjReg,
|
||||
argIdReg, argVpReg, argResultReg);
|
||||
argIdReg, argValueReg,
|
||||
argResultReg);
|
||||
|
||||
// masm.leaveExitFrame & pop locals.
|
||||
masm.adjustStack(IonOOLSetterOpExitFrameLayout::Size());
|
||||
|
|
|
@ -699,17 +699,14 @@ class IonOOLSetterOpExitFrameLayout : public IonOOLPropertyOpExitFrameLayout
|
|||
|
||||
// Proxy::get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
|
||||
// MutableHandleValue vp)
|
||||
// Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
|
||||
// MutableHandleValue vp, ObjectOpResult &result)
|
||||
// ProxySetProperty(JSContext *cx, HandleObject proxy, HandleId id, MutableHandleValue vp,
|
||||
// bool strict)
|
||||
class IonOOLProxyExitFrameLayout
|
||||
{
|
||||
protected: // only to silence a clang warning about unused private fields
|
||||
ExitFooterFrame footer_;
|
||||
ExitFrameLayout exit_;
|
||||
|
||||
// result out-parameter (unused for Proxy::get)
|
||||
JS::ObjectOpResult result_;
|
||||
|
||||
// The proxy object.
|
||||
JSObject *proxy_;
|
||||
|
||||
|
@ -734,22 +731,10 @@ class IonOOLProxyExitFrameLayout
|
|||
return sizeof(IonOOLProxyExitFrameLayout);
|
||||
}
|
||||
|
||||
static size_t offsetOfObject() {
|
||||
return offsetof(IonOOLProxyExitFrameLayout, proxy_);
|
||||
}
|
||||
|
||||
static size_t offsetOfResult() {
|
||||
return offsetof(IonOOLProxyExitFrameLayout, vp0_);
|
||||
}
|
||||
|
||||
static size_t offsetOfId() {
|
||||
return offsetof(IonOOLProxyExitFrameLayout, id_);
|
||||
}
|
||||
|
||||
static size_t offsetOfObjectOpResult() {
|
||||
return offsetof(IonOOLProxyExitFrameLayout, result_);
|
||||
}
|
||||
|
||||
inline JitCode **stubCode() {
|
||||
return &stubCode_;
|
||||
}
|
||||
|
|
|
@ -1542,9 +1542,14 @@ IonBuilder::inlineConstantStringSplit(CallInfo &callInfo)
|
|||
if (templateObject->getDenseInitializedLength() != initLength)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
JSContext *cx = GetJitContext()->cx;
|
||||
Vector<MConstant *, 0, SystemAllocPolicy> arrayValues;
|
||||
for (uint32_t i = 0; i < initLength; i++) {
|
||||
MConstant *value = MConstant::New(alloc(), templateObject->getDenseElement(i), constraints());
|
||||
JSAtom *str = js::AtomizeString(cx, templateObject->getDenseElement(i).toString());
|
||||
if (!str)
|
||||
return InliningStatus_Error;
|
||||
|
||||
MConstant *value = MConstant::New(alloc(), StringValue(str), constraints());
|
||||
if (!TypeSetIncludes(key.maybeTypes(), value->type(), value->resultTypeSet()))
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
|
|
|
@ -710,6 +710,8 @@ MConstant::MConstant(const js::Value &vp, CompilerConstraintList *constraints)
|
|||
setResultTypeSet(MakeUnknownTypeSet());
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(vp.isString(), vp.toString()->isAtom());
|
||||
|
||||
setMovable();
|
||||
}
|
||||
|
||||
|
|
|
@ -1153,7 +1153,8 @@ class MQuaternaryInstruction : public MAryInstruction<4>
|
|||
}
|
||||
};
|
||||
|
||||
class MVariadicInstruction : public MInstruction
|
||||
template <class T>
|
||||
class MVariadicT : public T
|
||||
{
|
||||
FixedList<MUse> operands_;
|
||||
|
||||
|
@ -1190,6 +1191,8 @@ class MVariadicInstruction : public MInstruction
|
|||
}
|
||||
};
|
||||
|
||||
typedef MVariadicT<MInstruction> MVariadicInstruction;
|
||||
|
||||
// Generates an LSnapshot without further effect.
|
||||
class MStart : public MNullaryInstruction
|
||||
{
|
||||
|
|
|
@ -434,7 +434,6 @@ bool
|
|||
SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value,
|
||||
bool strict, jsbytecode *pc)
|
||||
{
|
||||
RootedValue v(cx, value);
|
||||
RootedId id(cx, NameToId(name));
|
||||
|
||||
JSOp op = JSOp(*pc);
|
||||
|
@ -448,21 +447,21 @@ SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValu
|
|||
return true;
|
||||
}
|
||||
|
||||
RootedValue receiver(cx, ObjectValue(*obj));
|
||||
ObjectOpResult result;
|
||||
if (MOZ_LIKELY(!obj->getOps()->setProperty)) {
|
||||
if (!NativeSetProperty(
|
||||
cx, obj.as<NativeObject>(), obj.as<NativeObject>(), id,
|
||||
cx, obj.as<NativeObject>(), id, value, receiver,
|
||||
(op == JSOP_SETNAME || op == JSOP_STRICTSETNAME ||
|
||||
op == JSOP_SETGNAME || op == JSOP_STRICTSETGNAME)
|
||||
? Unqualified
|
||||
: Qualified,
|
||||
&v,
|
||||
result))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!SetProperty(cx, obj, obj, id, &v, result))
|
||||
if (!SetProperty(cx, obj, id, value, receiver, result))
|
||||
return false;
|
||||
}
|
||||
return result.checkStrictErrorOrWarning(cx, obj, id, strict);
|
||||
|
|
|
@ -2020,44 +2020,15 @@ CodeGeneratorMIPS::visitAsmJSPassStackArg(LAsmJSPassStackArg *ins)
|
|||
}
|
||||
|
||||
void
|
||||
CodeGeneratorMIPS::visitUDiv(LUDiv *ins)
|
||||
{
|
||||
Register lhs = ToRegister(ins->lhs());
|
||||
Register rhs = ToRegister(ins->rhs());
|
||||
Register output = ToRegister(ins->output());
|
||||
|
||||
Label done;
|
||||
if (ins->mir()->canBeDivideByZero()) {
|
||||
if (ins->mir()->isTruncated()) {
|
||||
Label notzero;
|
||||
masm.ma_b(rhs, rhs, ¬zero, Assembler::NonZero, ShortJump);
|
||||
masm.move32(Imm32(0), output);
|
||||
masm.ma_b(&done, ShortJump);
|
||||
masm.bind(¬zero);
|
||||
} else {
|
||||
MOZ_ASSERT(ins->mir()->fallible());
|
||||
bailoutCmp32(Assembler::Equal, rhs, Imm32(0), ins->snapshot());
|
||||
}
|
||||
}
|
||||
|
||||
masm.as_divu(lhs, rhs);
|
||||
masm.as_mflo(output);
|
||||
|
||||
if (!ins->mir()->isTruncated())
|
||||
bailoutCmp32(Assembler::LessThan, output, Imm32(0), ins->snapshot());
|
||||
|
||||
masm.bind(&done);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorMIPS::visitUMod(LUMod *ins)
|
||||
CodeGeneratorMIPS::visitUDivOrMod(LUDivOrMod *ins)
|
||||
{
|
||||
Register lhs = ToRegister(ins->lhs());
|
||||
Register rhs = ToRegister(ins->rhs());
|
||||
Register output = ToRegister(ins->output());
|
||||
Label done;
|
||||
|
||||
if (ins->mir()->canBeDivideByZero()) {
|
||||
// Prevent divide by zero.
|
||||
if (ins->canBeDivideByZero()) {
|
||||
if (ins->mir()->isTruncated()) {
|
||||
// Infinity|0 == 0
|
||||
Label notzero;
|
||||
|
@ -2066,7 +2037,6 @@ CodeGeneratorMIPS::visitUMod(LUMod *ins)
|
|||
masm.ma_b(&done, ShortJump);
|
||||
masm.bind(¬zero);
|
||||
} else {
|
||||
MOZ_ASSERT(ins->mir()->fallible());
|
||||
bailoutCmp32(Assembler::Equal, rhs, Imm32(0), ins->snapshot());
|
||||
}
|
||||
}
|
||||
|
@ -2074,6 +2044,14 @@ CodeGeneratorMIPS::visitUMod(LUMod *ins)
|
|||
masm.as_divu(lhs, rhs);
|
||||
masm.as_mfhi(output);
|
||||
|
||||
// If the remainder is > 0, bailout since this must be a double.
|
||||
if (ins->mir()->isDiv()) {
|
||||
if (!ins->mir()->toDiv()->canTruncateRemainder())
|
||||
bailoutCmp32(Assembler::NonZero, output, output, ins->snapshot());
|
||||
// Get quotient
|
||||
masm.as_mflo(output);
|
||||
}
|
||||
|
||||
if (!ins->mir()->isTruncated())
|
||||
bailoutCmp32(Assembler::LessThan, output, Imm32(0), ins->snapshot());
|
||||
|
||||
|
|
|
@ -273,8 +273,7 @@ class CodeGeneratorMIPS : public CodeGeneratorShared
|
|||
|
||||
protected:
|
||||
void visitEffectiveAddress(LEffectiveAddress *ins);
|
||||
void visitUDiv(LUDiv *ins);
|
||||
void visitUMod(LUMod *ins);
|
||||
void visitUDivOrMod(LUDivOrMod *ins);
|
||||
|
||||
public:
|
||||
// Unimplemented SIMD instructions
|
||||
|
|
|
@ -355,23 +355,20 @@ class LMulI : public LBinaryMath<0>
|
|||
}
|
||||
};
|
||||
|
||||
class LUDiv : public LBinaryMath<0>
|
||||
class LUDivOrMod : public LBinaryMath<0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(UDiv);
|
||||
LIR_HEADER(UDivOrMod);
|
||||
|
||||
MDiv *mir() {
|
||||
return mir_->toDiv();
|
||||
MBinaryArithInstruction *mir() const {
|
||||
MOZ_ASSERT(mir_->isDiv() || mir_->isMod());
|
||||
return static_cast<MBinaryArithInstruction *>(mir_);
|
||||
}
|
||||
};
|
||||
|
||||
class LUMod : public LBinaryMath<0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(UMod);
|
||||
|
||||
MMod *mir() {
|
||||
return mir_->toMod();
|
||||
bool canBeDivideByZero() const {
|
||||
if (mir_->isMod())
|
||||
return mir_->toMod()->canBeDivideByZero();
|
||||
return mir_->toDiv()->canBeDivideByZero();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -20,8 +20,7 @@
|
|||
_(PowHalfD) \
|
||||
_(AsmJSUInt32ToDouble) \
|
||||
_(AsmJSUInt32ToFloat32) \
|
||||
_(UDiv) \
|
||||
_(UMod) \
|
||||
_(UDivOrMod) \
|
||||
_(AsmJSLoadFuncPtr)
|
||||
|
||||
#endif // jit_mips_LOpcodes_mips_h__
|
||||
|
|
|
@ -419,7 +419,7 @@ LIRGeneratorMIPS::lowerUDiv(MDiv *div)
|
|||
MDefinition *lhs = div->getOperand(0);
|
||||
MDefinition *rhs = div->getOperand(1);
|
||||
|
||||
LUDiv *lir = new(alloc()) LUDiv;
|
||||
LUDivOrMod *lir = new(alloc()) LUDivOrMod;
|
||||
lir->setOperand(0, useRegister(lhs));
|
||||
lir->setOperand(1, useRegister(rhs));
|
||||
if (div->fallible())
|
||||
|
@ -434,7 +434,7 @@ LIRGeneratorMIPS::lowerUMod(MMod *mod)
|
|||
MDefinition *lhs = mod->getOperand(0);
|
||||
MDefinition *rhs = mod->getOperand(1);
|
||||
|
||||
LUMod *lir = new(alloc()) LUMod;
|
||||
LUDivOrMod *lir = new(alloc()) LUDivOrMod;
|
||||
lir->setOperand(0, useRegister(lhs));
|
||||
lir->setOperand(1, useRegister(rhs));
|
||||
if (mod->fallible())
|
||||
|
|
|
@ -234,6 +234,15 @@ class MacroAssemblerMIPS : public Assembler
|
|||
ma_li(ScratchRegister, imm);
|
||||
ma_b(lhs, ScratchRegister, l, c, jumpKind);
|
||||
}
|
||||
void ma_b(Register lhs, ImmWord imm, Label *l, Condition c, JumpKind jumpKind = LongJump)
|
||||
{
|
||||
ma_b(lhs, Imm32(uint32_t(imm.value)), l, c, jumpKind);
|
||||
}
|
||||
void ma_b(Address addr, ImmWord imm, Label *l, Condition c, JumpKind jumpKind = LongJump)
|
||||
{
|
||||
ma_b(addr, Imm32(uint32_t(imm.value)), l, c, jumpKind);
|
||||
}
|
||||
|
||||
void ma_b(Register lhs, Address addr, Label *l, Condition c, JumpKind jumpKind = LongJump);
|
||||
void ma_b(Address addr, Imm32 imm, Label *l, Condition c, JumpKind jumpKind = LongJump);
|
||||
void ma_b(Address addr, ImmGCPtr imm, Label *l, Condition c, JumpKind jumpKind = LongJump);
|
||||
|
|
|
@ -82,6 +82,7 @@ MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE, 0, JSEXN_TYPEERR, "reduce of empty array
|
|||
MSG_DEF(JSMSG_UNEXPECTED_TYPE, 2, JSEXN_TYPEERR, "{0} is {1}")
|
||||
MSG_DEF(JSMSG_MISSING_FUN_ARG, 2, JSEXN_TYPEERR, "missing argument {0} when calling function {1}")
|
||||
MSG_DEF(JSMSG_NOT_NONNULL_OBJECT, 1, JSEXN_TYPEERR, "{0} is not a non-null object")
|
||||
MSG_DEF(JSMSG_SET_NON_OBJECT_RECEIVER, 1, JSEXN_TYPEERR, "can't assign to properties of {0}: not an object")
|
||||
MSG_DEF(JSMSG_INVALID_DESCRIPTOR, 0, JSEXN_TYPEERR, "property descriptors must not specify a value or be writable when a getter or setter has been specified")
|
||||
MSG_DEF(JSMSG_OBJECT_NOT_EXTENSIBLE, 1, JSEXN_TYPEERR, "{0} is not extensible")
|
||||
MSG_DEF(JSMSG_CANT_REDEFINE_PROP, 1, JSEXN_TYPEERR, "can't redefine non-configurable property {0}")
|
||||
|
|
|
@ -27,13 +27,13 @@ class CustomProxyHandler : public DirectProxyHandler {
|
|||
return impl(cx, proxy, id, desc, true);
|
||||
}
|
||||
|
||||
bool set(JSContext *cx, HandleObject proxy, HandleObject receiver,
|
||||
HandleId id, MutableHandleValue vp, ObjectOpResult &result) const override
|
||||
bool set(JSContext *cx, HandleObject proxy, HandleId id, HandleValue v, HandleValue receiver,
|
||||
ObjectOpResult &result) const override
|
||||
{
|
||||
Rooted<JSPropertyDescriptor> desc(cx);
|
||||
if (!DirectProxyHandler::getPropertyDescriptor(cx, proxy, id, &desc))
|
||||
return false;
|
||||
return SetPropertyIgnoringNamedGetter(cx, proxy, id, vp, receiver, desc, result);
|
||||
return SetPropertyIgnoringNamedGetter(cx, proxy, id, v, receiver, desc, result);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче