зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to m-c a=merge
This commit is contained in:
Коммит
ed461fdf11
|
@ -83,9 +83,7 @@ addEventListener("blur", function(event) {
|
||||||
LoginManagerContent.onUsernameInput(event);
|
LoginManagerContent.onUsernameInput(event);
|
||||||
});
|
});
|
||||||
|
|
||||||
var gLastContextMenuEvent = null; // null or a WeakReference to a contextmenu event
|
|
||||||
var handleContentContextMenu = function (event) {
|
var handleContentContextMenu = function (event) {
|
||||||
gLastContextMenuEvent = null;
|
|
||||||
let defaultPrevented = event.defaultPrevented;
|
let defaultPrevented = event.defaultPrevented;
|
||||||
if (!Services.prefs.getBoolPref("dom.event.contextmenu.enabled")) {
|
if (!Services.prefs.getBoolPref("dom.event.contextmenu.enabled")) {
|
||||||
let plugin = null;
|
let plugin = null;
|
||||||
|
@ -100,36 +98,8 @@ var handleContentContextMenu = function (event) {
|
||||||
defaultPrevented = false;
|
defaultPrevented = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaultPrevented) {
|
if (defaultPrevented)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (event.mozInputSource == Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH) {
|
|
||||||
// If this was triggered by touch, then we don't want to show the actual
|
|
||||||
// context menu until we get the APZ:LongTapUp notification. However, we
|
|
||||||
// will need the |event| object when we get that notification, so we save
|
|
||||||
// it in a WeakReference. That way it won't leak things if we never get
|
|
||||||
// the APZ:LongTapUp notification (which is quite possible).
|
|
||||||
gLastContextMenuEvent = Cu.getWeakReference(event);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For non-touch-derived contextmenu events, we can handle it right away.
|
|
||||||
showContentContextMenu(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
var showContentContextMenu = function (event) {
|
|
||||||
if (event == null) {
|
|
||||||
// If we weren't given an event, then this is being invoked from the
|
|
||||||
// APZ:LongTapUp observer, and the contextmenu event is stashed in
|
|
||||||
// gLastContextMenuEvent.
|
|
||||||
event = (gLastContextMenuEvent ? gLastContextMenuEvent.get() : null);
|
|
||||||
gLastContextMenuEvent = null;
|
|
||||||
if (event == null) {
|
|
||||||
// Still no event? We can't do anything, bail out.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let addonInfo = {};
|
let addonInfo = {};
|
||||||
let subject = {
|
let subject = {
|
||||||
|
@ -247,11 +217,6 @@ Cc["@mozilla.org/eventlistenerservice;1"]
|
||||||
.getService(Ci.nsIEventListenerService)
|
.getService(Ci.nsIEventListenerService)
|
||||||
.addSystemEventListener(global, "contextmenu", handleContentContextMenu, false);
|
.addSystemEventListener(global, "contextmenu", handleContentContextMenu, false);
|
||||||
|
|
||||||
Services.obs.addObserver(showContentContextMenu, "APZ:LongTapUp", false);
|
|
||||||
addEventListener("unload", () => {
|
|
||||||
Services.obs.removeObserver(showContentContextMenu, "APZ:LongTapUp")
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
// Values for telemtery bins: see TLS_ERROR_REPORT_UI in Histograms.json
|
// Values for telemtery bins: see TLS_ERROR_REPORT_UI in Histograms.json
|
||||||
const TLS_ERROR_REPORT_TELEMETRY_UI_SHOWN = 0;
|
const TLS_ERROR_REPORT_TELEMETRY_UI_SHOWN = 0;
|
||||||
const TLS_ERROR_REPORT_TELEMETRY_EXPANDED = 1;
|
const TLS_ERROR_REPORT_TELEMETRY_EXPANDED = 1;
|
||||||
|
|
|
@ -39,6 +39,21 @@ const PAGECONTENT_SMALL =
|
||||||
" <option value='Six'>Six</option>" +
|
" <option value='Six'>Six</option>" +
|
||||||
"</select></body></html>";
|
"</select></body></html>";
|
||||||
|
|
||||||
|
const PAGECONTENT_SOMEHIDDEN =
|
||||||
|
"<html>" +
|
||||||
|
"<body><select id='one'>" +
|
||||||
|
" <option value='One' style='display: none;'>OneHidden</option>" +
|
||||||
|
" <option value='Two' style='display: none;'>TwoHidden</option>" +
|
||||||
|
" <option value='Three'>ThreeVisible</option>" +
|
||||||
|
" <option value='Four'style='display: table;'>FourVisible</option>" +
|
||||||
|
" <option value='Five'>FiveVisible</option>" +
|
||||||
|
" <optgroup label='GroupHidden' style='display: none;'>" +
|
||||||
|
" <option value='Four'>Six.OneHidden</option>" +
|
||||||
|
" <option value='Five' style='display: block;'>Six.TwoHidden</option>" +
|
||||||
|
" </optgroup>" +
|
||||||
|
" <option value='Six'>SevenVisible</option>" +
|
||||||
|
"</select></body></html>";
|
||||||
|
|
||||||
const PAGECONTENT_TRANSLATED =
|
const PAGECONTENT_TRANSLATED =
|
||||||
"<html><body>" +
|
"<html><body>" +
|
||||||
"<div id='div'>" +
|
"<div id='div'>" +
|
||||||
|
@ -485,3 +500,33 @@ add_task(function* test_mousemove_correcttarget() {
|
||||||
|
|
||||||
yield BrowserTestUtils.removeTab(tab);
|
yield BrowserTestUtils.removeTab(tab);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// This test checks when a <select> element has some options with altered display values.
|
||||||
|
add_task(function* test_somehidden() {
|
||||||
|
const pageUrl = "data:text/html," + escape(PAGECONTENT_SOMEHIDDEN);
|
||||||
|
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
|
||||||
|
|
||||||
|
let selectPopup = document.getElementById("ContentSelectDropdown").menupopup;
|
||||||
|
|
||||||
|
let popupShownPromise = BrowserTestUtils.waitForEvent(selectPopup, "popupshown");
|
||||||
|
yield BrowserTestUtils.synthesizeMouseAtCenter("#one", { type: "mousedown" }, gBrowser.selectedBrowser);
|
||||||
|
yield popupShownPromise;
|
||||||
|
|
||||||
|
// The exact number is not needed; just ensure the height is larger than 4 items to accomodate any popup borders.
|
||||||
|
ok(selectPopup.getBoundingClientRect().height >= selectPopup.lastChild.getBoundingClientRect().height * 4, "Height contains at least 4 items");
|
||||||
|
ok(selectPopup.getBoundingClientRect().height < selectPopup.lastChild.getBoundingClientRect().height * 5, "Height doesn't contain 5 items");
|
||||||
|
|
||||||
|
// The label contains the substring 'Visible' for items that are visible.
|
||||||
|
// Otherwise, it is expected to be display: none.
|
||||||
|
is(selectPopup.parentNode.itemCount, 9, "Correct number of items");
|
||||||
|
let child = selectPopup.firstChild;
|
||||||
|
let idx = 1;
|
||||||
|
while (child) {
|
||||||
|
is(getComputedStyle(child).display, child.label.indexOf("Visible") > 0 ? "-moz-box" : "none",
|
||||||
|
"Item " + (idx++) + " is visible");
|
||||||
|
child = child.nextSibling;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield hideSelectPopup(selectPopup, "escape");
|
||||||
|
yield BrowserTestUtils.removeTab(tab);
|
||||||
|
});
|
||||||
|
|
|
@ -59,7 +59,7 @@ add_task(function* () {
|
||||||
|
|
||||||
let obsPromise = TestUtils.topicObserved("PopupNotifications-updateNotShowing");
|
let obsPromise = TestUtils.topicObserved("PopupNotifications-updateNotShowing");
|
||||||
let overlayPromise = promisePopupNotification("click-to-play-plugins");
|
let overlayPromise = promisePopupNotification("click-to-play-plugins");
|
||||||
gTestBrowser.contentWindow.history.back();
|
gTestBrowser.goBack();
|
||||||
yield obsPromise;
|
yield obsPromise;
|
||||||
yield overlayPromise;
|
yield overlayPromise;
|
||||||
});
|
});
|
||||||
|
|
|
@ -177,6 +177,15 @@ restartNow=Restart Now
|
||||||
restartLater=Restart Later
|
restartLater=Restart Later
|
||||||
|
|
||||||
disableContainersAlertTitle=Close All Container Tabs?
|
disableContainersAlertTitle=Close All Container Tabs?
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (disableContainersMsg): Semi-colon list of plural forms.
|
||||||
|
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||||
|
# #S is the number of container tabs
|
||||||
disableContainersMsg=If you disable Container Tabs now, #S container tab will be closed. Are you sure you want to disable Container Tabs?;If you disable Containers Tabs now, #S container tabs will be closed. Are you sure you want to disable Containers Tabs?
|
disableContainersMsg=If you disable Container Tabs now, #S container tab will be closed. Are you sure you want to disable Container Tabs?;If you disable Containers Tabs now, #S container tabs will be closed. Are you sure you want to disable Containers Tabs?
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (disableContainersOkButton): Semi-colon list of plural forms.
|
||||||
|
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||||
|
# #S is the number of container tabs
|
||||||
disableContainersOkButton=Close #S Container Tab;Close #S Container Tabs
|
disableContainersOkButton=Close #S Container Tab;Close #S Container Tabs
|
||||||
|
|
||||||
disableContainersButton2=Keep enabled
|
disableContainersButton2=Keep enabled
|
||||||
|
|
|
@ -1054,7 +1054,7 @@ toolbaritem[cui-areatype="menu-panel"] > :-moz-any(@nestedButtons@) > .toolbarbu
|
||||||
}
|
}
|
||||||
|
|
||||||
#identity-box:-moz-focusring {
|
#identity-box:-moz-focusring {
|
||||||
outline: 1px dotted #000;
|
outline: 1px dotted;
|
||||||
outline-offset: -3px;
|
outline-offset: -3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#PopupAutoCompleteRichResult > hbox[anonid="search-suggestions-notification"] {
|
#PopupAutoCompleteRichResult > hbox[anonid="search-suggestions-notification"] {
|
||||||
border-bottom: 1px solid hsla(210, 4%, 10%, 0.14);
|
border-bottom: 1px solid var(--panel-separator-color);
|
||||||
background-color: hsla(210, 4%, 10%, 0.07);
|
background-color: hsla(210, 4%, 10%, 0.07);
|
||||||
padding: 6px 0;
|
padding: 6px 0;
|
||||||
padding-inline-start: 44px;
|
padding-inline-start: 44px;
|
||||||
|
|
|
@ -1489,7 +1489,7 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder,
|
||||||
/* identity box */
|
/* identity box */
|
||||||
|
|
||||||
#identity-box:-moz-focusring {
|
#identity-box:-moz-focusring {
|
||||||
outline: 1px dotted #000;
|
outline: 1px dotted;
|
||||||
outline-offset: -3px;
|
outline-offset: -3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -220,9 +220,9 @@ nsPrincipal::SubsumesInternal(nsIPrincipal* aOther,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIURI> otherURI;
|
nsCOMPtr<nsIURI> otherURI;
|
||||||
rv = aOther->GetURI(getter_AddRefs(otherURI));
|
rv = aOther->GetURI(getter_AddRefs(otherURI));
|
||||||
NS_ENSURE_SUCCESS(rv, false);
|
NS_ENSURE_SUCCESS(rv, false);
|
||||||
|
|
||||||
// Compare codebases.
|
// Compare codebases.
|
||||||
return nsScriptSecurityManager::SecurityCompareURIs(mCodebase, otherURI);
|
return nsScriptSecurityManager::SecurityCompareURIs(mCodebase, otherURI);
|
||||||
|
|
|
@ -4844,8 +4844,6 @@ nsDocument::SetScriptHandlingObject(nsIScriptGlobalObject* aScriptObject)
|
||||||
NS_ASSERTION(!mScriptGlobalObject ||
|
NS_ASSERTION(!mScriptGlobalObject ||
|
||||||
mScriptGlobalObject == aScriptObject,
|
mScriptGlobalObject == aScriptObject,
|
||||||
"Wrong script object!");
|
"Wrong script object!");
|
||||||
// XXXkhuey why bother?
|
|
||||||
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aScriptObject);
|
|
||||||
if (aScriptObject) {
|
if (aScriptObject) {
|
||||||
mScopeObject = do_GetWeakReference(aScriptObject);
|
mScopeObject = do_GetWeakReference(aScriptObject);
|
||||||
mHasHadScriptHandlingObject = true;
|
mHasHadScriptHandlingObject = true;
|
||||||
|
@ -7710,8 +7708,6 @@ nsDOMAttributeMap::BlastSubtreeToPieces(nsINode *aNode)
|
||||||
Element *element = aNode->AsElement();
|
Element *element = aNode->AsElement();
|
||||||
const nsDOMAttributeMap *map = element->GetAttributeMap();
|
const nsDOMAttributeMap *map = element->GetAttributeMap();
|
||||||
if (map) {
|
if (map) {
|
||||||
nsCOMPtr<nsIAttribute> attr;
|
|
||||||
|
|
||||||
// This non-standard style of iteration is presumably used because some
|
// This non-standard style of iteration is presumably used because some
|
||||||
// of the code in the loop body can trigger element removal, which
|
// of the code in the loop body can trigger element removal, which
|
||||||
// invalidates the iterator.
|
// invalidates the iterator.
|
||||||
|
@ -8764,7 +8760,6 @@ nsDocument::Sanitize()
|
||||||
|
|
||||||
RefPtr<nsContentList> nodes = GetElementsByTagName(NS_LITERAL_STRING("input"));
|
RefPtr<nsContentList> nodes = GetElementsByTagName(NS_LITERAL_STRING("input"));
|
||||||
|
|
||||||
nsCOMPtr<nsIContent> item;
|
|
||||||
nsAutoString value;
|
nsAutoString value;
|
||||||
|
|
||||||
uint32_t length = nodes->Length(true);
|
uint32_t length = nodes->Length(true);
|
||||||
|
@ -10439,7 +10434,6 @@ nsDocument::GetStateObject(nsIVariant** aState)
|
||||||
// mStateObjectContainer may be null; this just means that there's no
|
// mStateObjectContainer may be null; this just means that there's no
|
||||||
// current state object.
|
// current state object.
|
||||||
|
|
||||||
nsCOMPtr<nsIVariant> stateObj;
|
|
||||||
if (!mStateObjectCached && mStateObjectContainer) {
|
if (!mStateObjectCached && mStateObjectContainer) {
|
||||||
AutoJSContext cx;
|
AutoJSContext cx;
|
||||||
nsIGlobalObject* sgo = GetScopeObject();
|
nsIGlobalObject* sgo = GetScopeObject();
|
||||||
|
@ -10880,7 +10874,6 @@ nsIDocument::CaretPositionFromPoint(float aX, float aY)
|
||||||
if (nodeIsAnonymous) {
|
if (nodeIsAnonymous) {
|
||||||
node = ptFrame->GetContent();
|
node = ptFrame->GetContent();
|
||||||
nsIContent* nonanon = node->FindFirstNonChromeOnlyAccessContent();
|
nsIContent* nonanon = node->FindFirstNonChromeOnlyAccessContent();
|
||||||
nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(nonanon);
|
|
||||||
nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea = do_QueryInterface(nonanon);
|
nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea = do_QueryInterface(nonanon);
|
||||||
nsITextControlFrame* textFrame = do_QueryFrame(nonanon->GetPrimaryFrame());
|
nsITextControlFrame* textFrame = do_QueryFrame(nonanon->GetPrimaryFrame());
|
||||||
nsNumberControlFrame* numberFrame = do_QueryFrame(nonanon->GetPrimaryFrame());
|
nsNumberControlFrame* numberFrame = do_QueryFrame(nonanon->GetPrimaryFrame());
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* Object that can be used to serialize selections, ranges, or nodes
|
* Object that can be used to serialize selections, ranges, or nodes
|
||||||
* to strings in a gazillion different ways.
|
* to strings in a gazillion different ways.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "nsIDocumentEncoder.h"
|
#include "nsIDocumentEncoder.h"
|
||||||
|
|
||||||
#include "nscore.h"
|
#include "nscore.h"
|
||||||
|
@ -89,8 +89,8 @@ protected:
|
||||||
nsAString& aStr);
|
nsAString& aStr);
|
||||||
nsresult SerializeRangeToString(nsRange *aRange,
|
nsresult SerializeRangeToString(nsRange *aRange,
|
||||||
nsAString& aOutputString);
|
nsAString& aOutputString);
|
||||||
nsresult SerializeRangeNodes(nsRange* aRange,
|
nsresult SerializeRangeNodes(nsRange* aRange,
|
||||||
nsINode* aNode,
|
nsINode* aNode,
|
||||||
nsAString& aString,
|
nsAString& aString,
|
||||||
int32_t aDepth);
|
int32_t aDepth);
|
||||||
nsresult SerializeRangeContextStart(const nsTArray<nsINode*>& aAncestorArray,
|
nsresult SerializeRangeContextStart(const nsTArray<nsINode*>& aAncestorArray,
|
||||||
|
@ -167,7 +167,7 @@ protected:
|
||||||
AutoTArray<int32_t, 8> mStartOffsets;
|
AutoTArray<int32_t, 8> mStartOffsets;
|
||||||
AutoTArray<nsIContent*, 8> mEndNodes;
|
AutoTArray<nsIContent*, 8> mEndNodes;
|
||||||
AutoTArray<int32_t, 8> mEndOffsets;
|
AutoTArray<int32_t, 8> mEndOffsets;
|
||||||
bool mHaltRangeHint;
|
bool mHaltRangeHint;
|
||||||
// Used when context has already been serialized for
|
// Used when context has already been serialized for
|
||||||
// table cell selections (where parent is <tr>)
|
// table cell selections (where parent is <tr>)
|
||||||
bool mDisableContextSerialize;
|
bool mDisableContextSerialize;
|
||||||
|
@ -412,14 +412,14 @@ nsDocumentEncoder::SerializeNodeStart(nsINode* aNode,
|
||||||
{
|
{
|
||||||
if (!IsVisibleNode(aNode))
|
if (!IsVisibleNode(aNode))
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
||||||
nsINode* node = nullptr;
|
nsINode* node = nullptr;
|
||||||
nsCOMPtr<nsINode> fixedNodeKungfuDeathGrip;
|
nsCOMPtr<nsINode> fixedNodeKungfuDeathGrip;
|
||||||
|
|
||||||
// Caller didn't do fixup, so we'll do it ourselves
|
// Caller didn't do fixup, so we'll do it ourselves
|
||||||
if (!aOriginalNode) {
|
if (!aOriginalNode) {
|
||||||
aOriginalNode = aNode;
|
aOriginalNode = aNode;
|
||||||
if (mNodeFixup) {
|
if (mNodeFixup) {
|
||||||
bool dummy;
|
bool dummy;
|
||||||
nsCOMPtr<nsIDOMNode> domNodeIn = do_QueryInterface(aNode);
|
nsCOMPtr<nsIDOMNode> domNodeIn = do_QueryInterface(aNode);
|
||||||
nsCOMPtr<nsIDOMNode> domNodeOut;
|
nsCOMPtr<nsIDOMNode> domNodeOut;
|
||||||
|
@ -433,7 +433,7 @@ nsDocumentEncoder::SerializeNodeStart(nsINode* aNode,
|
||||||
// or the caller did fixup themselves and aNode is already fixed
|
// or the caller did fixup themselves and aNode is already fixed
|
||||||
if (!node)
|
if (!node)
|
||||||
node = aNode;
|
node = aNode;
|
||||||
|
|
||||||
if (node->IsElement()) {
|
if (node->IsElement()) {
|
||||||
if ((mFlags & (nsIDocumentEncoder::OutputPreformatted |
|
if ((mFlags & (nsIDocumentEncoder::OutputPreformatted |
|
||||||
nsIDocumentEncoder::OutputDropInvisibleBreak)) &&
|
nsIDocumentEncoder::OutputDropInvisibleBreak)) &&
|
||||||
|
@ -655,7 +655,7 @@ ConvertAndWrite(const nsAString& aString,
|
||||||
// If the converter couldn't convert a chraacer we replace the
|
// If the converter couldn't convert a chraacer we replace the
|
||||||
// character with a characre entity.
|
// character with a characre entity.
|
||||||
if (convert_rv == NS_ERROR_UENC_NOMAPPING) {
|
if (convert_rv == NS_ERROR_UENC_NOMAPPING) {
|
||||||
// Finishes the conversion.
|
// Finishes the conversion.
|
||||||
// The converter has the possibility to write some extra data and flush its final state.
|
// The converter has the possibility to write some extra data and flush its final state.
|
||||||
char finish_buf[33];
|
char finish_buf[33];
|
||||||
charLength = sizeof(finish_buf) - 1;
|
charLength = sizeof(finish_buf) - 1;
|
||||||
|
@ -671,7 +671,7 @@ ConvertAndWrite(const nsAString& aString,
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
nsAutoCString entString("&#");
|
nsAutoCString entString("&#");
|
||||||
if (NS_IS_HIGH_SURROGATE(unicodeBuf[unicodeLength - 1]) &&
|
if (NS_IS_HIGH_SURROGATE(unicodeBuf[unicodeLength - 1]) &&
|
||||||
unicodeLength < startLength && NS_IS_LOW_SURROGATE(unicodeBuf[unicodeLength])) {
|
unicodeLength < startLength && NS_IS_LOW_SURROGATE(unicodeBuf[unicodeLength])) {
|
||||||
entString.AppendInt(SURROGATE_TO_UCS4(unicodeBuf[unicodeLength - 1],
|
entString.AppendInt(SURROGATE_TO_UCS4(unicodeBuf[unicodeLength - 1],
|
||||||
unicodeBuf[unicodeLength]));
|
unicodeBuf[unicodeLength]));
|
||||||
|
@ -859,7 +859,7 @@ nsDocumentEncoder::SerializeRangeNodes(nsRange* aRange,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// due to implementation it is impossible for text node to be both start and end of
|
// due to implementation it is impossible for text node to be both start and end of
|
||||||
// range. We would have handled that case without getting here.
|
// range. We would have handled that case without getting here.
|
||||||
//XXXsmaug What does this all mean?
|
//XXXsmaug What does this all mean?
|
||||||
if (IsTextNode(aNode))
|
if (IsTextNode(aNode))
|
||||||
|
@ -889,12 +889,12 @@ nsDocumentEncoder::SerializeRangeNodes(nsRange* aRange,
|
||||||
}
|
}
|
||||||
if ((startNode == content) && !mHaltRangeHint) mStartDepth++;
|
if ((startNode == content) && !mHaltRangeHint) mStartDepth++;
|
||||||
if ((endNode == content) && !mHaltRangeHint) mEndDepth++;
|
if ((endNode == content) && !mHaltRangeHint) mEndDepth++;
|
||||||
|
|
||||||
// serialize the start of this node
|
// serialize the start of this node
|
||||||
rv = SerializeNodeStart(aNode, 0, -1, aString);
|
rv = SerializeNodeStart(aNode, 0, -1, aString);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
// do some calculations that will tell us which children of this
|
// do some calculations that will tell us which children of this
|
||||||
// node are in the range.
|
// node are in the range.
|
||||||
nsIContent* childAsNode = nullptr;
|
nsIContent* childAsNode = nullptr;
|
||||||
|
@ -903,7 +903,7 @@ nsDocumentEncoder::SerializeRangeNodes(nsRange* aRange,
|
||||||
startOffset = mStartOffsets[mStartRootIndex - aDepth];
|
startOffset = mStartOffsets[mStartRootIndex - aDepth];
|
||||||
if (endNode == content && mEndRootIndex >= aDepth)
|
if (endNode == content && mEndRootIndex >= aDepth)
|
||||||
endOffset = mEndOffsets[mEndRootIndex - aDepth];
|
endOffset = mEndOffsets[mEndRootIndex - aDepth];
|
||||||
// generated content will cause offset values of -1 to be returned.
|
// generated content will cause offset values of -1 to be returned.
|
||||||
int32_t j;
|
int32_t j;
|
||||||
uint32_t childCount = content->GetChildCount();
|
uint32_t childCount = content->GetChildCount();
|
||||||
|
|
||||||
|
@ -914,7 +914,7 @@ nsDocumentEncoder::SerializeRangeNodes(nsRange* aRange,
|
||||||
// if we are at the "tip" of the selection, endOffset is fine.
|
// if we are at the "tip" of the selection, endOffset is fine.
|
||||||
// otherwise, we need to add one. This is because of the semantics
|
// otherwise, we need to add one. This is because of the semantics
|
||||||
// of the offset list created by GetAncestorsAndOffsets(). The
|
// of the offset list created by GetAncestorsAndOffsets(). The
|
||||||
// intermediate points on the list use the endOffset of the
|
// intermediate points on the list use the endOffset of the
|
||||||
// location of the ancestor, rather than just past it. So we need
|
// location of the ancestor, rather than just past it. So we need
|
||||||
// to add one here in order to include it in the children we serialize.
|
// to add one here in order to include it in the children we serialize.
|
||||||
if (aNode != aRange->GetEndParent())
|
if (aNode != aRange->GetEndParent())
|
||||||
|
@ -939,7 +939,7 @@ nsDocumentEncoder::SerializeRangeNodes(nsRange* aRange,
|
||||||
if (aNode != mCommonParent)
|
if (aNode != mCommonParent)
|
||||||
{
|
{
|
||||||
rv = SerializeNodeEnd(aNode, aString);
|
rv = SerializeNodeEnd(aNode, aString);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1020,7 +1020,7 @@ nsDocumentEncoder::SerializeRangeToString(nsRange *aRange,
|
||||||
|
|
||||||
if (!mCommonParent)
|
if (!mCommonParent)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
||||||
nsINode* startParent = aRange->GetStartParent();
|
nsINode* startParent = aRange->GetStartParent();
|
||||||
NS_ENSURE_TRUE(startParent, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(startParent, NS_ERROR_FAILURE);
|
||||||
int32_t startOffset = aRange->StartOffset();
|
int32_t startOffset = aRange->StartOffset();
|
||||||
|
@ -1047,7 +1047,7 @@ nsDocumentEncoder::SerializeRangeToString(nsRange *aRange,
|
||||||
nsCOMPtr<nsIContent> commonContent = do_QueryInterface(mCommonParent);
|
nsCOMPtr<nsIContent> commonContent = do_QueryInterface(mCommonParent);
|
||||||
mStartRootIndex = mStartNodes.IndexOf(commonContent);
|
mStartRootIndex = mStartNodes.IndexOf(commonContent);
|
||||||
mEndRootIndex = mEndNodes.IndexOf(commonContent);
|
mEndRootIndex = mEndNodes.IndexOf(commonContent);
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
rv = SerializeRangeContextStart(mCommonAncestors, aOutputString);
|
rv = SerializeRangeContextStart(mCommonAncestors, aOutputString);
|
||||||
|
@ -1108,7 +1108,7 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
|
||||||
mCachedBuffer->ToString(0, output, true);
|
mCachedBuffer->ToString(0, output, true);
|
||||||
// output owns the buffer now!
|
// output owns the buffer now!
|
||||||
mCachedBuffer = nullptr;
|
mCachedBuffer = nullptr;
|
||||||
|
|
||||||
|
|
||||||
if (!mSerializer) {
|
if (!mSerializer) {
|
||||||
nsAutoCString progId(NS_CONTENTSERIALIZER_CONTRACTID_PREFIX);
|
nsAutoCString progId(NS_CONTENTSERIALIZER_CONTRACTID_PREFIX);
|
||||||
|
@ -1120,8 +1120,6 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
nsCOMPtr<nsIAtom> charsetAtom;
|
|
||||||
|
|
||||||
bool rewriteEncodingDeclaration = !(mSelection || mRange || mNode) && !(mFlags & OutputDontRewriteEncodingDeclaration);
|
bool rewriteEncodingDeclaration = !(mSelection || mRange || mNode) && !(mFlags & OutputDontRewriteEncodingDeclaration);
|
||||||
mSerializer->Init(mFlags, mWrapColumn, mCharset.get(), mIsCopying, rewriteEncodingDeclaration);
|
mSerializer->Init(mFlags, mWrapColumn, mCharset.get(), mIsCopying, rewriteEncodingDeclaration);
|
||||||
|
|
||||||
|
@ -1195,13 +1193,13 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
mCommonAncestors.Clear();
|
mCommonAncestors.Clear();
|
||||||
nsContentUtils::GetAncestors(p->GetParentNode(), mCommonAncestors);
|
nsContentUtils::GetAncestors(p->GetParentNode(), mCommonAncestors);
|
||||||
mDisableContextSerialize = false;
|
mDisableContextSerialize = false;
|
||||||
rv = SerializeRangeContextEnd(mCommonAncestors, output);
|
rv = SerializeRangeContextEnd(mCommonAncestors, output);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just to be safe
|
// Just to be safe
|
||||||
mDisableContextSerialize = false;
|
mDisableContextSerialize = false;
|
||||||
|
|
||||||
mSelection = nullptr;
|
mSelection = nullptr;
|
||||||
} else if (mRange) {
|
} else if (mRange) {
|
||||||
|
@ -1226,7 +1224,7 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
|
||||||
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
rv = mSerializer->Flush(output);
|
rv = mSerializer->Flush(output);
|
||||||
|
|
||||||
mCachedBuffer = nsStringBuffer::FromString(output);
|
mCachedBuffer = nsStringBuffer::FromString(output);
|
||||||
// We have to be careful how we set aOutputString, because we don't
|
// We have to be careful how we set aOutputString, because we don't
|
||||||
// want it to end up sharing mCachedBuffer if we plan to reuse it.
|
// want it to end up sharing mCachedBuffer if we plan to reuse it.
|
||||||
|
@ -1335,12 +1333,12 @@ protected:
|
||||||
kStart,
|
kStart,
|
||||||
kEnd
|
kEnd
|
||||||
};
|
};
|
||||||
|
|
||||||
nsresult PromoteRange(nsIDOMRange *inRange);
|
nsresult PromoteRange(nsIDOMRange *inRange);
|
||||||
nsresult PromoteAncestorChain(nsCOMPtr<nsIDOMNode> *ioNode,
|
nsresult PromoteAncestorChain(nsCOMPtr<nsIDOMNode> *ioNode,
|
||||||
int32_t *ioStartOffset,
|
int32_t *ioStartOffset,
|
||||||
int32_t *ioEndOffset);
|
int32_t *ioEndOffset);
|
||||||
nsresult GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t aOffset,
|
nsresult GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t aOffset,
|
||||||
nsCOMPtr<nsIDOMNode> *outNode, int32_t *outOffset, nsIDOMNode *aCommon);
|
nsCOMPtr<nsIDOMNode> *outNode, int32_t *outOffset, nsIDOMNode *aCommon);
|
||||||
nsCOMPtr<nsIDOMNode> GetChildAt(nsIDOMNode *aParent, int32_t aOffset);
|
nsCOMPtr<nsIDOMNode> GetChildAt(nsIDOMNode *aParent, int32_t aOffset);
|
||||||
bool IsMozBR(nsIDOMNode* aNode);
|
bool IsMozBR(nsIDOMNode* aNode);
|
||||||
|
@ -1406,10 +1404,10 @@ nsHTMLCopyEncoder::SetSelection(nsISelection* aSelection)
|
||||||
// check for text widgets: we need to recognize these so that
|
// check for text widgets: we need to recognize these so that
|
||||||
// we don't tweak the selection to be outside of the magic
|
// we don't tweak the selection to be outside of the magic
|
||||||
// div that ender-lite text widgets are embedded in.
|
// div that ender-lite text widgets are embedded in.
|
||||||
|
|
||||||
if (!aSelection)
|
if (!aSelection)
|
||||||
return NS_ERROR_NULL_POINTER;
|
return NS_ERROR_NULL_POINTER;
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMRange> range;
|
nsCOMPtr<nsIDOMRange> range;
|
||||||
nsCOMPtr<nsIDOMNode> commonParent;
|
nsCOMPtr<nsIDOMNode> commonParent;
|
||||||
Selection* selection = aSelection->AsSelection();
|
Selection* selection = aSelection->AsSelection();
|
||||||
|
@ -1418,7 +1416,7 @@ nsHTMLCopyEncoder::SetSelection(nsISelection* aSelection)
|
||||||
// if selection is uninitialized return
|
// if selection is uninitialized return
|
||||||
if (!rangeCount)
|
if (!rangeCount)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
// we'll just use the common parent of the first range. Implicit assumption
|
// we'll just use the common parent of the first range. Implicit assumption
|
||||||
// here that multi-range selections are table cell selections, in which case
|
// here that multi-range selections are table cell selections, in which case
|
||||||
// the common parent is somewhere in the table and we don't really care where.
|
// the common parent is somewhere in the table and we don't really care where.
|
||||||
|
@ -1481,7 +1479,7 @@ nsHTMLCopyEncoder::SetSelection(nsISelection* aSelection)
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalize selection if we are not in a widget
|
// normalize selection if we are not in a widget
|
||||||
if (mIsTextWidget)
|
if (mIsTextWidget)
|
||||||
{
|
{
|
||||||
mSelection = aSelection;
|
mSelection = aSelection;
|
||||||
mMimeType.AssignLiteral("text/plain");
|
mMimeType.AssignLiteral("text/plain");
|
||||||
|
@ -1496,13 +1494,13 @@ nsHTMLCopyEncoder::SetSelection(nsISelection* aSelection)
|
||||||
// mMimeType is set to text/plain when encoding starts.
|
// mMimeType is set to text/plain when encoding starts.
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// there's no Clone() for selection! fix...
|
// there's no Clone() for selection! fix...
|
||||||
//nsresult rv = aSelection->Clone(getter_AddRefs(mSelection);
|
//nsresult rv = aSelection->Clone(getter_AddRefs(mSelection);
|
||||||
//NS_ENSURE_SUCCESS(rv, rv);
|
//NS_ENSURE_SUCCESS(rv, rv);
|
||||||
NS_NewDomSelection(getter_AddRefs(mSelection));
|
NS_NewDomSelection(getter_AddRefs(mSelection));
|
||||||
NS_ENSURE_TRUE(mSelection, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(mSelection, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
// loop thru the ranges in the selection
|
// loop thru the ranges in the selection
|
||||||
for (uint32_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
|
for (uint32_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
|
||||||
range = selection->GetRangeAt(rangeIdx);
|
range = selection->GetRangeAt(rangeIdx);
|
||||||
|
@ -1514,7 +1512,7 @@ nsHTMLCopyEncoder::SetSelection(nsISelection* aSelection)
|
||||||
// adjust range to include any ancestors who's children are entirely selected
|
// adjust range to include any ancestors who's children are entirely selected
|
||||||
rv = PromoteRange(myRange);
|
rv = PromoteRange(myRange);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
rv = mSelection->AddRange(myRange);
|
rv = mSelection->AddRange(myRange);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
@ -1544,7 +1542,7 @@ nsHTMLCopyEncoder::EncodeToStringWithContext(nsAString& aContextString,
|
||||||
|
|
||||||
// now encode common ancestors into aContextString. Note that the common ancestors
|
// now encode common ancestors into aContextString. Note that the common ancestors
|
||||||
// will be for the last range in the selection in the case of multirange selections.
|
// will be for the last range in the selection in the case of multirange selections.
|
||||||
// encoding ancestors every range in a multirange selection in a way that could be
|
// encoding ancestors every range in a multirange selection in a way that could be
|
||||||
// understood by the paste code would be a lot more work to do. As a practical matter,
|
// understood by the paste code would be a lot more work to do. As a practical matter,
|
||||||
// selections are single range, and the ones that aren't are table cell selections
|
// selections are single range, and the ones that aren't are table cell selections
|
||||||
// where all the cells are in the same table.
|
// where all the cells are in the same table.
|
||||||
|
@ -1556,7 +1554,7 @@ nsHTMLCopyEncoder::EncodeToStringWithContext(nsAString& aContextString,
|
||||||
if (count > 0)
|
if (count > 0)
|
||||||
node = mCommonAncestors.ElementAt(0);
|
node = mCommonAncestors.ElementAt(0);
|
||||||
|
|
||||||
if (node && IsTextNode(node))
|
if (node && IsTextNode(node))
|
||||||
{
|
{
|
||||||
mCommonAncestors.RemoveElementAt(0);
|
mCommonAncestors.RemoveElementAt(0);
|
||||||
// don't forget to adjust range depth info
|
// don't forget to adjust range depth info
|
||||||
|
@ -1565,7 +1563,7 @@ nsHTMLCopyEncoder::EncodeToStringWithContext(nsAString& aContextString,
|
||||||
// and the count
|
// and the count
|
||||||
count--;
|
count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
i = count;
|
i = count;
|
||||||
while (i > 0)
|
while (i > 0)
|
||||||
{
|
{
|
||||||
|
@ -1579,7 +1577,7 @@ nsHTMLCopyEncoder::EncodeToStringWithContext(nsAString& aContextString,
|
||||||
SerializeNodeEnd(node, aContextString);
|
SerializeNodeEnd(node, aContextString);
|
||||||
}
|
}
|
||||||
|
|
||||||
// encode range info : the start and end depth of the selection, where the depth is
|
// encode range info : the start and end depth of the selection, where the depth is
|
||||||
// distance down in the parent hierarchy. Later we will need to add leading/trailing
|
// distance down in the parent hierarchy. Later we will need to add leading/trailing
|
||||||
// whitespace info to this.
|
// whitespace info to this.
|
||||||
nsAutoString infoString;
|
nsAutoString infoString;
|
||||||
|
@ -1587,7 +1585,7 @@ nsHTMLCopyEncoder::EncodeToStringWithContext(nsAString& aContextString,
|
||||||
infoString.Append(char16_t(','));
|
infoString.Append(char16_t(','));
|
||||||
infoString.AppendInt(mEndDepth);
|
infoString.AppendInt(mEndDepth);
|
||||||
aInfoString = infoString;
|
aInfoString = infoString;
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1629,14 +1627,14 @@ nsHTMLCopyEncoder::IncludeInContext(nsINode *aNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsHTMLCopyEncoder::PromoteRange(nsIDOMRange *inRange)
|
nsHTMLCopyEncoder::PromoteRange(nsIDOMRange *inRange)
|
||||||
{
|
{
|
||||||
if (!inRange) return NS_ERROR_NULL_POINTER;
|
if (!inRange) return NS_ERROR_NULL_POINTER;
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
nsCOMPtr<nsIDOMNode> startNode, endNode, common;
|
nsCOMPtr<nsIDOMNode> startNode, endNode, common;
|
||||||
int32_t startOffset, endOffset;
|
int32_t startOffset, endOffset;
|
||||||
|
|
||||||
rv = inRange->GetCommonAncestorContainer(getter_AddRefs(common));
|
rv = inRange->GetCommonAncestorContainer(getter_AddRefs(common));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
rv = inRange->GetStartContainer(getter_AddRefs(startNode));
|
rv = inRange->GetStartContainer(getter_AddRefs(startNode));
|
||||||
|
@ -1647,18 +1645,17 @@ nsHTMLCopyEncoder::PromoteRange(nsIDOMRange *inRange)
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
rv = inRange->GetEndOffset(&endOffset);
|
rv = inRange->GetEndOffset(&endOffset);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMNode> opStartNode;
|
nsCOMPtr<nsIDOMNode> opStartNode;
|
||||||
nsCOMPtr<nsIDOMNode> opEndNode;
|
nsCOMPtr<nsIDOMNode> opEndNode;
|
||||||
int32_t opStartOffset, opEndOffset;
|
int32_t opStartOffset, opEndOffset;
|
||||||
nsCOMPtr<nsIDOMRange> opRange;
|
|
||||||
|
// examine range endpoints.
|
||||||
// examine range endpoints.
|
|
||||||
rv = GetPromotedPoint( kStart, startNode, startOffset, address_of(opStartNode), &opStartOffset, common);
|
rv = GetPromotedPoint( kStart, startNode, startOffset, address_of(opStartNode), &opStartOffset, common);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
rv = GetPromotedPoint( kEnd, endNode, endOffset, address_of(opEndNode), &opEndOffset, common);
|
rv = GetPromotedPoint( kEnd, endNode, endOffset, address_of(opEndNode), &opEndOffset, common);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// if both range endpoints are at the common ancestor, check for possible inclusion of ancestors
|
// if both range endpoints are at the common ancestor, check for possible inclusion of ancestors
|
||||||
if ( (opStartNode == common) && (opEndNode == common) )
|
if ( (opStartNode == common) && (opEndNode == common) )
|
||||||
{
|
{
|
||||||
|
@ -1666,22 +1663,22 @@ nsHTMLCopyEncoder::PromoteRange(nsIDOMRange *inRange)
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
opEndNode = opStartNode;
|
opEndNode = opStartNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the range to the new values
|
// set the range to the new values
|
||||||
rv = inRange->SetStart(opStartNode, opStartOffset);
|
rv = inRange->SetStart(opStartNode, opStartOffset);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
rv = inRange->SetEnd(opEndNode, opEndOffset);
|
rv = inRange->SetEnd(opEndNode, opEndOffset);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// PromoteAncestorChain will promote a range represented by [{*ioNode,*ioStartOffset} , {*ioNode,*ioEndOffset}]
|
// PromoteAncestorChain will promote a range represented by [{*ioNode,*ioStartOffset} , {*ioNode,*ioEndOffset}]
|
||||||
// The promotion is different from that found in getPromotedPoint: it will only promote one endpoint if it can
|
// The promotion is different from that found in getPromotedPoint: it will only promote one endpoint if it can
|
||||||
// promote the other. Thus, instead of having a startnode/endNode, there is just the one ioNode.
|
// promote the other. Thus, instead of having a startnode/endNode, there is just the one ioNode.
|
||||||
nsresult
|
nsresult
|
||||||
nsHTMLCopyEncoder::PromoteAncestorChain(nsCOMPtr<nsIDOMNode> *ioNode,
|
nsHTMLCopyEncoder::PromoteAncestorChain(nsCOMPtr<nsIDOMNode> *ioNode,
|
||||||
int32_t *ioStartOffset,
|
int32_t *ioStartOffset,
|
||||||
int32_t *ioEndOffset)
|
int32_t *ioEndOffset)
|
||||||
{
|
{
|
||||||
if (!ioNode || !ioStartOffset || !ioEndOffset) return NS_ERROR_NULL_POINTER;
|
if (!ioNode || !ioStartOffset || !ioEndOffset) return NS_ERROR_NULL_POINTER;
|
||||||
|
|
||||||
|
@ -1694,7 +1691,7 @@ nsHTMLCopyEncoder::PromoteAncestorChain(nsCOMPtr<nsIDOMNode> *ioNode,
|
||||||
//save the editable state of the ioNode, so we don't promote an ancestor if it has different editable state
|
//save the editable state of the ioNode, so we don't promote an ancestor if it has different editable state
|
||||||
nsCOMPtr<nsINode> node = do_QueryInterface(*ioNode);
|
nsCOMPtr<nsINode> node = do_QueryInterface(*ioNode);
|
||||||
bool isEditable = node->IsEditable();
|
bool isEditable = node->IsEditable();
|
||||||
|
|
||||||
// loop for as long as we can promote both endpoints
|
// loop for as long as we can promote both endpoints
|
||||||
while (!done)
|
while (!done)
|
||||||
{
|
{
|
||||||
|
@ -1712,13 +1709,13 @@ nsHTMLCopyEncoder::PromoteAncestorChain(nsCOMPtr<nsIDOMNode> *ioNode,
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
nsCOMPtr<nsINode> frontINode = do_QueryInterface(frontNode);
|
nsCOMPtr<nsINode> frontINode = do_QueryInterface(frontNode);
|
||||||
// if both endpoints were promoted one level and isEditable is the same as the original node,
|
// if both endpoints were promoted one level and isEditable is the same as the original node,
|
||||||
// keep looping - otherwise we are done.
|
// keep looping - otherwise we are done.
|
||||||
if ( (frontNode != parent) || (endNode != parent) || (frontINode->IsEditable() != isEditable) )
|
if ( (frontNode != parent) || (endNode != parent) || (frontINode->IsEditable() != isEditable) )
|
||||||
done = true;
|
done = true;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*ioNode = frontNode;
|
*ioNode = frontNode;
|
||||||
*ioStartOffset = frontOffset;
|
*ioStartOffset = frontOffset;
|
||||||
*ioEndOffset = endOffset;
|
*ioEndOffset = endOffset;
|
||||||
}
|
}
|
||||||
|
@ -1728,7 +1725,7 @@ nsHTMLCopyEncoder::PromoteAncestorChain(nsCOMPtr<nsIDOMNode> *ioNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t aOffset,
|
nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t aOffset,
|
||||||
nsCOMPtr<nsIDOMNode> *outNode, int32_t *outOffset, nsIDOMNode *common)
|
nsCOMPtr<nsIDOMNode> *outNode, int32_t *outOffset, nsIDOMNode *common)
|
||||||
{
|
{
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
|
@ -1736,14 +1733,14 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
|
||||||
nsCOMPtr<nsIDOMNode> parent = aNode;
|
nsCOMPtr<nsIDOMNode> parent = aNode;
|
||||||
int32_t offset = aOffset;
|
int32_t offset = aOffset;
|
||||||
bool bResetPromotion = false;
|
bool bResetPromotion = false;
|
||||||
|
|
||||||
// default values
|
// default values
|
||||||
*outNode = node;
|
*outNode = node;
|
||||||
*outOffset = offset;
|
*outOffset = offset;
|
||||||
|
|
||||||
if (common == node)
|
if (common == node)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
||||||
if (aWhere == kStart)
|
if (aWhere == kStart)
|
||||||
{
|
{
|
||||||
// some special casing for text nodes
|
// some special casing for text nodes
|
||||||
|
@ -1751,7 +1748,7 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
|
||||||
if (IsTextNode(t))
|
if (IsTextNode(t))
|
||||||
{
|
{
|
||||||
// if not at beginning of text node, we are done
|
// if not at beginning of text node, we are done
|
||||||
if (offset > 0)
|
if (offset > 0)
|
||||||
{
|
{
|
||||||
// unless everything before us in just whitespace. NOTE: we need a more
|
// unless everything before us in just whitespace. NOTE: we need a more
|
||||||
// general solution that truly detects all cases of non-significant
|
// general solution that truly detects all cases of non-significant
|
||||||
|
@ -1774,7 +1771,7 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
|
||||||
}
|
}
|
||||||
if (!node) node = parent;
|
if (!node) node = parent;
|
||||||
|
|
||||||
// finding the real start for this point. look up the tree for as long as we are the
|
// finding the real start for this point. look up the tree for as long as we are the
|
||||||
// first node in the container, and as long as we haven't hit the body node.
|
// first node in the container, and as long as we haven't hit the body node.
|
||||||
if (!IsRoot(node) && (parent != common))
|
if (!IsRoot(node) && (parent != common))
|
||||||
{
|
{
|
||||||
|
@ -1798,9 +1795,9 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
|
||||||
{
|
{
|
||||||
bResetPromotion = false;
|
bResetPromotion = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node = parent;
|
node = parent;
|
||||||
rv = GetNodeLocation(node, address_of(parent), &offset);
|
rv = GetNodeLocation(node, address_of(parent), &offset);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
@ -1811,7 +1808,7 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
|
||||||
offset = 0;
|
offset = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bResetPromotion)
|
if (bResetPromotion)
|
||||||
{
|
{
|
||||||
*outNode = aNode;
|
*outNode = aNode;
|
||||||
|
@ -1825,7 +1822,7 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aWhere == kEnd)
|
if (aWhere == kEnd)
|
||||||
{
|
{
|
||||||
// some special casing for text nodes
|
// some special casing for text nodes
|
||||||
|
@ -1856,8 +1853,8 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
|
||||||
node = GetChildAt(parent,offset);
|
node = GetChildAt(parent,offset);
|
||||||
}
|
}
|
||||||
if (!node) node = parent;
|
if (!node) node = parent;
|
||||||
|
|
||||||
// finding the real end for this point. look up the tree for as long as we are the
|
// finding the real end for this point. look up the tree for as long as we are the
|
||||||
// last node in the container, and as long as we haven't hit the body node.
|
// last node in the container, and as long as we haven't hit the body node.
|
||||||
if (!IsRoot(node) && (parent != common))
|
if (!IsRoot(node) && (parent != common))
|
||||||
{
|
{
|
||||||
|
@ -1881,9 +1878,9 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
|
||||||
{
|
{
|
||||||
bResetPromotion = false;
|
bResetPromotion = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node = parent;
|
node = parent;
|
||||||
rv = GetNodeLocation(node, address_of(parent), &offset);
|
rv = GetNodeLocation(node, address_of(parent), &offset);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
@ -1894,7 +1891,7 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
|
||||||
offset = 0;
|
offset = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bResetPromotion)
|
if (bResetPromotion)
|
||||||
{
|
{
|
||||||
*outNode = aNode;
|
*outNode = aNode;
|
||||||
|
@ -1909,18 +1906,18 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMNode>
|
nsCOMPtr<nsIDOMNode>
|
||||||
nsHTMLCopyEncoder::GetChildAt(nsIDOMNode *aParent, int32_t aOffset)
|
nsHTMLCopyEncoder::GetChildAt(nsIDOMNode *aParent, int32_t aOffset)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIDOMNode> resultNode;
|
nsCOMPtr<nsIDOMNode> resultNode;
|
||||||
|
|
||||||
if (!aParent)
|
if (!aParent)
|
||||||
return resultNode;
|
return resultNode;
|
||||||
|
|
||||||
nsCOMPtr<nsIContent> content = do_QueryInterface(aParent);
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aParent);
|
||||||
NS_PRECONDITION(content, "null content in nsHTMLCopyEncoder::GetChildAt");
|
NS_PRECONDITION(content, "null content in nsHTMLCopyEncoder::GetChildAt");
|
||||||
|
|
||||||
|
@ -1929,7 +1926,7 @@ nsHTMLCopyEncoder::GetChildAt(nsIDOMNode *aParent, int32_t aOffset)
|
||||||
return resultNode;
|
return resultNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
nsHTMLCopyEncoder::IsMozBR(nsIDOMNode* aNode)
|
nsHTMLCopyEncoder::IsMozBR(nsIDOMNode* aNode)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aNode);
|
MOZ_ASSERT(aNode);
|
||||||
|
@ -1940,7 +1937,7 @@ nsHTMLCopyEncoder::IsMozBR(nsIDOMNode* aNode)
|
||||||
NS_LITERAL_STRING("_moz"), eIgnoreCase);
|
NS_LITERAL_STRING("_moz"), eIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsHTMLCopyEncoder::GetNodeLocation(nsIDOMNode *inChild,
|
nsHTMLCopyEncoder::GetNodeLocation(nsIDOMNode *inChild,
|
||||||
nsCOMPtr<nsIDOMNode> *outParent,
|
nsCOMPtr<nsIDOMNode> *outParent,
|
||||||
int32_t *outOffset)
|
int32_t *outOffset)
|
||||||
|
@ -1986,26 +1983,26 @@ nsHTMLCopyEncoder::IsFirstNode(nsIDOMNode *aNode)
|
||||||
nsCOMPtr<nsIDOMNode> parent;
|
nsCOMPtr<nsIDOMNode> parent;
|
||||||
int32_t offset, j=0;
|
int32_t offset, j=0;
|
||||||
nsresult rv = GetNodeLocation(aNode, address_of(parent), &offset);
|
nsresult rv = GetNodeLocation(aNode, address_of(parent), &offset);
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
{
|
{
|
||||||
NS_NOTREACHED("failure in IsFirstNode");
|
NS_NOTREACHED("failure in IsFirstNode");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (offset == 0) // easy case, we are first dom child
|
if (offset == 0) // easy case, we are first dom child
|
||||||
return true;
|
return true;
|
||||||
if (!parent)
|
if (!parent)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// need to check if any nodes before us are really visible.
|
// need to check if any nodes before us are really visible.
|
||||||
// Mike wrote something for me along these lines in nsSelectionController,
|
// Mike wrote something for me along these lines in nsSelectionController,
|
||||||
// but I don't think it's ready for use yet - revisit.
|
// but I don't think it's ready for use yet - revisit.
|
||||||
// HACK: for now, simply consider all whitespace text nodes to be
|
// HACK: for now, simply consider all whitespace text nodes to be
|
||||||
// invisible formatting nodes.
|
// invisible formatting nodes.
|
||||||
nsCOMPtr<nsIDOMNodeList> childList;
|
nsCOMPtr<nsIDOMNodeList> childList;
|
||||||
nsCOMPtr<nsIDOMNode> child;
|
nsCOMPtr<nsIDOMNode> child;
|
||||||
|
|
||||||
rv = parent->GetChildNodes(getter_AddRefs(childList));
|
rv = parent->GetChildNodes(getter_AddRefs(childList));
|
||||||
if (NS_FAILED(rv) || !childList)
|
if (NS_FAILED(rv) || !childList)
|
||||||
{
|
{
|
||||||
NS_NOTREACHED("failure in IsFirstNode");
|
NS_NOTREACHED("failure in IsFirstNode");
|
||||||
return true;
|
return true;
|
||||||
|
@ -2013,7 +2010,7 @@ nsHTMLCopyEncoder::IsFirstNode(nsIDOMNode *aNode)
|
||||||
while (j < offset)
|
while (j < offset)
|
||||||
{
|
{
|
||||||
childList->Item(j, getter_AddRefs(child));
|
childList->Item(j, getter_AddRefs(child));
|
||||||
if (!IsEmptyTextContent(child))
|
if (!IsEmptyTextContent(child))
|
||||||
return false;
|
return false;
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
|
@ -2027,7 +2024,7 @@ nsHTMLCopyEncoder::IsLastNode(nsIDOMNode *aNode)
|
||||||
nsCOMPtr<nsIDOMNode> parent;
|
nsCOMPtr<nsIDOMNode> parent;
|
||||||
int32_t offset,j;
|
int32_t offset,j;
|
||||||
nsresult rv = GetNodeLocation(aNode, address_of(parent), &offset);
|
nsresult rv = GetNodeLocation(aNode, address_of(parent), &offset);
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
{
|
{
|
||||||
NS_NOTREACHED("failure in IsLastNode");
|
NS_NOTREACHED("failure in IsLastNode");
|
||||||
return false;
|
return false;
|
||||||
|
@ -2043,13 +2040,13 @@ nsHTMLCopyEncoder::IsLastNode(nsIDOMNode *aNode)
|
||||||
// need to check if any nodes after us are really visible.
|
// need to check if any nodes after us are really visible.
|
||||||
// Mike wrote something for me along these lines in nsSelectionController,
|
// Mike wrote something for me along these lines in nsSelectionController,
|
||||||
// but I don't think it's ready for use yet - revisit.
|
// but I don't think it's ready for use yet - revisit.
|
||||||
// HACK: for now, simply consider all whitespace text nodes to be
|
// HACK: for now, simply consider all whitespace text nodes to be
|
||||||
// invisible formatting nodes.
|
// invisible formatting nodes.
|
||||||
j = (int32_t)numChildren-1;
|
j = (int32_t)numChildren-1;
|
||||||
nsCOMPtr<nsIDOMNodeList>childList;
|
nsCOMPtr<nsIDOMNodeList>childList;
|
||||||
nsCOMPtr<nsIDOMNode> child;
|
nsCOMPtr<nsIDOMNode> child;
|
||||||
rv = parent->GetChildNodes(getter_AddRefs(childList));
|
rv = parent->GetChildNodes(getter_AddRefs(childList));
|
||||||
if (NS_FAILED(rv) || !childList)
|
if (NS_FAILED(rv) || !childList)
|
||||||
{
|
{
|
||||||
NS_NOTREACHED("failure in IsLastNode");
|
NS_NOTREACHED("failure in IsLastNode");
|
||||||
return true;
|
return true;
|
||||||
|
@ -2058,9 +2055,9 @@ nsHTMLCopyEncoder::IsLastNode(nsIDOMNode *aNode)
|
||||||
{
|
{
|
||||||
childList->Item(j, getter_AddRefs(child));
|
childList->Item(j, getter_AddRefs(child));
|
||||||
j--;
|
j--;
|
||||||
if (IsMozBR(child)) // we ignore trailing moz BRs.
|
if (IsMozBR(child)) // we ignore trailing moz BRs.
|
||||||
continue;
|
continue;
|
||||||
if (!IsEmptyTextContent(child))
|
if (!IsEmptyTextContent(child))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -2105,4 +2102,3 @@ nsHTMLCopyEncoder::GetImmediateContextCount(const nsTArray<nsINode*>& aAncestorA
|
||||||
}
|
}
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14020,7 +14020,6 @@ nsGlobalModalWindow::GetReturnValue(nsIVariant **aRetVal)
|
||||||
{
|
{
|
||||||
FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetReturnValue, (aRetVal), NS_OK);
|
FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetReturnValue, (aRetVal), NS_OK);
|
||||||
|
|
||||||
nsCOMPtr<nsIVariant> result;
|
|
||||||
if (!mReturnValue) {
|
if (!mReturnValue) {
|
||||||
nsCOMPtr<nsIVariant> variant = CreateVoidVariant();
|
nsCOMPtr<nsIVariant> variant = CreateVoidVariant();
|
||||||
variant.forget(aRetVal);
|
variant.forget(aRetVal);
|
||||||
|
|
|
@ -220,7 +220,6 @@ class BlobURLsReporter final : public nsIMemoryReporter
|
||||||
"blob cannot be freed until all URLs for it have been explicitly "
|
"blob cannot be freed until all URLs for it have been explicitly "
|
||||||
"invalidated with URL.revokeObjectURL.");
|
"invalidated with URL.revokeObjectURL.");
|
||||||
nsAutoCString path, url, owner, specialDesc;
|
nsAutoCString path, url, owner, specialDesc;
|
||||||
nsCOMPtr<nsIURI> principalURI;
|
|
||||||
uint64_t size = 0;
|
uint64_t size = 0;
|
||||||
uint32_t refCount = 1;
|
uint32_t refCount = 1;
|
||||||
DebugOnly<bool> blobImplWasCounted;
|
DebugOnly<bool> blobImplWasCounted;
|
||||||
|
|
|
@ -263,7 +263,6 @@ nsLocation::SetURI(nsIURI* aURI, bool aReplace)
|
||||||
nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
|
nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
|
||||||
if (docShell) {
|
if (docShell) {
|
||||||
nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
|
nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
|
||||||
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
|
|
||||||
|
|
||||||
if(NS_FAILED(CheckURL(aURI, getter_AddRefs(loadInfo))))
|
if(NS_FAILED(CheckURL(aURI, getter_AddRefs(loadInfo))))
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
|
@ -2660,7 +2660,6 @@ nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIURI> baseURL;
|
|
||||||
channel->GetURI(getter_AddRefs(request->mBaseURL));
|
channel->GetURI(getter_AddRefs(request->mBaseURL));
|
||||||
|
|
||||||
// Attempt to compile off main thread.
|
// Attempt to compile off main thread.
|
||||||
|
|
|
@ -3118,8 +3118,6 @@ nsDOMDeviceStorage::AddOrAppendNamed(Blob* aBlob, const nsAString& aPath,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIRunnable> r;
|
|
||||||
|
|
||||||
if (IsFullPath(aPath)) {
|
if (IsFullPath(aPath)) {
|
||||||
nsString storagePath;
|
nsString storagePath;
|
||||||
RefPtr<nsDOMDeviceStorage> ds = GetStorage(aPath, storagePath);
|
RefPtr<nsDOMDeviceStorage> ds = GetStorage(aPath, storagePath);
|
||||||
|
|
|
@ -614,7 +614,6 @@ HTMLSelectElement::Add(nsIDOMHTMLElement* aElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsISupports> supports;
|
nsCOMPtr<nsISupports> supports;
|
||||||
nsCOMPtr<nsIDOMHTMLElement> beforeElement;
|
|
||||||
|
|
||||||
// whether aBefore is nsIDOMHTMLElement...
|
// whether aBefore is nsIDOMHTMLElement...
|
||||||
if (NS_SUCCEEDED(aBefore->GetAsISupports(getter_AddRefs(supports)))) {
|
if (NS_SUCCEEDED(aBefore->GetAsISupports(getter_AddRefs(supports)))) {
|
||||||
|
|
|
@ -3123,9 +3123,6 @@ nsGenericHTMLElement::GetInnerText(mozilla::dom::DOMString& aValue,
|
||||||
void
|
void
|
||||||
nsGenericHTMLElement::SetInnerText(const nsAString& aValue)
|
nsGenericHTMLElement::SetInnerText(const nsAString& aValue)
|
||||||
{
|
{
|
||||||
// Fire DOMNodeRemoved mutation events before we do anything else.
|
|
||||||
nsCOMPtr<nsIContent> kungFuDeathGrip;
|
|
||||||
|
|
||||||
// Batch possible DOMSubtreeModified events.
|
// Batch possible DOMSubtreeModified events.
|
||||||
mozAutoSubtreeModified subtree(OwnerDoc(), nullptr);
|
mozAutoSubtreeModified subtree(OwnerDoc(), nullptr);
|
||||||
FireNodeRemovedForChildren();
|
FireNodeRemovedForChildren();
|
||||||
|
|
|
@ -1303,6 +1303,14 @@ StartMacOSContentSandbox()
|
||||||
MOZ_CRASH("Failed to get NS_OS_TEMP_DIR path");
|
MOZ_CRASH("Failed to get NS_OS_TEMP_DIR path");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIFile> profileDir;
|
||||||
|
ContentChild::GetSingleton()->GetProfileDir(getter_AddRefs(profileDir));
|
||||||
|
nsCString profileDirPath;
|
||||||
|
rv = profileDir->GetNativePath(profileDirPath);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
MOZ_CRASH("Failed to get profile path");
|
||||||
|
}
|
||||||
|
|
||||||
MacSandboxInfo info;
|
MacSandboxInfo info;
|
||||||
info.type = MacSandboxType_Content;
|
info.type = MacSandboxType_Content;
|
||||||
info.level = info.level = sandboxLevel;
|
info.level = info.level = sandboxLevel;
|
||||||
|
@ -1310,6 +1318,7 @@ StartMacOSContentSandbox()
|
||||||
info.appBinaryPath.assign(appBinaryPath.get());
|
info.appBinaryPath.assign(appBinaryPath.get());
|
||||||
info.appDir.assign(appDir.get());
|
info.appDir.assign(appDir.get());
|
||||||
info.appTempDir.assign(tempDirPath.get());
|
info.appTempDir.assign(tempDirPath.get());
|
||||||
|
info.profileDir.assign(profileDirPath.get());
|
||||||
|
|
||||||
std::string err;
|
std::string err;
|
||||||
if (!mozilla::StartMacSandbox(info, err)) {
|
if (!mozilla::StartMacSandbox(info, err)) {
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
#include "nsWeakPtr.h"
|
#include "nsWeakPtr.h"
|
||||||
#include "nsIWindowProvider.h"
|
#include "nsIWindowProvider.h"
|
||||||
|
|
||||||
|
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||||
|
#include "nsIFile.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
struct ChromePackage;
|
struct ChromePackage;
|
||||||
class nsIObserver;
|
class nsIObserver;
|
||||||
|
@ -114,6 +117,19 @@ public:
|
||||||
|
|
||||||
void GetProcessName(nsACString& aName) const;
|
void GetProcessName(nsACString& aName) const;
|
||||||
|
|
||||||
|
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||||
|
void GetProfileDir(nsIFile** aProfileDir) const
|
||||||
|
{
|
||||||
|
*aProfileDir = mProfileDir;
|
||||||
|
NS_IF_ADDREF(*aProfileDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetProfileDir(nsIFile* aProfileDir)
|
||||||
|
{
|
||||||
|
mProfileDir = aProfileDir;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool IsAlive() const;
|
bool IsAlive() const;
|
||||||
|
|
||||||
static void AppendProcessId(nsACString& aName);
|
static void AppendProcessId(nsACString& aName);
|
||||||
|
@ -681,6 +697,10 @@ private:
|
||||||
nsCOMPtr<nsIDomainPolicy> mPolicy;
|
nsCOMPtr<nsIDomainPolicy> mPolicy;
|
||||||
nsCOMPtr<nsITimer> mForceKillTimer;
|
nsCOMPtr<nsITimer> mForceKillTimer;
|
||||||
|
|
||||||
|
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||||
|
nsCOMPtr<nsIFile> mProfileDir;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Hashtable to keep track of the pending GetFilesHelper objects.
|
// Hashtable to keep track of the pending GetFilesHelper objects.
|
||||||
// This GetFilesHelperChild objects are removed when RecvGetFilesResponse is
|
// This GetFilesHelperChild objects are removed when RecvGetFilesResponse is
|
||||||
// received.
|
// received.
|
||||||
|
|
|
@ -1085,7 +1085,6 @@ ContentParent::CreateBrowserOrApp(const TabContext& aContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aContext.IsMozBrowserElement() || !aContext.HasOwnApp()) {
|
if (aContext.IsMozBrowserElement() || !aContext.HasOwnApp()) {
|
||||||
RefPtr<TabParent> tp;
|
|
||||||
RefPtr<nsIContentParent> constructorSender;
|
RefPtr<nsIContentParent> constructorSender;
|
||||||
if (isInContentProcess) {
|
if (isInContentProcess) {
|
||||||
MOZ_ASSERT(aContext.IsMozBrowserElement());
|
MOZ_ASSERT(aContext.IsMozBrowserElement());
|
||||||
|
|
|
@ -114,6 +114,21 @@ ContentProcess::SetAppDir(const nsACString& aPath)
|
||||||
mXREEmbed.SetAppDir(aPath);
|
mXREEmbed.SetAppDir(aPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||||
|
void
|
||||||
|
ContentProcess::SetProfile(const nsACString& aProfile)
|
||||||
|
{
|
||||||
|
bool flag;
|
||||||
|
nsresult rv =
|
||||||
|
XRE_GetFileFromPath(aProfile.BeginReading(), getter_AddRefs(mProfileDir));
|
||||||
|
if (NS_FAILED(rv) ||
|
||||||
|
NS_FAILED(mProfileDir->Exists(&flag)) || !flag) {
|
||||||
|
NS_WARNING("Invalid profile directory passed to content process.");
|
||||||
|
mProfileDir = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ContentProcess::Init()
|
ContentProcess::Init()
|
||||||
{
|
{
|
||||||
|
@ -124,6 +139,10 @@ ContentProcess::Init()
|
||||||
mContent.InitXPCOM();
|
mContent.InitXPCOM();
|
||||||
mContent.InitGraphicsDeviceData();
|
mContent.InitGraphicsDeviceData();
|
||||||
|
|
||||||
|
#if (defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
|
||||||
|
mContent.SetProfileDir(mProfileDir);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
|
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
|
||||||
SetUpSandboxEnvironment();
|
SetUpSandboxEnvironment();
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -39,9 +39,18 @@ public:
|
||||||
|
|
||||||
void SetAppDir(const nsACString& aPath);
|
void SetAppDir(const nsACString& aPath);
|
||||||
|
|
||||||
|
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||||
|
void SetProfile(const nsACString& aProfile);
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ContentChild mContent;
|
ContentChild mContent;
|
||||||
mozilla::ipc::ScopedXREEmbed mXREEmbed;
|
mozilla::ipc::ScopedXREEmbed mXREEmbed;
|
||||||
|
|
||||||
|
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||||
|
nsCOMPtr<nsIFile> mProfileDir;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(XP_WIN)
|
#if defined(XP_WIN)
|
||||||
// This object initializes and configures COM.
|
// This object initializes and configures COM.
|
||||||
mozilla::mscom::MainThreadRuntime mCOMRuntime;
|
mozilla::mscom::MainThreadRuntime mCOMRuntime;
|
||||||
|
|
|
@ -398,21 +398,31 @@ SystemClockDriver::WaitForNextIteration()
|
||||||
|
|
||||||
PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
|
PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
|
||||||
TimeStamp now = TimeStamp::Now();
|
TimeStamp now = TimeStamp::Now();
|
||||||
if (mGraphImpl->mNeedAnotherIteration) {
|
|
||||||
|
// This lets us avoid hitting the Atomic twice when we know we won't sleep
|
||||||
|
bool another = mGraphImpl->mNeedAnotherIteration; // atomic
|
||||||
|
if (!another) {
|
||||||
|
mGraphImpl->mGraphDriverAsleep = true; // atomic
|
||||||
|
mWaitState = WAITSTATE_WAITING_INDEFINITELY;
|
||||||
|
}
|
||||||
|
// NOTE: mNeedAnotherIteration while also atomic may have changed before
|
||||||
|
// we could set mGraphDriverAsleep, so we must re-test it.
|
||||||
|
// (EnsureNextIteration sets mNeedAnotherIteration, then tests
|
||||||
|
// mGraphDriverAsleep
|
||||||
|
if (another || mGraphImpl->mNeedAnotherIteration) { // atomic
|
||||||
int64_t timeoutMS = MEDIA_GRAPH_TARGET_PERIOD_MS -
|
int64_t timeoutMS = MEDIA_GRAPH_TARGET_PERIOD_MS -
|
||||||
int64_t((now - mCurrentTimeStamp).ToMilliseconds());
|
int64_t((now - mCurrentTimeStamp).ToMilliseconds());
|
||||||
// Make sure timeoutMS doesn't overflow 32 bits by waking up at
|
// Make sure timeoutMS doesn't overflow 32 bits by waking up at
|
||||||
// least once a minute, if we need to wake up at all
|
// least once a minute, if we need to wake up at all
|
||||||
timeoutMS = std::max<int64_t>(0, std::min<int64_t>(timeoutMS, 60*1000));
|
timeoutMS = std::max<int64_t>(0, std::min<int64_t>(timeoutMS, 60*1000));
|
||||||
timeout = PR_MillisecondsToInterval(uint32_t(timeoutMS));
|
timeout = PR_MillisecondsToInterval(uint32_t(timeoutMS));
|
||||||
STREAM_LOG(LogLevel::Verbose, ("Waiting for next iteration; at %f, timeout=%f", (now - mInitialTimeStamp).ToSeconds(), timeoutMS/1000.0));
|
STREAM_LOG(LogLevel::Verbose,
|
||||||
|
("Waiting for next iteration; at %f, timeout=%f",
|
||||||
|
(now - mInitialTimeStamp).ToSeconds(), timeoutMS/1000.0));
|
||||||
if (mWaitState == WAITSTATE_WAITING_INDEFINITELY) {
|
if (mWaitState == WAITSTATE_WAITING_INDEFINITELY) {
|
||||||
mGraphImpl->mGraphDriverAsleep = false; // atomic
|
mGraphImpl->mGraphDriverAsleep = false; // atomic
|
||||||
}
|
}
|
||||||
mWaitState = WAITSTATE_WAITING_FOR_NEXT_ITERATION;
|
mWaitState = WAITSTATE_WAITING_FOR_NEXT_ITERATION;
|
||||||
} else {
|
|
||||||
mGraphImpl->mGraphDriverAsleep = true; // atomic
|
|
||||||
mWaitState = WAITSTATE_WAITING_INDEFINITELY;
|
|
||||||
}
|
}
|
||||||
if (timeout > 0) {
|
if (timeout > 0) {
|
||||||
mGraphImpl->GetMonitor().Wait(timeout);
|
mGraphImpl->GetMonitor().Wait(timeout);
|
||||||
|
@ -424,13 +434,19 @@ SystemClockDriver::WaitForNextIteration()
|
||||||
if (mWaitState == WAITSTATE_WAITING_INDEFINITELY) {
|
if (mWaitState == WAITSTATE_WAITING_INDEFINITELY) {
|
||||||
mGraphImpl->mGraphDriverAsleep = false; // atomic
|
mGraphImpl->mGraphDriverAsleep = false; // atomic
|
||||||
}
|
}
|
||||||
|
// Note: this can race against the EnsureNextIteration setting
|
||||||
|
// WAITSTATE_RUNNING and setting mGraphDriverAsleep to false, so you can
|
||||||
|
// have an iteration with WAITSTATE_WAKING_UP instead of RUNNING.
|
||||||
mWaitState = WAITSTATE_RUNNING;
|
mWaitState = WAITSTATE_RUNNING;
|
||||||
mGraphImpl->mNeedAnotherIteration = false;
|
mGraphImpl->mNeedAnotherIteration = false; // atomic
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemClockDriver::WakeUp()
|
void SystemClockDriver::WakeUp()
|
||||||
{
|
{
|
||||||
mGraphImpl->GetMonitor().AssertCurrentThreadOwns();
|
mGraphImpl->GetMonitor().AssertCurrentThreadOwns();
|
||||||
|
// Note: this can race against the thread setting WAITSTATE_RUNNING and
|
||||||
|
// setting mGraphDriverAsleep to false, so you can have an iteration
|
||||||
|
// with WAITSTATE_WAKING_UP instead of RUNNING.
|
||||||
mWaitState = WAITSTATE_WAKING_UP;
|
mWaitState = WAITSTATE_WAKING_UP;
|
||||||
mGraphImpl->mGraphDriverAsleep = false; // atomic
|
mGraphImpl->mGraphDriverAsleep = false; // atomic
|
||||||
mGraphImpl->GetMonitor().Notify();
|
mGraphImpl->GetMonitor().Notify();
|
||||||
|
|
|
@ -528,8 +528,6 @@ MediaDecoderReader::Shutdown()
|
||||||
// Shut down the watch manager before shutting down our task queue.
|
// Shut down the watch manager before shutting down our task queue.
|
||||||
mWatchManager.Shutdown();
|
mWatchManager.Shutdown();
|
||||||
|
|
||||||
RefPtr<ShutdownPromise> p;
|
|
||||||
|
|
||||||
mDecoder = nullptr;
|
mDecoder = nullptr;
|
||||||
|
|
||||||
ReaderQueue::Instance().Remove(this);
|
ReaderQueue::Instance().Remove(this);
|
||||||
|
|
|
@ -522,6 +522,8 @@ public:
|
||||||
void EnsureNextIteration()
|
void EnsureNextIteration()
|
||||||
{
|
{
|
||||||
mNeedAnotherIteration = true; // atomic
|
mNeedAnotherIteration = true; // atomic
|
||||||
|
// Note: GraphDriver must ensure that there's no race on setting
|
||||||
|
// mNeedAnotherIteration and mGraphDriverAsleep -- see WaitForNextIteration()
|
||||||
if (mGraphDriverAsleep) { // atomic
|
if (mGraphDriverAsleep) { // atomic
|
||||||
MonitorAutoLock mon(mMonitor);
|
MonitorAutoLock mon(mMonitor);
|
||||||
CurrentDriver()->WakeUp(); // Might not be the same driver; might have woken already
|
CurrentDriver()->WakeUp(); // Might not be the same driver; might have woken already
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
// Service instantiation
|
// Service instantiation
|
||||||
#include "ipc/SmsIPCService.h"
|
#include "ipc/SmsIPCService.h"
|
||||||
#include "MobileMessageService.h"
|
#include "MobileMessageService.h"
|
||||||
#ifdef MOZ_WIDGET_ANDROID
|
#if defined(MOZ_WIDGET_ANDROID) && defined(MOZ_WEBSMS_BACKEND)
|
||||||
#include "android/MobileMessageDatabaseService.h"
|
#include "android/MobileMessageDatabaseService.h"
|
||||||
#include "android/SmsService.h"
|
#include "android/SmsService.h"
|
||||||
#elif defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
|
#elif defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
|
||||||
|
@ -853,7 +853,7 @@ NS_CreateSmsService()
|
||||||
if (XRE_IsContentProcess()) {
|
if (XRE_IsContentProcess()) {
|
||||||
smsService = SmsIPCService::GetSingleton();
|
smsService = SmsIPCService::GetSingleton();
|
||||||
} else {
|
} else {
|
||||||
#ifdef MOZ_WIDGET_ANDROID
|
#if defined(MOZ_WIDGET_ANDROID) && defined(MOZ_WEBSMS_BACKEND)
|
||||||
smsService = new SmsService();
|
smsService = new SmsService();
|
||||||
#elif defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
|
#elif defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
|
||||||
smsService = do_GetService(GONK_SMSSERVICE_CONTRACTID);
|
smsService = do_GetService(GONK_SMSSERVICE_CONTRACTID);
|
||||||
|
@ -870,7 +870,7 @@ NS_CreateMobileMessageDatabaseService()
|
||||||
if (XRE_IsContentProcess()) {
|
if (XRE_IsContentProcess()) {
|
||||||
mobileMessageDBService = SmsIPCService::GetSingleton();
|
mobileMessageDBService = SmsIPCService::GetSingleton();
|
||||||
} else {
|
} else {
|
||||||
#ifdef MOZ_WIDGET_ANDROID
|
#if defined(MOZ_WIDGET_ANDROID) && defined(MOZ_WEBSMS_BACKEND)
|
||||||
mobileMessageDBService = new MobileMessageDatabaseService();
|
mobileMessageDBService = new MobileMessageDatabaseService();
|
||||||
#elif defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
|
#elif defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
|
||||||
mobileMessageDBService =
|
mobileMessageDBService =
|
||||||
|
|
|
@ -16,7 +16,7 @@ EXPORTS.mozilla.dom.mobilemessage += [
|
||||||
'Types.h', # Required by IPDL SmsTypes.h
|
'Types.h', # Required by IPDL SmsTypes.h
|
||||||
]
|
]
|
||||||
|
|
||||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android' and CONFIG['MOZ_WEBSMS_BACKEND']:
|
||||||
SOURCES += [
|
SOURCES += [
|
||||||
'android/MobileMessageDatabaseService.cpp',
|
'android/MobileMessageDatabaseService.cpp',
|
||||||
'android/SmsManager.cpp',
|
'android/SmsManager.cpp',
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
<h1>I'm just a support file</h1>
|
||||||
|
<p>I get loaded to do permission testing.</p>
|
|
@ -2,6 +2,7 @@
|
||||||
support-files =
|
support-files =
|
||||||
file_framework.js
|
file_framework.js
|
||||||
file_shim.html
|
file_shim.html
|
||||||
|
file_empty.html
|
||||||
|
|
||||||
[test_alarms.html]
|
[test_alarms.html]
|
||||||
skip-if = true
|
skip-if = true
|
||||||
|
|
|
@ -4,143 +4,203 @@
|
||||||
-->
|
-->
|
||||||
<!DOCTYPE HTML>
|
<!DOCTYPE HTML>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Test for Permissions API</title>
|
<title>Test for Permissions API</title>
|
||||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
||||||
</head>
|
</head>
|
||||||
<body onload='runTests()'>
|
|
||||||
<pre id="test">
|
|
||||||
<script type="application/javascript;version=1.8">
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
let { UNKNOWN_ACTION, PROMPT_ACTION, ALLOW_ACTION, DENY_ACTION } =
|
<body>
|
||||||
SpecialPowers.Ci.nsIPermissionManager;
|
<pre id="test"></pre>
|
||||||
|
<script type="application/javascript;version=1.8">
|
||||||
|
/*globals SpecialPowers, SimpleTest, is, ok, */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
const {
|
||||||
|
UNKNOWN_ACTION,
|
||||||
|
PROMPT_ACTION,
|
||||||
|
ALLOW_ACTION,
|
||||||
|
DENY_ACTION
|
||||||
|
} = SpecialPowers.Ci.nsIPermissionManager;
|
||||||
|
|
||||||
const PERMISSIONS = [
|
SimpleTest.waitForExplicitFinish();
|
||||||
{ name: 'geolocation', perm: 'geo' },
|
|
||||||
{ name: 'notifications', perm: 'desktop-notification' },
|
|
||||||
{ name: 'push', perm: 'desktop-notification' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const UNSUPPORTED_PERMISSIONS = [
|
const PERMISSIONS = [{
|
||||||
'foobarbaz', // Not in spec, for testing only.
|
name: 'geolocation',
|
||||||
'midi'
|
type: 'geo'
|
||||||
];
|
}, {
|
||||||
|
name: 'notifications',
|
||||||
|
type: 'desktop-notification'
|
||||||
|
}, {
|
||||||
|
name: 'push',
|
||||||
|
type: 'desktop-notification'
|
||||||
|
}, ];
|
||||||
|
|
||||||
function setPermissions(action) {
|
const UNSUPPORTED_PERMISSIONS = [
|
||||||
let permissions = PERMISSIONS.map(x => {
|
'foobarbaz', // Not in spec, for testing only.
|
||||||
return { 'type': x.perm, 'allow': action, 'context': document };
|
'midi',
|
||||||
});
|
];
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
SpecialPowers.popPermissions(() => {
|
// Create a closure, so that tests are run on the correct window object.
|
||||||
SpecialPowers.pushPermissions(permissions, resolve);
|
function createPermissionTester(aWindow) {
|
||||||
|
return {
|
||||||
|
setPermissions(allow) {
|
||||||
|
const permissions = PERMISSIONS.map(({ type }) => {
|
||||||
|
return {
|
||||||
|
type,
|
||||||
|
allow,
|
||||||
|
'context': aWindow.document
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
SpecialPowers.popPermissions(() => {
|
||||||
|
SpecialPowers.pushPermissions(permissions, resolve);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
revokePermissions() {
|
||||||
|
const promisesToRevoke = PERMISSIONS.map(({ name }) => {
|
||||||
|
return aWindow.navigator.permissions
|
||||||
|
.revoke({ name })
|
||||||
|
.then(
|
||||||
|
({ state }) => is(state, 'prompt', `correct state for '${name}'`),
|
||||||
|
() => ok(false, `revoke should not have rejected for '${name}'`)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return Promise.all(promisesToRevoke);
|
||||||
|
},
|
||||||
|
revokeUnsupportedPermissions() {
|
||||||
|
const promisesToRevoke = UNSUPPORTED_PERMISSIONS.map(({ name }) => {
|
||||||
|
return aWindow.navigator.permissions
|
||||||
|
.revoke({ name })
|
||||||
|
.then(
|
||||||
|
() => ok(false, `revoke should not have resolved for '${name}'`),
|
||||||
|
error => is(error.name, 'TypeError', `revoke should have thrown TypeError for '${name}'`)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return Promise.all(promisesToRevoke);
|
||||||
|
},
|
||||||
|
checkPermissions(state) {
|
||||||
|
const promisesToQuery = PERMISSIONS.map(({ name }) => {
|
||||||
|
return aWindow.navigator.permissions
|
||||||
|
.query({ name })
|
||||||
|
.then(
|
||||||
|
() => is(state, state, `correct state for '${name}'`),
|
||||||
|
() => ok(false, `query should not have rejected for '${name}'`)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return Promise.all(promisesToQuery);
|
||||||
|
},
|
||||||
|
checkUnsupportedPermissions() {
|
||||||
|
const promisesToQuery = UNSUPPORTED_PERMISSIONS.map(({ name }) => {
|
||||||
|
return aWindow.navigator.permissions
|
||||||
|
.query({ name })
|
||||||
|
.then(
|
||||||
|
() => ok(false, `query should not have resolved for '${name}'`),
|
||||||
|
error => {
|
||||||
|
is(error.name, 'TypeError',
|
||||||
|
`query should have thrown TypeError for '${name}'`);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return Promise.all(promisesToQuery);
|
||||||
|
},
|
||||||
|
promiseStateChanged(name, state) {
|
||||||
|
return aWindow.navigator.permissions
|
||||||
|
.query({ name })
|
||||||
|
.then(status => {
|
||||||
|
return new Promise( resolve => {
|
||||||
|
status.onchange = () => {
|
||||||
|
status.onchange = null;
|
||||||
|
is(status.state, state, `state changed for '${name}'`);
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
() => ok(false, `query should not have rejected for '${name}'`));
|
||||||
|
},
|
||||||
|
testStatusOnChange() {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
SpecialPowers.popPermissions(() => {
|
||||||
|
const permission = 'geolocation';
|
||||||
|
const promiseGranted = this.promiseStateChanged(permission, 'granted');
|
||||||
|
this.setPermissions(ALLOW_ACTION);
|
||||||
|
promiseGranted.then(() => {
|
||||||
|
const promisePrompt = this.promiseStateChanged(permission, 'prompt');
|
||||||
|
SpecialPowers.popPermissions();
|
||||||
|
return promisePrompt;
|
||||||
|
}).then(resolve);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
testInvalidQuery() {
|
||||||
|
return aWindow.navigator.permissions
|
||||||
|
.query({ name: 'invalid' })
|
||||||
|
.then(
|
||||||
|
() => ok(false, 'invalid query should not have resolved'),
|
||||||
|
() => ok(true, 'invalid query should have rejected')
|
||||||
|
);
|
||||||
|
},
|
||||||
|
testInvalidRevoke() {
|
||||||
|
return aWindow.navigator.permissions
|
||||||
|
.revoke({ name: 'invalid' })
|
||||||
|
.then(
|
||||||
|
() => ok(false, 'invalid revoke should not have resolved'),
|
||||||
|
() => ok(true, 'invalid revoke should have rejected')
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function enablePrefs() {
|
||||||
|
const ops = {
|
||||||
|
'set': [
|
||||||
|
['dom.permissions.revoke.enable', true],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
return SpecialPowers.pushPrefEnv(ops);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createIframe() {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const iframe = document.createElement('iframe');
|
||||||
|
iframe.src = 'file_empty.html';
|
||||||
|
iframe.onload = () => resolve(iframe.contentWindow);
|
||||||
|
document.body.appendChild(iframe);
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
debugger;
|
||||||
|
window.onload = () => {
|
||||||
function revokePermissions(action) {
|
enablePrefs()
|
||||||
return Promise.all(PERMISSIONS.map(x =>
|
.then(createIframe)
|
||||||
navigator.permissions.revoke({ name: x.name }).then(
|
.then(createPermissionTester)
|
||||||
result => is(result.state, "prompt", `correct state for '${x.name}'`),
|
.then((tester) => {
|
||||||
error => ok(false, `revoke should not have rejected for '${x.name}'`))
|
return tester
|
||||||
));
|
.checkUnsupportedPermissions()
|
||||||
}
|
.then(() => tester.setPermissions(UNKNOWN_ACTION))
|
||||||
|
.then(() => tester.checkPermissions('prompt'))
|
||||||
function revokeUnsupportedPermissions() {
|
.then(() => tester.setPermissions(PROMPT_ACTION))
|
||||||
return Promise.all(UNSUPPORTED_PERMISSIONS.map(name =>
|
.then(() => tester.checkPermissions('prompt'))
|
||||||
navigator.permissions.revoke({ name: name }).then(
|
.then(() => tester.setPermissions(ALLOW_ACTION))
|
||||||
result => ok(false, `revoke should not have resolved for '${name}'`),
|
.then(() => tester.checkPermissions('granted'))
|
||||||
error => is(error.name, 'TypeError', `revoke should have thrown TypeError for '${name}'`))
|
.then(() => tester.setPermissions(DENY_ACTION))
|
||||||
));
|
.then(() => tester.checkPermissions('denied'))
|
||||||
}
|
.then(() => tester.testStatusOnChange())
|
||||||
|
.then(() => tester.testInvalidQuery())
|
||||||
function checkPermissions(state) {
|
.then(() => tester.revokeUnsupportedPermissions())
|
||||||
return Promise.all(PERMISSIONS.map(x => {
|
.then(() => tester.revokePermissions())
|
||||||
return navigator.permissions.query({ name: x.name }).then(
|
.then(() => tester.checkPermissions('prompt'))
|
||||||
result => is(result.state, state, `correct state for '${x.name}'`),
|
.then(() => tester.testInvalidRevoke());
|
||||||
error => ok(false, `query should not have rejected for '${x.name}'`));
|
})
|
||||||
}));
|
.then(SimpleTest.finish)
|
||||||
}
|
.catch((e) => {
|
||||||
|
ok(false, `Unexpected error ${e}`);
|
||||||
function checkUnsupportedPermissions() {
|
SimpleTest.finish();
|
||||||
return Promise.all(UNSUPPORTED_PERMISSIONS.map(name => {
|
|
||||||
return navigator.permissions.query({ name: name }).then(
|
|
||||||
result => ok(false, `query should not have resolved for '${name}'`),
|
|
||||||
error => {
|
|
||||||
is(error.name, 'TypeError',
|
|
||||||
`query should have thrown TypeError for '${name}'`);
|
|
||||||
});
|
});
|
||||||
}));
|
};
|
||||||
}
|
</script>
|
||||||
|
|
||||||
function promiseStateChanged(name, state) {
|
|
||||||
return navigator.permissions.query({ name }).then(
|
|
||||||
status => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
status.onchange = () => {
|
|
||||||
status.onchange = null;
|
|
||||||
is(status.state, state, `state changed for '${name}'`);
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
|
||||||
error => ok(false, `query should not have rejected for '${name}'`));
|
|
||||||
}
|
|
||||||
|
|
||||||
function testStatusOnChange() {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
SpecialPowers.popPermissions(() => {
|
|
||||||
let permission = 'geolocation';
|
|
||||||
let promiseGranted = promiseStateChanged(permission, 'granted');
|
|
||||||
setPermissions(ALLOW_ACTION);
|
|
||||||
promiseGranted.then(() => {
|
|
||||||
let promisePrompt = promiseStateChanged(permission, 'prompt');
|
|
||||||
SpecialPowers.popPermissions();
|
|
||||||
return promisePrompt;
|
|
||||||
}).then(resolve);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function testInvalidQuery() {
|
|
||||||
navigator.permissions.query({ name: 'invalid' }).then(
|
|
||||||
result => ok(false, 'invalid query should not have resolved'),
|
|
||||||
error => ok(true, 'invalid query should have rejected'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function testInvalidRevoke() {
|
|
||||||
navigator.permissions.revoke({ name: 'invalid' }).then(
|
|
||||||
result => ok(false, 'invalid revoke should not have resolved'),
|
|
||||||
error => ok(true, 'invalid revoke should have rejected'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function runTests() {
|
|
||||||
checkUnsupportedPermissions()
|
|
||||||
.then(() => setPermissions(UNKNOWN_ACTION))
|
|
||||||
.then(() => checkPermissions('prompt'))
|
|
||||||
.then(() => setPermissions(PROMPT_ACTION))
|
|
||||||
.then(() => checkPermissions('prompt'))
|
|
||||||
.then(() => setPermissions(ALLOW_ACTION))
|
|
||||||
.then(() => checkPermissions('granted'))
|
|
||||||
.then(() => setPermissions(DENY_ACTION))
|
|
||||||
.then(() => checkPermissions('denied'))
|
|
||||||
.then(testStatusOnChange)
|
|
||||||
.then(testInvalidQuery)
|
|
||||||
.then(revokeUnsupportedPermissions)
|
|
||||||
.then(revokePermissions)
|
|
||||||
.then(() => checkPermissions('prompt'))
|
|
||||||
.then(testInvalidRevoke)
|
|
||||||
.then(SimpleTest.finish)
|
|
||||||
.catch ((e) => {
|
|
||||||
ok(false, 'Unexpected error ' + e);
|
|
||||||
SimpleTest.finish();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</pre>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -411,7 +411,6 @@ nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
|
||||||
return rv;
|
return rv;
|
||||||
|
|
||||||
// create a file output stream to write to...
|
// create a file output stream to write to...
|
||||||
nsCOMPtr<nsIOutputStream> outstream;
|
|
||||||
rv = NS_NewLocalFileOutputStream(getter_AddRefs(mFileCacheOutputStream), pluginTmp, -1, 00600);
|
rv = NS_NewLocalFileOutputStream(getter_AddRefs(mFileCacheOutputStream), pluginTmp, -1, 00600);
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
return rv;
|
return rv;
|
||||||
|
|
|
@ -3355,7 +3355,6 @@ PluginInstanceChild::CreateOptSurface(void)
|
||||||
"Need a valid surface type here");
|
"Need a valid surface type here");
|
||||||
NS_ASSERTION(!mCurrentSurface, "mCurrentSurfaceActor can get out of sync.");
|
NS_ASSERTION(!mCurrentSurface, "mCurrentSurfaceActor can get out of sync.");
|
||||||
|
|
||||||
RefPtr<gfxASurface> retsurf;
|
|
||||||
// Use an opaque surface unless we're transparent and *don't* have
|
// Use an opaque surface unless we're transparent and *don't* have
|
||||||
// a background to source from.
|
// a background to source from.
|
||||||
gfxImageFormat format =
|
gfxImageFormat format =
|
||||||
|
@ -3581,7 +3580,9 @@ PluginInstanceChild::EnsureCurrentBuffer(void)
|
||||||
void
|
void
|
||||||
PluginInstanceChild::UpdateWindowAttributes(bool aForceSetWindow)
|
PluginInstanceChild::UpdateWindowAttributes(bool aForceSetWindow)
|
||||||
{
|
{
|
||||||
|
#if defined(MOZ_X11) || defined(XP_WIN)
|
||||||
RefPtr<gfxASurface> curSurface = mHelperSurface ? mHelperSurface : mCurrentSurface;
|
RefPtr<gfxASurface> curSurface = mHelperSurface ? mHelperSurface : mCurrentSurface;
|
||||||
|
#endif // Only used within MOZ_X11 or XP_WIN blocks. Unused variable otherwise
|
||||||
bool needWindowUpdate = aForceSetWindow;
|
bool needWindowUpdate = aForceSetWindow;
|
||||||
#ifdef MOZ_X11
|
#ifdef MOZ_X11
|
||||||
Visual* visual = nullptr;
|
Visual* visual = nullptr;
|
||||||
|
|
|
@ -7488,8 +7488,6 @@ UpgradeDirectoryMetadataFrom1To2Helper::DoProcessOriginDirectories()
|
||||||
{
|
{
|
||||||
AssertIsOnIOThread();
|
AssertIsOnIOThread();
|
||||||
|
|
||||||
nsCOMPtr<nsIFile> permanentStorageDir;
|
|
||||||
|
|
||||||
for (uint32_t count = mOriginProps.Length(), index = 0;
|
for (uint32_t count = mOriginProps.Length(), index = 0;
|
||||||
index < count;
|
index < count;
|
||||||
index++) {
|
index++) {
|
||||||
|
|
|
@ -457,7 +457,6 @@ DOMStorageDBThread::OpenDatabaseConnection()
|
||||||
= do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
|
= do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
nsCOMPtr<mozIStorageConnection> connection;
|
|
||||||
rv = service->OpenUnsharedDatabase(mDatabaseFile, getter_AddRefs(mWorkerConnection));
|
rv = service->OpenUnsharedDatabase(mDatabaseFile, getter_AddRefs(mWorkerConnection));
|
||||||
if (rv == NS_ERROR_FILE_CORRUPTED) {
|
if (rv == NS_ERROR_FILE_CORRUPTED) {
|
||||||
// delete the db and try opening again
|
// delete the db and try opening again
|
||||||
|
|
|
@ -25,6 +25,6 @@ dictionary PermissionDescriptor {
|
||||||
interface Permissions {
|
interface Permissions {
|
||||||
[Throws]
|
[Throws]
|
||||||
Promise<PermissionStatus> query(object permission);
|
Promise<PermissionStatus> query(object permission);
|
||||||
[Throws]
|
[Throws, Pref="dom.permissions.revoke.enable"]
|
||||||
Promise<PermissionStatus> revoke(object permission);
|
Promise<PermissionStatus> revoke(object permission);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1050,7 +1050,8 @@ public:
|
||||||
const nsString& aLine, uint32_t aLineNumber,
|
const nsString& aLine, uint32_t aLineNumber,
|
||||||
uint32_t aColumnNumber, uint32_t aFlags,
|
uint32_t aColumnNumber, uint32_t aFlags,
|
||||||
uint32_t aErrorNumber, JSExnType aExnType,
|
uint32_t aErrorNumber, JSExnType aExnType,
|
||||||
bool aMutedError, uint64_t aInnerWindowId)
|
bool aMutedError, uint64_t aInnerWindowId,
|
||||||
|
JS::Handle<JS::Value> aException = JS::NullHandleValue)
|
||||||
{
|
{
|
||||||
if (aWorkerPrivate) {
|
if (aWorkerPrivate) {
|
||||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||||
|
@ -1070,6 +1071,7 @@ public:
|
||||||
init.mMessage = aMessage;
|
init.mMessage = aMessage;
|
||||||
init.mFilename = aFilename;
|
init.mFilename = aFilename;
|
||||||
init.mLineno = aLineNumber;
|
init.mLineno = aLineNumber;
|
||||||
|
init.mError = aException;
|
||||||
}
|
}
|
||||||
|
|
||||||
init.mCancelable = true;
|
init.mCancelable = true;
|
||||||
|
@ -5919,6 +5921,12 @@ WorkerPrivate::ReportError(JSContext* aCx, const char* aFallbackMessage,
|
||||||
mErrorHandlerRecursionCount == 1,
|
mErrorHandlerRecursionCount == 1,
|
||||||
"Bad recursion logic!");
|
"Bad recursion logic!");
|
||||||
|
|
||||||
|
JS::Rooted<JS::Value> exn(aCx);
|
||||||
|
if (!JS_GetPendingException(aCx, &exn)) {
|
||||||
|
// Probably shouldn't actually happen? But let's go ahead and just use null
|
||||||
|
// for lack of anything better.
|
||||||
|
exn.setNull();
|
||||||
|
}
|
||||||
JS_ClearPendingException(aCx);
|
JS_ClearPendingException(aCx);
|
||||||
|
|
||||||
nsString message, filename, line;
|
nsString message, filename, line;
|
||||||
|
@ -5966,7 +5974,7 @@ WorkerPrivate::ReportError(JSContext* aCx, const char* aFallbackMessage,
|
||||||
ReportErrorRunnable::ReportError(aCx, this, fireAtScope, nullptr, message,
|
ReportErrorRunnable::ReportError(aCx, this, fireAtScope, nullptr, message,
|
||||||
filename, line, lineNumber,
|
filename, line, lineNumber,
|
||||||
columnNumber, flags, errorNumber, exnType,
|
columnNumber, flags, errorNumber, exnType,
|
||||||
mutedError, 0);
|
mutedError, 0, exn);
|
||||||
|
|
||||||
mErrorHandlerRecursionCount--;
|
mErrorHandlerRecursionCount--;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2613,7 +2613,7 @@ XMLHttpRequestMainThread::InitiateFetch(nsIInputStream* aUploadStream,
|
||||||
|
|
||||||
// Per spec, we throw on sync errors, but not async.
|
// Per spec, we throw on sync errors, but not async.
|
||||||
if (mFlagSynchronous) {
|
if (mFlagSynchronous) {
|
||||||
return rv;
|
return NS_ERROR_DOM_NETWORK_ERR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2874,7 +2874,7 @@ XMLHttpRequestMainThread::SendInternal(const RequestBodyBase* aBody)
|
||||||
if (!mChannel) {
|
if (!mChannel) {
|
||||||
// Per spec, silently fail on async request failures; throw for sync.
|
// Per spec, silently fail on async request failures; throw for sync.
|
||||||
if (mFlagSynchronous) {
|
if (mFlagSynchronous) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_DOM_NETWORK_ERR;
|
||||||
} else {
|
} else {
|
||||||
// Defer the actual sending of async events just in case listeners
|
// Defer the actual sending of async events just in case listeners
|
||||||
// are attached after the send() method is called.
|
// are attached after the send() method is called.
|
||||||
|
|
|
@ -167,8 +167,6 @@ nsXMLFragmentContentSink::WillBuildModel(nsDTDMode aDTDMode)
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsXMLFragmentContentSink::DidBuildModel(bool aTerminated)
|
nsXMLFragmentContentSink::DidBuildModel(bool aTerminated)
|
||||||
{
|
{
|
||||||
RefPtr<nsParserBase> kungFuDeathGrip(mParser);
|
|
||||||
|
|
||||||
// Drop our reference to the parser to get rid of a circular
|
// Drop our reference to the parser to get rid of a circular
|
||||||
// reference.
|
// reference.
|
||||||
mParser = nullptr;
|
mParser = nullptr;
|
||||||
|
|
|
@ -225,7 +225,6 @@ nsXULTemplateQueryProcessorStorage::GetDatasource(nsIArray* aDataSources,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIFile> file;
|
|
||||||
rv = fileChannel->GetFile(getter_AddRefs(databaseFile));
|
rv = fileChannel->GetFile(getter_AddRefs(databaseFile));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
|
@ -281,11 +281,10 @@ RectTyped<units> IntRectToRect(const IntRectTyped<units>& aRect)
|
||||||
return RectTyped<units>(aRect.x, aRect.y, aRect.width, aRect.height);
|
return RectTyped<units>(aRect.x, aRect.y, aRect.width, aRect.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convenience function for intersecting two IntRects wrapped in Maybes.
|
// Convenience function for intersecting two rectangles wrapped in Maybes.
|
||||||
template <typename Units>
|
template <typename T>
|
||||||
Maybe<IntRectTyped<Units>>
|
Maybe<T>
|
||||||
IntersectMaybeRects(const Maybe<IntRectTyped<Units>>& a,
|
IntersectMaybeRects(const Maybe<T>& a, const Maybe<T>& b)
|
||||||
const Maybe<IntRectTyped<Units>>& b)
|
|
||||||
{
|
{
|
||||||
if (!a) {
|
if (!a) {
|
||||||
return b;
|
return b;
|
||||||
|
|
|
@ -51,7 +51,7 @@ public:
|
||||||
virtual void SetContentController(GeckoContentController* aController) = 0;
|
virtual void SetContentController(GeckoContentController* aController) = 0;
|
||||||
|
|
||||||
// Return the Async Pan/Zoom Tree Manager for this compositor.
|
// Return the Async Pan/Zoom Tree Manager for this compositor.
|
||||||
virtual already_AddRefed<IAPZCTreeManager> GetAPZCTreeManager() const = 0;
|
virtual RefPtr<IAPZCTreeManager> GetAPZCTreeManager() const = 0;
|
||||||
|
|
||||||
// Return the child end of the compositor IPC bridge.
|
// Return the child end of the compositor IPC bridge.
|
||||||
CompositorBridgeChild* GetCompositorBridgeChild();
|
CompositorBridgeChild* GetCompositorBridgeChild();
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "mozilla/Assertions.h"
|
#include "mozilla/Assertions.h"
|
||||||
#include "mozilla/gfx/gfxVars.h"
|
#include "mozilla/gfx/gfxVars.h"
|
||||||
#include "mozilla/ipc/ProcessChild.h"
|
#include "mozilla/ipc/ProcessChild.h"
|
||||||
|
#include "mozilla/layers/APZThreadUtils.h"
|
||||||
#include "mozilla/layers/CompositorBridgeParent.h"
|
#include "mozilla/layers/CompositorBridgeParent.h"
|
||||||
#include "mozilla/layers/CompositorThread.h"
|
#include "mozilla/layers/CompositorThread.h"
|
||||||
#include "mozilla/layers/ImageBridgeParent.h"
|
#include "mozilla/layers/ImageBridgeParent.h"
|
||||||
|
@ -63,6 +64,7 @@ GPUParent::Init(base::ProcessId aParentPid,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
CompositorThreadHolder::Start();
|
CompositorThreadHolder::Start();
|
||||||
|
APZThreadUtils::SetControllerThread(CompositorThreadHolder::Loop());
|
||||||
VRManager::ManagerInit();
|
VRManager::ManagerInit();
|
||||||
LayerTreeOwnerTracker::Initialize();
|
LayerTreeOwnerTracker::Initialize();
|
||||||
mozilla::ipc::SetThisProcessName("GPU Process");
|
mozilla::ipc::SetThisProcessName("GPU Process");
|
||||||
|
@ -170,8 +172,12 @@ GPUParent::RecvGetDeviceStatus(GPUDeviceData* aOut)
|
||||||
|
|
||||||
#if defined(XP_WIN)
|
#if defined(XP_WIN)
|
||||||
if (DeviceManagerDx* dm = DeviceManagerDx::Get()) {
|
if (DeviceManagerDx* dm = DeviceManagerDx::Get()) {
|
||||||
dm->ExportDeviceInfo(&aOut->d3d11Device());
|
D3D11DeviceStatus deviceStatus;
|
||||||
|
dm->ExportDeviceInfo(&deviceStatus);
|
||||||
|
aOut->gpuDevice() = deviceStatus;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
aOut->gpuDevice() = null_t();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "mozilla/StaticPtr.h"
|
#include "mozilla/StaticPtr.h"
|
||||||
#include "mozilla/dom/ContentParent.h"
|
#include "mozilla/dom/ContentParent.h"
|
||||||
#include "mozilla/layers/APZCTreeManager.h"
|
#include "mozilla/layers/APZCTreeManager.h"
|
||||||
|
#include "mozilla/layers/APZCTreeManagerChild.h"
|
||||||
#include "mozilla/layers/CompositorBridgeParent.h"
|
#include "mozilla/layers/CompositorBridgeParent.h"
|
||||||
#include "mozilla/layers/ImageBridgeChild.h"
|
#include "mozilla/layers/ImageBridgeChild.h"
|
||||||
#include "mozilla/layers/ImageBridgeParent.h"
|
#include "mozilla/layers/ImageBridgeParent.h"
|
||||||
|
@ -394,8 +395,17 @@ GPUProcessManager::CreateRemoteSession(nsBaseWidget* aWidget,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RefPtr<APZCTreeManagerChild> apz = nullptr;
|
||||||
|
if (aUseAPZ) {
|
||||||
|
PAPZCTreeManagerChild* papz = child->SendPAPZCTreeManagerConstructor(0);
|
||||||
|
if (!papz) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
apz = static_cast<APZCTreeManagerChild*>(papz);
|
||||||
|
}
|
||||||
|
|
||||||
RefPtr<RemoteCompositorSession> session =
|
RefPtr<RemoteCompositorSession> session =
|
||||||
new RemoteCompositorSession(child, widget, aRootLayerTreeId);
|
new RemoteCompositorSession(child, widget, apz, aRootLayerTreeId);
|
||||||
return session.forget();
|
return session.forget();
|
||||||
#else
|
#else
|
||||||
gfxCriticalNote << "Platform does not support out-of-process compositing";
|
gfxCriticalNote << "Platform does not support out-of-process compositing";
|
||||||
|
|
|
@ -54,12 +54,18 @@ union FeatureChange
|
||||||
FeatureFailure;
|
FeatureFailure;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
union GPUDeviceStatus
|
||||||
|
{
|
||||||
|
null_t;
|
||||||
|
D3D11DeviceStatus;
|
||||||
|
};
|
||||||
|
|
||||||
struct GPUDeviceData
|
struct GPUDeviceData
|
||||||
{
|
{
|
||||||
FeatureChange d3d11Compositing;
|
FeatureChange d3d11Compositing;
|
||||||
FeatureChange d3d9Compositing;
|
FeatureChange d3d9Compositing;
|
||||||
FeatureChange oglCompositing;
|
FeatureChange oglCompositing;
|
||||||
D3D11DeviceStatus d3d11Device;
|
GPUDeviceStatus gpuDevice;
|
||||||
};
|
};
|
||||||
|
|
||||||
union GfxVarValue
|
union GfxVarValue
|
||||||
|
|
|
@ -54,7 +54,7 @@ InProcessCompositorSession::SetContentController(GeckoContentController* aContro
|
||||||
mCompositorBridgeParent->SetControllerForLayerTree(mRootLayerTreeId, aController);
|
mCompositorBridgeParent->SetControllerForLayerTree(mRootLayerTreeId, aController);
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<IAPZCTreeManager>
|
RefPtr<IAPZCTreeManager>
|
||||||
InProcessCompositorSession::GetAPZCTreeManager() const
|
InProcessCompositorSession::GetAPZCTreeManager() const
|
||||||
{
|
{
|
||||||
return mCompositorBridgeParent->GetAPZCTreeManager(mRootLayerTreeId);
|
return mCompositorBridgeParent->GetAPZCTreeManager(mRootLayerTreeId);
|
||||||
|
|
|
@ -29,7 +29,7 @@ public:
|
||||||
|
|
||||||
CompositorBridgeParent* GetInProcessBridge() const override;
|
CompositorBridgeParent* GetInProcessBridge() const override;
|
||||||
void SetContentController(GeckoContentController* aController) override;
|
void SetContentController(GeckoContentController* aController) override;
|
||||||
already_AddRefed<IAPZCTreeManager> GetAPZCTreeManager() const override;
|
RefPtr<IAPZCTreeManager> GetAPZCTreeManager() const override;
|
||||||
void Shutdown() override;
|
void Shutdown() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -3,8 +3,12 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "RemoteCompositorSession.h"
|
#include "RemoteCompositorSession.h"
|
||||||
|
|
||||||
|
#include "mozilla/layers/APZChild.h"
|
||||||
|
#include "mozilla/layers/APZCTreeManagerChild.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace layers {
|
namespace layers {
|
||||||
|
|
||||||
|
@ -13,8 +17,10 @@ using namespace widget;
|
||||||
|
|
||||||
RemoteCompositorSession::RemoteCompositorSession(CompositorBridgeChild* aChild,
|
RemoteCompositorSession::RemoteCompositorSession(CompositorBridgeChild* aChild,
|
||||||
CompositorWidgetDelegate* aWidgetDelegate,
|
CompositorWidgetDelegate* aWidgetDelegate,
|
||||||
|
APZCTreeManagerChild* aAPZ,
|
||||||
const uint64_t& aRootLayerTreeId)
|
const uint64_t& aRootLayerTreeId)
|
||||||
: CompositorSession(aWidgetDelegate, aChild, aRootLayerTreeId)
|
: CompositorSession(aWidgetDelegate, aChild, aRootLayerTreeId)
|
||||||
|
, mAPZ(aAPZ)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,13 +33,13 @@ RemoteCompositorSession::GetInProcessBridge() const
|
||||||
void
|
void
|
||||||
RemoteCompositorSession::SetContentController(GeckoContentController* aController)
|
RemoteCompositorSession::SetContentController(GeckoContentController* aController)
|
||||||
{
|
{
|
||||||
MOZ_CRASH("NYI");
|
mCompositorBridgeChild->SendPAPZConstructor(new APZChild(aController), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<IAPZCTreeManager>
|
RefPtr<IAPZCTreeManager>
|
||||||
RemoteCompositorSession::GetAPZCTreeManager() const
|
RemoteCompositorSession::GetAPZCTreeManager() const
|
||||||
{
|
{
|
||||||
return nullptr;
|
return mAPZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -18,13 +18,16 @@ class RemoteCompositorSession final : public CompositorSession
|
||||||
public:
|
public:
|
||||||
RemoteCompositorSession(CompositorBridgeChild* aChild,
|
RemoteCompositorSession(CompositorBridgeChild* aChild,
|
||||||
CompositorWidgetDelegate* aWidgetDelegate,
|
CompositorWidgetDelegate* aWidgetDelegate,
|
||||||
|
APZCTreeManagerChild* aAPZ,
|
||||||
const uint64_t& aRootLayerTreeId);
|
const uint64_t& aRootLayerTreeId);
|
||||||
|
|
||||||
CompositorBridgeParent* GetInProcessBridge() const override;
|
CompositorBridgeParent* GetInProcessBridge() const override;
|
||||||
void SetContentController(GeckoContentController* aController) override;
|
void SetContentController(GeckoContentController* aController) override;
|
||||||
already_AddRefed<IAPZCTreeManager> GetAPZCTreeManager() const override;
|
RefPtr<IAPZCTreeManager> GetAPZCTreeManager() const override;
|
||||||
void Shutdown() override;
|
void Shutdown() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
RefPtr<APZCTreeManagerChild> mAPZ;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace layers
|
} // namespace layers
|
||||||
|
|
|
@ -27,7 +27,11 @@ public:
|
||||||
/**
|
/**
|
||||||
* Requests a paint of the given FrameMetrics |aFrameMetrics| from Gecko.
|
* Requests a paint of the given FrameMetrics |aFrameMetrics| from Gecko.
|
||||||
* Implementations per-platform are responsible for actually handling this.
|
* Implementations per-platform are responsible for actually handling this.
|
||||||
* This method will always be called on the Gecko main thread.
|
*
|
||||||
|
* This method must always be called on the repaint thread, which depends
|
||||||
|
* on the GeckoContentController. For ChromeProcessController it is the
|
||||||
|
* Gecko main thread, while for RemoteContentController it is the compositor
|
||||||
|
* thread where it can send IPDL messages.
|
||||||
*/
|
*/
|
||||||
virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) = 0;
|
virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) = 0;
|
||||||
|
|
||||||
|
|
|
@ -171,6 +171,10 @@ ChromeProcessController::HandleTap(TapType aType,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!mAPZEventState) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
|
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
|
||||||
if (!presShell) {
|
if (!presShell) {
|
||||||
return;
|
return;
|
||||||
|
@ -217,6 +221,10 @@ ChromeProcessController::NotifyAPZStateChange(const ScrollableLayerGuid& aGuid,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!mAPZEventState) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mAPZEventState->ProcessAPZStateChange(GetRootDocument(), aGuid.mScrollId, aChange, aArg);
|
mAPZEventState->ProcessAPZStateChange(GetRootDocument(), aGuid.mScrollId, aChange, aArg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,14 @@ namespace layers {
|
||||||
class IAPZCTreeManager;
|
class IAPZCTreeManager;
|
||||||
class APZEventState;
|
class APZEventState;
|
||||||
|
|
||||||
// A ChromeProcessController is attached to the root of a compositor's layer
|
/**
|
||||||
// tree.
|
* ChromeProcessController is a GeckoContentController attached to the root of
|
||||||
|
* a compositor's layer tree. It's used directly by APZ by default, and remoted
|
||||||
|
* using PAPZ if there is a gpu process.
|
||||||
|
*
|
||||||
|
* If ChromeProcessController needs to implement a new method on GeckoContentController
|
||||||
|
* PAPZ, APZChild, and RemoteContentController must be updated to handle it.
|
||||||
|
*/
|
||||||
class ChromeProcessController : public mozilla::layers::GeckoContentController
|
class ChromeProcessController : public mozilla::layers::GeckoContentController
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -21,6 +21,17 @@ namespace layers {
|
||||||
|
|
||||||
class APZChild;
|
class APZChild;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ContentProcessController is a GeckoContentController for a TabChild, and is always
|
||||||
|
* remoted using PAPZ/APZChild.
|
||||||
|
*
|
||||||
|
* ContentProcessController is created in ContentChild when a layer tree id has
|
||||||
|
* been allocated for a PBrowser that lives in that content process, and is destroyed
|
||||||
|
* when the Destroy message is received, or when the tab dies.
|
||||||
|
*
|
||||||
|
* If ContentProcessController needs to implement a new method on GeckoContentController
|
||||||
|
* PAPZ, APZChild, and RemoteContentController must be updated to handle it.
|
||||||
|
*/
|
||||||
class ContentProcessController final
|
class ContentProcessController final
|
||||||
: public GeckoContentController
|
: public GeckoContentController
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,6 +15,10 @@ namespace layers {
|
||||||
|
|
||||||
class GeckoContentController;
|
class GeckoContentController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APZChild implements PAPZChild and is used to remote a GeckoContentController
|
||||||
|
* that lives in a different process than where APZ lives.
|
||||||
|
*/
|
||||||
class APZChild final : public PAPZChild
|
class APZChild final : public PAPZChild
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -1432,31 +1432,64 @@ CompositorBridgeParent::ForceComposeToTarget(DrawTarget* aTarget, const gfx::Int
|
||||||
PAPZCTreeManagerParent*
|
PAPZCTreeManagerParent*
|
||||||
CompositorBridgeParent::AllocPAPZCTreeManagerParent(const uint64_t& aLayersId)
|
CompositorBridgeParent::AllocPAPZCTreeManagerParent(const uint64_t& aLayersId)
|
||||||
{
|
{
|
||||||
return nullptr;
|
// The main process should pass in 0 because we assume mRootLayerTreeID
|
||||||
|
MOZ_ASSERT(aLayersId == 0);
|
||||||
|
|
||||||
|
// This message doubles as initialization
|
||||||
|
MOZ_ASSERT(!mApzcTreeManager);
|
||||||
|
mApzcTreeManager = new APZCTreeManager();
|
||||||
|
|
||||||
|
MonitorAutoLock lock(*sIndirectLayerTreesLock);
|
||||||
|
CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[mRootLayerTreeID];
|
||||||
|
MOZ_ASSERT(state.mParent);
|
||||||
|
MOZ_ASSERT(!state.mApzcTreeManagerParent);
|
||||||
|
state.mApzcTreeManagerParent = new APZCTreeManagerParent(mRootLayerTreeID, state.mParent->GetAPZCTreeManager());
|
||||||
|
|
||||||
|
return state.mApzcTreeManagerParent;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CompositorBridgeParent::DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent* aActor)
|
CompositorBridgeParent::DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent* aActor)
|
||||||
{
|
{
|
||||||
return false;
|
delete aActor;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
PAPZParent*
|
PAPZParent*
|
||||||
CompositorBridgeParent::AllocPAPZParent(const uint64_t& aLayersId)
|
CompositorBridgeParent::AllocPAPZParent(const uint64_t& aLayersId)
|
||||||
{
|
{
|
||||||
return nullptr;
|
// The main process should pass in 0 because we assume mRootLayerTreeID
|
||||||
|
MOZ_ASSERT(aLayersId == 0);
|
||||||
|
|
||||||
|
RemoteContentController* controller = new RemoteContentController();
|
||||||
|
|
||||||
|
// Increment the controller's refcount before we return it. This will keep the
|
||||||
|
// controller alive until it is released by IPDL in DeallocPAPZParent.
|
||||||
|
controller->AddRef();
|
||||||
|
|
||||||
|
MonitorAutoLock lock(*sIndirectLayerTreesLock);
|
||||||
|
CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[mRootLayerTreeID];
|
||||||
|
MOZ_ASSERT(!state.mController);
|
||||||
|
state.mController = controller;
|
||||||
|
|
||||||
|
return controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CompositorBridgeParent::DeallocPAPZParent(PAPZParent* aActor)
|
CompositorBridgeParent::DeallocPAPZParent(PAPZParent* aActor)
|
||||||
{
|
{
|
||||||
return false;
|
RemoteContentController* controller = static_cast<RemoteContentController*>(aActor);
|
||||||
|
controller->Release();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CompositorBridgeParent::RecvAsyncPanZoomEnabled(const uint64_t& aLayersId, bool* aHasAPZ)
|
CompositorBridgeParent::RecvAsyncPanZoomEnabled(const uint64_t& aLayersId, bool* aHasAPZ)
|
||||||
{
|
{
|
||||||
return false;
|
// The main process should pass in 0 because we assume mRootLayerTreeID
|
||||||
|
MOZ_ASSERT(aLayersId == 0);
|
||||||
|
*aHasAPZ = AsyncPanZoomEnabled();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<APZCTreeManager>
|
RefPtr<APZCTreeManager>
|
||||||
|
|
|
@ -29,13 +29,19 @@ namespace layers {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If APZ is enabled then one PAPZ will be opened per PBrowser between the
|
* PAPZ is a protocol for remoting a GeckoContentController. PAPZ lives on the
|
||||||
* process where the PBrowser child actor lives and the main process (the
|
* PCompositorBridge protocol which either connects to the compositor thread
|
||||||
* PBrowser parent actor doesn't necessarily live in the main process, for
|
* in the main process, or to the compositor thread in the gpu processs.
|
||||||
* example with nested browsers). This will typically be set up when the layers
|
|
||||||
* id is allocated for the PBrowser.
|
|
||||||
*
|
*
|
||||||
* Opened through PContent and runs on the main thread in both parent and child.
|
* PAPZParent lives in the compositor thread, while PAPZChild lives wherever the remoted
|
||||||
|
* GeckoContentController lives (generally the main thread of the main or content process).
|
||||||
|
* RemoteContentController implements PAPZParent, while APZChild implements PAPZChild.
|
||||||
|
*
|
||||||
|
* PAPZ is always used for ContentProcessController and only used for ChromeProcessController
|
||||||
|
* when there is a gpu process, otherwhise ChromeProcessController is used directly on the
|
||||||
|
* compositor thread. Only the methods that are used by the [Chrome,Content]ProcessController
|
||||||
|
* are implemented. If a new method is needed then PAPZ, APZChild, and RemoteContentController
|
||||||
|
* must be updated to handle it.
|
||||||
*/
|
*/
|
||||||
sync protocol PAPZ
|
sync protocol PAPZ
|
||||||
{
|
{
|
||||||
|
@ -48,6 +54,7 @@ parent:
|
||||||
async __delete__();
|
async __delete__();
|
||||||
|
|
||||||
child:
|
child:
|
||||||
|
|
||||||
async RequestContentRepaint(FrameMetrics frame);
|
async RequestContentRepaint(FrameMetrics frame);
|
||||||
|
|
||||||
// The aCallTakeFocusForClickFromTap argument is used for eSingleTap types,
|
// The aCallTakeFocusForClickFromTap argument is used for eSingleTap types,
|
||||||
|
|
|
@ -34,6 +34,15 @@ using class mozilla::ScrollWheelInput from "InputData.h";
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace layers {
|
namespace layers {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PAPZCTreeManager is a protocol for remoting an IAPZCTreeManager. PAPZCTreeManager
|
||||||
|
* lives on the PCompositorBridge protocol which either connects to the compositor
|
||||||
|
* thread in the main process, or to the compositor thread in the gpu processs.
|
||||||
|
*
|
||||||
|
* PAPZCTreeManagerParent lives in the compositor thread, while PAPZCTreeManagerChild
|
||||||
|
* lives in the main thread of the main or the content process. APZCTreeManagerParent
|
||||||
|
* and APZCTreeManagerChild implement this protocol.
|
||||||
|
*/
|
||||||
sync protocol PAPZCTreeManager
|
sync protocol PAPZCTreeManager
|
||||||
{
|
{
|
||||||
manager PCompositorBridge;
|
manager PCompositorBridge;
|
||||||
|
|
|
@ -20,11 +20,14 @@ class TabParent;
|
||||||
namespace layers {
|
namespace layers {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RemoteContentController uses the PAPZ protocol to implement a
|
* RemoteContentController implements PAPZChild and is used to access a
|
||||||
* GeckoContentController for a browser living in a remote process.
|
* GeckoContentController that lives in a different process.
|
||||||
* Most of the member functions can be called on any thread, exceptions are
|
*
|
||||||
* annotated in comments. The PAPZ protocol runs on the main thread (so all the
|
* RemoteContentController lives on the compositor thread. All methods can
|
||||||
* Recv* member functions do too).
|
* be called off the compositor thread and will get dispatched to the right
|
||||||
|
* thread, with the exception of RequestContentRepaint and NotifyFlushComplete,
|
||||||
|
* which must be called on the repaint thread, which in this case is the compositor
|
||||||
|
* thread.
|
||||||
*/
|
*/
|
||||||
class RemoteContentController : public GeckoContentController
|
class RemoteContentController : public GeckoContentController
|
||||||
, public PAPZParent
|
, public PAPZParent
|
||||||
|
|
|
@ -219,6 +219,9 @@ public:
|
||||||
if (!gFontHintingEnabled || !isAxisAligned(*rec)) {
|
if (!gFontHintingEnabled || !isAxisAligned(*rec)) {
|
||||||
rec->setHinting(SkPaint::kNo_Hinting);
|
rec->setHinting(SkPaint::kNo_Hinting);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't apply any gamma so that we match cairo-ft's results.
|
||||||
|
rec->ignorePreBlend();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const override
|
virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const override
|
||||||
|
@ -760,7 +763,7 @@ void SkScalerContext_CairoFT::generatePath(const SkGlyph& glyph, SkPath* path)
|
||||||
CairoLockedFTFace faceLock(fScaledFont);
|
CairoLockedFTFace faceLock(fScaledFont);
|
||||||
FT_Face face = faceLock.getFace();
|
FT_Face face = faceLock.getFace();
|
||||||
|
|
||||||
SkASSERT(&glyph && path);
|
SkASSERT(path);
|
||||||
|
|
||||||
uint32_t flags = fLoadGlyphFlags;
|
uint32_t flags = fLoadGlyphFlags;
|
||||||
flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline
|
flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline
|
||||||
|
@ -780,7 +783,9 @@ void SkScalerContext_CairoFT::generatePath(const SkGlyph& glyph, SkPath* path)
|
||||||
|
|
||||||
void SkScalerContext_CairoFT::generateFontMetrics(SkPaint::FontMetrics* metrics)
|
void SkScalerContext_CairoFT::generateFontMetrics(SkPaint::FontMetrics* metrics)
|
||||||
{
|
{
|
||||||
SkDEBUGCODE(SkDebugf("SkScalerContext_CairoFT::generateFontMetrics unimplemented\n"));
|
if (metrics) {
|
||||||
|
memset(metrics, 0, sizeof(SkPaint::FontMetrics));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SkUnichar SkScalerContext_CairoFT::generateGlyphToChar(uint16_t glyph)
|
SkUnichar SkScalerContext_CairoFT::generateGlyphToChar(uint16_t glyph)
|
||||||
|
|
|
@ -2004,7 +2004,7 @@ gfxWindowsPlatform::ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData
|
||||||
|
|
||||||
DeviceManagerDx* dm = DeviceManagerDx::Get();
|
DeviceManagerDx* dm = DeviceManagerDx::Get();
|
||||||
if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
|
if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
|
||||||
dm->ImportDeviceInfo(aData.d3d11Device());
|
dm->ImportDeviceInfo(aData.gpuDevice().get_D3D11DeviceStatus());
|
||||||
} else {
|
} else {
|
||||||
// There should be no devices, so this just takes away the device status.
|
// There should be no devices, so this just takes away the device status.
|
||||||
dm->ResetDevices();
|
dm->ResetDevices();
|
||||||
|
|
|
@ -23,6 +23,10 @@
|
||||||
#include "prenv.h"
|
#include "prenv.h"
|
||||||
#include "nsXPCOMPrivate.h"
|
#include "nsXPCOMPrivate.h"
|
||||||
|
|
||||||
|
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||||
|
#include "nsAppDirectoryServiceDefs.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "nsExceptionHandler.h"
|
#include "nsExceptionHandler.h"
|
||||||
|
|
||||||
#include "nsDirectoryServiceDefs.h"
|
#include "nsDirectoryServiceDefs.h"
|
||||||
|
@ -608,6 +612,20 @@ AddAppDirToCommandLine(std::vector<std::string>& aCmdLine)
|
||||||
aCmdLine.push_back(path.get());
|
aCmdLine.push_back(path.get());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||||
|
// Full path to the profile dir
|
||||||
|
nsCOMPtr<nsIFile> profileDir;
|
||||||
|
rv = directoryService->Get(NS_APP_USER_PROFILE_50_DIR,
|
||||||
|
NS_GET_IID(nsIFile),
|
||||||
|
getter_AddRefs(profileDir));
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
nsAutoCString path;
|
||||||
|
MOZ_ALWAYS_SUCCEEDS(profileDir->GetNativePath(path));
|
||||||
|
aCmdLine.push_back("-profile");
|
||||||
|
aCmdLine.push_back(path.get());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -464,5 +464,17 @@ void ArrayLengthReadError(const char* aElementName)
|
||||||
NS_RUNTIMEABORT(message.get());
|
NS_RUNTIMEABORT(message.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TableToArray(const nsTHashtable<nsPtrHashKey<void>>& aTable,
|
||||||
|
nsTArray<void*>& aArray)
|
||||||
|
{
|
||||||
|
uint32_t i = 0;
|
||||||
|
void** elements = aArray.AppendElements(aTable.Count());
|
||||||
|
for (auto iter = aTable.ConstIter(); !iter.Done(); iter.Next()) {
|
||||||
|
elements[i] = iter.Get()->GetKey();
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ipc
|
} // namespace ipc
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||||
* vim: sw=4 ts=4 et :
|
* vim: sw=4 ts=4 et :
|
||||||
*/
|
*/
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
@ -121,11 +121,13 @@ struct Trigger
|
||||||
|
|
||||||
Trigger(Action action, int32_t msg) :
|
Trigger(Action action, int32_t msg) :
|
||||||
mAction(action),
|
mAction(action),
|
||||||
mMsg(msg)
|
mMessage(msg)
|
||||||
{}
|
{
|
||||||
|
MOZ_ASSERT(0 <= msg && msg < INT32_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
Action mAction;
|
uint32_t mAction : 1;
|
||||||
int32_t mMsg;
|
uint32_t mMessage : 31;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ProtocolCloneContext
|
class ProtocolCloneContext
|
||||||
|
@ -604,10 +606,31 @@ CreateEndpoints(const PrivateIPDLInterface& aPrivate,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TableToArray(const nsTHashtable<nsPtrHashKey<void>>& aTable,
|
||||||
|
nsTArray<void*>& aArray);
|
||||||
|
|
||||||
} // namespace ipc
|
} // namespace ipc
|
||||||
|
|
||||||
template<typename Protocol>
|
template<typename Protocol>
|
||||||
using ManagedContainer = nsTHashtable<nsPtrHashKey<Protocol>>;
|
class ManagedContainer : public nsTHashtable<nsPtrHashKey<Protocol>>
|
||||||
|
{
|
||||||
|
typedef nsTHashtable<nsPtrHashKey<Protocol>> BaseClass;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Having the core logic work on void pointers, rather than typed pointers,
|
||||||
|
// means that we can have one instance of this code out-of-line, rather
|
||||||
|
// than several hundred instances of this code out-of-lined. (Those
|
||||||
|
// repeated instances don't necessarily get folded together by the linker
|
||||||
|
// because they contain member offsets and such that differ between the
|
||||||
|
// functions.) We do have to pay for it with some eye-bleedingly bad casts,
|
||||||
|
// though.
|
||||||
|
void ToArray(nsTArray<Protocol*>& aArray) const {
|
||||||
|
::mozilla::ipc::TableToArray(*reinterpret_cast<const nsTHashtable<nsPtrHashKey<void>>*>
|
||||||
|
(static_cast<const BaseClass*>(this)),
|
||||||
|
reinterpret_cast<nsTArray<void*>&>(aArray));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<typename Protocol>
|
template<typename Protocol>
|
||||||
Protocol*
|
Protocol*
|
||||||
|
|
|
@ -50,6 +50,7 @@ HeaderIncludes = (
|
||||||
'nsTArray.h',
|
'nsTArray.h',
|
||||||
'mozilla/ipc/ProtocolUtils.h',
|
'mozilla/ipc/ProtocolUtils.h',
|
||||||
'nsTHashtable.h',
|
'nsTHashtable.h',
|
||||||
|
'mozilla/OperatorNewExtensions.h',
|
||||||
)
|
)
|
||||||
|
|
||||||
CppIncludes = (
|
CppIncludes = (
|
||||||
|
|
|
@ -851,7 +851,7 @@ IPDL union type."""
|
||||||
else:
|
else:
|
||||||
return ExprNew(self.bareType(self.side),
|
return ExprNew(self.bareType(self.side),
|
||||||
args=args,
|
args=args,
|
||||||
newargs=[ self.callGetPtr() ])
|
newargs=[ ExprVar('mozilla::KnownNotNull'), self.callGetPtr() ])
|
||||||
|
|
||||||
def callDtor(self):
|
def callDtor(self):
|
||||||
if self.recursive:
|
if self.recursive:
|
||||||
|
@ -1797,17 +1797,17 @@ class _GenerateProtocolCode(ipdl.ast.Visitor):
|
||||||
else:
|
else:
|
||||||
return ExprVar(s.decl.cxxname)
|
return ExprVar(s.decl.cxxname)
|
||||||
|
|
||||||
# bool Transition(State from, Trigger trigger, State* next)
|
# bool Transition(Trigger trigger, State* next)
|
||||||
|
# The state we are transitioning from is stored in *next.
|
||||||
fromvar = ExprVar('from')
|
fromvar = ExprVar('from')
|
||||||
triggervar = ExprVar('trigger')
|
triggervar = ExprVar('trigger')
|
||||||
nextvar = ExprVar('next')
|
nextvar = ExprVar('next')
|
||||||
msgexpr = ExprSelect(triggervar, '.', 'mMsg')
|
msgexpr = ExprSelect(triggervar, '.', 'mMessage')
|
||||||
actionexpr = ExprSelect(triggervar, '.', 'mAction')
|
actionexpr = ExprSelect(triggervar, '.', 'mAction')
|
||||||
|
|
||||||
transitionfunc = FunctionDefn(FunctionDecl(
|
transitionfunc = FunctionDefn(FunctionDecl(
|
||||||
'Transition',
|
'Transition',
|
||||||
params=[ Decl(Type('State'), fromvar.name),
|
params=[ Decl(Type('mozilla::ipc::Trigger'), triggervar.name),
|
||||||
Decl(Type('mozilla::ipc::Trigger'), triggervar.name),
|
|
||||||
Decl(Type('State', ptr=1), nextvar.name) ],
|
Decl(Type('State', ptr=1), nextvar.name) ],
|
||||||
ret=Type.BOOL))
|
ret=Type.BOOL))
|
||||||
|
|
||||||
|
@ -1902,6 +1902,8 @@ class _GenerateProtocolCode(ipdl.ast.Visitor):
|
||||||
if usesend or userecv:
|
if usesend or userecv:
|
||||||
transitionfunc.addstmt(Whitespace.NL)
|
transitionfunc.addstmt(Whitespace.NL)
|
||||||
|
|
||||||
|
transitionfunc.addstmt(StmtDecl(Decl(Type('State'), fromvar.name),
|
||||||
|
init=ExprDeref(nextvar)))
|
||||||
transitionfunc.addstmt(fromswitch)
|
transitionfunc.addstmt(fromswitch)
|
||||||
# all --> Error transitions break to here. But only insert this
|
# all --> Error transitions break to here. But only insert this
|
||||||
# block if there is any possibility of such transitions.
|
# block if there is any possibility of such transitions.
|
||||||
|
@ -3086,22 +3088,10 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
|
||||||
params=[ Decl(_cxxArrayType(p.managedCxxType(managed, self.side), ref=1),
|
params=[ Decl(_cxxArrayType(p.managedCxxType(managed, self.side), ref=1),
|
||||||
arrvar.name) ],
|
arrvar.name) ],
|
||||||
const=1))
|
const=1))
|
||||||
ivar = ExprVar('i')
|
meth.addstmt(StmtExpr(
|
||||||
elementsvar = ExprVar('elements')
|
ExprCall(ExprSelect(p.managedVar(managed, self.side),
|
||||||
itervar = ExprVar('iter')
|
'.', 'ToArray'),
|
||||||
meth.addstmt(StmtDecl(Decl(Type.UINT32, ivar.name),
|
args=[ arrvar ])))
|
||||||
init=ExprLiteral.ZERO))
|
|
||||||
meth.addstmt(StmtDecl(Decl(Type(_actorName(managed.name(), self.side), ptrptr=1), elementsvar.name),
|
|
||||||
init=ExprCall(ExprSelect(arrvar, '.', 'AppendElements'),
|
|
||||||
args=[ ExprCall(ExprSelect(p.managedVar(managed, self.side),
|
|
||||||
'.', 'Count')) ])))
|
|
||||||
foreachaccumulate = forLoopOverHashtable(p.managedVar(managed, self.side),
|
|
||||||
itervar, const=True)
|
|
||||||
foreachaccumulate.addstmt(StmtExpr(
|
|
||||||
ExprAssn(ExprIndex(elementsvar, ivar),
|
|
||||||
actorFromIter(itervar))))
|
|
||||||
foreachaccumulate.addstmt(StmtExpr(ExprPrefixUnop(ivar, '++')))
|
|
||||||
meth.addstmt(foreachaccumulate)
|
|
||||||
|
|
||||||
refmeth = MethodDefn(MethodDecl(
|
refmeth = MethodDefn(MethodDecl(
|
||||||
p.managedMethod(managed, self.side).name,
|
p.managedMethod(managed, self.side).name,
|
||||||
|
@ -5441,8 +5431,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
|
||||||
ifbad = StmtIf(ExprNot(
|
ifbad = StmtIf(ExprNot(
|
||||||
ExprCall(
|
ExprCall(
|
||||||
ExprVar(self.protocol.name +'::Transition'),
|
ExprVar(self.protocol.name +'::Transition'),
|
||||||
args=[ stateexpr,
|
args=[ ExprCall(ExprVar('Trigger'),
|
||||||
ExprCall(ExprVar('Trigger'),
|
|
||||||
args=[ action, ExprVar(msgid) ]),
|
args=[ action, ExprVar(msgid) ]),
|
||||||
ExprAddrOf(stateexpr) ])))
|
ExprAddrOf(stateexpr) ])))
|
||||||
ifbad.addifstmts(_badTransition())
|
ifbad.addifstmts(_badTransition())
|
||||||
|
|
|
@ -132,7 +132,7 @@ struct ParamTraits<mozilla::mscom::COMPtrHolder<Interface, _IID>>
|
||||||
if (!proxyStream.GetInterface(_IID, (void**)&rawInterface)) {
|
if (!proxyStream.GetInterface(_IID, (void**)&rawInterface)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
paramType::COMPtrType ptr(rawInterface);
|
typename paramType::COMPtrType ptr(rawInterface);
|
||||||
aResult->Set(mozilla::Move(ptr));
|
aResult->Set(mozilla::Move(ptr));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include "mozilla/DebugOnly.h"
|
#include "mozilla/DebugOnly.h"
|
||||||
#include "mozilla/Function.h"
|
#include "mozilla/Function.h"
|
||||||
#include "mozilla/mscom/COMApartmentRegion.h"
|
#include "mozilla/mscom/COMApartmentRegion.h"
|
||||||
#include "mozilla/mscom/utils.h"
|
#include "mozilla/mscom/Utils.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsIThread.h"
|
#include "nsIThread.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include "mozilla/mscom/DispatchForwarder.h"
|
#include "mozilla/mscom/DispatchForwarder.h"
|
||||||
#include "mozilla/mscom/MainThreadInvoker.h"
|
#include "mozilla/mscom/MainThreadInvoker.h"
|
||||||
#include "mozilla/mscom/Registration.h"
|
#include "mozilla/mscom/Registration.h"
|
||||||
#include "mozilla/mscom/utils.h"
|
#include "mozilla/mscom/Utils.h"
|
||||||
#include "MainThreadUtils.h"
|
#include "MainThreadUtils.h"
|
||||||
#include "mozilla/Assertions.h"
|
#include "mozilla/Assertions.h"
|
||||||
#include "mozilla/DebugOnly.h"
|
#include "mozilla/DebugOnly.h"
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
#include "mozilla/mscom/InterceptorLog.h"
|
#include "mozilla/mscom/InterceptorLog.h"
|
||||||
#include "mozilla/mscom/Registration.h"
|
#include "mozilla/mscom/Registration.h"
|
||||||
#include "mozilla/mscom/utils.h"
|
#include "mozilla/mscom/Utils.h"
|
||||||
#include "mozilla/Assertions.h"
|
#include "mozilla/Assertions.h"
|
||||||
#include "mozilla/DebugOnly.h"
|
#include "mozilla/DebugOnly.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include "DynamicallyLinkedFunctionPtr.h"
|
#include "DynamicallyLinkedFunctionPtr.h"
|
||||||
#include "mozilla/mscom/EnsureMTA.h"
|
#include "mozilla/mscom/EnsureMTA.h"
|
||||||
#include "mozilla/mscom/ProxyStream.h"
|
#include "mozilla/mscom/ProxyStream.h"
|
||||||
#include "mozilla/mscom/utils.h"
|
#include "mozilla/mscom/Utils.h"
|
||||||
|
|
||||||
#include "mozilla/Move.h"
|
#include "mozilla/Move.h"
|
||||||
|
|
||||||
|
|
|
@ -781,7 +781,7 @@ ParseVarOrConstStatement(AsmJSParser& parser, ParseNode** var)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
*var = parser.statement(YieldIsName);
|
*var = parser.statementListItem(YieldIsName);
|
||||||
if (!*var)
|
if (!*var)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -7206,7 +7206,7 @@ CheckModuleReturn(ModuleValidator& m)
|
||||||
}
|
}
|
||||||
ts.ungetToken();
|
ts.ungetToken();
|
||||||
|
|
||||||
ParseNode* returnStmt = m.parser().statement(YieldIsName);
|
ParseNode* returnStmt = m.parser().statementListItem(YieldIsName);
|
||||||
if (!returnStmt)
|
if (!returnStmt)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -698,6 +698,19 @@ class FunctionCompiler
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// False means we're sure to be out-of-bounds after this bounds check.
|
||||||
|
bool maybeAddBoundsCheck(MDefinition* base, const MWasmMemoryAccess& access)
|
||||||
|
{
|
||||||
|
if (access.offset() > uint32_t(INT32_MAX)) {
|
||||||
|
curBlock_->end(MWasmTrap::New(alloc(), Trap::OutOfBounds));
|
||||||
|
curBlock_ = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!mg().usesSignal.forOOB)
|
||||||
|
curBlock_->add(MWasmBoundsCheck::New(alloc(), base, access));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
MDefinition* loadHeapPrivate(MDefinition* base, const MWasmMemoryAccess& access,
|
MDefinition* loadHeapPrivate(MDefinition* base, const MWasmMemoryAccess& access,
|
||||||
bool isInt64 = false)
|
bool isInt64 = false)
|
||||||
{
|
{
|
||||||
|
@ -708,8 +721,8 @@ class FunctionCompiler
|
||||||
if (mg().isAsmJS()) {
|
if (mg().isAsmJS()) {
|
||||||
load = MAsmJSLoadHeap::New(alloc(), base, access);
|
load = MAsmJSLoadHeap::New(alloc(), base, access);
|
||||||
} else {
|
} else {
|
||||||
if (!mg().usesSignal.forOOB)
|
if (!maybeAddBoundsCheck(base, access))
|
||||||
curBlock_->add(MWasmBoundsCheck::New(alloc(), base, access));
|
return nullptr;
|
||||||
load = MWasmLoad::New(alloc(), base, access, isInt64);
|
load = MWasmLoad::New(alloc(), base, access, isInt64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -726,8 +739,8 @@ class FunctionCompiler
|
||||||
if (mg().isAsmJS()) {
|
if (mg().isAsmJS()) {
|
||||||
store = MAsmJSStoreHeap::New(alloc(), base, access, v);
|
store = MAsmJSStoreHeap::New(alloc(), base, access, v);
|
||||||
} else {
|
} else {
|
||||||
if (!mg().usesSignal.forOOB)
|
if (!maybeAddBoundsCheck(base, access))
|
||||||
curBlock_->add(MWasmBoundsCheck::New(alloc(), base, access));
|
return;
|
||||||
store = MWasmStore::New(alloc(), base, access, v);
|
store = MWasmStore::New(alloc(), base, access, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1109,7 +1122,7 @@ class FunctionCompiler
|
||||||
if (inDeadCode())
|
if (inDeadCode())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto* ins = MAsmThrowUnreachable::New(alloc());
|
auto* ins = MWasmTrap::New(alloc(), wasm::Trap::Unreachable);
|
||||||
curBlock_->end(ins);
|
curBlock_->end(ins);
|
||||||
curBlock_ = nullptr;
|
curBlock_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,9 +101,6 @@ function RadixSort(array, len, buffer, nbytes, signed, floating, comparefn) {
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that the buffer is non-null
|
|
||||||
assert(buffer !== null, "Attached data buffer should be reified when array length is >= 128.");
|
|
||||||
|
|
||||||
let aux = new List();
|
let aux = new List();
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
aux[i] = 0;
|
aux[i] = 0;
|
||||||
|
@ -114,6 +111,14 @@ function RadixSort(array, len, buffer, nbytes, signed, floating, comparefn) {
|
||||||
|
|
||||||
// Preprocess
|
// Preprocess
|
||||||
if (floating) {
|
if (floating) {
|
||||||
|
// This happens if the array object is constructed under JIT
|
||||||
|
if (buffer === null) {
|
||||||
|
buffer = callFunction(std_TypedArray_buffer, array);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that the buffer is non-null
|
||||||
|
assert(buffer !== null, "Attached data buffer should be reified when array length is >= 128.");
|
||||||
|
|
||||||
view = new Int32Array(buffer);
|
view = new Int32Array(buffer);
|
||||||
|
|
||||||
// Flip sign bit for positive numbers; flip all bits for negative
|
// Flip sign bit for positive numbers; flip all bits for negative
|
||||||
|
|
|
@ -766,7 +766,7 @@ Parser<ParseHandler>::parse()
|
||||||
if (!varScope.init(pc))
|
if (!varScope.init(pc))
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
Node pn = statements(YieldIsName);
|
Node pn = statementList(YieldIsName);
|
||||||
if (!pn)
|
if (!pn)
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
|
@ -1296,7 +1296,7 @@ Parser<FullParseHandler>::checkStatementsEOF()
|
||||||
// This is designed to be paired with parsing a statement list at the top
|
// This is designed to be paired with parsing a statement list at the top
|
||||||
// level.
|
// level.
|
||||||
//
|
//
|
||||||
// The statements() call breaks on TOK_RC, so make sure we've
|
// The statementList() call breaks on TOK_RC, so make sure we've
|
||||||
// reached EOF here.
|
// reached EOF here.
|
||||||
TokenKind tt;
|
TokenKind tt;
|
||||||
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
|
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
|
||||||
|
@ -1732,7 +1732,7 @@ Parser<FullParseHandler>::evalBody(EvalSharedContext* evalsc)
|
||||||
if (!lexicalScope.init(pc))
|
if (!lexicalScope.init(pc))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
ParseNode* body = statements(YieldIsName);
|
ParseNode* body = statementList(YieldIsName);
|
||||||
if (!body)
|
if (!body)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
@ -1805,7 +1805,7 @@ Parser<FullParseHandler>::globalBody(GlobalSharedContext* globalsc)
|
||||||
if (!varScope.init(pc))
|
if (!varScope.init(pc))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
ParseNode* body = statements(YieldIsName);
|
ParseNode* body = statementList(YieldIsName);
|
||||||
if (!body)
|
if (!body)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
@ -1844,7 +1844,7 @@ Parser<FullParseHandler>::moduleBody(ModuleSharedContext* modulesc)
|
||||||
if (!mn)
|
if (!mn)
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
ParseNode* pn = statements(YieldIsKeyword);
|
ParseNode* pn = statementList(YieldIsKeyword);
|
||||||
if (!pn)
|
if (!pn)
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
|
@ -2249,7 +2249,7 @@ Parser<ParseHandler>::functionBody(InHandling inHandling, YieldHandling yieldHan
|
||||||
|
|
||||||
Node pn;
|
Node pn;
|
||||||
if (type == StatementListBody) {
|
if (type == StatementListBody) {
|
||||||
pn = statements(yieldHandling);
|
pn = statementList(yieldHandling);
|
||||||
if (!pn)
|
if (!pn)
|
||||||
return null();
|
return null();
|
||||||
} else {
|
} else {
|
||||||
|
@ -2714,12 +2714,12 @@ Parser<ParseHandler>::checkFunctionDefinition(HandleAtom funAtom, Node pn, Funct
|
||||||
// declarations. Otherwise it is a parse error.
|
// declarations. Otherwise it is a parse error.
|
||||||
ParseContext::Statement* declaredInStmt = pc->innermostStatement();
|
ParseContext::Statement* declaredInStmt = pc->innermostStatement();
|
||||||
if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) {
|
if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) {
|
||||||
if (pc->sc()->strict()) {
|
MOZ_ASSERT(!pc->sc()->strict(),
|
||||||
reportWithOffset(ParseError, false, pos.begin, JSMSG_FUNCTION_LABEL);
|
"labeled functions shouldn't be parsed in strict mode");
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the innermost non-label statement.
|
// Find the innermost non-label statement. Report an error if it's
|
||||||
|
// unbraced: functions can't appear in it. Otherwise the statement
|
||||||
|
// (or its absence) determines the scope the function's bound in.
|
||||||
while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label)
|
while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label)
|
||||||
declaredInStmt = declaredInStmt->enclosing();
|
declaredInStmt = declaredInStmt->enclosing();
|
||||||
|
|
||||||
|
@ -2730,9 +2730,8 @@ Parser<ParseHandler>::checkFunctionDefinition(HandleAtom funAtom, Node pn, Funct
|
||||||
}
|
}
|
||||||
|
|
||||||
if (declaredInStmt) {
|
if (declaredInStmt) {
|
||||||
DeclarationKind declKind = DeclarationKind::LexicalFunction;
|
MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label);
|
||||||
if (!checkLexicalDeclarationDirectlyWithinBlock(*declaredInStmt, declKind, pos))
|
MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind()));
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!pc->sc()->strict()) {
|
if (!pc->sc()->strict()) {
|
||||||
// Under sloppy mode, try Annex B.3.3 semantics. If making an
|
// Under sloppy mode, try Annex B.3.3 semantics. If making an
|
||||||
|
@ -2745,7 +2744,7 @@ Parser<ParseHandler>::checkFunctionDefinition(HandleAtom funAtom, Node pn, Funct
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!noteDeclaredName(funName, declKind, pos))
|
if (!noteDeclaredName(funName, DeclarationKind::LexicalFunction, pos))
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
if (!noteDeclaredName(funName, DeclarationKind::BodyLevelFunction, pos))
|
if (!noteDeclaredName(funName, DeclarationKind::BodyLevelFunction, pos))
|
||||||
|
@ -3528,14 +3527,9 @@ Parser<ParseHandler>::maybeParseDirective(Node list, Node pn, bool* cont)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Parse the statements in a block, creating a StatementList node that lists
|
|
||||||
* the statements. If called from block-parsing code, the caller must match
|
|
||||||
* '{' before and '}' after.
|
|
||||||
*/
|
|
||||||
template <typename ParseHandler>
|
template <typename ParseHandler>
|
||||||
typename ParseHandler::Node
|
typename ParseHandler::Node
|
||||||
Parser<ParseHandler>::statements(YieldHandling yieldHandling)
|
Parser<ParseHandler>::statementList(YieldHandling yieldHandling)
|
||||||
{
|
{
|
||||||
JS_CHECK_RECURSION(context, return null());
|
JS_CHECK_RECURSION(context, return null());
|
||||||
|
|
||||||
|
@ -3562,7 +3556,7 @@ Parser<ParseHandler>::statements(YieldHandling yieldHandling)
|
||||||
return null();
|
return null();
|
||||||
statementBegin = pos.begin;
|
statementBegin = pos.begin;
|
||||||
}
|
}
|
||||||
Node next = statement(yieldHandling, canHaveDirectives);
|
Node next = statementListItem(yieldHandling, canHaveDirectives);
|
||||||
if (!next) {
|
if (!next) {
|
||||||
if (tokenStream.isEOF())
|
if (tokenStream.isEOF())
|
||||||
isUnexpectedEOF_ = true;
|
isUnexpectedEOF_ = true;
|
||||||
|
@ -3957,7 +3951,7 @@ Parser<ParseHandler>::blockStatement(YieldHandling yieldHandling, unsigned error
|
||||||
if (!scope.init(pc))
|
if (!scope.init(pc))
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
Node list = statements(yieldHandling);
|
Node list = statementList(yieldHandling);
|
||||||
if (!list)
|
if (!list)
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
|
@ -4864,6 +4858,27 @@ Parser<ParseHandler>::expressionStatement(YieldHandling yieldHandling, InvokedPr
|
||||||
return handler.newExprStatement(pnexpr, pos().end);
|
return handler.newExprStatement(pnexpr, pos().end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class ParseHandler>
|
||||||
|
typename ParseHandler::Node
|
||||||
|
Parser<ParseHandler>::consequentOrAlternative(YieldHandling yieldHandling)
|
||||||
|
{
|
||||||
|
TokenKind next;
|
||||||
|
if (!tokenStream.peekToken(&next, TokenStream::Operand))
|
||||||
|
return null();
|
||||||
|
|
||||||
|
if (next == TOK_FUNCTION) {
|
||||||
|
// Apply Annex B.3.4 in non-strict code to allow FunctionDeclaration as
|
||||||
|
// the consequent/alternative of an |if| or |else|. Parser::statement
|
||||||
|
// will report the strict mode error.
|
||||||
|
if (!pc->sc()->strict()) {
|
||||||
|
tokenStream.consumeKnownToken(next, TokenStream::Operand);
|
||||||
|
return functionStmt(yieldHandling, NameRequired);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return statement(yieldHandling);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename ParseHandler>
|
template <typename ParseHandler>
|
||||||
typename ParseHandler::Node
|
typename ParseHandler::Node
|
||||||
Parser<ParseHandler>::ifStatement(YieldHandling yieldHandling)
|
Parser<ParseHandler>::ifStatement(YieldHandling yieldHandling)
|
||||||
|
@ -4890,7 +4905,7 @@ Parser<ParseHandler>::ifStatement(YieldHandling yieldHandling)
|
||||||
return null();
|
return null();
|
||||||
}
|
}
|
||||||
|
|
||||||
Node thenBranch = statement(yieldHandling);
|
Node thenBranch = consequentOrAlternative(yieldHandling);
|
||||||
if (!thenBranch)
|
if (!thenBranch)
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
|
@ -4905,7 +4920,7 @@ Parser<ParseHandler>::ifStatement(YieldHandling yieldHandling)
|
||||||
return null();
|
return null();
|
||||||
if (matched)
|
if (matched)
|
||||||
continue;
|
continue;
|
||||||
elseBranch = statement(yieldHandling);
|
elseBranch = consequentOrAlternative(yieldHandling);
|
||||||
if (!elseBranch)
|
if (!elseBranch)
|
||||||
return null();
|
return null();
|
||||||
} else {
|
} else {
|
||||||
|
@ -5062,13 +5077,24 @@ Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
|
||||||
parsingLexicalDeclaration = true;
|
parsingLexicalDeclaration = true;
|
||||||
tokenStream.consumeKnownToken(tt, TokenStream::Operand);
|
tokenStream.consumeKnownToken(tt, TokenStream::Operand);
|
||||||
} else if (tt == TOK_NAME && tokenStream.nextName() == context->names().let) {
|
} else if (tt == TOK_NAME && tokenStream.nextName() == context->names().let) {
|
||||||
// Check for the backwards-compatibility corner case in sloppy
|
MOZ_ASSERT(!pc->sc()->strict(),
|
||||||
// mode like |for (let in e)| where the 'let' token should be
|
"should parse |let| as TOK_LET in strict mode code");
|
||||||
// parsed as an identifier.
|
|
||||||
if (!peekShouldParseLetDeclaration(&parsingLexicalDeclaration, TokenStream::Operand))
|
// We could have a {For,Lexical}Declaration, or we could have a
|
||||||
|
// LeftHandSideExpression with lookahead restrictions so it's not
|
||||||
|
// ambiguous with the former. Check for a continuation of the former
|
||||||
|
// to decide which we have.
|
||||||
|
tokenStream.consumeKnownToken(TOK_NAME, TokenStream::Operand);
|
||||||
|
|
||||||
|
TokenKind next;
|
||||||
|
if (!tokenStream.peekToken(&next))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
letIsIdentifier = !parsingLexicalDeclaration;
|
parsingLexicalDeclaration = nextTokenContinuesLetDeclaration(next, yieldHandling);
|
||||||
|
if (!parsingLexicalDeclaration) {
|
||||||
|
tokenStream.ungetToken();
|
||||||
|
letIsIdentifier = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parsingLexicalDeclaration) {
|
if (parsingLexicalDeclaration) {
|
||||||
|
@ -5386,7 +5412,7 @@ Parser<ParseHandler>::switchStatement(YieldHandling yieldHandling)
|
||||||
return null();
|
return null();
|
||||||
statementBegin = pos.begin;
|
statementBegin = pos.begin;
|
||||||
}
|
}
|
||||||
Node stmt = statement(yieldHandling);
|
Node stmt = statementListItem(yieldHandling);
|
||||||
if (!stmt)
|
if (!stmt)
|
||||||
return null();
|
return null();
|
||||||
if (!warnedAboutStatementsAfterReturn) {
|
if (!warnedAboutStatementsAfterReturn) {
|
||||||
|
@ -5774,6 +5800,41 @@ Parser<SyntaxParseHandler>::withStatement(YieldHandling yieldHandling)
|
||||||
return null();
|
return null();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename ParseHandler>
|
||||||
|
typename ParseHandler::Node
|
||||||
|
Parser<ParseHandler>::labeledItem(YieldHandling yieldHandling)
|
||||||
|
{
|
||||||
|
TokenKind tt;
|
||||||
|
if (!tokenStream.getToken(&tt, TokenStream::Operand))
|
||||||
|
return null();
|
||||||
|
|
||||||
|
if (tt == TOK_FUNCTION) {
|
||||||
|
TokenKind next;
|
||||||
|
if (!tokenStream.peekToken(&next))
|
||||||
|
return null();
|
||||||
|
|
||||||
|
// GeneratorDeclaration is only matched by HoistableDeclaration in
|
||||||
|
// StatementListItem, so generators can't be inside labels.
|
||||||
|
if (next == TOK_MUL) {
|
||||||
|
report(ParseError, false, null(), JSMSG_GENERATOR_LABEL);
|
||||||
|
return null();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Per 13.13.1 it's a syntax error if LabelledItem: FunctionDeclaration
|
||||||
|
// is ever matched. Per Annex B.3.2 that modifies this text, this
|
||||||
|
// applies only to strict mode code.
|
||||||
|
if (pc->sc()->strict()) {
|
||||||
|
report(ParseError, false, null(), JSMSG_FUNCTION_LABEL);
|
||||||
|
return null();
|
||||||
|
}
|
||||||
|
|
||||||
|
return functionStmt(yieldHandling, NameRequired);
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenStream.ungetToken();
|
||||||
|
return statement(yieldHandling);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename ParseHandler>
|
template <typename ParseHandler>
|
||||||
typename ParseHandler::Node
|
typename ParseHandler::Node
|
||||||
Parser<ParseHandler>::labeledStatement(YieldHandling yieldHandling)
|
Parser<ParseHandler>::labeledStatement(YieldHandling yieldHandling)
|
||||||
|
@ -5794,7 +5855,7 @@ Parser<ParseHandler>::labeledStatement(YieldHandling yieldHandling)
|
||||||
|
|
||||||
/* Push a label struct and parse the statement. */
|
/* Push a label struct and parse the statement. */
|
||||||
ParseContext::LabelStatement stmt(pc, label);
|
ParseContext::LabelStatement stmt(pc, label);
|
||||||
Node pn = statement(yieldHandling);
|
Node pn = labeledItem(yieldHandling);
|
||||||
if (!pn)
|
if (!pn)
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
|
@ -5865,7 +5926,7 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
|
||||||
if (!scope.init(pc))
|
if (!scope.init(pc))
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
innerBlock = statements(yieldHandling);
|
innerBlock = statementList(yieldHandling);
|
||||||
if (!innerBlock)
|
if (!innerBlock)
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
|
@ -6005,7 +6066,7 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
|
||||||
if (!scope.init(pc))
|
if (!scope.init(pc))
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
finallyBlock = statements(yieldHandling);
|
finallyBlock = statementList(yieldHandling);
|
||||||
if (!finallyBlock)
|
if (!finallyBlock)
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
|
@ -6047,7 +6108,7 @@ Parser<ParseHandler>::catchBlockStatement(YieldHandling yieldHandling,
|
||||||
if (!noteDeclaredName(simpleCatchParam, DeclarationKind::SimpleCatchParameter, pos()))
|
if (!noteDeclaredName(simpleCatchParam, DeclarationKind::SimpleCatchParameter, pos()))
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
Node list = statements(yieldHandling);
|
Node list = statementList(yieldHandling);
|
||||||
if (!list)
|
if (!list)
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
|
@ -6057,7 +6118,7 @@ Parser<ParseHandler>::catchBlockStatement(YieldHandling yieldHandling,
|
||||||
|
|
||||||
body = finishLexicalScope(scope, list);
|
body = finishLexicalScope(scope, list);
|
||||||
} else {
|
} else {
|
||||||
body = statements(yieldHandling);
|
body = statementList(yieldHandling);
|
||||||
}
|
}
|
||||||
if (!body)
|
if (!body)
|
||||||
return null();
|
return null();
|
||||||
|
@ -6361,77 +6422,71 @@ Parser<SyntaxParseHandler>::classDefinition(YieldHandling yieldHandling,
|
||||||
return SyntaxParseHandler::NodeFailure;
|
return SyntaxParseHandler::NodeFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ParseHandler>
|
template <class ParseHandler>
|
||||||
bool
|
bool
|
||||||
Parser<ParseHandler>::shouldParseLetDeclaration(bool* parseDeclOut)
|
Parser<ParseHandler>::nextTokenContinuesLetDeclaration(TokenKind next, YieldHandling yieldHandling)
|
||||||
{
|
{
|
||||||
TokenKind tt;
|
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_NAME),
|
||||||
if (!tokenStream.peekToken(&tt))
|
"TOK_LET should have been summarily considered a "
|
||||||
return false;
|
"LexicalDeclaration");
|
||||||
|
MOZ_ASSERT(tokenStream.currentName() == context->names().let);
|
||||||
if (tt == TOK_NAME) {
|
|
||||||
// |let| followed by a name is a lexical declaration. This is so even
|
|
||||||
// if the name is on a new line. ASI applies *only* if an offending
|
|
||||||
// token not allowed by the grammar is encountered, and there's no
|
|
||||||
// [no LineTerminator here] restriction in LexicalDeclaration or
|
|
||||||
// ForDeclaration forbidding a line break.
|
|
||||||
//
|
|
||||||
// It's a tricky point, but this is true *even if* the name is "let", a
|
|
||||||
// name that can't be bound by LexicalDeclaration or ForDeclaration.
|
|
||||||
// Per ES6 5.3, static semantics early errors are validated *after*
|
|
||||||
// determining productions matching the source text. So in this
|
|
||||||
// example:
|
|
||||||
//
|
|
||||||
// let // ASI opportunity...except not
|
|
||||||
// let;
|
|
||||||
//
|
|
||||||
// the text matches LexicalDeclaration. *Then* static semantics in
|
|
||||||
// ES6 13.3.1.1 (corresponding to the LexicalDeclaration production
|
|
||||||
// just chosen), per ES6 5.3, are validated to recognize the Script as
|
|
||||||
// invalid. It can't be evaluated, so a SyntaxError is thrown.
|
|
||||||
*parseDeclOut = true;
|
|
||||||
} else if (tt == TOK_LB || tt == TOK_LC) {
|
|
||||||
*parseDeclOut = true;
|
|
||||||
} else {
|
|
||||||
// Whatever we have isn't a declaration. Either it's an expression, or
|
|
||||||
// it's invalid: expression-parsing code will decide.
|
|
||||||
*parseDeclOut = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename ParseHandler>
|
|
||||||
bool
|
|
||||||
Parser<ParseHandler>::peekShouldParseLetDeclaration(bool* parseDeclOut,
|
|
||||||
TokenStream::Modifier modifier)
|
|
||||||
{
|
|
||||||
// 'let' is a reserved keyword in strict mode and we shouldn't get here.
|
|
||||||
MOZ_ASSERT(!pc->sc()->strict());
|
|
||||||
|
|
||||||
*parseDeclOut = false;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
TokenKind tt;
|
TokenKind verify;
|
||||||
if (!tokenStream.peekToken(&tt, modifier))
|
MOZ_ALWAYS_TRUE(tokenStream.peekToken(&verify));
|
||||||
return false;
|
MOZ_ASSERT(next == verify);
|
||||||
MOZ_ASSERT(tt == TOK_NAME && tokenStream.nextName() == context->names().let);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
tokenStream.consumeKnownToken(TOK_NAME, modifier);
|
// Destructuring is (for once) the easy case.
|
||||||
if (!shouldParseLetDeclaration(parseDeclOut))
|
if (next == TOK_LB || next == TOK_LC)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Otherwise a let declaration must have a name.
|
||||||
|
if (next == TOK_NAME) {
|
||||||
|
// One non-"yield" TOK_NAME edge case deserves special comment.
|
||||||
|
// Consider this:
|
||||||
|
//
|
||||||
|
// let // not an ASI opportunity
|
||||||
|
// let;
|
||||||
|
//
|
||||||
|
// Static semantics in §13.3.1.1 turn a LexicalDeclaration that binds
|
||||||
|
// "let" into an early error. Does this retroactively permit ASI so
|
||||||
|
// that we should parse this as two ExpressionStatements? No. ASI
|
||||||
|
// resolves during parsing. Static semantics only apply to the full
|
||||||
|
// parse tree with ASI applied. No backsies!
|
||||||
|
if (tokenStream.nextName() != context->names().yield)
|
||||||
|
return true;
|
||||||
|
} else if (next != TOK_YIELD) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Unget the TOK_NAME of 'let' if not parsing a declaration.
|
// We have the name "yield": the grammar parameter exactly states whether
|
||||||
if (!*parseDeclOut)
|
// this is okay. Even if YieldIsKeyword, the code might be valid if ASI
|
||||||
tokenStream.ungetToken();
|
// induces a preceding semicolon. If YieldIsName, the code is valid
|
||||||
|
// outside strict mode, and declaration-parsing code will enforce strict
|
||||||
return true;
|
// mode restrictions.
|
||||||
|
//
|
||||||
|
// No checkYieldNameValidity for TOK_YIELD is needed here. It'll happen
|
||||||
|
// when TOK_YIELD is consumed as BindingIdentifier or as start of a fresh
|
||||||
|
// Statement.
|
||||||
|
return yieldHandling == YieldIsName;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ParseHandler>
|
template <typename ParseHandler>
|
||||||
typename ParseHandler::Node
|
typename ParseHandler::Node
|
||||||
Parser<ParseHandler>::statement(YieldHandling yieldHandling, bool canHaveDirectives)
|
Parser<ParseHandler>::variableStatement(YieldHandling yieldHandling)
|
||||||
|
{
|
||||||
|
Node vars = declarationList(yieldHandling, PNK_VAR);
|
||||||
|
if (!vars)
|
||||||
|
return null();
|
||||||
|
if (!MatchOrInsertSemicolonAfterExpression(tokenStream))
|
||||||
|
return null();
|
||||||
|
return vars;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ParseHandler>
|
||||||
|
typename ParseHandler::Node
|
||||||
|
Parser<ParseHandler>::statement(YieldHandling yieldHandling)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(checkOptionsCalled);
|
MOZ_ASSERT(checkOptionsCalled);
|
||||||
|
|
||||||
|
@ -6447,31 +6502,14 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling, bool canHaveDirecti
|
||||||
return blockStatement(yieldHandling);
|
return blockStatement(yieldHandling);
|
||||||
|
|
||||||
// VariableStatement[?Yield]
|
// VariableStatement[?Yield]
|
||||||
case TOK_VAR: {
|
case TOK_VAR:
|
||||||
Node pn = declarationList(yieldHandling, PNK_VAR);
|
return variableStatement(yieldHandling);
|
||||||
if (!pn)
|
|
||||||
return null();
|
|
||||||
if (!MatchOrInsertSemicolonAfterExpression(tokenStream))
|
|
||||||
return null();
|
|
||||||
return pn;
|
|
||||||
}
|
|
||||||
|
|
||||||
// EmptyStatement
|
// EmptyStatement
|
||||||
case TOK_SEMI:
|
case TOK_SEMI:
|
||||||
return handler.newEmptyStatement(pos());
|
return handler.newEmptyStatement(pos());
|
||||||
|
|
||||||
// ExpressionStatement[?Yield].
|
// ExpressionStatement[?Yield].
|
||||||
//
|
|
||||||
// These should probably be handled by a single ExpressionStatement
|
|
||||||
// function in a default, not split up this way.
|
|
||||||
case TOK_STRING:
|
|
||||||
if (!canHaveDirectives && tokenStream.currentToken().atom() == context->names().useAsm) {
|
|
||||||
if (!abortIfSyntaxParser())
|
|
||||||
return null();
|
|
||||||
if (!report(ParseWarning, false, null(), JSMSG_USE_ASM_DIRECTIVE_FAIL))
|
|
||||||
return null();
|
|
||||||
}
|
|
||||||
return expressionStatement(yieldHandling);
|
|
||||||
|
|
||||||
case TOK_YIELD: {
|
case TOK_YIELD: {
|
||||||
// Don't use a ternary operator here due to obscure linker issues
|
// Don't use a ternary operator here due to obscure linker issues
|
||||||
|
@ -6494,29 +6532,58 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling, bool canHaveDirecti
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOK_NAME: {
|
case TOK_NAME: {
|
||||||
// 'let' is a contextual keyword outside strict mode. In strict mode
|
|
||||||
// it's always tokenized as TOK_LET except in this one weird case:
|
|
||||||
//
|
|
||||||
// "use strict" // ExpressionStatement, terminated by ASI
|
|
||||||
// let a = 1; // LexicalDeclaration
|
|
||||||
//
|
|
||||||
// We can't apply strict mode until we know "use strict" is the entire
|
|
||||||
// statement, but we can't know "use strict" is the entire statement
|
|
||||||
// until we see the next token. So 'let' is still TOK_NAME here.
|
|
||||||
if (tokenStream.currentName() == context->names().let) {
|
|
||||||
bool parseDecl;
|
|
||||||
if (!shouldParseLetDeclaration(&parseDecl))
|
|
||||||
return null();
|
|
||||||
|
|
||||||
if (parseDecl)
|
|
||||||
return lexicalDeclaration(yieldHandling, /* isConst = */ false);
|
|
||||||
}
|
|
||||||
|
|
||||||
TokenKind next;
|
TokenKind next;
|
||||||
if (!tokenStream.peekToken(&next))
|
if (!tokenStream.peekToken(&next))
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (tokenStream.currentName() == context->names().let) {
|
||||||
|
MOZ_ASSERT(!pc->sc()->strict(),
|
||||||
|
"observing |let| as TOK_NAME and not TOK_LET implies "
|
||||||
|
"non-strict code (and the edge case of 'use strict' "
|
||||||
|
"immediately followed by |let| on a new line only "
|
||||||
|
"applies to StatementListItems, not to Statements)");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Statement context forbids LexicalDeclaration.
|
||||||
|
if ((next == TOK_LB || next == TOK_LC || next == TOK_NAME) &&
|
||||||
|
tokenStream.currentName() == context->names().let)
|
||||||
|
{
|
||||||
|
bool forbiddenLetDeclaration = false;
|
||||||
|
if (next == TOK_LB) {
|
||||||
|
// ExpressionStatement has a 'let [' lookahead restriction.
|
||||||
|
forbiddenLetDeclaration = true;
|
||||||
|
} else {
|
||||||
|
// 'let {' and 'let foo' aren't completely forbidden, if ASI
|
||||||
|
// causes 'let' to be the entire Statement. But if they're
|
||||||
|
// same-line, we can aggressively give a better error message.
|
||||||
|
//
|
||||||
|
// Note that this ignores 'yield' as TOK_YIELD: we'll handle it
|
||||||
|
// correctly but with a worse error message.
|
||||||
|
TokenKind nextSameLine;
|
||||||
|
if (!tokenStream.peekTokenSameLine(&nextSameLine))
|
||||||
|
return null();
|
||||||
|
|
||||||
|
MOZ_ASSERT(nextSameLine == TOK_NAME ||
|
||||||
|
nextSameLine == TOK_LC ||
|
||||||
|
nextSameLine == TOK_EOL);
|
||||||
|
|
||||||
|
forbiddenLetDeclaration = nextSameLine != TOK_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (forbiddenLetDeclaration) {
|
||||||
|
report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT,
|
||||||
|
"lexical declarations");
|
||||||
|
return null();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: It's unfortunately allowed to have a label named 'let' in
|
||||||
|
// non-strict code. 💯
|
||||||
if (next == TOK_COLON)
|
if (next == TOK_COLON)
|
||||||
return labeledStatement(yieldHandling);
|
return labeledStatement(yieldHandling);
|
||||||
|
|
||||||
return expressionStatement(yieldHandling);
|
return expressionStatement(yieldHandling);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6585,23 +6652,222 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling, bool canHaveDirecti
|
||||||
case TOK_DEBUGGER:
|
case TOK_DEBUGGER:
|
||||||
return debuggerStatement();
|
return debuggerStatement();
|
||||||
|
|
||||||
// HoistableDeclaration[?Yield]
|
// |function| is forbidden by lookahead restriction (unless as child
|
||||||
|
// statement of |if| or |else|, but Parser::consequentOrAlternative
|
||||||
|
// handles that).
|
||||||
|
case TOK_FUNCTION:
|
||||||
|
report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations");
|
||||||
|
return null();
|
||||||
|
|
||||||
|
// |class| is also forbidden by lookahead restriction.
|
||||||
|
case TOK_CLASS:
|
||||||
|
report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT, "classes");
|
||||||
|
return null();
|
||||||
|
|
||||||
|
// ImportDeclaration (only inside modules)
|
||||||
|
case TOK_IMPORT:
|
||||||
|
return importDeclaration();
|
||||||
|
|
||||||
|
// ExportDeclaration (only inside modules)
|
||||||
|
case TOK_EXPORT:
|
||||||
|
return exportDeclaration();
|
||||||
|
|
||||||
|
// Miscellaneous error cases arguably better caught here than elsewhere.
|
||||||
|
|
||||||
|
case TOK_CATCH:
|
||||||
|
report(ParseError, false, null(), JSMSG_CATCH_WITHOUT_TRY);
|
||||||
|
return null();
|
||||||
|
|
||||||
|
case TOK_FINALLY:
|
||||||
|
report(ParseError, false, null(), JSMSG_FINALLY_WITHOUT_TRY);
|
||||||
|
return null();
|
||||||
|
|
||||||
|
// TOK_LET implies we're in strict mode code where static semantics
|
||||||
|
// forbid IdentifierName to be "let": a stronger restriction than
|
||||||
|
// Statement's lookahead restriction on |let [|. Provide a better error
|
||||||
|
// message here than the default case would.
|
||||||
|
case TOK_LET:
|
||||||
|
report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT, "let declarations");
|
||||||
|
return null();
|
||||||
|
|
||||||
|
// NOTE: default case handled in the ExpressionStatement section.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ParseHandler>
|
||||||
|
typename ParseHandler::Node
|
||||||
|
Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
|
||||||
|
bool canHaveDirectives /* = false */)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(checkOptionsCalled);
|
||||||
|
|
||||||
|
JS_CHECK_RECURSION(context, return null());
|
||||||
|
|
||||||
|
TokenKind tt;
|
||||||
|
if (!tokenStream.getToken(&tt, TokenStream::Operand))
|
||||||
|
return null();
|
||||||
|
|
||||||
|
switch (tt) {
|
||||||
|
// BlockStatement[?Yield, ?Return]
|
||||||
|
case TOK_LC:
|
||||||
|
return blockStatement(yieldHandling);
|
||||||
|
|
||||||
|
// VariableStatement[?Yield]
|
||||||
|
case TOK_VAR:
|
||||||
|
return variableStatement(yieldHandling);
|
||||||
|
|
||||||
|
// EmptyStatement
|
||||||
|
case TOK_SEMI:
|
||||||
|
return handler.newEmptyStatement(pos());
|
||||||
|
|
||||||
|
// ExpressionStatement[?Yield].
|
||||||
|
//
|
||||||
|
// These should probably be handled by a single ExpressionStatement
|
||||||
|
// function in a default, not split up this way.
|
||||||
|
case TOK_STRING:
|
||||||
|
if (!canHaveDirectives && tokenStream.currentToken().atom() == context->names().useAsm) {
|
||||||
|
if (!abortIfSyntaxParser())
|
||||||
|
return null();
|
||||||
|
if (!report(ParseWarning, false, null(), JSMSG_USE_ASM_DIRECTIVE_FAIL))
|
||||||
|
return null();
|
||||||
|
}
|
||||||
|
return expressionStatement(yieldHandling);
|
||||||
|
|
||||||
|
case TOK_YIELD: {
|
||||||
|
// Don't use a ternary operator here due to obscure linker issues
|
||||||
|
// around using static consts in the arms of a ternary.
|
||||||
|
TokenStream::Modifier modifier;
|
||||||
|
if (yieldExpressionsSupported())
|
||||||
|
modifier = TokenStream::Operand;
|
||||||
|
else
|
||||||
|
modifier = TokenStream::None;
|
||||||
|
|
||||||
|
TokenKind next;
|
||||||
|
if (!tokenStream.peekToken(&next, modifier))
|
||||||
|
return null();
|
||||||
|
if (next == TOK_COLON) {
|
||||||
|
if (!checkYieldNameValidity())
|
||||||
|
return null();
|
||||||
|
return labeledStatement(yieldHandling);
|
||||||
|
}
|
||||||
|
return expressionStatement(yieldHandling);
|
||||||
|
}
|
||||||
|
|
||||||
|
case TOK_NAME: {
|
||||||
|
TokenKind next;
|
||||||
|
if (!tokenStream.peekToken(&next))
|
||||||
|
return null();
|
||||||
|
|
||||||
|
if (tokenStream.currentName() == context->names().let) {
|
||||||
|
if (nextTokenContinuesLetDeclaration(next, yieldHandling))
|
||||||
|
return lexicalDeclaration(yieldHandling, /* isConst = */ false);
|
||||||
|
|
||||||
|
// IdentifierName can't be "let" in strict mode code. |let| in
|
||||||
|
// strict mode code is usually TOK_LET, but in this one weird case
|
||||||
|
// in global code it's TOK_NAME:
|
||||||
|
//
|
||||||
|
// "use strict" // ExpressionStatement ended by ASI
|
||||||
|
// let <...whatever else...> // a fresh StatementListItem
|
||||||
|
//
|
||||||
|
// Carefully reject strict mode |let| non-declarations.
|
||||||
|
if (pc->sc()->strict()) {
|
||||||
|
report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
|
||||||
|
"declaration pattern", TokenKindToDesc(next));
|
||||||
|
return null();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next == TOK_COLON)
|
||||||
|
return labeledStatement(yieldHandling);
|
||||||
|
|
||||||
|
return expressionStatement(yieldHandling);
|
||||||
|
}
|
||||||
|
|
||||||
|
case TOK_NEW:
|
||||||
|
return expressionStatement(yieldHandling, PredictInvoked);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return expressionStatement(yieldHandling);
|
||||||
|
|
||||||
|
// IfStatement[?Yield, ?Return]
|
||||||
|
case TOK_IF:
|
||||||
|
return ifStatement(yieldHandling);
|
||||||
|
|
||||||
|
// BreakableStatement[?Yield, ?Return]
|
||||||
|
//
|
||||||
|
// BreakableStatement[Yield, Return]:
|
||||||
|
// IterationStatement[?Yield, ?Return]
|
||||||
|
// SwitchStatement[?Yield, ?Return]
|
||||||
|
case TOK_DO:
|
||||||
|
return doWhileStatement(yieldHandling);
|
||||||
|
|
||||||
|
case TOK_WHILE:
|
||||||
|
return whileStatement(yieldHandling);
|
||||||
|
|
||||||
|
case TOK_FOR:
|
||||||
|
return forStatement(yieldHandling);
|
||||||
|
|
||||||
|
case TOK_SWITCH:
|
||||||
|
return switchStatement(yieldHandling);
|
||||||
|
|
||||||
|
// ContinueStatement[?Yield]
|
||||||
|
case TOK_CONTINUE:
|
||||||
|
return continueStatement(yieldHandling);
|
||||||
|
|
||||||
|
// BreakStatement[?Yield]
|
||||||
|
case TOK_BREAK:
|
||||||
|
return breakStatement(yieldHandling);
|
||||||
|
|
||||||
|
// [+Return] ReturnStatement[?Yield]
|
||||||
|
case TOK_RETURN:
|
||||||
|
// The Return parameter is only used here, and the effect is easily
|
||||||
|
// detected this way, so don't bother passing around an extra parameter
|
||||||
|
// everywhere.
|
||||||
|
if (!pc->isFunctionBox()) {
|
||||||
|
report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_return_str);
|
||||||
|
return null();
|
||||||
|
}
|
||||||
|
return returnStatement(yieldHandling);
|
||||||
|
|
||||||
|
// WithStatement[?Yield, ?Return]
|
||||||
|
case TOK_WITH:
|
||||||
|
return withStatement(yieldHandling);
|
||||||
|
|
||||||
|
// LabelledStatement[?Yield, ?Return]
|
||||||
|
// This is really handled by TOK_NAME and TOK_YIELD cases above.
|
||||||
|
|
||||||
|
// ThrowStatement[?Yield]
|
||||||
|
case TOK_THROW:
|
||||||
|
return throwStatement(yieldHandling);
|
||||||
|
|
||||||
|
// TryStatement[?Yield, ?Return]
|
||||||
|
case TOK_TRY:
|
||||||
|
return tryStatement(yieldHandling);
|
||||||
|
|
||||||
|
// DebuggerStatement
|
||||||
|
case TOK_DEBUGGER:
|
||||||
|
return debuggerStatement();
|
||||||
|
|
||||||
|
// Declaration[Yield]:
|
||||||
|
|
||||||
|
// HoistableDeclaration[?Yield, ~Default]
|
||||||
case TOK_FUNCTION:
|
case TOK_FUNCTION:
|
||||||
return functionStmt(yieldHandling, NameRequired);
|
return functionStmt(yieldHandling, NameRequired);
|
||||||
|
|
||||||
// ClassDeclaration[?Yield]
|
// ClassDeclaration[?Yield, ~Default]
|
||||||
case TOK_CLASS:
|
case TOK_CLASS:
|
||||||
if (!abortIfSyntaxParser())
|
if (!abortIfSyntaxParser())
|
||||||
return null();
|
return null();
|
||||||
return classDefinition(yieldHandling, ClassStatement, NameRequired);
|
return classDefinition(yieldHandling, ClassStatement, NameRequired);
|
||||||
|
|
||||||
// LexicalDeclaration[In, ?Yield]
|
// LexicalDeclaration[In, ?Yield]
|
||||||
|
// LetOrConst BindingList[?In, ?Yield]
|
||||||
case TOK_LET:
|
case TOK_LET:
|
||||||
case TOK_CONST:
|
case TOK_CONST:
|
||||||
if (!abortIfSyntaxParser())
|
if (!abortIfSyntaxParser())
|
||||||
return null();
|
return null();
|
||||||
// [In] is the default behavior, because for-loops currently specially
|
// [In] is the default behavior, because for-loops specially parse
|
||||||
// parse their heads to handle |in| in this situation.
|
// their heads to handle |in| in this situation.
|
||||||
return lexicalDeclaration(yieldHandling, /* isConst = */ tt == TOK_CONST);
|
return lexicalDeclaration(yieldHandling, /* isConst = */ tt == TOK_CONST);
|
||||||
|
|
||||||
// ImportDeclaration (only inside modules)
|
// ImportDeclaration (only inside modules)
|
||||||
|
|
|
@ -938,7 +938,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/* Public entry points for parsing. */
|
/* Public entry points for parsing. */
|
||||||
Node statement(YieldHandling yieldHandling, bool canHaveDirectives = false);
|
Node statement(YieldHandling yieldHandling);
|
||||||
|
Node statementListItem(YieldHandling yieldHandling, bool canHaveDirectives = false);
|
||||||
|
|
||||||
bool maybeParseDirective(Node list, Node pn, bool* cont);
|
bool maybeParseDirective(Node list, Node pn, bool* cont);
|
||||||
|
|
||||||
|
@ -1017,11 +1018,11 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
|
||||||
*/
|
*/
|
||||||
Node functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling);
|
Node functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling);
|
||||||
Node functionExpr(InvokedPrediction invoked = PredictUninvoked);
|
Node functionExpr(InvokedPrediction invoked = PredictUninvoked);
|
||||||
Node statements(YieldHandling yieldHandling);
|
|
||||||
|
Node statementList(YieldHandling yieldHandling);
|
||||||
|
|
||||||
Node blockStatement(YieldHandling yieldHandling,
|
Node blockStatement(YieldHandling yieldHandling,
|
||||||
unsigned errorNumber = JSMSG_CURLY_IN_COMPOUND);
|
unsigned errorNumber = JSMSG_CURLY_IN_COMPOUND);
|
||||||
Node ifStatement(YieldHandling yieldHandling);
|
|
||||||
Node doWhileStatement(YieldHandling yieldHandling);
|
Node doWhileStatement(YieldHandling yieldHandling);
|
||||||
Node whileStatement(YieldHandling yieldHandling);
|
Node whileStatement(YieldHandling yieldHandling);
|
||||||
|
|
||||||
|
@ -1039,13 +1040,26 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
|
||||||
Node breakStatement(YieldHandling yieldHandling);
|
Node breakStatement(YieldHandling yieldHandling);
|
||||||
Node returnStatement(YieldHandling yieldHandling);
|
Node returnStatement(YieldHandling yieldHandling);
|
||||||
Node withStatement(YieldHandling yieldHandling);
|
Node withStatement(YieldHandling yieldHandling);
|
||||||
Node labeledStatement(YieldHandling yieldHandling);
|
|
||||||
Node throwStatement(YieldHandling yieldHandling);
|
Node throwStatement(YieldHandling yieldHandling);
|
||||||
Node tryStatement(YieldHandling yieldHandling);
|
Node tryStatement(YieldHandling yieldHandling);
|
||||||
Node catchBlockStatement(YieldHandling yieldHandling, HandlePropertyName simpleCatchParam);
|
Node catchBlockStatement(YieldHandling yieldHandling, HandlePropertyName simpleCatchParam);
|
||||||
Node debuggerStatement();
|
Node debuggerStatement();
|
||||||
|
|
||||||
|
Node variableStatement(YieldHandling yieldHandling);
|
||||||
|
|
||||||
|
Node labeledStatement(YieldHandling yieldHandling);
|
||||||
|
Node labeledItem(YieldHandling yieldHandling);
|
||||||
|
|
||||||
|
Node ifStatement(YieldHandling yieldHandling);
|
||||||
|
Node consequentOrAlternative(YieldHandling yieldHandling);
|
||||||
|
|
||||||
|
// While on a |let| TOK_NAME token, examine |next|. Indicate whether
|
||||||
|
// |next|, the next token already gotten with modifier TokenStream::None,
|
||||||
|
// continues a LexicalDeclaration.
|
||||||
|
bool nextTokenContinuesLetDeclaration(TokenKind next, YieldHandling yieldHandling);
|
||||||
|
|
||||||
Node lexicalDeclaration(YieldHandling yieldHandling, bool isConst);
|
Node lexicalDeclaration(YieldHandling yieldHandling, bool isConst);
|
||||||
|
|
||||||
Node importDeclaration();
|
Node importDeclaration();
|
||||||
Node exportDeclaration();
|
Node exportDeclaration();
|
||||||
Node expressionStatement(YieldHandling yieldHandling,
|
Node expressionStatement(YieldHandling yieldHandling,
|
||||||
|
@ -1239,15 +1253,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
|
||||||
bool finishFunction();
|
bool finishFunction();
|
||||||
bool leaveInnerFunction(ParseContext* outerpc);
|
bool leaveInnerFunction(ParseContext* outerpc);
|
||||||
|
|
||||||
// Use when the current token is TOK_NAME and is known to be 'let'.
|
|
||||||
bool shouldParseLetDeclaration(bool* parseDeclOut);
|
|
||||||
|
|
||||||
// Use when the lookahead token is TOK_NAME and is known to be 'let'. If a
|
|
||||||
// let declaration should be parsed, the TOK_NAME token of 'let' is
|
|
||||||
// consumed. Otherwise, the current token remains the TOK_NAME token of
|
|
||||||
// 'let'.
|
|
||||||
bool peekShouldParseLetDeclaration(bool* parseDeclOut, TokenStream::Modifier modifier);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum FunctionCallBehavior {
|
enum FunctionCallBehavior {
|
||||||
PermitAssignmentToFunctionCalls,
|
PermitAssignmentToFunctionCalls,
|
||||||
|
|
|
@ -2,6 +2,8 @@ setJitCompilerOption("baseline.warmup.trigger", 10);
|
||||||
setJitCompilerOption("ion.warmup.trigger", 20);
|
setJitCompilerOption("ion.warmup.trigger", 20);
|
||||||
var i;
|
var i;
|
||||||
|
|
||||||
|
var config = getBuildConfiguration();
|
||||||
|
|
||||||
// Check that we are able to remove the operation inside recover test functions (denoted by "rop..."),
|
// Check that we are able to remove the operation inside recover test functions (denoted by "rop..."),
|
||||||
// when we inline the first version of uceFault, and ensure that the bailout is correct
|
// when we inline the first version of uceFault, and ensure that the bailout is correct
|
||||||
// when uceFault is replaced (which cause an invalidation bailout)
|
// when uceFault is replaced (which cause an invalidation bailout)
|
||||||
|
@ -1286,6 +1288,29 @@ function rhypot_object_4args(i) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var uceFault_random = eval(uneval(uceFault).replace('uceFault', 'uceFault_random'));
|
||||||
|
function rrandom(i) {
|
||||||
|
// setRNGState() exists only in debug builds
|
||||||
|
|
||||||
|
if(config.debug) {
|
||||||
|
setRNGState(2, 0);
|
||||||
|
var x = Math.random();
|
||||||
|
if (uceFault_random(i) || uceFault_random(i)) {
|
||||||
|
setRNGState(2, 0);
|
||||||
|
assertEq(x, Math.random());
|
||||||
|
}
|
||||||
|
assertRecoveredOnBailout(x, true);
|
||||||
|
} else {
|
||||||
|
var x = Math.random();
|
||||||
|
if (uceFault_random(i) || uceFault_random(i)) {
|
||||||
|
Math.random();
|
||||||
|
}
|
||||||
|
assertRecoveredOnBailout(x, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
var uceFault_sin_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_sin_number'));
|
var uceFault_sin_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_sin_number'));
|
||||||
function rsin_number(i) {
|
function rsin_number(i) {
|
||||||
var x = Math.sin(i);
|
var x = Math.sin(i);
|
||||||
|
@ -1444,6 +1469,7 @@ for (i = 0; i < 100; i++) {
|
||||||
rhypot_object_2args(i);
|
rhypot_object_2args(i);
|
||||||
rhypot_object_3args(i);
|
rhypot_object_3args(i);
|
||||||
rhypot_object_4args(i);
|
rhypot_object_4args(i);
|
||||||
|
rrandom(i);
|
||||||
rsin_number(i);
|
rsin_number(i);
|
||||||
rsin_object(i);
|
rsin_object(i);
|
||||||
rlog_number(i);
|
rlog_number(i);
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
setJitCompilerOption("ion.warmup.trigger", 40);
|
||||||
|
|
||||||
|
const constructors = [
|
||||||
|
Int8Array,
|
||||||
|
Uint8Array,
|
||||||
|
Uint8ClampedArray,
|
||||||
|
Int16Array,
|
||||||
|
Uint16Array,
|
||||||
|
Int32Array,
|
||||||
|
Uint32Array,
|
||||||
|
Float32Array,
|
||||||
|
Float64Array ];
|
||||||
|
|
||||||
|
// Ensure that when creating TypedArrays under JIT
|
||||||
|
// the sort() method works as expected (bug 1295034).
|
||||||
|
for (var ctor of constructors) {
|
||||||
|
for (var _ of Array(1024)) {
|
||||||
|
var testArray = new ctor(10);
|
||||||
|
testArray.sort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof reportCompare === "function")
|
||||||
|
reportCompare(true, true);
|
|
@ -11520,10 +11520,10 @@ CodeGenerator::visitAsmJSInterruptCheck(LAsmJSInterruptCheck* lir)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CodeGenerator::visitAsmThrowUnreachable(LAsmThrowUnreachable* lir)
|
CodeGenerator::visitWasmTrap(LWasmTrap* lir)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(gen->compilingAsmJS());
|
MOZ_ASSERT(gen->compilingAsmJS());
|
||||||
masm.jump(wasm::JumpTarget::Unreachable);
|
masm.jump(wasm::JumpTarget(lir->mir()->trap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef bool (*RecompileFn)(JSContext*);
|
typedef bool (*RecompileFn)(JSContext*);
|
||||||
|
|
|
@ -415,7 +415,7 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
||||||
void visitInterruptCheck(LInterruptCheck* lir);
|
void visitInterruptCheck(LInterruptCheck* lir);
|
||||||
void visitOutOfLineInterruptCheckImplicit(OutOfLineInterruptCheckImplicit* ins);
|
void visitOutOfLineInterruptCheckImplicit(OutOfLineInterruptCheckImplicit* ins);
|
||||||
void visitAsmJSInterruptCheck(LAsmJSInterruptCheck* lir);
|
void visitAsmJSInterruptCheck(LAsmJSInterruptCheck* lir);
|
||||||
void visitAsmThrowUnreachable(LAsmThrowUnreachable* lir);
|
void visitWasmTrap(LWasmTrap* lir);
|
||||||
void visitRecompileCheck(LRecompileCheck* ins);
|
void visitRecompileCheck(LRecompileCheck* ins);
|
||||||
void visitRotate(LRotate* ins);
|
void visitRotate(LRotate* ins);
|
||||||
|
|
||||||
|
|
|
@ -2530,9 +2530,9 @@ LIRGenerator::visitAsmJSInterruptCheck(MAsmJSInterruptCheck* ins)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LIRGenerator::visitAsmThrowUnreachable(MAsmThrowUnreachable* ins)
|
LIRGenerator::visitWasmTrap(MWasmTrap* ins)
|
||||||
{
|
{
|
||||||
add(new(alloc()) LAsmThrowUnreachable, ins);
|
add(new(alloc()) LWasmTrap, ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -191,7 +191,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
||||||
void visitFunctionEnvironment(MFunctionEnvironment* ins);
|
void visitFunctionEnvironment(MFunctionEnvironment* ins);
|
||||||
void visitInterruptCheck(MInterruptCheck* ins);
|
void visitInterruptCheck(MInterruptCheck* ins);
|
||||||
void visitAsmJSInterruptCheck(MAsmJSInterruptCheck* ins);
|
void visitAsmJSInterruptCheck(MAsmJSInterruptCheck* ins);
|
||||||
void visitAsmThrowUnreachable(MAsmThrowUnreachable* ins);
|
void visitWasmTrap(MWasmTrap* ins);
|
||||||
void visitAsmReinterpret(MAsmReinterpret* ins);
|
void visitAsmReinterpret(MAsmReinterpret* ins);
|
||||||
void visitStoreSlot(MStoreSlot* ins);
|
void visitStoreSlot(MStoreSlot* ins);
|
||||||
void visitFilterTypeSet(MFilterTypeSet* ins);
|
void visitFilterTypeSet(MFilterTypeSet* ins);
|
||||||
|
|
|
@ -6584,6 +6584,16 @@ class MRandom : public MNullaryInstruction
|
||||||
|
|
||||||
void computeRange(TempAllocator& alloc) override;
|
void computeRange(TempAllocator& alloc) override;
|
||||||
|
|
||||||
|
MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
|
||||||
|
|
||||||
|
bool canRecoverOnBailout() const override {
|
||||||
|
#ifdef JS_MORE_DETERMINISTIC
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
ALLOW_CLONE(MRandom)
|
ALLOW_CLONE(MRandom)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7738,18 +7748,28 @@ class MAsmJSInterruptCheck
|
||||||
TRIVIAL_NEW_WRAPPERS
|
TRIVIAL_NEW_WRAPPERS
|
||||||
};
|
};
|
||||||
|
|
||||||
// Directly jumps to the unreachable trap handler.
|
// Directly jumps to the indicated trap, leaving Wasm code and reporting a
|
||||||
class MAsmThrowUnreachable
|
// runtime error.
|
||||||
|
|
||||||
|
class MWasmTrap
|
||||||
: public MAryControlInstruction<0, 0>,
|
: public MAryControlInstruction<0, 0>,
|
||||||
public NoTypePolicy::Data
|
public NoTypePolicy::Data
|
||||||
{
|
{
|
||||||
|
wasm::Trap trap_;
|
||||||
|
|
||||||
|
explicit MWasmTrap(wasm::Trap trap)
|
||||||
|
: trap_(trap)
|
||||||
|
{}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
INSTRUCTION_HEADER(AsmThrowUnreachable)
|
INSTRUCTION_HEADER(WasmTrap)
|
||||||
TRIVIAL_NEW_WRAPPERS
|
TRIVIAL_NEW_WRAPPERS
|
||||||
|
|
||||||
AliasSet getAliasSet() const override {
|
AliasSet getAliasSet() const override {
|
||||||
return AliasSet::None();
|
return AliasSet::None();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wasm::Trap trap() const { return trap_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Checks if a value is JS_UNINITIALIZED_LEXICAL, bailout out if so, leaving
|
// Checks if a value is JS_UNINITIALIZED_LEXICAL, bailout out if so, leaving
|
||||||
|
|
|
@ -262,7 +262,6 @@ namespace jit {
|
||||||
_(CallInstanceOf) \
|
_(CallInstanceOf) \
|
||||||
_(InterruptCheck) \
|
_(InterruptCheck) \
|
||||||
_(AsmJSInterruptCheck) \
|
_(AsmJSInterruptCheck) \
|
||||||
_(AsmThrowUnreachable) \
|
|
||||||
_(GetDOMProperty) \
|
_(GetDOMProperty) \
|
||||||
_(GetDOMMember) \
|
_(GetDOMMember) \
|
||||||
_(SetDOMProperty) \
|
_(SetDOMProperty) \
|
||||||
|
@ -274,6 +273,7 @@ namespace jit {
|
||||||
_(WasmBoundsCheck) \
|
_(WasmBoundsCheck) \
|
||||||
_(WasmLoad) \
|
_(WasmLoad) \
|
||||||
_(WasmStore) \
|
_(WasmStore) \
|
||||||
|
_(WasmTrap) \
|
||||||
_(WasmTruncateToInt32) \
|
_(WasmTruncateToInt32) \
|
||||||
_(AsmJSNeg) \
|
_(AsmJSNeg) \
|
||||||
_(AsmJSUnsignedToDouble) \
|
_(AsmJSUnsignedToDouble) \
|
||||||
|
|
|
@ -1005,6 +1005,24 @@ RMathFunction::recover(JSContext* cx, SnapshotIterator& iter) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MRandom::writeRecoverData(CompactBufferWriter& writer) const
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(this->canRecoverOnBailout());
|
||||||
|
writer.writeUnsigned(uint32_t(RInstruction::Recover_Random));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RRandom::RRandom(CompactBufferReader& reader)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RRandom::recover(JSContext* cx, SnapshotIterator& iter) const
|
||||||
|
{
|
||||||
|
iter.storeInstructionResult(DoubleValue(math_random_impl(cx)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
MStringSplit::writeRecoverData(CompactBufferWriter& writer) const
|
MStringSplit::writeRecoverData(CompactBufferWriter& writer) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -88,6 +88,7 @@ namespace jit {
|
||||||
_(Atan2) \
|
_(Atan2) \
|
||||||
_(Hypot) \
|
_(Hypot) \
|
||||||
_(MathFunction) \
|
_(MathFunction) \
|
||||||
|
_(Random) \
|
||||||
_(StringSplit) \
|
_(StringSplit) \
|
||||||
_(RegExpMatcher) \
|
_(RegExpMatcher) \
|
||||||
_(RegExpSearcher) \
|
_(RegExpSearcher) \
|
||||||
|
@ -462,6 +463,13 @@ class RMathFunction final : public RInstruction
|
||||||
MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const;
|
MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RRandom final : public RInstruction
|
||||||
|
{
|
||||||
|
RINSTRUCTION_HEADER_NUM_OP_(Random, 0)
|
||||||
|
public:
|
||||||
|
MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const;
|
||||||
|
};
|
||||||
|
|
||||||
class RStringSplit final : public RInstruction
|
class RStringSplit final : public RInstruction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -2291,11 +2291,7 @@ CodeGeneratorARM::visitWasmBoundsCheck(LWasmBoundsCheck* ins)
|
||||||
{
|
{
|
||||||
MWasmBoundsCheck* mir = ins->mir();
|
MWasmBoundsCheck* mir = ins->mir();
|
||||||
|
|
||||||
uint32_t offset = mir->offset();
|
MOZ_ASSERT(mir->offset() <= INT32_MAX);
|
||||||
if (offset > INT32_MAX) {
|
|
||||||
masm.as_b(wasm::JumpTarget::OutOfBounds);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mir->isRedundant()) {
|
if (!mir->isRedundant()) {
|
||||||
// No guarantee that heapBase + endOffset can be properly encoded in
|
// No guarantee that heapBase + endOffset can be properly encoded in
|
||||||
|
@ -2348,11 +2344,7 @@ CodeGeneratorARM::emitWasmLoad(T* lir)
|
||||||
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
|
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
|
||||||
|
|
||||||
uint32_t offset = mir->offset();
|
uint32_t offset = mir->offset();
|
||||||
if (offset > INT32_MAX) {
|
MOZ_ASSERT(offset <= INT32_MAX);
|
||||||
// This is unreachable because of bounds checks.
|
|
||||||
masm.breakpoint();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Register ptr = ToRegister(lir->ptr());
|
Register ptr = ToRegister(lir->ptr());
|
||||||
Scalar::Type type = mir->accessType();
|
Scalar::Type type = mir->accessType();
|
||||||
|
@ -2419,11 +2411,7 @@ CodeGeneratorARM::emitWasmUnalignedLoad(T* lir)
|
||||||
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
|
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
|
||||||
|
|
||||||
uint32_t offset = mir->offset();
|
uint32_t offset = mir->offset();
|
||||||
if (offset > INT32_MAX) {
|
MOZ_ASSERT(offset <= INT32_MAX);
|
||||||
// This is unreachable because of bounds checks.
|
|
||||||
masm.breakpoint();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Register ptr = ToRegister(lir->ptrCopy());
|
Register ptr = ToRegister(lir->ptrCopy());
|
||||||
if (offset)
|
if (offset)
|
||||||
|
@ -2503,11 +2491,7 @@ CodeGeneratorARM::emitWasmStore(T* lir)
|
||||||
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
|
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
|
||||||
|
|
||||||
uint32_t offset = mir->offset();
|
uint32_t offset = mir->offset();
|
||||||
if (offset > INT32_MAX) {
|
MOZ_ASSERT(offset <= INT32_MAX);
|
||||||
// This is unreachable because of bounds checks.
|
|
||||||
masm.breakpoint();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Register ptr = ToRegister(lir->ptr());
|
Register ptr = ToRegister(lir->ptr());
|
||||||
unsigned byteSize = mir->byteSize();
|
unsigned byteSize = mir->byteSize();
|
||||||
|
|
|
@ -1666,10 +1666,7 @@ CodeGeneratorMIPSShared::visitWasmBoundsCheck(LWasmBoundsCheck* ins)
|
||||||
MWasmBoundsCheck* mir = ins->mir();
|
MWasmBoundsCheck* mir = ins->mir();
|
||||||
|
|
||||||
uint32_t offset = mir->offset();
|
uint32_t offset = mir->offset();
|
||||||
if (offset > INT32_MAX) {
|
MOZ_ASSERT(offset <= INT32_MAX);
|
||||||
masm.jump(wasm::JumpTarget::OutOfBounds);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t endOffset = mir->endOffset();
|
uint32_t endOffset = mir->endOffset();
|
||||||
Register ptr = ToRegister(ins->ptr());
|
Register ptr = ToRegister(ins->ptr());
|
||||||
|
@ -1693,11 +1690,7 @@ CodeGeneratorMIPSShared::visitWasmLoad(LWasmLoad* lir)
|
||||||
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
|
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
|
||||||
|
|
||||||
uint32_t offset = mir->offset();
|
uint32_t offset = mir->offset();
|
||||||
if (offset > INT32_MAX) {
|
MOZ_ASSERT(offset <= INT32_MAX);
|
||||||
// This is unreachable because of bounds checks.
|
|
||||||
masm.breakpoint();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Register ptr = ToRegister(lir->ptr());
|
Register ptr = ToRegister(lir->ptr());
|
||||||
|
|
||||||
|
@ -1745,11 +1738,7 @@ CodeGeneratorMIPSShared::visitWasmStore(LWasmStore* lir)
|
||||||
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
|
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
|
||||||
|
|
||||||
uint32_t offset = mir->offset();
|
uint32_t offset = mir->offset();
|
||||||
if (offset > INT32_MAX) {
|
MOZ_ASSERT(offset <= INT32_MAX);
|
||||||
// This is unreachable because of bounds checks.
|
|
||||||
masm.breakpoint();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Register ptr = ToRegister(lir->ptr());
|
Register ptr = ToRegister(lir->ptr());
|
||||||
|
|
||||||
|
|
|
@ -1067,26 +1067,14 @@ MacroAssemblerMIPSCompat::storePtr(Register src, AbsoluteAddress dest)
|
||||||
void
|
void
|
||||||
MacroAssemblerMIPSCompat::clampIntToUint8(Register reg)
|
MacroAssemblerMIPSCompat::clampIntToUint8(Register reg)
|
||||||
{
|
{
|
||||||
// look at (reg >> 8) if it is 0, then src shouldn't be clamped
|
// If reg is < 0, then we want to clamp to 0.
|
||||||
// if it is <0, then we want to clamp to 0,
|
as_slti(ScratchRegister, reg, 0);
|
||||||
// otherwise, we wish to clamp to 255
|
as_movn(reg, zero, ScratchRegister);
|
||||||
Label done;
|
|
||||||
ma_move(ScratchRegister, reg);
|
// If reg is >= 255, then we want to clamp to 255.
|
||||||
asMasm().rshiftPtrArithmetic(Imm32(8), ScratchRegister);
|
ma_li(SecondScratchReg, Imm32(255));
|
||||||
ma_b(ScratchRegister, ScratchRegister, &done, Assembler::Zero, ShortJump);
|
as_slti(ScratchRegister, reg, 255);
|
||||||
{
|
as_movz(reg, SecondScratchReg, ScratchRegister);
|
||||||
Label negative;
|
|
||||||
ma_b(ScratchRegister, ScratchRegister, &negative, Assembler::Signed, ShortJump);
|
|
||||||
{
|
|
||||||
ma_li(reg, Imm32(255));
|
|
||||||
ma_b(&done, ShortJump);
|
|
||||||
}
|
|
||||||
bind(&negative);
|
|
||||||
{
|
|
||||||
ma_move(reg, zero);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bind(&done);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: this function clobbers the input register.
|
// Note: this function clobbers the input register.
|
||||||
|
|
|
@ -1214,26 +1214,14 @@ MacroAssemblerMIPS64Compat::storePtr(Register src, AbsoluteAddress dest)
|
||||||
void
|
void
|
||||||
MacroAssemblerMIPS64Compat::clampIntToUint8(Register reg)
|
MacroAssemblerMIPS64Compat::clampIntToUint8(Register reg)
|
||||||
{
|
{
|
||||||
// look at (reg >> 8) if it is 0, then src shouldn't be clamped
|
// If reg is < 0, then we want to clamp to 0.
|
||||||
// if it is <0, then we want to clamp to 0,
|
as_slti(ScratchRegister, reg, 0);
|
||||||
// otherwise, we wish to clamp to 255
|
as_movn(reg, zero, ScratchRegister);
|
||||||
Label done;
|
|
||||||
ma_move(ScratchRegister, reg);
|
// If reg is >= 255, then we want to clamp to 255.
|
||||||
asMasm().rshiftPtrArithmetic(Imm32(8), ScratchRegister);
|
ma_li(SecondScratchReg, Imm32(255));
|
||||||
ma_b(ScratchRegister, ScratchRegister, &done, Assembler::Zero, ShortJump);
|
as_slti(ScratchRegister, reg, 255);
|
||||||
{
|
as_movz(reg, SecondScratchReg, ScratchRegister);
|
||||||
Label negative;
|
|
||||||
ma_b(ScratchRegister, ScratchRegister, &negative, Assembler::Signed, ShortJump);
|
|
||||||
{
|
|
||||||
ma_li(reg, Imm32(255));
|
|
||||||
ma_b(&done, ShortJump);
|
|
||||||
}
|
|
||||||
bind(&negative);
|
|
||||||
{
|
|
||||||
ma_move(reg, zero);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bind(&done);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: this function clobbers the input register.
|
// Note: this function clobbers the input register.
|
||||||
|
@ -1330,15 +1318,13 @@ MacroAssemblerMIPS64Compat::unboxNonDouble(const BaseIndex& src, Register dest)
|
||||||
void
|
void
|
||||||
MacroAssemblerMIPS64Compat::unboxInt32(const ValueOperand& operand, Register dest)
|
MacroAssemblerMIPS64Compat::unboxInt32(const ValueOperand& operand, Register dest)
|
||||||
{
|
{
|
||||||
ma_dsll(dest, operand.valueReg(), Imm32(32));
|
ma_sll(dest, operand.valueReg(), Imm32(0));
|
||||||
ma_dsra(dest, dest, Imm32(32));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MacroAssemblerMIPS64Compat::unboxInt32(Register src, Register dest)
|
MacroAssemblerMIPS64Compat::unboxInt32(Register src, Register dest)
|
||||||
{
|
{
|
||||||
ma_dsll(dest, src, Imm32(32));
|
ma_sll(dest, src, Imm32(0));
|
||||||
ma_dsra(dest, dest, Imm32(32));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -1404,13 +1404,17 @@ class LAsmJSInterruptCheck : public LInstructionHelper<0, 0, 0>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class LAsmThrowUnreachable : public LInstructionHelper<0, 0, 0>
|
class LWasmTrap : public LInstructionHelper<0, 0, 0>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LIR_HEADER(AsmThrowUnreachable);
|
LIR_HEADER(WasmTrap);
|
||||||
|
|
||||||
LAsmThrowUnreachable()
|
LWasmTrap()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
const MWasmTrap* mir() const {
|
||||||
|
return mir_->toWasmTrap();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<size_t Defs, size_t Ops>
|
template<size_t Defs, size_t Ops>
|
||||||
|
|
|
@ -369,7 +369,7 @@
|
||||||
_(CallInstanceOf) \
|
_(CallInstanceOf) \
|
||||||
_(InterruptCheck) \
|
_(InterruptCheck) \
|
||||||
_(AsmJSInterruptCheck) \
|
_(AsmJSInterruptCheck) \
|
||||||
_(AsmThrowUnreachable) \
|
_(WasmTrap) \
|
||||||
_(AsmReinterpret) \
|
_(AsmReinterpret) \
|
||||||
_(AsmReinterpretToI64) \
|
_(AsmReinterpretToI64) \
|
||||||
_(AsmReinterpretFromI64) \
|
_(AsmReinterpretFromI64) \
|
||||||
|
|
|
@ -538,11 +538,7 @@ CodeGeneratorX64::emitWasmLoad(T* ins)
|
||||||
Scalar::Type accessType = mir->accessType();
|
Scalar::Type accessType = mir->accessType();
|
||||||
MOZ_ASSERT(!Scalar::isSimdType(accessType), "SIMD NYI");
|
MOZ_ASSERT(!Scalar::isSimdType(accessType), "SIMD NYI");
|
||||||
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
|
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
|
||||||
|
MOZ_ASSERT(mir->offset() <= INT32_MAX);
|
||||||
if (mir->offset() > INT32_MAX) {
|
|
||||||
masm.jump(wasm::JumpTarget::OutOfBounds);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const LAllocation* ptr = ins->ptr();
|
const LAllocation* ptr = ins->ptr();
|
||||||
Operand srcAddr = ptr->isBogus()
|
Operand srcAddr = ptr->isBogus()
|
||||||
|
@ -583,11 +579,7 @@ CodeGeneratorX64::emitWasmStore(T* ins)
|
||||||
Scalar::Type accessType = mir->accessType();
|
Scalar::Type accessType = mir->accessType();
|
||||||
MOZ_ASSERT(!Scalar::isSimdType(accessType), "SIMD NYI");
|
MOZ_ASSERT(!Scalar::isSimdType(accessType), "SIMD NYI");
|
||||||
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
|
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
|
||||||
|
MOZ_ASSERT(mir->offset() <= INT32_MAX);
|
||||||
if (mir->offset() > INT32_MAX) {
|
|
||||||
masm.jump(wasm::JumpTarget::OutOfBounds);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const LAllocation* value = ins->getOperand(ins->ValueIndex);
|
const LAllocation* value = ins->getOperand(ins->ValueIndex);
|
||||||
const LAllocation* ptr = ins->ptr();
|
const LAllocation* ptr = ins->ptr();
|
||||||
|
|
|
@ -494,11 +494,9 @@ void
|
||||||
CodeGeneratorX86Shared::visitWasmBoundsCheck(LWasmBoundsCheck* ins)
|
CodeGeneratorX86Shared::visitWasmBoundsCheck(LWasmBoundsCheck* ins)
|
||||||
{
|
{
|
||||||
const MWasmBoundsCheck* mir = ins->mir();
|
const MWasmBoundsCheck* mir = ins->mir();
|
||||||
|
|
||||||
MOZ_ASSERT(gen->needsBoundsCheckBranch(mir));
|
MOZ_ASSERT(gen->needsBoundsCheckBranch(mir));
|
||||||
if (mir->offset() > INT32_MAX) {
|
MOZ_ASSERT(mir->offset() <= INT32_MAX);
|
||||||
masm.jump(wasm::JumpTarget::OutOfBounds);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Register ptrReg = ToRegister(ins->ptr());
|
Register ptrReg = ToRegister(ins->ptr());
|
||||||
maybeEmitWasmBoundsCheckBranch(mir, ptrReg, mir->isRedundant());
|
maybeEmitWasmBoundsCheckBranch(mir, ptrReg, mir->isRedundant());
|
||||||
|
@ -548,9 +546,8 @@ CodeGeneratorX86Shared::maybeEmitWasmBoundsCheckBranch(const MWasmMemoryAccess*
|
||||||
|
|
||||||
MOZ_ASSERT(mir->endOffset() >= 1,
|
MOZ_ASSERT(mir->endOffset() >= 1,
|
||||||
"need to subtract 1 to use JAE, see also AssemblerX86Shared::UpdateBoundsCheck");
|
"need to subtract 1 to use JAE, see also AssemblerX86Shared::UpdateBoundsCheck");
|
||||||
/*
|
|
||||||
* TODO: See 1287224 Unify MWasmBoundsCheck::redunant_ and needsBoundsCheck
|
// TODO: See 1287224 Unify MWasmBoundsCheck::redunant_ and needsBoundsCheck
|
||||||
*/
|
|
||||||
if (!redundant) {
|
if (!redundant) {
|
||||||
uint32_t cmpOffset = masm.cmp32WithPatch(ptr, Imm32(1 - mir->endOffset())).offset();
|
uint32_t cmpOffset = masm.cmp32WithPatch(ptr, Imm32(1 - mir->endOffset())).offset();
|
||||||
masm.j(Assembler::AboveOrEqual, wasm::JumpTarget::OutOfBounds);
|
masm.j(Assembler::AboveOrEqual, wasm::JumpTarget::OutOfBounds);
|
||||||
|
|
|
@ -500,12 +500,7 @@ CodeGeneratorX86::emitWasmLoad(T* ins)
|
||||||
Scalar::Type accessType = mir->accessType();
|
Scalar::Type accessType = mir->accessType();
|
||||||
MOZ_ASSERT(!Scalar::isSimdType(accessType), "SIMD NYI");
|
MOZ_ASSERT(!Scalar::isSimdType(accessType), "SIMD NYI");
|
||||||
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
|
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
|
||||||
|
MOZ_ASSERT(mir->offset() <= INT32_MAX);
|
||||||
if (mir->offset() > INT32_MAX) {
|
|
||||||
// This is unreachable because of the bounds check.
|
|
||||||
masm.breakpoint();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const LAllocation* ptr = ins->ptr();
|
const LAllocation* ptr = ins->ptr();
|
||||||
Operand srcAddr = ptr->isBogus()
|
Operand srcAddr = ptr->isBogus()
|
||||||
|
@ -539,12 +534,7 @@ CodeGeneratorX86::emitWasmStore(T* ins)
|
||||||
Scalar::Type accessType = mir->accessType();
|
Scalar::Type accessType = mir->accessType();
|
||||||
MOZ_ASSERT(!Scalar::isSimdType(accessType), "SIMD NYI");
|
MOZ_ASSERT(!Scalar::isSimdType(accessType), "SIMD NYI");
|
||||||
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
|
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
|
||||||
|
MOZ_ASSERT(mir->offset() <= INT32_MAX);
|
||||||
if (mir->offset() > INT32_MAX) {
|
|
||||||
// This is unreachable because of the bounds check.
|
|
||||||
masm.breakpoint();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const LAllocation* ptr = ins->ptr();
|
const LAllocation* ptr = ins->ptr();
|
||||||
Operand dstAddr = ptr->isBogus()
|
Operand dstAddr = ptr->isBogus()
|
||||||
|
|
|
@ -248,6 +248,7 @@ MSG_DEF(JSMSG_EMPTY_CONSEQUENT, 0, JSEXN_SYNTAXERR, "mistyped ; after con
|
||||||
MSG_DEF(JSMSG_EQUAL_AS_ASSIGN, 0, JSEXN_SYNTAXERR, "test for equality (==) mistyped as assignment (=)?")
|
MSG_DEF(JSMSG_EQUAL_AS_ASSIGN, 0, JSEXN_SYNTAXERR, "test for equality (==) mistyped as assignment (=)?")
|
||||||
MSG_DEF(JSMSG_EXPORT_DECL_AT_TOP_LEVEL,0, JSEXN_SYNTAXERR, "export declarations may only appear at top level of a module")
|
MSG_DEF(JSMSG_EXPORT_DECL_AT_TOP_LEVEL,0, JSEXN_SYNTAXERR, "export declarations may only appear at top level of a module")
|
||||||
MSG_DEF(JSMSG_FINALLY_WITHOUT_TRY, 0, JSEXN_SYNTAXERR, "finally without try")
|
MSG_DEF(JSMSG_FINALLY_WITHOUT_TRY, 0, JSEXN_SYNTAXERR, "finally without try")
|
||||||
|
MSG_DEF(JSMSG_FORBIDDEN_AS_STATEMENT, 1, JSEXN_SYNTAXERR, "{0} can't appear in single-statement context")
|
||||||
MSG_DEF(JSMSG_FROM_AFTER_IMPORT_CLAUSE, 0, JSEXN_SYNTAXERR, "missing keyword 'from' after import clause")
|
MSG_DEF(JSMSG_FROM_AFTER_IMPORT_CLAUSE, 0, JSEXN_SYNTAXERR, "missing keyword 'from' after import clause")
|
||||||
MSG_DEF(JSMSG_FROM_AFTER_EXPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'from' after export *")
|
MSG_DEF(JSMSG_FROM_AFTER_EXPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'from' after export *")
|
||||||
MSG_DEF(JSMSG_GARBAGE_AFTER_INPUT, 2, JSEXN_SYNTAXERR, "unexpected garbage after {0}, starting with {1}")
|
MSG_DEF(JSMSG_GARBAGE_AFTER_INPUT, 2, JSEXN_SYNTAXERR, "unexpected garbage after {0}, starting with {1}")
|
||||||
|
@ -260,6 +261,7 @@ MSG_DEF(JSMSG_LET_CLASS_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid
|
||||||
MSG_DEF(JSMSG_LET_COMP_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable")
|
MSG_DEF(JSMSG_LET_COMP_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable")
|
||||||
MSG_DEF(JSMSG_LEXICAL_DECL_NOT_IN_BLOCK, 1, JSEXN_SYNTAXERR, "{0} declaration not directly within block")
|
MSG_DEF(JSMSG_LEXICAL_DECL_NOT_IN_BLOCK, 1, JSEXN_SYNTAXERR, "{0} declaration not directly within block")
|
||||||
MSG_DEF(JSMSG_LEXICAL_DECL_LABEL, 1, JSEXN_SYNTAXERR, "{0} declarations cannot be labelled")
|
MSG_DEF(JSMSG_LEXICAL_DECL_LABEL, 1, JSEXN_SYNTAXERR, "{0} declarations cannot be labelled")
|
||||||
|
MSG_DEF(JSMSG_GENERATOR_LABEL, 0, JSEXN_SYNTAXERR, "generator functions cannot be labelled")
|
||||||
MSG_DEF(JSMSG_FUNCTION_LABEL, 0, JSEXN_SYNTAXERR, "functions cannot be labelled")
|
MSG_DEF(JSMSG_FUNCTION_LABEL, 0, JSEXN_SYNTAXERR, "functions cannot be labelled")
|
||||||
MSG_DEF(JSMSG_SLOPPY_FUNCTION_LABEL, 0, JSEXN_SYNTAXERR, "functions can only be labelled inside blocks")
|
MSG_DEF(JSMSG_SLOPPY_FUNCTION_LABEL, 0, JSEXN_SYNTAXERR, "functions can only be labelled inside blocks")
|
||||||
MSG_DEF(JSMSG_LINE_BREAK_AFTER_THROW, 0, JSEXN_SYNTAXERR, "no line break is allowed between 'throw' and its expression")
|
MSG_DEF(JSMSG_LINE_BREAK_AFTER_THROW, 0, JSEXN_SYNTAXERR, "no line break is allowed between 'throw' and its expression")
|
||||||
|
|
|
@ -719,16 +719,19 @@ JSCompartment::ensureRandomNumberGenerator()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double
|
||||||
|
js::math_random_impl(JSContext* cx)
|
||||||
|
{
|
||||||
|
JSCompartment* comp = cx->compartment();
|
||||||
|
comp->ensureRandomNumberGenerator();
|
||||||
|
return comp->randomNumberGenerator.ref().nextDouble();
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
js::math_random(JSContext* cx, unsigned argc, Value* vp)
|
js::math_random(JSContext* cx, unsigned argc, Value* vp)
|
||||||
{
|
{
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
args.rval().setNumber(math_random_impl(cx));
|
||||||
JSCompartment* comp = cx->compartment();
|
|
||||||
comp->ensureRandomNumberGenerator();
|
|
||||||
|
|
||||||
double z = comp->randomNumberGenerator.ref().nextDouble();
|
|
||||||
args.rval().setDouble(z);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,9 @@ GenerateXorShift128PlusSeed(mozilla::Array<uint64_t, 2>& seed);
|
||||||
extern uint64_t
|
extern uint64_t
|
||||||
random_next(uint64_t* rngState, int bits);
|
random_next(uint64_t* rngState, int bits);
|
||||||
|
|
||||||
|
extern double
|
||||||
|
math_random_impl(JSContext* cx);
|
||||||
|
|
||||||
extern bool
|
extern bool
|
||||||
math_random(JSContext* cx, unsigned argc, js::Value* vp);
|
math_random(JSContext* cx, unsigned argc, js::Value* vp);
|
||||||
|
|
||||||
|
|
|
@ -2544,6 +2544,13 @@ js::SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto, JS::Object
|
||||||
return Proxy::setPrototype(cx, obj, proto, result);
|
return Proxy::setPrototype(cx, obj, proto, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ES6 9.1.2 step 3-4 if |obj.[[Prototype]]| has SameValue as |proto| return true.
|
||||||
|
* Since the values in question are objects, we can just compare pointers.
|
||||||
|
*/
|
||||||
|
if (proto == obj->staticPrototype())
|
||||||
|
return result.succeed();
|
||||||
|
|
||||||
/* Disallow mutation of immutable [[Prototype]]s. */
|
/* Disallow mutation of immutable [[Prototype]]s. */
|
||||||
if (obj->staticPrototypeIsImmutable() && ImmutablePrototypesEnabled)
|
if (obj->staticPrototypeIsImmutable() && ImmutablePrototypesEnabled)
|
||||||
return result.fail(JSMSG_CANT_SET_PROTO);
|
return result.fail(JSMSG_CANT_SET_PROTO);
|
||||||
|
@ -2578,13 +2585,6 @@ js::SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto, JS::Object
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* ES6 9.1.2 step 3-4 if |obj.[[Prototype]]| has SameValue as |proto| return true.
|
|
||||||
* Since the values in question are objects, we can just compare pointers.
|
|
||||||
*/
|
|
||||||
if (proto == obj->staticPrototype())
|
|
||||||
return result.succeed();
|
|
||||||
|
|
||||||
/* ES6 9.1.2 step 5 forbids changing [[Prototype]] if not [[Extensible]]. */
|
/* ES6 9.1.2 step 5 forbids changing [[Prototype]] if not [[Extensible]]. */
|
||||||
bool extensible;
|
bool extensible;
|
||||||
if (!IsExtensible(cx, obj, &extensible))
|
if (!IsExtensible(cx, obj, &extensible))
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
// Setting a "new" prototype to the current [[Prototype]] value should never fail
|
||||||
|
|
||||||
|
var x = {}, t = Object.create(x);
|
||||||
|
Object.preventExtensions(t);
|
||||||
|
// Should not fail, because it is the same [[Prototype]] value
|
||||||
|
Object.setPrototypeOf(t, x);
|
||||||
|
|
||||||
|
// Object.prototype's [[Prototype]] is immutable, make sure we can still set null
|
||||||
|
Object.setPrototypeOf(Object.prototype, null);
|
||||||
|
|
||||||
|
reportCompare(true, true);
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/licenses/publicdomain/
|
||||||
|
*/
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
var BUGNUMBER = 1288459;
|
||||||
|
var summary =
|
||||||
|
"Properly implement the spec's distinctions between StatementListItem and " +
|
||||||
|
"Statement grammar productions and their uses";
|
||||||
|
|
||||||
|
print(BUGNUMBER + ": " + summary);
|
||||||
|
|
||||||
|
/**************
|
||||||
|
* BEGIN TEST *
|
||||||
|
**************/
|
||||||
|
|
||||||
|
assertThrowsInstanceOf(() => Function("a: let x;"), SyntaxError);
|
||||||
|
assertThrowsInstanceOf(() => Function("b: const y = 3;"), SyntaxError);
|
||||||
|
assertThrowsInstanceOf(() => Function("c: class z {};"), SyntaxError);
|
||||||
|
|
||||||
|
assertThrowsInstanceOf(() => Function("'use strict'; d: function w() {};"), SyntaxError);
|
||||||
|
|
||||||
|
// Annex B.3.2 allows this in non-strict mode code.
|
||||||
|
Function("e: function x() {};");
|
||||||
|
|
||||||
|
assertThrowsInstanceOf(() => Function("f: function* y() {}"), SyntaxError);
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
if (typeof reportCompare === "function")
|
||||||
|
reportCompare(true, true);
|
||||||
|
|
||||||
|
print("Tests complete");
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/licenses/publicdomain/
|
||||||
|
*/
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
var BUGNUMBER = 1288459;
|
||||||
|
var summary = "let can't be used as a label in strict mode code";
|
||||||
|
|
||||||
|
print(BUGNUMBER + ": " + summary);
|
||||||
|
|
||||||
|
/**************
|
||||||
|
* BEGIN TEST *
|
||||||
|
**************/
|
||||||
|
|
||||||
|
Function("let: 42")
|
||||||
|
assertThrowsInstanceOf(() => Function(" 'use strict'; let: 42"), SyntaxError);
|
||||||
|
assertThrowsInstanceOf(() => Function(" 'use strict' \n let: 42"), SyntaxError);
|
||||||
|
|
||||||
|
eval("let: 42")
|
||||||
|
assertThrowsInstanceOf(() => eval(" 'use strict'; let: 42"), SyntaxError);
|
||||||
|
assertThrowsInstanceOf(() => eval(" 'use strict' \n let: 42;"), SyntaxError);
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
if (typeof reportCompare === "function")
|
||||||
|
reportCompare(true, true);
|
||||||
|
|
||||||
|
print("Tests complete");
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче