зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to m-c. a=merge
This commit is contained in:
Коммит
833b27ac01
|
@ -99,6 +99,7 @@ testing/web-platform/products/
|
||||||
mobile/android/gradle/.gradle
|
mobile/android/gradle/.gradle
|
||||||
|
|
||||||
# XCode project cruft
|
# XCode project cruft
|
||||||
|
/*.xcodeproj/
|
||||||
embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/project.xcworkspace/xcuserdata
|
embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/project.xcworkspace/xcuserdata
|
||||||
embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/xcuserdata
|
embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/xcuserdata
|
||||||
|
|
||||||
|
|
|
@ -107,6 +107,7 @@ GPATH
|
||||||
^mobile/android/gradle/.gradle
|
^mobile/android/gradle/.gradle
|
||||||
|
|
||||||
# XCode project cruft
|
# XCode project cruft
|
||||||
|
^[^/]*\.xcodeproj/
|
||||||
^embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/project.xcworkspace/xcuserdata
|
^embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/project.xcworkspace/xcuserdata
|
||||||
^embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/xcuserdata
|
^embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/xcuserdata
|
||||||
|
|
||||||
|
|
|
@ -1336,6 +1336,13 @@ HyperTextAccessible::SetSelectionRange(int32_t aStartPos, int32_t aEndPos)
|
||||||
domSel->RemoveRange(domSel->GetRangeAt(idx));
|
domSel->RemoveRange(domSel->GetRangeAt(idx));
|
||||||
SetSelectionBoundsAt(0, aStartPos, aEndPos);
|
SetSelectionBoundsAt(0, aStartPos, aEndPos);
|
||||||
|
|
||||||
|
// Make sure it is visible
|
||||||
|
domSel->ScrollIntoView(nsISelectionController::SELECTION_FOCUS_REGION,
|
||||||
|
nsIPresShell::ScrollAxis(),
|
||||||
|
nsIPresShell::ScrollAxis(),
|
||||||
|
dom::Selection::SCROLL_FOR_CARET_MOVE |
|
||||||
|
dom::Selection::SCROLL_OVERFLOW_HIDDEN);
|
||||||
|
|
||||||
// When selection is done, move the focus to the selection if accessible is
|
// When selection is done, move the focus to the selection if accessible is
|
||||||
// not focusable. That happens when selection is set within hypertext
|
// not focusable. That happens when selection is set within hypertext
|
||||||
// accessible.
|
// accessible.
|
||||||
|
|
|
@ -2002,17 +2002,6 @@ if (AppConstants.platform == "macosx") {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Legacy global init functions */
|
|
||||||
var BrowserStartup = gBrowserInit.onLoad.bind(gBrowserInit);
|
|
||||||
var BrowserShutdown = gBrowserInit.onUnload.bind(gBrowserInit);
|
|
||||||
|
|
||||||
if (AppConstants.platform == "macosx") {
|
|
||||||
var nonBrowserWindowStartup = gBrowserInit.nonBrowserWindowStartup.bind(gBrowserInit);
|
|
||||||
var nonBrowserWindowDelayedStartup = gBrowserInit.nonBrowserWindowDelayedStartup.bind(gBrowserInit);
|
|
||||||
var nonBrowserWindowShutdown = gBrowserInit.nonBrowserWindowShutdown.bind(gBrowserInit);
|
|
||||||
}
|
|
||||||
|
|
||||||
function HandleAppCommandEvent(evt) {
|
function HandleAppCommandEvent(evt) {
|
||||||
switch (evt.command) {
|
switch (evt.command) {
|
||||||
case "Back":
|
case "Back":
|
||||||
|
|
|
@ -25,6 +25,10 @@ const CHROMEROOT = croot;
|
||||||
var gApp = document.getElementById("bundle_brand").getString("brandShortName");
|
var gApp = document.getElementById("bundle_brand").getString("brandShortName");
|
||||||
var gVersion = Services.appinfo.version;
|
var gVersion = Services.appinfo.version;
|
||||||
|
|
||||||
|
function waitForTick() {
|
||||||
|
return new Promise(resolve => executeSoon(resolve));
|
||||||
|
}
|
||||||
|
|
||||||
function getObserverTopic(aNotificationId) {
|
function getObserverTopic(aNotificationId) {
|
||||||
let topic = aNotificationId;
|
let topic = aNotificationId;
|
||||||
if (topic == "xpinstall-disabled")
|
if (topic == "xpinstall-disabled")
|
||||||
|
@ -69,6 +73,7 @@ async function waitForProgressNotification(aPanelOpen = false, aExpectedCount =
|
||||||
|
|
||||||
await observerPromise;
|
await observerPromise;
|
||||||
await panelEventPromise;
|
await panelEventPromise;
|
||||||
|
await waitForTick();
|
||||||
|
|
||||||
info("Saw a notification");
|
info("Saw a notification");
|
||||||
ok(PopupNotifications.isPanelOpen, "Panel should be open");
|
ok(PopupNotifications.isPanelOpen, "Panel should be open");
|
||||||
|
@ -114,6 +119,7 @@ async function waitForNotification(aId, aExpectedCount = 1) {
|
||||||
|
|
||||||
await observerPromise;
|
await observerPromise;
|
||||||
await panelEventPromise;
|
await panelEventPromise;
|
||||||
|
await waitForTick();
|
||||||
|
|
||||||
info("Saw a " + aId + " notification");
|
info("Saw a " + aId + " notification");
|
||||||
ok(PopupNotifications.isPanelOpen, "Panel should be open");
|
ok(PopupNotifications.isPanelOpen, "Panel should be open");
|
||||||
|
|
|
@ -15,8 +15,11 @@ add_task(async function closing_tab_with_dependents_should_close_window() {
|
||||||
let openedTab = (await depTabOpened).target;
|
let openedTab = (await depTabOpened).target;
|
||||||
info("Got opened tab");
|
info("Got opened tab");
|
||||||
|
|
||||||
|
let otherTabClosePromise = BrowserTestUtils.tabRemoved(openedTab);
|
||||||
let windowClosedPromise = BrowserTestUtils.windowClosed(win);
|
let windowClosedPromise = BrowserTestUtils.windowClosed(win);
|
||||||
await BrowserTestUtils.removeTab(tab);
|
await BrowserTestUtils.removeTab(tab);
|
||||||
|
info("Wait for other tab to close, this shouldn't time out");
|
||||||
|
await otherTabClosePromise;
|
||||||
is(Cu.isDeadWrapper(openedTab) || openedTab.linkedBrowser == null, true, "Opened tab should also have closed");
|
is(Cu.isDeadWrapper(openedTab) || openedTab.linkedBrowser == null, true, "Opened tab should also have closed");
|
||||||
info("If we timeout now, the window failed to close - that shouldn't happen!");
|
info("If we timeout now, the window failed to close - that shouldn't happen!");
|
||||||
await windowClosedPromise;
|
await windowClosedPromise;
|
||||||
|
|
|
@ -1933,8 +1933,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
let identityIcon = document.getElementById("identity-icon");
|
let identityIcon = document.getElementById("identity-icon");
|
||||||
let identityRect =
|
let identityRect =
|
||||||
this.DOMWindowUtils.getBoundsWithoutFlushing(identityIcon);
|
this.DOMWindowUtils.getBoundsWithoutFlushing(identityIcon);
|
||||||
this.siteIconStart = popupDirection == "rtl" ? identityRect.right
|
if (popupDirection == "rtl") {
|
||||||
: identityRect.left;
|
this.siteIconStart = documentRect.right - identityRect.right;
|
||||||
|
} else {
|
||||||
|
this.siteIconStart = identityRect.left;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Reset the alignment so that the site icons are positioned
|
// Reset the alignment so that the site icons are positioned
|
||||||
// according to whatever's in the CSS.
|
// according to whatever's in the CSS.
|
||||||
|
@ -1989,10 +1992,8 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
deckIndex = 1;
|
deckIndex = 1;
|
||||||
|
|
||||||
if (this.siteIconStart) {
|
if (this.siteIconStart) {
|
||||||
let rect = this.DOMWindowUtils.getBoundsWithoutFlushing(window.document.documentElement);
|
this.searchSuggestionsNotification.style.paddingInlineStart =
|
||||||
let padding = popupDirection == "rtl" ? rect.right - this.siteIconStart
|
this.siteIconStart + "px";
|
||||||
: this.siteIconStart;
|
|
||||||
this.searchSuggestionsNotification.style.paddingInlineStart = padding + "px";
|
|
||||||
} else {
|
} else {
|
||||||
this.searchSuggestionsNotification.style.removeProperty("padding-inline-start");
|
this.searchSuggestionsNotification.style.removeProperty("padding-inline-start");
|
||||||
}
|
}
|
||||||
|
|
|
@ -266,6 +266,12 @@
|
||||||
font-size: 1.25em;
|
font-size: 1.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ensure diacritics and other edge-of-font-box glyphs do not get clipped,
|
||||||
|
* even in non-Latin scripts. */
|
||||||
|
html|input.urlbar-input {
|
||||||
|
line-height: 1.745em;
|
||||||
|
}
|
||||||
|
|
||||||
#urlbar[focused="true"],
|
#urlbar[focused="true"],
|
||||||
.searchbar-textbox[focused="true"] {
|
.searchbar-textbox[focused="true"] {
|
||||||
border-color: -moz-mac-focusring;
|
border-color: -moz-mac-focusring;
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
|
|
||||||
const { CanvasFrameAnonymousContentHelper, getCSSStyleRules,
|
const { CanvasFrameAnonymousContentHelper, getCSSStyleRules,
|
||||||
createSVGNode, createNode, getComputedStyle } = require("./utils/markup");
|
createSVGNode, createNode, getComputedStyle } = require("./utils/markup");
|
||||||
const { setIgnoreLayoutChanges, getCurrentZoom } = require("devtools/shared/layout/utils");
|
const { setIgnoreLayoutChanges, getCurrentZoom,
|
||||||
|
getAdjustedQuads } = require("devtools/shared/layout/utils");
|
||||||
const { AutoRefreshHighlighter } = require("./auto-refresh");
|
const { AutoRefreshHighlighter } = require("./auto-refresh");
|
||||||
const {
|
const {
|
||||||
getDistance,
|
getDistance,
|
||||||
|
@ -176,6 +177,27 @@ class ShapesHighlighter extends AutoRefreshHighlighter {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get frameDimensions() {
|
||||||
|
// In an iframe, we get the node's quads relative to the frame,
|
||||||
|
// instead of the parent document.
|
||||||
|
let dims = getAdjustedQuads(this.currentNode.ownerGlobal,
|
||||||
|
this.currentNode, this.referenceBox)[0].bounds;
|
||||||
|
let zoom = getCurrentZoom(this.win);
|
||||||
|
|
||||||
|
if (this.currentNode.getBBox &&
|
||||||
|
getComputedStyle(this.currentNode).stroke !== "none" && !this.useStrokeBox) {
|
||||||
|
dims = getObjectBoundingBox(dims.top, dims.left,
|
||||||
|
dims.width, dims.height, this.currentNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
top: dims.top / zoom,
|
||||||
|
left: dims.left / zoom,
|
||||||
|
width: dims.width / zoom,
|
||||||
|
height: dims.height / zoom
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
handleEvent(event, id) {
|
handleEvent(event, id) {
|
||||||
// No event handling if the highlighter is hidden
|
// No event handling if the highlighter is hidden
|
||||||
if (this.areShapesHidden()) {
|
if (this.areShapesHidden()) {
|
||||||
|
@ -702,7 +724,10 @@ class ShapesHighlighter extends AutoRefreshHighlighter {
|
||||||
* in percentages relative to the element.
|
* in percentages relative to the element.
|
||||||
*/
|
*/
|
||||||
convertPageCoordsToPercent(pageX, pageY) {
|
convertPageCoordsToPercent(pageX, pageY) {
|
||||||
let { top, left, width, height } = this.zoomAdjustedDimensions;
|
// If the current node is in an iframe, we get dimensions relative to the frame.
|
||||||
|
let dims = (this.highlighterEnv.window.document === this.currentNode.ownerDocument) ?
|
||||||
|
this.zoomAdjustedDimensions : this.frameDimensions;
|
||||||
|
let { top, left, width, height } = dims;
|
||||||
pageX -= left;
|
pageX -= left;
|
||||||
pageY -= top;
|
pageY -= top;
|
||||||
let percentX = pageX * 100 / width;
|
let percentX = pageX * 100 / width;
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
<script>
|
||||||
|
setTimeout(function(){document.getElementById('id0510').removeAttribute('max');}, 46);
|
||||||
|
</script>
|
||||||
|
<input id='id0510'type='range'max=765>
|
|
@ -205,6 +205,7 @@ load 1230422.html
|
||||||
load 1251361.html
|
load 1251361.html
|
||||||
load 1304437.html
|
load 1304437.html
|
||||||
pref(dom.IntersectionObserver.enabled,true) load 1324209.html
|
pref(dom.IntersectionObserver.enabled,true) load 1324209.html
|
||||||
|
load 1324500.html
|
||||||
pref(dom.IntersectionObserver.enabled,true) load 1326194-1.html
|
pref(dom.IntersectionObserver.enabled,true) load 1326194-1.html
|
||||||
pref(dom.IntersectionObserver.enabled,true) load 1326194-2.html
|
pref(dom.IntersectionObserver.enabled,true) load 1326194-2.html
|
||||||
pref(dom.IntersectionObserver.enabled,true) load 1332939.html
|
pref(dom.IntersectionObserver.enabled,true) load 1332939.html
|
||||||
|
|
|
@ -32,8 +32,6 @@ using mozilla::dom::Element;
|
||||||
AutoTArray<RefPtr<nsDOMMutationObserver>, 4>*
|
AutoTArray<RefPtr<nsDOMMutationObserver>, 4>*
|
||||||
nsDOMMutationObserver::sScheduledMutationObservers = nullptr;
|
nsDOMMutationObserver::sScheduledMutationObservers = nullptr;
|
||||||
|
|
||||||
nsDOMMutationObserver* nsDOMMutationObserver::sCurrentObserver = nullptr;
|
|
||||||
|
|
||||||
uint32_t nsDOMMutationObserver::sMutationLevel = 0;
|
uint32_t nsDOMMutationObserver::sMutationLevel = 0;
|
||||||
uint64_t nsDOMMutationObserver::sCount = 0;
|
uint64_t nsDOMMutationObserver::sCount = 0;
|
||||||
|
|
||||||
|
@ -599,10 +597,32 @@ nsDOMMutationObserver::ScheduleForRun()
|
||||||
RescheduleForRun();
|
RescheduleForRun();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MutationObserverMicroTask final : public MicroTaskRunnable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void Run(AutoSlowOperation& aAso) override
|
||||||
|
{
|
||||||
|
nsDOMMutationObserver::HandleMutations(aAso);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Suppressed() override
|
||||||
|
{
|
||||||
|
return nsDOMMutationObserver::AllScheduledMutationObserversAreSuppressed();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
nsDOMMutationObserver::RescheduleForRun()
|
nsDOMMutationObserver::RescheduleForRun()
|
||||||
{
|
{
|
||||||
if (!sScheduledMutationObservers) {
|
if (!sScheduledMutationObservers) {
|
||||||
|
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
|
||||||
|
if (!ccjs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<MutationObserverMicroTask> momt =
|
||||||
|
new MutationObserverMicroTask();
|
||||||
|
ccjs->DispatchMicroTaskRunnable(momt.forget());
|
||||||
sScheduledMutationObservers = new AutoTArray<RefPtr<nsDOMMutationObserver>, 4>;
|
sScheduledMutationObservers = new AutoTArray<RefPtr<nsDOMMutationObserver>, 4>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -864,37 +884,9 @@ nsDOMMutationObserver::HandleMutation()
|
||||||
mCallback->Call(this, mutations, *this);
|
mCallback->Call(this, mutations, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
class AsyncMutationHandler : public mozilla::Runnable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AsyncMutationHandler() : mozilla::Runnable("AsyncMutationHandler") {}
|
|
||||||
NS_IMETHOD Run() override
|
|
||||||
{
|
|
||||||
nsDOMMutationObserver::HandleMutations();
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nsDOMMutationObserver::HandleMutationsInternal()
|
nsDOMMutationObserver::HandleMutationsInternal(AutoSlowOperation& aAso)
|
||||||
{
|
{
|
||||||
if (!nsContentUtils::IsSafeToRunScript()) {
|
|
||||||
nsContentUtils::AddScriptRunner(new AsyncMutationHandler());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
static RefPtr<nsDOMMutationObserver> sCurrentObserver;
|
|
||||||
if (sCurrentObserver && !sCurrentObserver->Suppressed()) {
|
|
||||||
// In normal cases sScheduledMutationObservers will be handled
|
|
||||||
// after previous mutations are handled. But in case some
|
|
||||||
// callback calls a sync API, which spins the eventloop, we need to still
|
|
||||||
// process other mutations happening during that sync call.
|
|
||||||
// This does *not* catch all cases, but should work for stuff running
|
|
||||||
// in separate tabs.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mozilla::AutoSlowOperation aso;
|
|
||||||
|
|
||||||
nsTArray<RefPtr<nsDOMMutationObserver> >* suppressedObservers = nullptr;
|
nsTArray<RefPtr<nsDOMMutationObserver> >* suppressedObservers = nullptr;
|
||||||
|
|
||||||
while (sScheduledMutationObservers) {
|
while (sScheduledMutationObservers) {
|
||||||
|
@ -902,20 +894,21 @@ nsDOMMutationObserver::HandleMutationsInternal()
|
||||||
sScheduledMutationObservers;
|
sScheduledMutationObservers;
|
||||||
sScheduledMutationObservers = nullptr;
|
sScheduledMutationObservers = nullptr;
|
||||||
for (uint32_t i = 0; i < observers->Length(); ++i) {
|
for (uint32_t i = 0; i < observers->Length(); ++i) {
|
||||||
sCurrentObserver = static_cast<nsDOMMutationObserver*>((*observers)[i]);
|
RefPtr<nsDOMMutationObserver> currentObserver =
|
||||||
if (!sCurrentObserver->Suppressed()) {
|
static_cast<nsDOMMutationObserver*>((*observers)[i]);
|
||||||
sCurrentObserver->HandleMutation();
|
if (!currentObserver->Suppressed()) {
|
||||||
|
currentObserver->HandleMutation();
|
||||||
} else {
|
} else {
|
||||||
if (!suppressedObservers) {
|
if (!suppressedObservers) {
|
||||||
suppressedObservers = new nsTArray<RefPtr<nsDOMMutationObserver> >;
|
suppressedObservers = new nsTArray<RefPtr<nsDOMMutationObserver> >;
|
||||||
}
|
}
|
||||||
if (!suppressedObservers->Contains(sCurrentObserver)) {
|
if (!suppressedObservers->Contains(currentObserver)) {
|
||||||
suppressedObservers->AppendElement(sCurrentObserver);
|
suppressedObservers->AppendElement(currentObserver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete observers;
|
delete observers;
|
||||||
aso.CheckForInterrupt();
|
aAso.CheckForInterrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (suppressedObservers) {
|
if (suppressedObservers) {
|
||||||
|
@ -926,7 +919,6 @@ nsDOMMutationObserver::HandleMutationsInternal()
|
||||||
delete suppressedObservers;
|
delete suppressedObservers;
|
||||||
suppressedObservers = nullptr;
|
suppressedObservers = nullptr;
|
||||||
}
|
}
|
||||||
sCurrentObserver = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsDOMMutationRecord*
|
nsDOMMutationRecord*
|
||||||
|
|
|
@ -575,13 +575,29 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// static methods
|
// static methods
|
||||||
static void HandleMutations()
|
static void HandleMutations(mozilla::AutoSlowOperation& aAso)
|
||||||
{
|
{
|
||||||
if (sScheduledMutationObservers) {
|
if (sScheduledMutationObservers) {
|
||||||
HandleMutationsInternal();
|
HandleMutationsInternal(aAso);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool AllScheduledMutationObserversAreSuppressed()
|
||||||
|
{
|
||||||
|
if (sScheduledMutationObservers) {
|
||||||
|
uint32_t len = sScheduledMutationObservers->Length();
|
||||||
|
if (len > 0) {
|
||||||
|
for (uint32_t i = 0; i < len; ++i) {
|
||||||
|
if (!(*sScheduledMutationObservers)[i]->Suppressed()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static void EnterMutationHandling();
|
static void EnterMutationHandling();
|
||||||
static void LeaveMutationHandling();
|
static void LeaveMutationHandling();
|
||||||
|
|
||||||
|
@ -613,7 +629,7 @@ protected:
|
||||||
return mOwner && nsGlobalWindow::Cast(mOwner)->IsInSyncOperation();
|
return mOwner && nsGlobalWindow::Cast(mOwner)->IsInSyncOperation();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HandleMutationsInternal();
|
static void HandleMutationsInternal(mozilla::AutoSlowOperation& aAso);
|
||||||
|
|
||||||
static void AddCurrentlyHandlingObserver(nsDOMMutationObserver* aObserver,
|
static void AddCurrentlyHandlingObserver(nsDOMMutationObserver* aObserver,
|
||||||
uint32_t aMutationLevel);
|
uint32_t aMutationLevel);
|
||||||
|
@ -641,7 +657,6 @@ protected:
|
||||||
|
|
||||||
static uint64_t sCount;
|
static uint64_t sCount;
|
||||||
static AutoTArray<RefPtr<nsDOMMutationObserver>, 4>* sScheduledMutationObservers;
|
static AutoTArray<RefPtr<nsDOMMutationObserver>, 4>* sScheduledMutationObservers;
|
||||||
static nsDOMMutationObserver* sCurrentObserver;
|
|
||||||
|
|
||||||
static uint32_t sMutationLevel;
|
static uint32_t sMutationLevel;
|
||||||
static AutoTArray<AutoTArray<RefPtr<nsDOMMutationObserver>, 4>, 4>*
|
static AutoTArray<AutoTArray<RefPtr<nsDOMMutationObserver>, 4>, 4>*
|
||||||
|
|
|
@ -576,8 +576,6 @@ DumpString(const nsAString &str)
|
||||||
|
|
||||||
#define JS_OPTIONS_DOT_STR "javascript.options."
|
#define JS_OPTIONS_DOT_STR "javascript.options."
|
||||||
|
|
||||||
static const char js_options_dot_str[] = JS_OPTIONS_DOT_STR;
|
|
||||||
|
|
||||||
nsJSContext::nsJSContext(bool aGCOnDestruction,
|
nsJSContext::nsJSContext(bool aGCOnDestruction,
|
||||||
nsIScriptGlobalObject* aGlobalObject)
|
nsIScriptGlobalObject* aGlobalObject)
|
||||||
: mWindowProxy(nullptr)
|
: mWindowProxy(nullptr)
|
||||||
|
|
|
@ -21,9 +21,6 @@
|
||||||
#include "nsJSUtils.h"
|
#include "nsJSUtils.h"
|
||||||
#include "WorkerPrivate.h"
|
#include "WorkerPrivate.h"
|
||||||
|
|
||||||
static const char kSetIntervalStr[] = "setInterval";
|
|
||||||
static const char kSetTimeoutStr[] = "setTimeout";
|
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
using namespace mozilla::dom::workers;
|
using namespace mozilla::dom::workers;
|
||||||
|
|
|
@ -362,7 +362,7 @@ function testChildList5() {
|
||||||
is(records[5].previousSibling, c3, "");
|
is(records[5].previousSibling, c3, "");
|
||||||
is(records[5].nextSibling, c5, "");
|
is(records[5].nextSibling, c5, "");
|
||||||
observer.disconnect();
|
observer.disconnect();
|
||||||
then(testAdoptNode);
|
then(testNestedMutations);
|
||||||
m = null;
|
m = null;
|
||||||
});
|
});
|
||||||
m.observe(div, { childList: true, subtree: true });
|
m.observe(div, { childList: true, subtree: true });
|
||||||
|
@ -375,6 +375,37 @@ function testChildList5() {
|
||||||
div.appendChild(emptyDF); // empty document shouldn't cause mutation records
|
div.appendChild(emptyDF); // empty document shouldn't cause mutation records
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testNestedMutations() {
|
||||||
|
div.textContent = null;
|
||||||
|
div.appendChild(document.createTextNode("foo"));
|
||||||
|
var m2WasCalled = false;
|
||||||
|
m = new M(function(records, observer) {
|
||||||
|
is(records[0].type, "characterData", "Should have got characterData");
|
||||||
|
observer.disconnect();
|
||||||
|
m = null;
|
||||||
|
m3 = new M(function(records, observer) {
|
||||||
|
ok(m2WasCalled, "m2 should have been called before m3!");
|
||||||
|
is(records[0].type, "characterData", "Should have got characterData");
|
||||||
|
observer.disconnect();
|
||||||
|
then(testAdoptNode);
|
||||||
|
m3 = null;
|
||||||
|
});
|
||||||
|
m3.observe(div, { characterData: true, subtree: true});
|
||||||
|
div.firstChild.data = "foo";
|
||||||
|
});
|
||||||
|
m2 = new M(function(records, observer) {
|
||||||
|
m2WasCalled = true;
|
||||||
|
is(records[0].type, "characterData", "Should have got characterData");
|
||||||
|
observer.disconnect();
|
||||||
|
m2 = null;
|
||||||
|
});
|
||||||
|
m2.observe(div, { characterData: true, subtree: true});
|
||||||
|
div.appendChild(document.createTextNode("foo"));
|
||||||
|
m.observe(div, { characterData: true, subtree: true });
|
||||||
|
|
||||||
|
div.firstChild.data = "bar";
|
||||||
|
}
|
||||||
|
|
||||||
function testAdoptNode() {
|
function testAdoptNode() {
|
||||||
var d1 = document.implementation.createHTMLDocument(null);
|
var d1 = document.implementation.createHTMLDocument(null);
|
||||||
var d2 = document.implementation.createHTMLDocument(null);
|
var d2 = document.implementation.createHTMLDocument(null);
|
||||||
|
|
|
@ -345,18 +345,19 @@ template<>
|
||||||
class Optional<nsAString>
|
class Optional<nsAString>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Optional() : mPassed(false) {}
|
Optional()
|
||||||
|
: mStr(nullptr)
|
||||||
|
{}
|
||||||
|
|
||||||
bool WasPassed() const
|
bool WasPassed() const
|
||||||
{
|
{
|
||||||
return mPassed;
|
return !!mStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator=(const nsAString* str)
|
void operator=(const nsAString* str)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(str);
|
MOZ_ASSERT(str);
|
||||||
mStr = str;
|
mStr = str;
|
||||||
mPassed = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this code ever goes away, remove the comment pointing to it in the
|
// If this code ever goes away, remove the comment pointing to it in the
|
||||||
|
@ -365,7 +366,6 @@ public:
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(str);
|
MOZ_ASSERT(str);
|
||||||
mStr = reinterpret_cast<const nsString*>(str);
|
mStr = reinterpret_cast<const nsString*>(str);
|
||||||
mPassed = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const nsAString& Value() const
|
const nsAString& Value() const
|
||||||
|
@ -379,7 +379,6 @@ private:
|
||||||
Optional(const Optional& other) = delete;
|
Optional(const Optional& other) = delete;
|
||||||
const Optional &operator=(const Optional &other) = delete;
|
const Optional &operator=(const Optional &other) = delete;
|
||||||
|
|
||||||
bool mPassed;
|
|
||||||
const nsAString* mStr;
|
const nsAString* mStr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -388,8 +387,9 @@ class NonNull
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NonNull()
|
NonNull()
|
||||||
|
: ptr(nullptr)
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
: inited(false)
|
, inited(false)
|
||||||
#endif
|
#endif
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@ namespace binding_detail {
|
||||||
// for small strings and a nsStringBuffer for longer strings.
|
// for small strings and a nsStringBuffer for longer strings.
|
||||||
struct FakeString {
|
struct FakeString {
|
||||||
FakeString() :
|
FakeString() :
|
||||||
|
mData(nsString::char_traits::sEmptyBuffer),
|
||||||
|
mLength(0),
|
||||||
mDataFlags(nsString::DataFlags::TERMINATED),
|
mDataFlags(nsString::DataFlags::TERMINATED),
|
||||||
mClassFlags(nsString::ClassFlags(0))
|
mClassFlags(nsString::ClassFlags(0))
|
||||||
{
|
{
|
||||||
|
|
|
@ -2084,17 +2084,7 @@ ReadResponse(mozIStorageConnection* aConn, EntryId aEntryId,
|
||||||
rv = state->GetIsNull(6, &nullPadding);
|
rv = state->GetIsNull(6, &nullPadding);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||||
|
|
||||||
#ifdef NIGHTLY_BUILD
|
|
||||||
bool shouldUpdateTo26 = false;
|
|
||||||
if (nullPadding && aSavedResponseOut->mValue.type() == ResponseType::Opaque) {
|
|
||||||
// XXXtt: This should be removed in the future (e.g. Nightly 58) by
|
|
||||||
// bug 1398167.
|
|
||||||
shouldUpdateTo26 = true;
|
|
||||||
aSavedResponseOut->mValue.paddingSize() = 0;
|
|
||||||
} else if (nullPadding) {
|
|
||||||
#else
|
|
||||||
if (nullPadding) {
|
if (nullPadding) {
|
||||||
#endif // NIGHTLY_BUILD
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aSavedResponseOut->mValue.type() !=
|
MOZ_DIAGNOSTIC_ASSERT(aSavedResponseOut->mValue.type() !=
|
||||||
ResponseType::Opaque);
|
ResponseType::Opaque);
|
||||||
aSavedResponseOut->mValue.paddingSize() =
|
aSavedResponseOut->mValue.paddingSize() =
|
||||||
|
@ -2113,20 +2103,6 @@ ReadResponse(mozIStorageConnection* aConn, EntryId aEntryId,
|
||||||
rv = state->GetBlobAsUTF8String(7, aSavedResponseOut->mValue.channelInfo().securityInfo());
|
rv = state->GetBlobAsUTF8String(7, aSavedResponseOut->mValue.channelInfo().securityInfo());
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||||
|
|
||||||
#ifdef NIGHTLY_BUILD
|
|
||||||
if (shouldUpdateTo26) {
|
|
||||||
// XXXtt: This is a quick fix for not updating properly in Nightly 57.
|
|
||||||
// Note: This should be removed in the future (e.g. Nightly 58) by
|
|
||||||
// bug 1398167.
|
|
||||||
rv = aConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
|
||||||
"UPDATE entries SET response_padding_size = 0 "
|
|
||||||
"WHERE response_type = 4 " // opaque response
|
|
||||||
"AND response_padding_size IS NULL"
|
|
||||||
));
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
|
||||||
}
|
|
||||||
#endif // NIGHTLY_BUILD
|
|
||||||
|
|
||||||
rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
|
rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||||
"SELECT "
|
"SELECT "
|
||||||
"name, "
|
"name, "
|
||||||
|
|
|
@ -389,19 +389,6 @@ WebGLContext::ValidateStencilParamsForDrawCall()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int32_t
|
|
||||||
FloorPOT(int32_t x)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(x > 0);
|
|
||||||
int32_t pot = 1;
|
|
||||||
while (pot < 0x40000000) {
|
|
||||||
if (x < pot*2)
|
|
||||||
break;
|
|
||||||
pot *= 2;
|
|
||||||
}
|
|
||||||
return pot;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
WebGLContext::InitAndValidateGL(FailureReason* const out_failReason)
|
WebGLContext::InitAndValidateGL(FailureReason* const out_failReason)
|
||||||
{
|
{
|
||||||
|
|
|
@ -936,21 +936,6 @@ DoCompressedTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level,
|
||||||
return errorScope.GetError();
|
return errorScope.GetError();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline GLenum
|
|
||||||
DoCopyTexImage2D(gl::GLContext* gl, TexImageTarget target, GLint level,
|
|
||||||
GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
|
|
||||||
{
|
|
||||||
const GLint border = 0;
|
|
||||||
|
|
||||||
gl::GLContext::LocalErrorScope errorScope(*gl);
|
|
||||||
|
|
||||||
MOZ_ASSERT(!IsTarget3D(target));
|
|
||||||
gl->fCopyTexImage2D(target.get(), level, internalFormat, x, y, width, height,
|
|
||||||
border);
|
|
||||||
|
|
||||||
return errorScope.GetError();
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline GLenum
|
static inline GLenum
|
||||||
DoCopyTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level, GLint xOffset,
|
DoCopyTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level, GLint xOffset,
|
||||||
GLint yOffset, GLint zOffset, GLint x, GLint y, GLsizei width,
|
GLint yOffset, GLint zOffset, GLint x, GLint y, GLsizei width,
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<script>
|
||||||
|
window.onload=function(){
|
||||||
|
var gl = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas").getContext("webgl");
|
||||||
|
var shader = gl.createShader(gl.FRAGMENT_SHADER);
|
||||||
|
gl.shaderSource(shader, 'void main(){d[vec4[]()}');
|
||||||
|
gl.compileShader(shader);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<script>
|
||||||
|
o0 = document.createElement('canvas');
|
||||||
|
o1 = o0.getContext('2d');
|
||||||
|
o3 = o1.createImageData(32, 0.696);
|
||||||
|
o1.arc(128, 0.37, 256, 4, 0.070, true);
|
||||||
|
o1.moveTo(-2, 0.973);
|
||||||
|
o1.clip('evenodd');
|
||||||
|
o1.strokeText("A",0.610,-0.335,0.817);
|
||||||
|
</script>
|
|
@ -19,6 +19,7 @@ load 802926-1.html
|
||||||
load 896047-1.html
|
load 896047-1.html
|
||||||
load 916128-1.html
|
load 916128-1.html
|
||||||
load 934939-1.html
|
load 934939-1.html
|
||||||
|
load 989628.html
|
||||||
load 1099143-1.html
|
load 1099143-1.html
|
||||||
load 1161277-1.html
|
load 1161277-1.html
|
||||||
load 1183363.html
|
load 1183363.html
|
||||||
|
@ -38,10 +39,11 @@ load 1290628-1.html
|
||||||
load 1283113-1.html
|
load 1283113-1.html
|
||||||
load 1286458-1.html
|
load 1286458-1.html
|
||||||
load 1296410-1.html
|
load 1296410-1.html
|
||||||
|
load 1298576-1.html
|
||||||
load 1299062-1.html
|
load 1299062-1.html
|
||||||
load 1305085-1.html
|
load 1305085-1.html
|
||||||
load 1305312-1.html
|
load 1305312-1.html
|
||||||
load 1298576-1.html
|
load 1305850.html
|
||||||
load 1334366-1.html
|
load 1334366-1.html
|
||||||
load 1334647-1.html
|
load 1334647-1.html
|
||||||
load 1357092.html
|
load 1357092.html
|
||||||
|
|
|
@ -75,6 +75,7 @@ fail-if = (os == 'win' && os_version == '5.1')
|
||||||
skip-if = android_version == '18' #Android 4.3 aws only; bug 1030942
|
skip-if = android_version == '18' #Android 4.3 aws only; bug 1030942
|
||||||
[test_noprog_draw.html]
|
[test_noprog_draw.html]
|
||||||
[test_pixel_pack_buffer.html]
|
[test_pixel_pack_buffer.html]
|
||||||
|
skip-if = os == "win" && os_version == "10.0" # Bug 1302199
|
||||||
[test_privileged_exts.html]
|
[test_privileged_exts.html]
|
||||||
[test_renderer_strings.html]
|
[test_renderer_strings.html]
|
||||||
[test_sab_with_webgl.html]
|
[test_sab_with_webgl.html]
|
||||||
|
|
|
@ -14,8 +14,6 @@
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
static const char16_t kReplacementChar = static_cast<char16_t>(0xFFFD);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TextDecoder::Init(const nsAString& aLabel, const bool aFatal,
|
TextDecoder::Init(const nsAString& aLabel, const bool aFatal,
|
||||||
ErrorResult& aRv)
|
ErrorResult& aRv)
|
||||||
|
|
|
@ -4277,7 +4277,8 @@ EventStateManager::GeneratePointerEnterExit(EventMessage aMessage,
|
||||||
/* static */ void
|
/* static */ void
|
||||||
EventStateManager::UpdateLastRefPointOfMouseEvent(WidgetMouseEvent* aMouseEvent)
|
EventStateManager::UpdateLastRefPointOfMouseEvent(WidgetMouseEvent* aMouseEvent)
|
||||||
{
|
{
|
||||||
if (aMouseEvent->mMessage != eMouseMove) {
|
if (aMouseEvent->mMessage != eMouseMove &&
|
||||||
|
aMouseEvent->mMessage != ePointerMove) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4310,10 +4311,15 @@ EventStateManager::ResetPointerToWindowCenterWhilePointerLocked(
|
||||||
WidgetMouseEvent* aMouseEvent)
|
WidgetMouseEvent* aMouseEvent)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(sIsPointerLocked);
|
MOZ_ASSERT(sIsPointerLocked);
|
||||||
if (aMouseEvent->mMessage != eMouseMove || !aMouseEvent->mWidget) {
|
if ((aMouseEvent->mMessage != eMouseMove &&
|
||||||
|
aMouseEvent->mMessage != ePointerMove) || !aMouseEvent->mWidget) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We generate pointermove from mousemove event, so only synthesize native
|
||||||
|
// mouse move and update sSynthCenteringPoint by mousemove event.
|
||||||
|
bool updateSynthCenteringPoint = aMouseEvent->mMessage == eMouseMove;
|
||||||
|
|
||||||
// The pointer is locked. If the pointer is not located at the center of
|
// The pointer is locked. If the pointer is not located at the center of
|
||||||
// the window, dispatch a synthetic mousemove to return the pointer there.
|
// the window, dispatch a synthetic mousemove to return the pointer there.
|
||||||
// Doing this between "real" pointer moves gives the impression that the
|
// Doing this between "real" pointer moves gives the impression that the
|
||||||
|
@ -4323,7 +4329,7 @@ EventStateManager::ResetPointerToWindowCenterWhilePointerLocked(
|
||||||
LayoutDeviceIntPoint center =
|
LayoutDeviceIntPoint center =
|
||||||
GetWindowClientRectCenter(aMouseEvent->mWidget);
|
GetWindowClientRectCenter(aMouseEvent->mWidget);
|
||||||
|
|
||||||
if (aMouseEvent->mRefPoint != center) {
|
if (aMouseEvent->mRefPoint != center && updateSynthCenteringPoint) {
|
||||||
// Mouse move doesn't finish at the center of the window. Dispatch a
|
// Mouse move doesn't finish at the center of the window. Dispatch a
|
||||||
// synthetic native mouse event to move the pointer back to the center
|
// synthetic native mouse event to move the pointer back to the center
|
||||||
// of the window, to faciliate more movement. But first, record that
|
// of the window, to faciliate more movement. But first, record that
|
||||||
|
@ -4338,7 +4344,9 @@ EventStateManager::ResetPointerToWindowCenterWhilePointerLocked(
|
||||||
aMouseEvent->StopPropagation();
|
aMouseEvent->StopPropagation();
|
||||||
// Clear sSynthCenteringPoint so we don't cancel other events
|
// Clear sSynthCenteringPoint so we don't cancel other events
|
||||||
// targeted at the center.
|
// targeted at the center.
|
||||||
sSynthCenteringPoint = kInvalidRefPoint;
|
if (updateSynthCenteringPoint) {
|
||||||
|
sSynthCenteringPoint = kInvalidRefPoint;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,7 @@ UIEvent::GetMovementPoint()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mEvent || !mEvent->AsGUIEvent()->mWidget ||
|
if (!mEvent || !mEvent->AsGUIEvent()->mWidget ||
|
||||||
(mEvent->mMessage != eMouseMove)) {
|
(mEvent->mMessage != eMouseMove && mEvent->mMessage != ePointerMove)) {
|
||||||
// Pointer Lock spec defines that movementX/Y must be zero for all mouse
|
// Pointer Lock spec defines that movementX/Y must be zero for all mouse
|
||||||
// events except mousemove.
|
// events except mousemove.
|
||||||
return nsIntPoint(0, 0);
|
return nsIntPoint(0, 0);
|
||||||
|
|
|
@ -6,6 +6,10 @@ support-files =
|
||||||
../pointerevent_styles.css
|
../pointerevent_styles.css
|
||||||
../pointerevent_support.js
|
../pointerevent_support.js
|
||||||
|
|
||||||
|
[test_pointerevent_movementxy-manual.html]
|
||||||
|
support-files =
|
||||||
|
pointerevent_movementxy-manual.html
|
||||||
|
./resources/pointerevent_movementxy-iframe.html
|
||||||
[test_pointerevent_pointerlock_after_pointercapture-manual.html]
|
[test_pointerevent_pointerlock_after_pointercapture-manual.html]
|
||||||
support-files = pointerevent_pointerlock_after_pointercapture-manual.html
|
support-files = pointerevent_pointerlock_after_pointercapture-manual.html
|
||||||
disabled = disabled # We don't allow pointer lock in mousemove handlers.
|
disabled = disabled # We don't allow pointer lock in mousemove handlers.
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Pointer Events properties tests</title>
|
||||||
|
<meta name="viewport" content="width=device-width">
|
||||||
|
<link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<!-- Additional helper script for common checks across event types -->
|
||||||
|
<script type="text/javascript" src="../pointerevent_support.js"></script>
|
||||||
|
<style>
|
||||||
|
#testContainer {
|
||||||
|
touch-action: none;
|
||||||
|
user-select: none;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
#box1 {
|
||||||
|
top: 30px;
|
||||||
|
left: 50px;
|
||||||
|
background: black;
|
||||||
|
}
|
||||||
|
#box2 {
|
||||||
|
top: 70px;
|
||||||
|
left: 250px;
|
||||||
|
background: red;
|
||||||
|
}
|
||||||
|
#innerFrame {
|
||||||
|
top: 10px;
|
||||||
|
left: 100px;
|
||||||
|
}
|
||||||
|
#square2 {
|
||||||
|
visibility: block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
var expectedPointerId = NaN;
|
||||||
|
var startSummation = false;
|
||||||
|
var lastScreenX = 0;
|
||||||
|
var lastScreenY = 0;
|
||||||
|
|
||||||
|
function resetTestState() {
|
||||||
|
startSummation = false;
|
||||||
|
lastScreenX = 0;
|
||||||
|
lastScreenY = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function run() {
|
||||||
|
var test_pointerEvent = setup_pointerevent_test("pointerevent attributes", ['mouse', 'touch']);
|
||||||
|
|
||||||
|
[document, document.getElementById('innerFrame').contentDocument].forEach(function(element) {
|
||||||
|
on_event(element, 'pointermove', function (event) {
|
||||||
|
if (startSummation) {
|
||||||
|
test_pointerEvent.step(function() {
|
||||||
|
assert_equals(event.movementX, event.screenX - lastScreenX, "movementX should be the delta between current event's and last event's screenX");
|
||||||
|
assert_equals(event.movementY, event.screenY - lastScreenY, "movementY should be the delta between current event's and last event's screenY");
|
||||||
|
});
|
||||||
|
lastScreenX = event.screenX;
|
||||||
|
lastScreenY = event.screenY;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
on_event(document.querySelector('#box1'), 'pointerdown', function(event) {
|
||||||
|
event.target.releasePointerCapture(event.pointerId);
|
||||||
|
test_pointerEvent.step(function() {
|
||||||
|
assert_equals(event.pointerType, expectedPointerType, "Use the instructed pointer type.");
|
||||||
|
});
|
||||||
|
startSummation = true;
|
||||||
|
lastScreenX = event.screenX;
|
||||||
|
lastScreenY = event.screenY;
|
||||||
|
});
|
||||||
|
on_event(document.querySelector('#box2'), 'pointerup', function(event) {
|
||||||
|
startSummation = false;
|
||||||
|
test_pointerEvent.done();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="run()">
|
||||||
|
<h1>Pointer Events movementX/Y attribute test</h1>
|
||||||
|
<h2 id="pointerTypeDescription"></h2>
|
||||||
|
<h4>
|
||||||
|
Test Description: This test checks the properties of pointer events that do not support hover.
|
||||||
|
<ol>
|
||||||
|
<li>Press down on the black square.</li>
|
||||||
|
<li>Move your pointer slowly along a straight line to the red square.</li>
|
||||||
|
<li>Release the pointer when you are over the red square.</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
Test passes if the proper behavior of the events is observed.
|
||||||
|
</h4>
|
||||||
|
<div id="testContainer">
|
||||||
|
<div id="box1" class="square"></div>
|
||||||
|
<div id="box2" class="square"></div>
|
||||||
|
<iframe id="innerFrame" src="resources/pointerevent_movementxy-iframe.html"></iframe>
|
||||||
|
</div>
|
||||||
|
<div class="spacer"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,53 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1399740
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Test for Bug 1399740</title>
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||||
|
<script type="text/javascript" src="mochitest_support_external.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
|
<script type="text/javascript">
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
function startTest() {
|
||||||
|
runTestInNewWindow("pointerevent_movementxy-manual.html");
|
||||||
|
}
|
||||||
|
function executeTest(int_win) {
|
||||||
|
let box1 = int_win.document.getElementById("box1");
|
||||||
|
let box2 = int_win.document.getElementById("box2");
|
||||||
|
let rect1 = box1.getBoundingClientRect();
|
||||||
|
let rect2 = box2.getBoundingClientRect();
|
||||||
|
let offsetX = rect1.left + rect1.width / 2;
|
||||||
|
let offsetY = rect1.top + rect1.height / 2;
|
||||||
|
let stepX = (rect2.left + rect2.width / 2 - offsetX) / 10;
|
||||||
|
let stepY = (rect2.top + rect2.height / 2 - offsetY) / 10;
|
||||||
|
sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
|
||||||
|
sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousedown", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
|
||||||
|
sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
|
||||||
|
for (var i = 0; i < 10; ++i) {
|
||||||
|
offsetX += stepX;
|
||||||
|
offsetY += stepY;
|
||||||
|
sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
|
||||||
|
}
|
||||||
|
sendMouseEventAtPoint(int_win, offsetX, offsetY, "mouseup", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
|
||||||
|
|
||||||
|
offsetX = rect1.left + rect1.width / 2;
|
||||||
|
offsetY = rect1.top + rect1.height / 2;
|
||||||
|
sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_TOUCH});
|
||||||
|
sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousedown", {inputSource:MouseEvent.MOZ_SOURCE_TOUCH});
|
||||||
|
sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_TOUCH});
|
||||||
|
for (var i = 0; i < 10; ++i) {
|
||||||
|
offsetX += stepX;
|
||||||
|
offsetY += stepY;
|
||||||
|
sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_TOUCH});
|
||||||
|
}
|
||||||
|
sendMouseEventAtPoint(int_win, offsetX, offsetY, "mouseup", {inputSource:MouseEvent.MOZ_SOURCE_TOUCH});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -147,6 +147,7 @@ InternalRequest::InternalRequest(const InternalRequest& aOther)
|
||||||
: mMethod(aOther.mMethod)
|
: mMethod(aOther.mMethod)
|
||||||
, mURLList(aOther.mURLList)
|
, mURLList(aOther.mURLList)
|
||||||
, mHeaders(new InternalHeaders(*aOther.mHeaders))
|
, mHeaders(new InternalHeaders(*aOther.mHeaders))
|
||||||
|
, mBodyLength(InternalResponse::UNKNOWN_BODY_SIZE)
|
||||||
, mContentPolicyType(aOther.mContentPolicyType)
|
, mContentPolicyType(aOther.mContentPolicyType)
|
||||||
, mReferrer(aOther.mReferrer)
|
, mReferrer(aOther.mReferrer)
|
||||||
, mReferrerPolicy(aOther.mReferrerPolicy)
|
, mReferrerPolicy(aOther.mReferrerPolicy)
|
||||||
|
|
|
@ -227,9 +227,6 @@ const double HTMLInputElement::kMsPerDay = 24 * 60 * 60 * 1000;
|
||||||
{0xb5, 0x13, 0x7b, 0x36, 0x93, 0x43, 0xe3, 0xa0} \
|
{0xb5, 0x13, 0x7b, 0x36, 0x93, 0x43, 0xe3, 0xa0} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PROGRESS_STR "progress"
|
|
||||||
static const uint32_t kProgressEventInterval = 50; // ms
|
|
||||||
|
|
||||||
// An helper class for the dispatching of the 'change' event.
|
// An helper class for the dispatching of the 'change' event.
|
||||||
// This class is used when the FilePicker finished its task (or when files and
|
// This class is used when the FilePicker finished its task (or when files and
|
||||||
// directories are set by some chrome/test only method).
|
// directories are set by some chrome/test only method).
|
||||||
|
|
|
@ -53,8 +53,6 @@ using namespace mozilla;
|
||||||
using namespace mozilla::dom;
|
using namespace mozilla::dom;
|
||||||
using mozilla::layers::ScrollInputMethod;
|
using mozilla::layers::ScrollInputMethod;
|
||||||
|
|
||||||
static NS_DEFINE_CID(kTextEditorCID, NS_TEXTEDITOR_CID);
|
|
||||||
|
|
||||||
class MOZ_STACK_CLASS ValueSetter
|
class MOZ_STACK_CLASS ValueSetter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -189,8 +189,6 @@ cubeb_channel_layout sPreferredChannelLayout;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
extern LazyLogModule gAudioStreamLog;
|
|
||||||
|
|
||||||
static const uint32_t CUBEB_NORMAL_LATENCY_MS = 100;
|
static const uint32_t CUBEB_NORMAL_LATENCY_MS = 100;
|
||||||
// Consevative default that can work on all platforms.
|
// Consevative default that can work on all platforms.
|
||||||
static const uint32_t CUBEB_NORMAL_LATENCY_FRAMES = 1024;
|
static const uint32_t CUBEB_NORMAL_LATENCY_FRAMES = 1024;
|
||||||
|
|
|
@ -104,12 +104,6 @@ static constexpr auto AMPLE_AUDIO_THRESHOLD = TimeUnit::FromMicroseconds(AMPLE_A
|
||||||
// which is at or after the current playback position.
|
// which is at or after the current playback position.
|
||||||
static const uint32_t LOW_VIDEO_FRAMES = 2;
|
static const uint32_t LOW_VIDEO_FRAMES = 2;
|
||||||
|
|
||||||
// Threshold that used to check if we are low on decoded video.
|
|
||||||
// If the last video frame's end time |mDecodedVideoEndTime| is more than
|
|
||||||
// |LOW_VIDEO_THRESHOLD*mPlaybackRate| after the current clock in
|
|
||||||
// Advanceframe(), the video decode is lagging, and we skip to next keyframe.
|
|
||||||
static constexpr auto LOW_VIDEO_THRESHOLD = TimeUnit::FromMicroseconds(60000);
|
|
||||||
|
|
||||||
// Arbitrary "frame duration" when playing only audio.
|
// Arbitrary "frame duration" when playing only audio.
|
||||||
static const int AUDIO_DURATION_USECS = 40000;
|
static const int AUDIO_DURATION_USECS = 40000;
|
||||||
|
|
||||||
|
|
|
@ -60,8 +60,6 @@ void MediaDeviceInfo::GetLabel(nsString& retval)
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaDeviceKind Kind();
|
MediaDeviceKind Kind();
|
||||||
void GetLabel(nsString& retval);
|
|
||||||
void GetGroupId(nsString& retval);
|
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -1435,11 +1435,6 @@ MediaRecorder::SetOptions(const MediaRecorderOptions& aInitDict)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static char const *const gWebMAudioEncoderCodecs[2] = {
|
|
||||||
"opus",
|
|
||||||
// no VP9 yet
|
|
||||||
nullptr,
|
|
||||||
};
|
|
||||||
static char const *const gWebMVideoEncoderCodecs[4] = {
|
static char const *const gWebMVideoEncoderCodecs[4] = {
|
||||||
"opus",
|
"opus",
|
||||||
"vp8",
|
"vp8",
|
||||||
|
|
|
@ -9,10 +9,11 @@
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
|
||||||
extern LazyLogModule gMediaStreamGraphLog;
|
extern LazyLogModule gMediaStreamGraphLog;
|
||||||
#define STREAM_LOG(type, msg) MOZ_LOG(gMediaStreamGraphLog, type, msg)
|
#define STREAM_LOG(type, msg) MOZ_LOG(gMediaStreamGraphLog, type, msg)
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
void
|
void
|
||||||
StreamTracks::DumpTrackInfo() const
|
StreamTracks::DumpTrackInfo() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,7 +23,6 @@ static const int DEFAULT_CHANNELS = 1;
|
||||||
static const int DEFAULT_SAMPLING_RATE = 16000;
|
static const int DEFAULT_SAMPLING_RATE = 16000;
|
||||||
static const int DEFAULT_FRAME_WIDTH = 640;
|
static const int DEFAULT_FRAME_WIDTH = 640;
|
||||||
static const int DEFAULT_FRAME_HEIGHT = 480;
|
static const int DEFAULT_FRAME_HEIGHT = 480;
|
||||||
static const int DEFAULT_TRACK_RATE = USECS_PER_S;
|
|
||||||
// 1 second threshold if the audio encoder cannot be initialized.
|
// 1 second threshold if the audio encoder cannot be initialized.
|
||||||
static const int AUDIO_INIT_FAILED_DURATION = 1;
|
static const int AUDIO_INIT_FAILED_DURATION = 1;
|
||||||
// 30 second threshold if the video encoder cannot be initialized.
|
// 30 second threshold if the video encoder cannot be initialized.
|
||||||
|
|
|
@ -69,18 +69,18 @@ skip-if = toolkit == 'android' # Not supported on android
|
||||||
[test_DurationUpdated_mp4.html]
|
[test_DurationUpdated_mp4.html]
|
||||||
skip-if = toolkit == 'android' # Not supported on android
|
skip-if = toolkit == 'android' # Not supported on android
|
||||||
[test_EndedEvent.html]
|
[test_EndedEvent.html]
|
||||||
skip-if = android_version == '22' # bug 1358640
|
skip-if = android_version == '22' || toolkit == 'android' # bug 1358640, bug 1401090
|
||||||
[test_EndOfStream.html]
|
[test_EndOfStream.html]
|
||||||
[test_EndOfStream_mp4.html]
|
[test_EndOfStream_mp4.html]
|
||||||
skip-if = toolkit == 'android' # Not supported on android
|
skip-if = toolkit == 'android' # Not supported on android
|
||||||
[test_Eviction_mp4.html]
|
[test_Eviction_mp4.html]
|
||||||
skip-if = android_version == '15' # Not supported on Android(Bug 1358271)
|
skip-if = android_version == '15' # Not supported on Android(Bug 1358271)
|
||||||
[test_FrameSelection.html]
|
[test_FrameSelection.html]
|
||||||
skip-if = android_version == '22' # bug 1341519
|
skip-if = android_version == '22' || toolkit == 'android' # bug 1341519, bug 1401090
|
||||||
[test_FrameSelection_mp4.html]
|
[test_FrameSelection_mp4.html]
|
||||||
skip-if = toolkit == 'android' # Not supported on android
|
skip-if = toolkit == 'android' # Not supported on android
|
||||||
[test_HaveMetadataUnbufferedSeek.html]
|
[test_HaveMetadataUnbufferedSeek.html]
|
||||||
skip-if = android_version == '22' # bug 1342247
|
skip-if = android_version == '22' || toolkit == 'android' # bug 1342247, bug 1401090
|
||||||
[test_HaveMetadataUnbufferedSeek_mp4.html]
|
[test_HaveMetadataUnbufferedSeek_mp4.html]
|
||||||
skip-if = toolkit == 'android' # Not supported on android
|
skip-if = toolkit == 'android' # Not supported on android
|
||||||
[test_LiveSeekable.html]
|
[test_LiveSeekable.html]
|
||||||
|
|
|
@ -49,7 +49,6 @@
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
extern already_AddRefed<PlatformDecoderModule> CreateAgnosticDecoderModule();
|
|
||||||
extern already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule();
|
extern already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule();
|
||||||
extern already_AddRefed<PlatformDecoderModule> CreateNullDecoderModule();
|
extern already_AddRefed<PlatformDecoderModule> CreateNullDecoderModule();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<video src="1180881.webm" autoplay></video>
|
||||||
|
</body>
|
||||||
|
</html>
|
Двоичный файл не отображается.
|
@ -0,0 +1,8 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<video src="1197935.mp4" autoplay></video>
|
||||||
|
</body>
|
||||||
|
</html>
|
Двоичный файл не отображается.
|
@ -0,0 +1,8 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<video src="1270303.webm" autoplay></video>
|
||||||
|
</body>
|
||||||
|
</html>
|
Двоичный файл не отображается.
|
@ -75,12 +75,15 @@ skip-if(Android) test-pref(media.navigator.permission.disabled,true) load 102845
|
||||||
load 1041466.html
|
load 1041466.html
|
||||||
load 1045650.html
|
load 1045650.html
|
||||||
load 1080986.html
|
load 1080986.html
|
||||||
|
load 1180881.html
|
||||||
|
load 1197935.html
|
||||||
load 1122218.html
|
load 1122218.html
|
||||||
load 1127188.html
|
load 1127188.html
|
||||||
load 1157994.html
|
load 1157994.html
|
||||||
load 1158427.html
|
load 1158427.html
|
||||||
load 1185176.html
|
load 1185176.html
|
||||||
load 1185192.html
|
load 1185192.html
|
||||||
|
load 1270303.html
|
||||||
load 1304948.html
|
load 1304948.html
|
||||||
load 1319486.html
|
load 1319486.html
|
||||||
load 1368490.html
|
load 1368490.html
|
||||||
|
|
|
@ -43,8 +43,6 @@ using namespace mozilla;
|
||||||
using namespace mozilla::plugins::parent;
|
using namespace mozilla::plugins::parent;
|
||||||
using namespace mozilla::layers;
|
using namespace mozilla::layers;
|
||||||
|
|
||||||
static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID);
|
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(nsNPAPIPluginInstance, nsIAudioChannelAgentCallback)
|
NS_IMPL_ISUPPORTS(nsNPAPIPluginInstance, nsIAudioChannelAgentCallback)
|
||||||
|
|
||||||
nsNPAPIPluginInstance::nsNPAPIPluginInstance()
|
nsNPAPIPluginInstance::nsNPAPIPluginInstance()
|
||||||
|
|
|
@ -615,17 +615,6 @@ PluginInstanceParent::RecvNPN_InvalidateRect(const NPRect& rect)
|
||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline NPRect
|
|
||||||
IntRectToNPRect(const gfx::IntRect& rect)
|
|
||||||
{
|
|
||||||
NPRect r;
|
|
||||||
r.left = rect.x;
|
|
||||||
r.top = rect.y;
|
|
||||||
r.right = rect.x + rect.width;
|
|
||||||
r.bottom = rect.y + rect.height;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
mozilla::ipc::IPCResult
|
mozilla::ipc::IPCResult
|
||||||
PluginInstanceParent::RecvRevokeCurrentDirectSurface()
|
PluginInstanceParent::RecvRevokeCurrentDirectSurface()
|
||||||
{
|
{
|
||||||
|
|
|
@ -3838,6 +3838,13 @@ QuotaManager::GetQuotaObject(PersistenceType aPersistenceType,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(NIGHTLY_BUILD)
|
||||||
|
{
|
||||||
|
MutexAutoLock autoLock(mQuotaMutex);
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(mTemporaryStorageInitialized);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
nsString path;
|
nsString path;
|
||||||
nsresult rv = aFile->GetPath(path);
|
nsresult rv = aFile->GetPath(path);
|
||||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||||
|
@ -3923,6 +3930,13 @@ QuotaManager::GetQuotaObject(PersistenceType aPersistenceType,
|
||||||
{
|
{
|
||||||
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
|
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
|
||||||
|
|
||||||
|
#if defined(NIGHTLY_BUILD)
|
||||||
|
if (aPersistenceType != PERSISTENCE_TYPE_PERSISTENT){
|
||||||
|
MutexAutoLock autoLock(mQuotaMutex);
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(mTemporaryStorageInitialized);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (aFileSizeOut) {
|
if (aFileSizeOut) {
|
||||||
*aFileSizeOut = 0;
|
*aFileSizeOut = 0;
|
||||||
}
|
}
|
||||||
|
@ -5242,7 +5256,14 @@ QuotaManager::EnsureOriginIsInitializedInternal(
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(NIGHTLY_BUILD)
|
||||||
|
{
|
||||||
|
MutexAutoLock autoLock(mQuotaMutex);
|
||||||
mTemporaryStorageInitialized = true;
|
mTemporaryStorageInitialized = true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
mTemporaryStorageInitialized = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
CheckTemporaryStorageLimits();
|
CheckTemporaryStorageLimits();
|
||||||
}
|
}
|
||||||
|
@ -5328,7 +5349,16 @@ QuotaManager::ResetOrClearCompleted()
|
||||||
AssertIsOnIOThread();
|
AssertIsOnIOThread();
|
||||||
|
|
||||||
mInitializedOrigins.Clear();
|
mInitializedOrigins.Clear();
|
||||||
mTemporaryStorageInitialized = false;
|
|
||||||
|
#if defined(NIGHTLY_BUILD)
|
||||||
|
{
|
||||||
|
MutexAutoLock autoLock(mQuotaMutex);
|
||||||
|
mTemporaryStorageInitialized = false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
mTemporaryStorageInitialized = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
mStorageInitialized = false;
|
mStorageInitialized = false;
|
||||||
|
|
||||||
ReleaseIOThreadObjects();
|
ReleaseIOThreadObjects();
|
||||||
|
|
|
@ -224,14 +224,6 @@ nsCSPContext::permitsInternal(CSPDirective aDir,
|
||||||
|
|
||||||
nsAutoString violatedDirective;
|
nsAutoString violatedDirective;
|
||||||
for (uint32_t p = 0; p < mPolicies.Length(); p++) {
|
for (uint32_t p = 0; p < mPolicies.Length(); p++) {
|
||||||
|
|
||||||
// According to the W3C CSP spec, frame-ancestors checks are ignored for
|
|
||||||
// report-only policies (when "monitoring").
|
|
||||||
if (aDir == nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE &&
|
|
||||||
mPolicies[p]->getReportOnlyFlag()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mPolicies[p]->permits(aDir,
|
if (!mPolicies[p]->permits(aDir,
|
||||||
aContentLocation,
|
aContentLocation,
|
||||||
aNonce,
|
aNonce,
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<html><body>Child Document</body></html>
|
|
@ -0,0 +1 @@
|
||||||
|
Content-Security-Policy-Report-Only: frame-ancestors 'none'; report-uri http://mochi.test:8888/foo.sjs
|
|
@ -90,6 +90,8 @@ support-files =
|
||||||
file_bug941404.html
|
file_bug941404.html
|
||||||
file_bug941404_xhr.html
|
file_bug941404_xhr.html
|
||||||
file_bug941404_xhr.html^headers^
|
file_bug941404_xhr.html^headers^
|
||||||
|
file_frame_ancestors_ro.html
|
||||||
|
file_frame_ancestors_ro.html^headers^
|
||||||
file_hash_source.html
|
file_hash_source.html
|
||||||
file_dual_header_testserver.sjs
|
file_dual_header_testserver.sjs
|
||||||
file_hash_source.html^headers^
|
file_hash_source.html^headers^
|
||||||
|
@ -246,6 +248,7 @@ skip-if = toolkit == 'android' # Times out, not sure why (bug 1008445)
|
||||||
[test_bug910139.html]
|
[test_bug910139.html]
|
||||||
[test_bug909029.html]
|
[test_bug909029.html]
|
||||||
[test_bug1229639.html]
|
[test_bug1229639.html]
|
||||||
|
[test_frame_ancestors_ro.html]
|
||||||
[test_policyuri_regression_from_multipolicy.html]
|
[test_policyuri_regression_from_multipolicy.html]
|
||||||
[test_nonce_source.html]
|
[test_nonce_source.html]
|
||||||
[test_bug941404.html]
|
[test_bug941404.html]
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Test for frame-ancestors support in Content-Security-Policy-Report-Only</title>
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<iframe style="width: 100%" id="cspframe"></iframe>
|
||||||
|
<script type="text/javascript">
|
||||||
|
const docUri = "http://mochi.test:8888/tests/dom/security/test/csp/file_frame_ancestors_ro.html";
|
||||||
|
const frame = document.getElementById("cspframe");
|
||||||
|
|
||||||
|
let testResults = {
|
||||||
|
reportFired: false,
|
||||||
|
frameLoaded: false
|
||||||
|
};
|
||||||
|
|
||||||
|
function checkResults(reportObj) {
|
||||||
|
let cspReport = reportObj["csp-report"];
|
||||||
|
is(cspReport["document-uri"], docUri, "Incorrect document-uri");
|
||||||
|
|
||||||
|
// we can not test for the whole referrer since it includes platform specific information
|
||||||
|
is(cspReport["referrer"], document.location.toString(), "Incorrect referrer");
|
||||||
|
is(cspReport["blocked-uri"], document.location.toString(), "Incorrect blocked-uri");
|
||||||
|
is(cspReport["violated-directive"], "frame-ancestors 'none'", "Incorrect violated-directive");
|
||||||
|
is(cspReport["original-policy"], "frame-ancestors 'none'; report-uri http://mochi.test:8888/foo.sjs", "Incorrect original-policy");
|
||||||
|
testResults.reportFired = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let chromeScriptUrl = SimpleTest.getTestFileURL("file_report_chromescript.js");
|
||||||
|
let script = SpecialPowers.loadChromeScript(chromeScriptUrl);
|
||||||
|
|
||||||
|
script.addMessageListener('opening-request-completed', function ml(msg) {
|
||||||
|
if (msg.error) {
|
||||||
|
ok(false, "Could not query report (exception: " + msg.error + ")");
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
let reportObj = JSON.parse(msg.report);
|
||||||
|
// test for the proper values in the report object
|
||||||
|
checkResults(reportObj);
|
||||||
|
} catch (e) {
|
||||||
|
ok(false, "Error verifying report object (exception: " + e + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
script.removeMessageListener('opening-request-completed', ml);
|
||||||
|
script.sendAsyncMessage("finish");
|
||||||
|
checkTestResults();
|
||||||
|
});
|
||||||
|
|
||||||
|
frame.addEventListener( 'load', () => {
|
||||||
|
// Make sure the frame is still loaded
|
||||||
|
testResults.frameLoaded = true;
|
||||||
|
checkTestResults()
|
||||||
|
} );
|
||||||
|
|
||||||
|
function checkTestResults() {
|
||||||
|
if( testResults.reportFired && testResults.frameLoaded ) {
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
frame.src = docUri;
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -244,9 +244,6 @@ LocalStorage::ApplyEvent(StorageEvent* aStorageEvent)
|
||||||
mCache->SetItem(this, key, value, old, LocalStorageCache::E10sPropagated);
|
mCache->SetItem(this, key, value, old, LocalStorageCache::E10sPropagated);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char kPermissionType[] = "cookie";
|
|
||||||
static const char kStorageEnabled[] = "dom.storage.enabled";
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
LocalStorage::PrincipalEquals(nsIPrincipal* aPrincipal)
|
LocalStorage::PrincipalEquals(nsIPrincipal* aPrincipal)
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
|
static const char kStorageEnabled[] = "dom.storage.enabled";
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Storage, mWindow, mPrincipal)
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Storage, mWindow, mPrincipal)
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(Storage)
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(Storage)
|
||||||
|
|
|
@ -24,11 +24,6 @@
|
||||||
#include "mozilla/dom/BindingUtils.h"
|
#include "mozilla/dom/BindingUtils.h"
|
||||||
#include "mozilla/dom/XPathNSResolverBinding.h"
|
#include "mozilla/dom/XPathNSResolverBinding.h"
|
||||||
|
|
||||||
extern nsresult
|
|
||||||
TX_ResolveFunctionCallXPCOM(const nsCString &aContractID, int32_t aNamespaceID,
|
|
||||||
nsAtom *aName, nsISupports *aState,
|
|
||||||
FunctionCall **aFunction);
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
|
|
|
@ -64,8 +64,10 @@ DeleteRangeTransaction::DoTransaction()
|
||||||
|
|
||||||
if (startContainer == endContainer) {
|
if (startContainer == endContainer) {
|
||||||
// the selection begins and ends in the same node
|
// the selection begins and ends in the same node
|
||||||
|
nsIContent* startChild = rangeToDelete->GetChildAtStartOffset();
|
||||||
nsresult rv =
|
nsresult rv =
|
||||||
CreateTxnsToDeleteBetween(startContainer, startOffset, endOffset);
|
CreateTxnsToDeleteBetween(startContainer, startOffset,
|
||||||
|
startChild, endOffset);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
} else {
|
} else {
|
||||||
// the selection ends in a different node from where it started. delete
|
// the selection ends in a different node from where it started. delete
|
||||||
|
@ -122,6 +124,7 @@ DeleteRangeTransaction::GetTxnDescription(nsAString& aString)
|
||||||
nsresult
|
nsresult
|
||||||
DeleteRangeTransaction::CreateTxnsToDeleteBetween(nsINode* aNode,
|
DeleteRangeTransaction::CreateTxnsToDeleteBetween(nsINode* aNode,
|
||||||
int32_t aStartOffset,
|
int32_t aStartOffset,
|
||||||
|
nsIContent* aChildAtStartOffset,
|
||||||
int32_t aEndOffset)
|
int32_t aEndOffset)
|
||||||
{
|
{
|
||||||
if (NS_WARN_IF(!mEditorBase)) {
|
if (NS_WARN_IF(!mEditorBase)) {
|
||||||
|
@ -153,7 +156,7 @@ DeleteRangeTransaction::CreateTxnsToDeleteBetween(nsINode* aNode,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIContent> child = aNode->GetChildAt(aStartOffset);
|
nsIContent* child = aChildAtStartOffset;
|
||||||
for (int32_t i = aStartOffset; i < aEndOffset; ++i) {
|
for (int32_t i = aStartOffset; i < aEndOffset; ++i) {
|
||||||
// Even if we detect invalid range, we should ignore it for removing
|
// Even if we detect invalid range, we should ignore it for removing
|
||||||
// specified range's nodes as far as possible.
|
// specified range's nodes as far as possible.
|
||||||
|
|
|
@ -52,6 +52,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
nsresult CreateTxnsToDeleteBetween(nsINode* aNode,
|
nsresult CreateTxnsToDeleteBetween(nsINode* aNode,
|
||||||
int32_t aStartOffset,
|
int32_t aStartOffset,
|
||||||
|
nsIContent* aChildAtStartOffset,
|
||||||
int32_t aEndOffset);
|
int32_t aEndOffset);
|
||||||
|
|
||||||
nsresult CreateTxnsToDeleteNodesBetween(nsRange* aRangeToDelete);
|
nsresult CreateTxnsToDeleteNodesBetween(nsRange* aRangeToDelete);
|
||||||
|
|
|
@ -2391,13 +2391,14 @@ EditorBase::FindBetterInsertionPoint(nsCOMPtr<nsIDOMNode>& aNode,
|
||||||
int32_t& aOffset)
|
int32_t& aOffset)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
|
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
|
||||||
FindBetterInsertionPoint(node, aOffset);
|
FindBetterInsertionPoint(node, aOffset, nullptr);
|
||||||
aNode = do_QueryInterface(node);
|
aNode = do_QueryInterface(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
EditorBase::FindBetterInsertionPoint(nsCOMPtr<nsINode>& aNode,
|
EditorBase::FindBetterInsertionPoint(nsCOMPtr<nsINode>& aNode,
|
||||||
int32_t& aOffset)
|
int32_t& aOffset,
|
||||||
|
nsCOMPtr<nsIContent>* aSelChild)
|
||||||
{
|
{
|
||||||
if (aNode->IsNodeOfType(nsINode::eTEXT)) {
|
if (aNode->IsNodeOfType(nsINode::eTEXT)) {
|
||||||
// There is no "better" insertion point.
|
// There is no "better" insertion point.
|
||||||
|
@ -2424,6 +2425,9 @@ EditorBase::FindBetterInsertionPoint(nsCOMPtr<nsINode>& aNode,
|
||||||
node->GetFirstChild()->IsNodeOfType(nsINode::eTEXT)) {
|
node->GetFirstChild()->IsNodeOfType(nsINode::eTEXT)) {
|
||||||
aNode = node->GetFirstChild();
|
aNode = node->GetFirstChild();
|
||||||
aOffset = 0;
|
aOffset = 0;
|
||||||
|
if (aSelChild) {
|
||||||
|
*aSelChild = nullptr;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2439,6 +2443,9 @@ EditorBase::FindBetterInsertionPoint(nsCOMPtr<nsINode>& aNode,
|
||||||
NS_ENSURE_TRUE_VOID(node->Length() <= INT32_MAX);
|
NS_ENSURE_TRUE_VOID(node->Length() <= INT32_MAX);
|
||||||
aNode = child;
|
aNode = child;
|
||||||
aOffset = static_cast<int32_t>(aNode->Length());
|
aOffset = static_cast<int32_t>(aNode->Length());
|
||||||
|
if (aSelChild) {
|
||||||
|
*aSelChild = nullptr;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -2450,6 +2457,9 @@ EditorBase::FindBetterInsertionPoint(nsCOMPtr<nsINode>& aNode,
|
||||||
NS_ENSURE_TRUE_VOID(node->Length() <= INT32_MAX);
|
NS_ENSURE_TRUE_VOID(node->Length() <= INT32_MAX);
|
||||||
aNode = child;
|
aNode = child;
|
||||||
aOffset = static_cast<int32_t>(aNode->Length());
|
aOffset = static_cast<int32_t>(aNode->Length());
|
||||||
|
if (aSelChild) {
|
||||||
|
*aSelChild = nullptr;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
child = child->GetPreviousSibling();
|
child = child->GetPreviousSibling();
|
||||||
|
@ -2467,10 +2477,16 @@ EditorBase::FindBetterInsertionPoint(nsCOMPtr<nsINode>& aNode,
|
||||||
NS_ENSURE_TRUE_VOID(node->Length() <= INT32_MAX);
|
NS_ENSURE_TRUE_VOID(node->Length() <= INT32_MAX);
|
||||||
aNode = node->GetPreviousSibling();
|
aNode = node->GetPreviousSibling();
|
||||||
aOffset = static_cast<int32_t>(aNode->Length());
|
aOffset = static_cast<int32_t>(aNode->Length());
|
||||||
|
if (aSelChild) {
|
||||||
|
*aSelChild = nullptr;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->GetParentNode() && node->GetParentNode() == root) {
|
if (node->GetParentNode() && node->GetParentNode() == root) {
|
||||||
|
if (aSelChild) {
|
||||||
|
*aSelChild = node->AsContent();
|
||||||
|
}
|
||||||
aNode = node->GetParentNode();
|
aNode = node->GetParentNode();
|
||||||
aOffset = 0;
|
aOffset = 0;
|
||||||
return;
|
return;
|
||||||
|
@ -2481,6 +2497,7 @@ EditorBase::FindBetterInsertionPoint(nsCOMPtr<nsINode>& aNode,
|
||||||
nsresult
|
nsresult
|
||||||
EditorBase::InsertTextImpl(const nsAString& aStringToInsert,
|
EditorBase::InsertTextImpl(const nsAString& aStringToInsert,
|
||||||
nsCOMPtr<nsINode>* aInOutNode,
|
nsCOMPtr<nsINode>* aInOutNode,
|
||||||
|
nsCOMPtr<nsIContent>* aInOutChildAtOffset,
|
||||||
int32_t* aInOutOffset,
|
int32_t* aInOutOffset,
|
||||||
nsIDocument* aDoc)
|
nsIDocument* aDoc)
|
||||||
{
|
{
|
||||||
|
@ -2502,15 +2519,17 @@ EditorBase::InsertTextImpl(const nsAString& aStringToInsert,
|
||||||
|
|
||||||
nsCOMPtr<nsINode> node = *aInOutNode;
|
nsCOMPtr<nsINode> node = *aInOutNode;
|
||||||
int32_t offset = *aInOutOffset;
|
int32_t offset = *aInOutOffset;
|
||||||
|
nsCOMPtr<nsIContent> child = *aInOutChildAtOffset;
|
||||||
|
|
||||||
|
MOZ_ASSERT(node->GetChildAt(offset) == *aInOutChildAtOffset);
|
||||||
|
|
||||||
// In some cases, the node may be the anonymous div elemnt or a mozBR
|
// In some cases, the node may be the anonymous div elemnt or a mozBR
|
||||||
// element. Let's try to look for better insertion point in the nearest
|
// element. Let's try to look for better insertion point in the nearest
|
||||||
// text node if there is.
|
// text node if there is.
|
||||||
FindBetterInsertionPoint(node, offset);
|
FindBetterInsertionPoint(node, offset, address_of(child));
|
||||||
|
|
||||||
// If a neighboring text node already exists, use that
|
// If a neighboring text node already exists, use that
|
||||||
if (!node->IsNodeOfType(nsINode::eTEXT)) {
|
if (!node->IsNodeOfType(nsINode::eTEXT)) {
|
||||||
nsIContent* child = node->GetChildAt(offset);
|
|
||||||
if (offset && child && child->GetPreviousSibling() &&
|
if (offset && child && child->GetPreviousSibling() &&
|
||||||
child->GetPreviousSibling()->IsNodeOfType(nsINode::eTEXT)) {
|
child->GetPreviousSibling()->IsNodeOfType(nsINode::eTEXT)) {
|
||||||
node = child->GetPreviousSibling();
|
node = child->GetPreviousSibling();
|
||||||
|
@ -2566,6 +2585,7 @@ EditorBase::InsertTextImpl(const nsAString& aStringToInsert,
|
||||||
|
|
||||||
*aInOutNode = node;
|
*aInOutNode = node;
|
||||||
*aInOutOffset = offset;
|
*aInOutOffset = offset;
|
||||||
|
*aInOutChildAtOffset = nullptr;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3278,6 +3298,7 @@ EditorBase::GetLengthOfDOMNode(nsIDOMNode* aNode,
|
||||||
nsIContent*
|
nsIContent*
|
||||||
EditorBase::GetPriorNode(nsINode* aParentNode,
|
EditorBase::GetPriorNode(nsINode* aParentNode,
|
||||||
int32_t aOffset,
|
int32_t aOffset,
|
||||||
|
nsINode* aChildAtOffset,
|
||||||
bool aEditableNode,
|
bool aEditableNode,
|
||||||
bool aNoBlockCrossing)
|
bool aNoBlockCrossing)
|
||||||
{
|
{
|
||||||
|
@ -3294,8 +3315,8 @@ EditorBase::GetPriorNode(nsINode* aParentNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
// else look before the child at 'aOffset'
|
// else look before the child at 'aOffset'
|
||||||
if (nsIContent* child = aParentNode->GetChildAt(aOffset)) {
|
if (aChildAtOffset) {
|
||||||
return GetPriorNode(child, aEditableNode, aNoBlockCrossing);
|
return GetPriorNode(aChildAtOffset, aEditableNode, aNoBlockCrossing);
|
||||||
}
|
}
|
||||||
|
|
||||||
// unless there isn't one, in which case we are at the end of the node
|
// unless there isn't one, in which case we are at the end of the node
|
||||||
|
@ -3312,6 +3333,7 @@ EditorBase::GetPriorNode(nsINode* aParentNode,
|
||||||
nsIContent*
|
nsIContent*
|
||||||
EditorBase::GetNextNode(nsINode* aParentNode,
|
EditorBase::GetNextNode(nsINode* aParentNode,
|
||||||
int32_t aOffset,
|
int32_t aOffset,
|
||||||
|
nsINode* aChildAtOffset,
|
||||||
bool aEditableNode,
|
bool aEditableNode,
|
||||||
bool aNoBlockCrossing)
|
bool aNoBlockCrossing)
|
||||||
{
|
{
|
||||||
|
@ -3326,15 +3348,16 @@ EditorBase::GetNextNode(nsINode* aParentNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
// look at the child at 'aOffset'
|
// look at the child at 'aOffset'
|
||||||
nsIContent* child = aParentNode->GetChildAt(aOffset);
|
if (aChildAtOffset) {
|
||||||
if (child) {
|
if (aNoBlockCrossing && IsBlockNode(aChildAtOffset)) {
|
||||||
if (aNoBlockCrossing && IsBlockNode(child)) {
|
MOZ_ASSERT(aChildAtOffset->IsContent());
|
||||||
return child;
|
return aChildAtOffset->AsContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIContent* resultNode = GetLeftmostChild(child, aNoBlockCrossing);
|
nsIContent* resultNode = GetLeftmostChild(aChildAtOffset, aNoBlockCrossing);
|
||||||
if (!resultNode) {
|
if (!resultNode) {
|
||||||
return child;
|
MOZ_ASSERT(aChildAtOffset->IsContent());
|
||||||
|
return aChildAtOffset->AsContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsDescendantOfEditorRoot(resultNode)) {
|
if (!IsDescendantOfEditorRoot(resultNode)) {
|
||||||
|
@ -4078,8 +4101,12 @@ EditorBase::JoinNodeDeep(nsIContent& aLeftNode,
|
||||||
|
|
||||||
// Get new left and right nodes, and begin anew
|
// Get new left and right nodes, and begin anew
|
||||||
parentNode = rightNodeToJoin;
|
parentNode = rightNodeToJoin;
|
||||||
leftNodeToJoin = parentNode->GetChildAt(length - 1);
|
|
||||||
rightNodeToJoin = parentNode->GetChildAt(length);
|
rightNodeToJoin = parentNode->GetChildAt(length);
|
||||||
|
if (rightNodeToJoin) {
|
||||||
|
leftNodeToJoin = rightNodeToJoin->GetPreviousSibling();
|
||||||
|
} else {
|
||||||
|
leftNodeToJoin = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Skip over non-editable nodes
|
// Skip over non-editable nodes
|
||||||
while (leftNodeToJoin && !IsEditable(leftNodeToJoin)) {
|
while (leftNodeToJoin && !IsEditable(leftNodeToJoin)) {
|
||||||
|
@ -4540,6 +4567,7 @@ EditorBase::CreateTxnForDeleteRange(nsRange* aRangeToDelete,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsIContent* child = aRangeToDelete->GetChildAtStartOffset();
|
||||||
int32_t offset = aRangeToDelete->StartOffset();
|
int32_t offset = aRangeToDelete->StartOffset();
|
||||||
|
|
||||||
// determine if the insertion point is at the beginning, middle, or end of
|
// determine if the insertion point is at the beginning, middle, or end of
|
||||||
|
@ -4652,9 +4680,9 @@ EditorBase::CreateTxnForDeleteRange(nsRange* aRangeToDelete,
|
||||||
// node to find out
|
// node to find out
|
||||||
nsCOMPtr<nsINode> selectedNode;
|
nsCOMPtr<nsINode> selectedNode;
|
||||||
if (aAction == ePrevious) {
|
if (aAction == ePrevious) {
|
||||||
selectedNode = GetPriorNode(node, offset, true);
|
selectedNode = GetPriorNode(node, offset, child, true);
|
||||||
} else if (aAction == eNext) {
|
} else if (aAction == eNext) {
|
||||||
selectedNode = GetNextNode(node, offset, true);
|
selectedNode = GetNextNode(node, offset, child, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (selectedNode &&
|
while (selectedNode &&
|
||||||
|
@ -4958,7 +4986,7 @@ EditorBase::InitializeSelection(nsIDOMEventTarget* aFocusEventTarget)
|
||||||
NS_ENSURE_TRUE(firstRange, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(firstRange, NS_ERROR_FAILURE);
|
||||||
nsCOMPtr<nsINode> startNode = firstRange->GetStartContainer();
|
nsCOMPtr<nsINode> startNode = firstRange->GetStartContainer();
|
||||||
int32_t startOffset = firstRange->StartOffset();
|
int32_t startOffset = firstRange->StartOffset();
|
||||||
FindBetterInsertionPoint(startNode, startOffset);
|
FindBetterInsertionPoint(startNode, startOffset, nullptr);
|
||||||
Text* textNode = startNode->GetAsText();
|
Text* textNode = startNode->GetAsText();
|
||||||
MOZ_ASSERT(textNode,
|
MOZ_ASSERT(textNode,
|
||||||
"There must be text node if mIMETextLength is larger than 0");
|
"There must be text node if mIMETextLength is larger than 0");
|
||||||
|
|
|
@ -287,6 +287,7 @@ public:
|
||||||
|
|
||||||
virtual nsresult InsertTextImpl(const nsAString& aStringToInsert,
|
virtual nsresult InsertTextImpl(const nsAString& aStringToInsert,
|
||||||
nsCOMPtr<nsINode>* aInOutNode,
|
nsCOMPtr<nsINode>* aInOutNode,
|
||||||
|
nsCOMPtr<nsIContent>* aInOutChildAtOffset,
|
||||||
int32_t* aInOutOffset,
|
int32_t* aInOutOffset,
|
||||||
nsIDocument* aDoc);
|
nsIDocument* aDoc);
|
||||||
nsresult InsertTextIntoTextNodeImpl(const nsAString& aStringToInsert,
|
nsresult InsertTextIntoTextNodeImpl(const nsAString& aStringToInsert,
|
||||||
|
@ -708,6 +709,7 @@ public:
|
||||||
*/
|
*/
|
||||||
nsIContent* GetPriorNode(nsINode* aParentNode,
|
nsIContent* GetPriorNode(nsINode* aParentNode,
|
||||||
int32_t aOffset,
|
int32_t aOffset,
|
||||||
|
nsINode* aChildAtOffset,
|
||||||
bool aEditableNode,
|
bool aEditableNode,
|
||||||
bool aNoBlockCrossing = false);
|
bool aNoBlockCrossing = false);
|
||||||
|
|
||||||
|
@ -730,6 +732,7 @@ public:
|
||||||
*/
|
*/
|
||||||
nsIContent* GetNextNode(nsINode* aParentNode,
|
nsIContent* GetNextNode(nsINode* aParentNode,
|
||||||
int32_t aOffset,
|
int32_t aOffset,
|
||||||
|
nsINode* aChildAtOffset,
|
||||||
bool aEditableNode,
|
bool aEditableNode,
|
||||||
bool aNoBlockCrossing = false);
|
bool aNoBlockCrossing = false);
|
||||||
|
|
||||||
|
@ -1220,11 +1223,23 @@ public:
|
||||||
/**
|
/**
|
||||||
* FindBetterInsertionPoint() tries to look for better insertion point which
|
* FindBetterInsertionPoint() tries to look for better insertion point which
|
||||||
* is typically the nearest text node and offset in it.
|
* is typically the nearest text node and offset in it.
|
||||||
|
*
|
||||||
|
* @param aNode in/out param, on input set to the node to use to start the search,
|
||||||
|
* on output set to the node found as the better insertion point.
|
||||||
|
* @param aOffset in/out param, on input set to the offset to use to start the
|
||||||
|
* search, on putput set to the offset found as the better insertion
|
||||||
|
* point.
|
||||||
|
* @param aSelChild in/out param, on input, can be set to nullptr if the caller
|
||||||
|
* doesn't want to pass this in, or set to a pointer to an nsCOMPtr
|
||||||
|
* pointing to the child at the input node and offset, and on output
|
||||||
|
* the method will make it point to the child at the output node and
|
||||||
|
* offset returned in aNode and aOffset.
|
||||||
*/
|
*/
|
||||||
void FindBetterInsertionPoint(nsCOMPtr<nsIDOMNode>& aNode,
|
void FindBetterInsertionPoint(nsCOMPtr<nsIDOMNode>& aNode,
|
||||||
int32_t& aOffset);
|
int32_t& aOffset);
|
||||||
void FindBetterInsertionPoint(nsCOMPtr<nsINode>& aNode,
|
void FindBetterInsertionPoint(nsCOMPtr<nsINode>& aNode,
|
||||||
int32_t& aOffset);
|
int32_t& aOffset,
|
||||||
|
nsCOMPtr<nsIContent>* aSelChild);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HideCaret() hides caret with nsCaret::AddForceHide() or may show carent
|
* HideCaret() hides caret with nsCaret::AddForceHide() or may show carent
|
||||||
|
|
|
@ -854,6 +854,7 @@ HTMLEditRules::GetAlignment(bool* aMixed,
|
||||||
selection->GetRangeAt(0)->GetStartContainer());
|
selection->GetRangeAt(0)->GetStartContainer());
|
||||||
OwningNonNull<nsINode> parent =
|
OwningNonNull<nsINode> parent =
|
||||||
*selection->GetRangeAt(0)->GetStartContainer();
|
*selection->GetRangeAt(0)->GetStartContainer();
|
||||||
|
nsIContent* child = selection->GetRangeAt(0)->GetChildAtStartOffset();
|
||||||
int32_t offset = selection->GetRangeAt(0)->StartOffset();
|
int32_t offset = selection->GetRangeAt(0)->StartOffset();
|
||||||
|
|
||||||
// Is the selection collapsed?
|
// Is the selection collapsed?
|
||||||
|
@ -865,7 +866,7 @@ HTMLEditRules::GetAlignment(bool* aMixed,
|
||||||
nodeToExamine = parent;
|
nodeToExamine = parent;
|
||||||
} else if (parent->IsHTMLElement(nsGkAtoms::html) && offset == rootOffset) {
|
} else if (parent->IsHTMLElement(nsGkAtoms::html) && offset == rootOffset) {
|
||||||
// If we have selected the body, let's look at the first editable node
|
// If we have selected the body, let's look at the first editable node
|
||||||
nodeToExamine = htmlEditor->GetNextNode(parent, offset, true);
|
nodeToExamine = htmlEditor->GetNextNode(parent, offset, child, true);
|
||||||
} else {
|
} else {
|
||||||
nsTArray<RefPtr<nsRange>> arrayOfRanges;
|
nsTArray<RefPtr<nsRange>> arrayOfRanges;
|
||||||
GetPromotedRanges(selection, arrayOfRanges, EditAction::align);
|
GetPromotedRanges(selection, arrayOfRanges, EditAction::align);
|
||||||
|
@ -1219,11 +1220,13 @@ HTMLEditRules::WillInsert(Selection& aSelection,
|
||||||
aSelection.GetRangeAt(0)->GetStartContainer());
|
aSelection.GetRangeAt(0)->GetStartContainer());
|
||||||
OwningNonNull<nsINode> selNode =
|
OwningNonNull<nsINode> selNode =
|
||||||
*aSelection.GetRangeAt(0)->GetStartContainer();
|
*aSelection.GetRangeAt(0)->GetStartContainer();
|
||||||
|
nsIContent* selChild = aSelection.GetRangeAt(0)->GetChildAtStartOffset();
|
||||||
int32_t selOffset = aSelection.GetRangeAt(0)->StartOffset();
|
int32_t selOffset = aSelection.GetRangeAt(0)->StartOffset();
|
||||||
|
|
||||||
// Get prior node
|
// Get prior node
|
||||||
nsCOMPtr<nsIContent> priorNode = htmlEditor->GetPriorHTMLNode(selNode,
|
nsCOMPtr<nsIContent> priorNode = htmlEditor->GetPriorHTMLNode(selNode,
|
||||||
selOffset);
|
selOffset,
|
||||||
|
selChild);
|
||||||
if (priorNode && TextEditUtils::IsMozBR(priorNode)) {
|
if (priorNode && TextEditUtils::IsMozBR(priorNode)) {
|
||||||
nsCOMPtr<Element> block1 = htmlEditor->GetBlock(selNode);
|
nsCOMPtr<Element> block1 = htmlEditor->GetBlock(selNode);
|
||||||
nsCOMPtr<Element> block2 = htmlEditor->GetBlockNodeParent(priorNode);
|
nsCOMPtr<Element> block2 = htmlEditor->GetBlockNodeParent(priorNode);
|
||||||
|
@ -1296,6 +1299,8 @@ HTMLEditRules::WillInsertText(EditAction aAction,
|
||||||
NS_ENSURE_STATE(mHTMLEditor);
|
NS_ENSURE_STATE(mHTMLEditor);
|
||||||
NS_ENSURE_STATE(aSelection->GetRangeAt(0));
|
NS_ENSURE_STATE(aSelection->GetRangeAt(0));
|
||||||
nsCOMPtr<nsINode> selNode = aSelection->GetRangeAt(0)->GetStartContainer();
|
nsCOMPtr<nsINode> selNode = aSelection->GetRangeAt(0)->GetStartContainer();
|
||||||
|
nsCOMPtr<nsIContent> selChild =
|
||||||
|
aSelection->GetRangeAt(0)->GetChildAtStartOffset();
|
||||||
int32_t selOffset = aSelection->GetRangeAt(0)->StartOffset();
|
int32_t selOffset = aSelection->GetRangeAt(0)->StartOffset();
|
||||||
NS_ENSURE_STATE(selNode);
|
NS_ENSURE_STATE(selNode);
|
||||||
|
|
||||||
|
@ -1320,13 +1325,15 @@ HTMLEditRules::WillInsertText(EditAction aAction,
|
||||||
}
|
}
|
||||||
if (inString->IsEmpty()) {
|
if (inString->IsEmpty()) {
|
||||||
rv = mHTMLEditor->InsertTextImpl(*inString, address_of(selNode),
|
rv = mHTMLEditor->InsertTextImpl(*inString, address_of(selNode),
|
||||||
|
address_of(selChild),
|
||||||
&selOffset, doc);
|
&selOffset, doc);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
WSRunObject wsObj(mHTMLEditor, selNode, selOffset);
|
WSRunObject wsObj(mHTMLEditor, selNode, selOffset);
|
||||||
rv = wsObj.InsertText(*inString, address_of(selNode), &selOffset, doc);
|
rv = wsObj.InsertText(*inString, address_of(selNode),
|
||||||
|
address_of(selChild), &selOffset, doc);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -1398,6 +1405,7 @@ HTMLEditRules::WillInsertText(EditAction aAction,
|
||||||
} else {
|
} else {
|
||||||
NS_ENSURE_STATE(mHTMLEditor);
|
NS_ENSURE_STATE(mHTMLEditor);
|
||||||
rv = mHTMLEditor->InsertTextImpl(subStr, address_of(curNode),
|
rv = mHTMLEditor->InsertTextImpl(subStr, address_of(curNode),
|
||||||
|
address_of(selChild),
|
||||||
&curOffset, doc);
|
&curOffset, doc);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
@ -1430,7 +1438,8 @@ HTMLEditRules::WillInsertText(EditAction aAction,
|
||||||
// is it a tab?
|
// is it a tab?
|
||||||
if (subStr.Equals(tabStr)) {
|
if (subStr.Equals(tabStr)) {
|
||||||
rv =
|
rv =
|
||||||
wsObj.InsertText(spacesStr, address_of(curNode), &curOffset, doc);
|
wsObj.InsertText(spacesStr, address_of(curNode),
|
||||||
|
address_of(selChild), &curOffset, doc);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
|
@ -1441,8 +1450,10 @@ HTMLEditRules::WillInsertText(EditAction aAction,
|
||||||
nsIEditor::eNone);
|
nsIEditor::eNone);
|
||||||
NS_ENSURE_TRUE(br, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(br, NS_ERROR_FAILURE);
|
||||||
pos++;
|
pos++;
|
||||||
|
selChild = br->GetNextSibling();;
|
||||||
} else {
|
} else {
|
||||||
rv = wsObj.InsertText(subStr, address_of(curNode), &curOffset, doc);
|
rv = wsObj.InsertText(subStr, address_of(curNode),
|
||||||
|
address_of(selChild), &curOffset, doc);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1533,6 +1544,7 @@ HTMLEditRules::WillInsertBreak(Selection& aSelection,
|
||||||
aSelection.GetRangeAt(0)->GetStartContainer(),
|
aSelection.GetRangeAt(0)->GetStartContainer(),
|
||||||
NS_ERROR_FAILURE);
|
NS_ERROR_FAILURE);
|
||||||
OwningNonNull<nsINode> node = *aSelection.GetRangeAt(0)->GetStartContainer();
|
OwningNonNull<nsINode> node = *aSelection.GetRangeAt(0)->GetStartContainer();
|
||||||
|
nsIContent* child = aSelection.GetRangeAt(0)->GetChildAtStartOffset();
|
||||||
int32_t offset = aSelection.GetRangeAt(0)->StartOffset();
|
int32_t offset = aSelection.GetRangeAt(0)->StartOffset();
|
||||||
|
|
||||||
// Do nothing if the node is read-only
|
// Do nothing if the node is read-only
|
||||||
|
@ -1585,6 +1597,7 @@ HTMLEditRules::WillInsertBreak(Selection& aSelection,
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
node = *aSelection.GetRangeAt(0)->GetStartContainer();
|
node = *aSelection.GetRangeAt(0)->GetStartContainer();
|
||||||
|
child = aSelection.GetRangeAt(0)->GetChildAtStartOffset();
|
||||||
offset = aSelection.GetRangeAt(0)->StartOffset();
|
offset = aSelection.GetRangeAt(0)->StartOffset();
|
||||||
|
|
||||||
blockParent = mHTMLEditor->GetBlock(node);
|
blockParent = mHTMLEditor->GetBlock(node);
|
||||||
|
@ -1638,8 +1651,8 @@ HTMLEditRules::WillInsertBreak(Selection& aSelection,
|
||||||
blockParent->IsAnyOfHTMLElements(nsGkAtoms::p, nsGkAtoms::div))) {
|
blockParent->IsAnyOfHTMLElements(nsGkAtoms::p, nsGkAtoms::div))) {
|
||||||
// Paragraphs: special rules to look for <br>s
|
// Paragraphs: special rules to look for <br>s
|
||||||
nsresult rv =
|
nsresult rv =
|
||||||
ReturnInParagraph(&aSelection, GetAsDOMNode(blockParent),
|
ReturnInParagraph(&aSelection, blockParent, node,
|
||||||
GetAsDOMNode(node), offset, aCancel, aHandled);
|
offset, child, aCancel, aHandled);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
// Fall through, we may not have handled it in ReturnInParagraph()
|
// Fall through, we may not have handled it in ReturnInParagraph()
|
||||||
}
|
}
|
||||||
|
@ -3596,6 +3609,7 @@ HTMLEditRules::MakeBasicBlock(Selection& aSelection, nsAtom& blockType)
|
||||||
aSelection.GetRangeAt(0)->GetStartContainer());
|
aSelection.GetRangeAt(0)->GetStartContainer());
|
||||||
OwningNonNull<nsINode> container =
|
OwningNonNull<nsINode> container =
|
||||||
*aSelection.GetRangeAt(0)->GetStartContainer();
|
*aSelection.GetRangeAt(0)->GetStartContainer();
|
||||||
|
nsIContent* child = aSelection.GetRangeAt(0)->GetChildAtStartOffset();
|
||||||
int32_t offset = aSelection.GetRangeAt(0)->StartOffset();
|
int32_t offset = aSelection.GetRangeAt(0)->StartOffset();
|
||||||
|
|
||||||
if (&blockType == nsGkAtoms::normal ||
|
if (&blockType == nsGkAtoms::normal ||
|
||||||
|
@ -3608,7 +3622,7 @@ HTMLEditRules::MakeBasicBlock(Selection& aSelection, nsAtom& blockType)
|
||||||
// Otherwise it gets pushed into a following block after the split,
|
// Otherwise it gets pushed into a following block after the split,
|
||||||
// which is visually bad.
|
// which is visually bad.
|
||||||
nsCOMPtr<nsIContent> brNode =
|
nsCOMPtr<nsIContent> brNode =
|
||||||
htmlEditor->GetNextHTMLNode(container, offset);
|
htmlEditor->GetNextHTMLNode(container, offset, child);
|
||||||
if (brNode && brNode->IsHTMLElement(nsGkAtoms::br)) {
|
if (brNode && brNode->IsHTMLElement(nsGkAtoms::br)) {
|
||||||
rv = htmlEditor->DeleteNode(brNode);
|
rv = htmlEditor->DeleteNode(brNode);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
@ -3631,7 +3645,7 @@ HTMLEditRules::MakeBasicBlock(Selection& aSelection, nsAtom& blockType)
|
||||||
} else {
|
} else {
|
||||||
// We are making a block. Consume a br, if needed.
|
// We are making a block. Consume a br, if needed.
|
||||||
nsCOMPtr<nsIContent> brNode =
|
nsCOMPtr<nsIContent> brNode =
|
||||||
htmlEditor->GetNextHTMLNode(container, offset, true);
|
htmlEditor->GetNextHTMLNode(container, offset, child, true);
|
||||||
if (brNode && brNode->IsHTMLElement(nsGkAtoms::br)) {
|
if (brNode && brNode->IsHTMLElement(nsGkAtoms::br)) {
|
||||||
rv = htmlEditor->DeleteNode(brNode);
|
rv = htmlEditor->DeleteNode(brNode);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
@ -4738,7 +4752,7 @@ HTMLEditRules::WillAlign(Selection& aSelection,
|
||||||
// Consume a trailing br, if any. This is to keep an alignment from
|
// Consume a trailing br, if any. This is to keep an alignment from
|
||||||
// creating extra lines, if possible.
|
// creating extra lines, if possible.
|
||||||
nsCOMPtr<nsIContent> brContent =
|
nsCOMPtr<nsIContent> brContent =
|
||||||
htmlEditor->GetNextHTMLNode(parent, offset);
|
htmlEditor->GetNextHTMLNode(parent, offset, child);
|
||||||
if (brContent && TextEditUtils::IsBreak(brContent)) {
|
if (brContent && TextEditUtils::IsBreak(brContent)) {
|
||||||
// Making use of html structure... if next node after where we are
|
// Making use of html structure... if next node after where we are
|
||||||
// putting our div is not a block, then the br we found is in same block
|
// putting our div is not a block, then the br we found is in same block
|
||||||
|
@ -5042,8 +5056,9 @@ HTMLEditRules::CheckForEmptyBlock(nsINode* aStartNode,
|
||||||
if (aAction == nsIEditor::eNext || aAction == nsIEditor::eNextWord ||
|
if (aAction == nsIEditor::eNext || aAction == nsIEditor::eNextWord ||
|
||||||
aAction == nsIEditor::eToEndOfLine) {
|
aAction == nsIEditor::eToEndOfLine) {
|
||||||
// Move to the start of the next node, if any
|
// Move to the start of the next node, if any
|
||||||
nsCOMPtr<nsIContent> nextNode = htmlEditor->GetNextNode(blockParent,
|
nsINode* child = emptyBlock->GetNextSibling();
|
||||||
offset + 1, true);
|
nsCOMPtr<nsIContent> nextNode =
|
||||||
|
htmlEditor->GetNextNode(blockParent, offset + 1, child, true);
|
||||||
if (nextNode) {
|
if (nextNode) {
|
||||||
EditorDOMPoint pt = GetGoodSelPointForNode(*nextNode, aAction);
|
EditorDOMPoint pt = GetGoodSelPointForNode(*nextNode, aAction);
|
||||||
nsresult rv = aSelection->Collapse(pt.node, pt.offset);
|
nsresult rv = aSelection->Collapse(pt.node, pt.offset);
|
||||||
|
@ -5059,6 +5074,7 @@ HTMLEditRules::CheckForEmptyBlock(nsINode* aStartNode,
|
||||||
// Move to the end of the previous node
|
// Move to the end of the previous node
|
||||||
nsCOMPtr<nsIContent> priorNode = htmlEditor->GetPriorNode(blockParent,
|
nsCOMPtr<nsIContent> priorNode = htmlEditor->GetPriorNode(blockParent,
|
||||||
offset,
|
offset,
|
||||||
|
emptyBlock,
|
||||||
true);
|
true);
|
||||||
if (priorNode) {
|
if (priorNode) {
|
||||||
EditorDOMPoint pt = GetGoodSelPointForNode(*priorNode, aAction);
|
EditorDOMPoint pt = GetGoodSelPointForNode(*priorNode, aAction);
|
||||||
|
@ -5318,6 +5334,8 @@ HTMLEditRules::NormalizeSelection(Selection* inSelection)
|
||||||
if (NS_WARN_IF(!endNode)) {
|
if (NS_WARN_IF(!endNode)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
nsIContent* startChild = range->GetChildAtStartOffset();
|
||||||
|
nsIContent* endChild = range->GetChildAtEndOffset();
|
||||||
uint32_t startOffset = range->StartOffset();
|
uint32_t startOffset = range->StartOffset();
|
||||||
uint32_t endOffset = range->EndOffset();
|
uint32_t endOffset = range->EndOffset();
|
||||||
|
|
||||||
|
@ -5355,7 +5373,8 @@ HTMLEditRules::NormalizeSelection(Selection* inSelection)
|
||||||
} else if (wsEndObj.mStartReason == WSType::thisBlock) {
|
} else if (wsEndObj.mStartReason == WSType::thisBlock) {
|
||||||
// endpoint is just after start of this block
|
// endpoint is just after start of this block
|
||||||
nsINode* child =
|
nsINode* child =
|
||||||
htmlEditor->GetPriorHTMLNode(endNode, static_cast<int32_t>(endOffset));
|
htmlEditor->GetPriorHTMLNode(endNode, static_cast<int32_t>(endOffset),
|
||||||
|
endChild);
|
||||||
if (child) {
|
if (child) {
|
||||||
int32_t offset = -1;
|
int32_t offset = -1;
|
||||||
newEndNode = EditorBase::GetNodeLocation(child, &offset);
|
newEndNode = EditorBase::GetNodeLocation(child, &offset);
|
||||||
|
@ -5397,7 +5416,8 @@ HTMLEditRules::NormalizeSelection(Selection* inSelection)
|
||||||
// startpoint is just before end of this block
|
// startpoint is just before end of this block
|
||||||
nsINode* child =
|
nsINode* child =
|
||||||
htmlEditor->GetNextHTMLNode(startNode,
|
htmlEditor->GetNextHTMLNode(startNode,
|
||||||
static_cast<int32_t>(startOffset));
|
static_cast<int32_t>(startOffset),
|
||||||
|
startChild);
|
||||||
if (child) {
|
if (child) {
|
||||||
int32_t offset = -1;
|
int32_t offset = -1;
|
||||||
newStartNode = EditorBase::GetNodeLocation(child, &offset);
|
newStartNode = EditorBase::GetNodeLocation(child, &offset);
|
||||||
|
@ -5493,6 +5513,7 @@ HTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsINode> node = &aNode;
|
nsCOMPtr<nsINode> node = &aNode;
|
||||||
|
nsINode* child = node->GetChildAt(aOffset);
|
||||||
int32_t offset = aOffset;
|
int32_t offset = aOffset;
|
||||||
|
|
||||||
// else not a text section. In this case we want to see if we should grab
|
// else not a text section. In this case we want to see if we should grab
|
||||||
|
@ -5505,27 +5526,29 @@ HTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere,
|
||||||
return EditorDOMPoint(node, offset);
|
return EditorDOMPoint(node, offset);
|
||||||
}
|
}
|
||||||
offset = node->GetParentNode()->IndexOf(node);
|
offset = node->GetParentNode()->IndexOf(node);
|
||||||
|
child = node;
|
||||||
node = node->GetParentNode();
|
node = node->GetParentNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
// look back through any further inline nodes that aren't across a <br>
|
// look back through any further inline nodes that aren't across a <br>
|
||||||
// from us, and that are enclosed in the same block.
|
// from us, and that are enclosed in the same block.
|
||||||
nsCOMPtr<nsINode> priorNode =
|
nsCOMPtr<nsINode> priorNode =
|
||||||
htmlEditor->GetPriorHTMLNode(node, offset, true);
|
htmlEditor->GetPriorHTMLNode(node, offset, child, true);
|
||||||
|
|
||||||
while (priorNode && priorNode->GetParentNode() &&
|
while (priorNode && priorNode->GetParentNode() &&
|
||||||
!htmlEditor->IsVisibleBRElement(priorNode) &&
|
!htmlEditor->IsVisibleBRElement(priorNode) &&
|
||||||
!IsBlockNode(*priorNode)) {
|
!IsBlockNode(*priorNode)) {
|
||||||
offset = priorNode->GetParentNode()->IndexOf(priorNode);
|
offset = priorNode->GetParentNode()->IndexOf(priorNode);
|
||||||
|
child = node;
|
||||||
node = priorNode->GetParentNode();
|
node = priorNode->GetParentNode();
|
||||||
priorNode = htmlEditor->GetPriorHTMLNode(node, offset, true);
|
priorNode = htmlEditor->GetPriorHTMLNode(node, offset, child, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finding the real start for this point. look up the tree for as long as
|
// 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
|
// we are the first node in the container, and as long as we haven't hit
|
||||||
// the body node.
|
// the body node.
|
||||||
nsCOMPtr<nsIContent> nearNode =
|
nsCOMPtr<nsIContent> nearNode =
|
||||||
htmlEditor->GetPriorHTMLNode(node, offset, true);
|
htmlEditor->GetPriorHTMLNode(node, offset, child, true);
|
||||||
while (!nearNode && !node->IsHTMLElement(nsGkAtoms::body) &&
|
while (!nearNode && !node->IsHTMLElement(nsGkAtoms::body) &&
|
||||||
node->GetParentNode()) {
|
node->GetParentNode()) {
|
||||||
// some cutoffs are here: we don't need to also include them in the
|
// some cutoffs are here: we don't need to also include them in the
|
||||||
|
@ -5554,9 +5577,10 @@ HTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
child = node;
|
||||||
node = parent;
|
node = parent;
|
||||||
offset = parentOffset;
|
offset = parentOffset;
|
||||||
nearNode = htmlEditor->GetPriorHTMLNode(node, offset, true);
|
nearNode = htmlEditor->GetPriorHTMLNode(node, offset, child, true);
|
||||||
}
|
}
|
||||||
return EditorDOMPoint(node, offset);
|
return EditorDOMPoint(node, offset);
|
||||||
}
|
}
|
||||||
|
@ -5570,16 +5594,18 @@ HTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere,
|
||||||
}
|
}
|
||||||
// want to be after the text node
|
// want to be after the text node
|
||||||
offset = 1 + node->GetParentNode()->IndexOf(node);
|
offset = 1 + node->GetParentNode()->IndexOf(node);
|
||||||
|
child = node;
|
||||||
node = node->GetParentNode();
|
node = node->GetParentNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
// look ahead through any further inline nodes that aren't across a <br> from
|
// look ahead through any further inline nodes that aren't across a <br> from
|
||||||
// us, and that are enclosed in the same block.
|
// us, and that are enclosed in the same block.
|
||||||
nsCOMPtr<nsIContent> nextNode =
|
nsCOMPtr<nsIContent> nextNode =
|
||||||
htmlEditor->GetNextHTMLNode(node, offset, true);
|
htmlEditor->GetNextHTMLNode(node, offset, child, true);
|
||||||
|
|
||||||
while (nextNode && !IsBlockNode(*nextNode) && nextNode->GetParentNode()) {
|
while (nextNode && !IsBlockNode(*nextNode) && nextNode->GetParentNode()) {
|
||||||
offset = 1 + nextNode->GetParentNode()->IndexOf(nextNode);
|
offset = 1 + nextNode->GetParentNode()->IndexOf(nextNode);
|
||||||
|
child = nextNode->GetNextSibling();
|
||||||
node = nextNode->GetParentNode();
|
node = nextNode->GetParentNode();
|
||||||
if (htmlEditor->IsVisibleBRElement(nextNode)) {
|
if (htmlEditor->IsVisibleBRElement(nextNode)) {
|
||||||
break;
|
break;
|
||||||
|
@ -5602,14 +5628,14 @@ HTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nextNode = htmlEditor->GetNextHTMLNode(node, offset, true);
|
nextNode = htmlEditor->GetNextHTMLNode(node, offset, child, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finding the real end for this point. look up the tree for as long as we
|
// 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
|
// are the last node in the container, and as long as we haven't hit the body
|
||||||
// node.
|
// node.
|
||||||
nsCOMPtr<nsIContent> nearNode =
|
nsCOMPtr<nsIContent> nearNode =
|
||||||
htmlEditor->GetNextHTMLNode(node, offset, true);
|
htmlEditor->GetNextHTMLNode(node, offset, child, true);
|
||||||
while (!nearNode && !node->IsHTMLElement(nsGkAtoms::body) &&
|
while (!nearNode && !node->IsHTMLElement(nsGkAtoms::body) &&
|
||||||
node->GetParentNode()) {
|
node->GetParentNode()) {
|
||||||
int32_t parentOffset = node->GetParentNode()->IndexOf(node);
|
int32_t parentOffset = node->GetParentNode()->IndexOf(node);
|
||||||
|
@ -5623,10 +5649,11 @@ HTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
child = node->GetNextSibling();
|
||||||
node = parent;
|
node = parent;
|
||||||
// we want to be AFTER nearNode
|
// we want to be AFTER nearNode
|
||||||
offset = parentOffset + 1;
|
offset = parentOffset + 1;
|
||||||
nearNode = htmlEditor->GetNextHTMLNode(node, offset, true);
|
nearNode = htmlEditor->GetNextHTMLNode(node, offset, child, true);
|
||||||
}
|
}
|
||||||
return EditorDOMPoint(node, offset);
|
return EditorDOMPoint(node, offset);
|
||||||
}
|
}
|
||||||
|
@ -6440,9 +6467,10 @@ HTMLEditRules::ReturnInHeader(Selection& aSelection,
|
||||||
*/
|
*/
|
||||||
nsresult
|
nsresult
|
||||||
HTMLEditRules::ReturnInParagraph(Selection* aSelection,
|
HTMLEditRules::ReturnInParagraph(Selection* aSelection,
|
||||||
nsIDOMNode* aPara,
|
nsINode* aPara,
|
||||||
nsIDOMNode* aNode,
|
nsINode* aNode,
|
||||||
int32_t aOffset,
|
int32_t aOffset,
|
||||||
|
nsIContent* aChildAtOffset,
|
||||||
bool* aCancel,
|
bool* aCancel,
|
||||||
bool* aHandled)
|
bool* aHandled)
|
||||||
{
|
{
|
||||||
|
@ -6462,7 +6490,7 @@ HTMLEditRules::ReturnInParagraph(Selection* aSelection,
|
||||||
bool newBRneeded = false;
|
bool newBRneeded = false;
|
||||||
bool newSelNode = false;
|
bool newSelNode = false;
|
||||||
nsCOMPtr<nsIContent> sibling;
|
nsCOMPtr<nsIContent> sibling;
|
||||||
nsCOMPtr<nsIDOMNode> selNode = aNode;
|
nsCOMPtr<nsIDOMNode> selNode = GetAsDOMNode(aNode);
|
||||||
int32_t selOffset = aOffset;
|
int32_t selOffset = aOffset;
|
||||||
|
|
||||||
NS_ENSURE_STATE(mHTMLEditor);
|
NS_ENSURE_STATE(mHTMLEditor);
|
||||||
|
@ -6500,7 +6528,7 @@ HTMLEditRules::ReturnInParagraph(Selection* aSelection,
|
||||||
return NS_ERROR_UNEXPECTED;
|
return NS_ERROR_UNEXPECTED;
|
||||||
}
|
}
|
||||||
nsresult rv =
|
nsresult rv =
|
||||||
mHTMLEditor->SplitNode(aNode, aOffset, getter_AddRefs(tmp));
|
mHTMLEditor->SplitNode(selNode, aOffset, getter_AddRefs(tmp));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
selNode = tmp;
|
selNode = tmp;
|
||||||
}
|
}
|
||||||
|
@ -6513,13 +6541,13 @@ HTMLEditRules::ReturnInParagraph(Selection* aSelection,
|
||||||
// is there a BR prior to it?
|
// is there a BR prior to it?
|
||||||
nsCOMPtr<nsIContent> nearNode;
|
nsCOMPtr<nsIContent> nearNode;
|
||||||
NS_ENSURE_STATE(mHTMLEditor);
|
NS_ENSURE_STATE(mHTMLEditor);
|
||||||
nearNode = mHTMLEditor->GetPriorHTMLNode(node, aOffset);
|
nearNode = mHTMLEditor->GetPriorHTMLNode(node, aOffset, aChildAtOffset);
|
||||||
NS_ENSURE_STATE(mHTMLEditor);
|
NS_ENSURE_STATE(mHTMLEditor);
|
||||||
if (!nearNode || !mHTMLEditor->IsVisibleBRElement(nearNode) ||
|
if (!nearNode || !mHTMLEditor->IsVisibleBRElement(nearNode) ||
|
||||||
TextEditUtils::HasMozAttr(GetAsDOMNode(nearNode))) {
|
TextEditUtils::HasMozAttr(GetAsDOMNode(nearNode))) {
|
||||||
// is there a BR after it?
|
// is there a BR after it?
|
||||||
NS_ENSURE_STATE(mHTMLEditor);
|
NS_ENSURE_STATE(mHTMLEditor);
|
||||||
nearNode = mHTMLEditor->GetNextHTMLNode(node, aOffset);
|
nearNode = mHTMLEditor->GetNextHTMLNode(node, aOffset, aChildAtOffset);
|
||||||
NS_ENSURE_STATE(mHTMLEditor);
|
NS_ENSURE_STATE(mHTMLEditor);
|
||||||
if (!nearNode || !mHTMLEditor->IsVisibleBRElement(nearNode) ||
|
if (!nearNode || !mHTMLEditor->IsVisibleBRElement(nearNode) ||
|
||||||
TextEditUtils::HasMozAttr(GetAsDOMNode(nearNode))) {
|
TextEditUtils::HasMozAttr(GetAsDOMNode(nearNode))) {
|
||||||
|
@ -6546,7 +6574,8 @@ HTMLEditRules::ReturnInParagraph(Selection* aSelection,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*aHandled = true;
|
*aHandled = true;
|
||||||
return SplitParagraph(aPara, sibling, aSelection, address_of(selNode), &selOffset);
|
return SplitParagraph(GetAsDOMNode(aPara), sibling, aSelection,
|
||||||
|
address_of(selNode), &selOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7489,7 +7518,7 @@ HTMLEditRules::CheckInterlinePosition(Selection& aSelection)
|
||||||
// special-case first so that we don't accidentally fall through into one of
|
// special-case first so that we don't accidentally fall through into one of
|
||||||
// the other conditionals.
|
// the other conditionals.
|
||||||
nsCOMPtr<nsIContent> node =
|
nsCOMPtr<nsIContent> node =
|
||||||
htmlEditor->GetPriorHTMLNode(selNode, selOffset, true);
|
htmlEditor->GetPriorHTMLNode(selNode, selOffset, child, true);
|
||||||
if (node && node->IsHTMLElement(nsGkAtoms::br)) {
|
if (node && node->IsHTMLElement(nsGkAtoms::br)) {
|
||||||
aSelection.SetInterlinePosition(true);
|
aSelection.SetInterlinePosition(true);
|
||||||
return;
|
return;
|
||||||
|
@ -7537,12 +7566,14 @@ HTMLEditRules::AdjustSelection(Selection* aSelection,
|
||||||
EditorBase::GetStartNodeAndOffset(aSelection,
|
EditorBase::GetStartNodeAndOffset(aSelection,
|
||||||
getter_AddRefs(selNode), &selOffset);
|
getter_AddRefs(selNode), &selOffset);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
nsINode* child = aSelection->GetRangeAt(0)->GetChildAtStartOffset();
|
||||||
temp = selNode;
|
temp = selNode;
|
||||||
|
|
||||||
// are we in an editable node?
|
// are we in an editable node?
|
||||||
NS_ENSURE_STATE(mHTMLEditor);
|
NS_ENSURE_STATE(mHTMLEditor);
|
||||||
while (!mHTMLEditor->IsEditable(selNode)) {
|
while (!mHTMLEditor->IsEditable(selNode)) {
|
||||||
// scan up the tree until we find an editable place to be
|
// scan up the tree until we find an editable place to be
|
||||||
|
child = temp;
|
||||||
selNode = EditorBase::GetNodeLocation(temp, &selOffset);
|
selNode = EditorBase::GetNodeLocation(temp, &selOffset);
|
||||||
NS_ENSURE_TRUE(selNode, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(selNode, NS_ERROR_FAILURE);
|
||||||
temp = selNode;
|
temp = selNode;
|
||||||
|
@ -7589,7 +7620,7 @@ HTMLEditRules::AdjustSelection(Selection* aSelection,
|
||||||
|
|
||||||
NS_ENSURE_STATE(mHTMLEditor);
|
NS_ENSURE_STATE(mHTMLEditor);
|
||||||
nsCOMPtr<nsIContent> nearNode =
|
nsCOMPtr<nsIContent> nearNode =
|
||||||
mHTMLEditor->GetPriorHTMLNode(selNode, selOffset);
|
mHTMLEditor->GetPriorHTMLNode(selNode, selOffset, child);
|
||||||
if (nearNode) {
|
if (nearNode) {
|
||||||
// is nearNode also a descendant of same block?
|
// is nearNode also a descendant of same block?
|
||||||
NS_ENSURE_STATE(mHTMLEditor);
|
NS_ENSURE_STATE(mHTMLEditor);
|
||||||
|
@ -7628,7 +7659,7 @@ HTMLEditRules::AdjustSelection(Selection* aSelection,
|
||||||
|
|
||||||
// we aren't in a textnode: are we adjacent to text or a break or an image?
|
// we aren't in a textnode: are we adjacent to text or a break or an image?
|
||||||
NS_ENSURE_STATE(mHTMLEditor);
|
NS_ENSURE_STATE(mHTMLEditor);
|
||||||
nearNode = mHTMLEditor->GetPriorHTMLNode(selNode, selOffset, true);
|
nearNode = mHTMLEditor->GetPriorHTMLNode(selNode, selOffset, child, true);
|
||||||
if (nearNode && (TextEditUtils::IsBreak(nearNode) ||
|
if (nearNode && (TextEditUtils::IsBreak(nearNode) ||
|
||||||
EditorBase::IsTextNode(nearNode) ||
|
EditorBase::IsTextNode(nearNode) ||
|
||||||
HTMLEditUtils::IsImage(nearNode) ||
|
HTMLEditUtils::IsImage(nearNode) ||
|
||||||
|
@ -7637,7 +7668,7 @@ HTMLEditRules::AdjustSelection(Selection* aSelection,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
NS_ENSURE_STATE(mHTMLEditor);
|
NS_ENSURE_STATE(mHTMLEditor);
|
||||||
nearNode = mHTMLEditor->GetNextHTMLNode(selNode, selOffset, true);
|
nearNode = mHTMLEditor->GetNextHTMLNode(selNode, selOffset, child, true);
|
||||||
if (nearNode && (TextEditUtils::IsBreak(nearNode) ||
|
if (nearNode && (TextEditUtils::IsBreak(nearNode) ||
|
||||||
EditorBase::IsTextNode(nearNode) ||
|
EditorBase::IsTextNode(nearNode) ||
|
||||||
nearNode->IsAnyOfHTMLElements(nsGkAtoms::img,
|
nearNode->IsAnyOfHTMLElements(nsGkAtoms::img,
|
||||||
|
@ -7647,7 +7678,7 @@ HTMLEditRules::AdjustSelection(Selection* aSelection,
|
||||||
|
|
||||||
// look for a nearby text node.
|
// look for a nearby text node.
|
||||||
// prefer the correct direction.
|
// prefer the correct direction.
|
||||||
rv = FindNearSelectableNode(selNode, selOffset, aAction,
|
rv = FindNearSelectableNode(selNode, selOffset, child, aAction,
|
||||||
address_of(nearNode));
|
address_of(nearNode));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
@ -7666,6 +7697,7 @@ HTMLEditRules::AdjustSelection(Selection* aSelection,
|
||||||
nsresult
|
nsresult
|
||||||
HTMLEditRules::FindNearSelectableNode(nsINode* aSelNode,
|
HTMLEditRules::FindNearSelectableNode(nsINode* aSelNode,
|
||||||
int32_t aSelOffset,
|
int32_t aSelOffset,
|
||||||
|
nsINode* aChildAtOffset,
|
||||||
nsIEditor::EDirection& aDirection,
|
nsIEditor::EDirection& aDirection,
|
||||||
nsCOMPtr<nsIContent>* outSelectableNode)
|
nsCOMPtr<nsIContent>* outSelectableNode)
|
||||||
{
|
{
|
||||||
|
@ -7675,13 +7707,15 @@ HTMLEditRules::FindNearSelectableNode(nsINode* aSelNode,
|
||||||
nsCOMPtr<nsIContent> nearNode, curNode;
|
nsCOMPtr<nsIContent> nearNode, curNode;
|
||||||
if (aDirection == nsIEditor::ePrevious) {
|
if (aDirection == nsIEditor::ePrevious) {
|
||||||
NS_ENSURE_STATE(mHTMLEditor);
|
NS_ENSURE_STATE(mHTMLEditor);
|
||||||
nearNode = mHTMLEditor->GetPriorHTMLNode(aSelNode, aSelOffset);
|
nearNode = mHTMLEditor->GetPriorHTMLNode(aSelNode, aSelOffset,
|
||||||
|
aChildAtOffset);
|
||||||
if (NS_WARN_IF(!nearNode)) {
|
if (NS_WARN_IF(!nearNode)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
NS_ENSURE_STATE(mHTMLEditor);
|
NS_ENSURE_STATE(mHTMLEditor);
|
||||||
nearNode = mHTMLEditor->GetNextHTMLNode(aSelNode, aSelOffset);
|
nearNode = mHTMLEditor->GetNextHTMLNode(aSelNode, aSelOffset,
|
||||||
|
aChildAtOffset);
|
||||||
if (NS_WARN_IF(!nearNode)) {
|
if (NS_WARN_IF(!nearNode)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -7697,13 +7731,15 @@ HTMLEditRules::FindNearSelectableNode(nsINode* aSelNode,
|
||||||
|
|
||||||
if (aDirection == nsIEditor::ePrevious) {
|
if (aDirection == nsIEditor::ePrevious) {
|
||||||
NS_ENSURE_STATE(mHTMLEditor);
|
NS_ENSURE_STATE(mHTMLEditor);
|
||||||
nearNode = mHTMLEditor->GetPriorHTMLNode(aSelNode, aSelOffset);
|
nearNode = mHTMLEditor->GetPriorHTMLNode(aSelNode, aSelOffset,
|
||||||
|
aChildAtOffset);
|
||||||
if (NS_WARN_IF(!nearNode)) {
|
if (NS_WARN_IF(!nearNode)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
NS_ENSURE_STATE(mHTMLEditor);
|
NS_ENSURE_STATE(mHTMLEditor);
|
||||||
nearNode = mHTMLEditor->GetPriorHTMLNode(aSelNode, aSelOffset);
|
nearNode = mHTMLEditor->GetPriorHTMLNode(aSelNode, aSelOffset,
|
||||||
|
aChildAtOffset);
|
||||||
if (NS_WARN_IF(!nearNode)) {
|
if (NS_WARN_IF(!nearNode)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -289,9 +289,10 @@ protected:
|
||||||
nsAtom& DefaultParagraphSeparator();
|
nsAtom& DefaultParagraphSeparator();
|
||||||
nsresult ReturnInHeader(Selection& aSelection, Element& aHeader,
|
nsresult ReturnInHeader(Selection& aSelection, Element& aHeader,
|
||||||
nsINode& aNode, int32_t aOffset);
|
nsINode& aNode, int32_t aOffset);
|
||||||
nsresult ReturnInParagraph(Selection* aSelection, nsIDOMNode* aHeader,
|
nsresult ReturnInParagraph(Selection* aSelection, nsINode* aHeader,
|
||||||
nsIDOMNode* aTextNode, int32_t aOffset,
|
nsINode* aTextNode, int32_t aOffset,
|
||||||
bool* aCancel, bool* aHandled);
|
nsIContent* aChildAtOffset, bool* aCancel,
|
||||||
|
bool* aHandled);
|
||||||
nsresult SplitParagraph(nsIDOMNode* aPara,
|
nsresult SplitParagraph(nsIDOMNode* aPara,
|
||||||
nsIContent* aBRNode,
|
nsIContent* aBRNode,
|
||||||
Selection* aSelection,
|
Selection* aSelection,
|
||||||
|
@ -399,6 +400,7 @@ protected:
|
||||||
nsIEditor::EDirection aAction);
|
nsIEditor::EDirection aAction);
|
||||||
nsresult FindNearSelectableNode(nsINode* aSelNode,
|
nsresult FindNearSelectableNode(nsINode* aSelNode,
|
||||||
int32_t aSelOffset,
|
int32_t aSelOffset,
|
||||||
|
nsINode* aChildAtOffset,
|
||||||
nsIEditor::EDirection& aDirection,
|
nsIEditor::EDirection& aDirection,
|
||||||
nsCOMPtr<nsIContent>* outSelectableNode);
|
nsCOMPtr<nsIContent>* outSelectableNode);
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -3118,6 +3118,7 @@ HTMLEditor::DeleteText(nsGenericDOMDataNode& aCharData,
|
||||||
nsresult
|
nsresult
|
||||||
HTMLEditor::InsertTextImpl(const nsAString& aStringToInsert,
|
HTMLEditor::InsertTextImpl(const nsAString& aStringToInsert,
|
||||||
nsCOMPtr<nsINode>* aInOutNode,
|
nsCOMPtr<nsINode>* aInOutNode,
|
||||||
|
nsCOMPtr<nsIContent>* aInOutChildAtOffset,
|
||||||
int32_t* aInOutOffset,
|
int32_t* aInOutOffset,
|
||||||
nsIDocument* aDoc)
|
nsIDocument* aDoc)
|
||||||
{
|
{
|
||||||
|
@ -3126,8 +3127,9 @@ HTMLEditor::InsertTextImpl(const nsAString& aStringToInsert,
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return EditorBase::InsertTextImpl(aStringToInsert, aInOutNode, aInOutOffset,
|
return EditorBase::InsertTextImpl(aStringToInsert, aInOutNode,
|
||||||
aDoc);
|
aInOutChildAtOffset,
|
||||||
|
aInOutOffset, aDoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -3892,6 +3894,7 @@ HTMLEditor::GetPriorHTMLNode(nsIDOMNode* aNode,
|
||||||
nsIContent*
|
nsIContent*
|
||||||
HTMLEditor::GetPriorHTMLNode(nsINode* aParent,
|
HTMLEditor::GetPriorHTMLNode(nsINode* aParent,
|
||||||
int32_t aOffset,
|
int32_t aOffset,
|
||||||
|
nsINode* aChildAtOffset,
|
||||||
bool aNoBlockCrossing)
|
bool aNoBlockCrossing)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aParent);
|
MOZ_ASSERT(aParent);
|
||||||
|
@ -3900,7 +3903,7 @@ HTMLEditor::GetPriorHTMLNode(nsINode* aParent,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetPriorNode(aParent, aOffset, true, aNoBlockCrossing);
|
return GetPriorNode(aParent, aOffset, aChildAtOffset, true, aNoBlockCrossing);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3942,9 +3945,11 @@ HTMLEditor::GetNextHTMLNode(nsIDOMNode* aNode,
|
||||||
nsIContent*
|
nsIContent*
|
||||||
HTMLEditor::GetNextHTMLNode(nsINode* aParent,
|
HTMLEditor::GetNextHTMLNode(nsINode* aParent,
|
||||||
int32_t aOffset,
|
int32_t aOffset,
|
||||||
|
nsINode* aChildAtOffset,
|
||||||
bool aNoBlockCrossing)
|
bool aNoBlockCrossing)
|
||||||
{
|
{
|
||||||
nsIContent* content = GetNextNode(aParent, aOffset, true, aNoBlockCrossing);
|
nsIContent* content = GetNextNode(aParent, aOffset, aChildAtOffset,
|
||||||
|
true, aNoBlockCrossing);
|
||||||
if (content && !IsDescendantOfEditorRoot(content)) {
|
if (content && !IsDescendantOfEditorRoot(content)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -313,6 +313,7 @@ public:
|
||||||
uint32_t aLength);
|
uint32_t aLength);
|
||||||
virtual nsresult InsertTextImpl(const nsAString& aStringToInsert,
|
virtual nsresult InsertTextImpl(const nsAString& aStringToInsert,
|
||||||
nsCOMPtr<nsINode>* aInOutNode,
|
nsCOMPtr<nsINode>* aInOutNode,
|
||||||
|
nsCOMPtr<nsIContent>* aInOutChildAtOffset,
|
||||||
int32_t* aInOutOffset,
|
int32_t* aInOutOffset,
|
||||||
nsIDocument* aDoc) override;
|
nsIDocument* aDoc) override;
|
||||||
NS_IMETHOD_(bool) IsModifiableNode(nsIDOMNode* aNode) override;
|
NS_IMETHOD_(bool) IsModifiableNode(nsIDOMNode* aNode) override;
|
||||||
|
@ -779,12 +780,14 @@ protected:
|
||||||
nsresult GetPriorHTMLNode(nsIDOMNode* inNode, nsCOMPtr<nsIDOMNode>* outNode,
|
nsresult GetPriorHTMLNode(nsIDOMNode* inNode, nsCOMPtr<nsIDOMNode>* outNode,
|
||||||
bool bNoBlockCrossing = false);
|
bool bNoBlockCrossing = false);
|
||||||
nsIContent* GetPriorHTMLNode(nsINode* aParent, int32_t aOffset,
|
nsIContent* GetPriorHTMLNode(nsINode* aParent, int32_t aOffset,
|
||||||
|
nsINode* aChildAtOffset,
|
||||||
bool aNoBlockCrossing = false);
|
bool aNoBlockCrossing = false);
|
||||||
|
|
||||||
nsIContent* GetNextHTMLNode(nsINode* aNode, bool aNoBlockCrossing = false);
|
nsIContent* GetNextHTMLNode(nsINode* aNode, bool aNoBlockCrossing = false);
|
||||||
nsresult GetNextHTMLNode(nsIDOMNode* inNode, nsCOMPtr<nsIDOMNode>* outNode,
|
nsresult GetNextHTMLNode(nsIDOMNode* inNode, nsCOMPtr<nsIDOMNode>* outNode,
|
||||||
bool bNoBlockCrossing = false);
|
bool bNoBlockCrossing = false);
|
||||||
nsIContent* GetNextHTMLNode(nsINode* aParent, int32_t aOffset,
|
nsIContent* GetNextHTMLNode(nsINode* aParent, int32_t aOffset,
|
||||||
|
nsINode* aChildAtOffset,
|
||||||
bool aNoBlockCrossing = false);
|
bool aNoBlockCrossing = false);
|
||||||
|
|
||||||
bool IsFirstEditableChild(nsINode* aNode);
|
bool IsFirstEditableChild(nsINode* aNode);
|
||||||
|
|
|
@ -726,6 +726,8 @@ TextEditRules::WillInsertText(EditAction aAction,
|
||||||
// get the (collapsed) selection location
|
// get the (collapsed) selection location
|
||||||
NS_ENSURE_STATE(aSelection->GetRangeAt(0));
|
NS_ENSURE_STATE(aSelection->GetRangeAt(0));
|
||||||
nsCOMPtr<nsINode> selNode = aSelection->GetRangeAt(0)->GetStartContainer();
|
nsCOMPtr<nsINode> selNode = aSelection->GetRangeAt(0)->GetStartContainer();
|
||||||
|
nsCOMPtr<nsIContent> selChild =
|
||||||
|
aSelection->GetRangeAt(0)->GetChildAtStartOffset();
|
||||||
int32_t selOffset = aSelection->GetRangeAt(0)->StartOffset();
|
int32_t selOffset = aSelection->GetRangeAt(0)->StartOffset();
|
||||||
NS_ENSURE_STATE(selNode);
|
NS_ENSURE_STATE(selNode);
|
||||||
|
|
||||||
|
@ -744,7 +746,8 @@ TextEditRules::WillInsertText(EditAction aAction,
|
||||||
if (aAction == EditAction::insertIMEText) {
|
if (aAction == EditAction::insertIMEText) {
|
||||||
NS_ENSURE_STATE(mTextEditor);
|
NS_ENSURE_STATE(mTextEditor);
|
||||||
// Find better insertion point to insert text.
|
// Find better insertion point to insert text.
|
||||||
mTextEditor->FindBetterInsertionPoint(selNode, selOffset);
|
mTextEditor->FindBetterInsertionPoint(selNode, selOffset,
|
||||||
|
address_of(selChild));
|
||||||
// If there is one or more IME selections, its minimum offset should be
|
// If there is one or more IME selections, its minimum offset should be
|
||||||
// the insertion point.
|
// the insertion point.
|
||||||
int32_t IMESelectionOffset =
|
int32_t IMESelectionOffset =
|
||||||
|
@ -753,7 +756,7 @@ TextEditRules::WillInsertText(EditAction aAction,
|
||||||
selOffset = IMESelectionOffset;
|
selOffset = IMESelectionOffset;
|
||||||
}
|
}
|
||||||
rv = mTextEditor->InsertTextImpl(*outString, address_of(selNode),
|
rv = mTextEditor->InsertTextImpl(*outString, address_of(selNode),
|
||||||
&selOffset, doc);
|
address_of(selChild), &selOffset, doc);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
} else {
|
} else {
|
||||||
// aAction == EditAction::insertText; find where we are
|
// aAction == EditAction::insertText; find where we are
|
||||||
|
@ -765,7 +768,7 @@ TextEditRules::WillInsertText(EditAction aAction,
|
||||||
AutoTransactionsConserveSelection dontChangeMySelection(mTextEditor);
|
AutoTransactionsConserveSelection dontChangeMySelection(mTextEditor);
|
||||||
|
|
||||||
rv = mTextEditor->InsertTextImpl(*outString, address_of(curNode),
|
rv = mTextEditor->InsertTextImpl(*outString, address_of(curNode),
|
||||||
&curOffset, doc);
|
address_of(selChild), &curOffset, doc);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (curNode) {
|
if (curNode) {
|
||||||
|
|
|
@ -551,7 +551,7 @@ TextEditor::ExtendSelectionForDelete(Selection* aSelection,
|
||||||
NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
// node might be anonymous DIV, so we find better text node
|
// node might be anonymous DIV, so we find better text node
|
||||||
FindBetterInsertionPoint(node, offset);
|
FindBetterInsertionPoint(node, offset, nullptr);
|
||||||
|
|
||||||
if (IsTextNode(node)) {
|
if (IsTextNode(node)) {
|
||||||
const nsTextFragment* data = node->GetAsText()->GetText();
|
const nsTextFragment* data = node->GetAsText()->GetText();
|
||||||
|
@ -704,6 +704,7 @@ TextEditor::InsertLineBreak()
|
||||||
// get the (collapsed) selection location
|
// get the (collapsed) selection location
|
||||||
NS_ENSURE_STATE(selection->GetRangeAt(0));
|
NS_ENSURE_STATE(selection->GetRangeAt(0));
|
||||||
nsCOMPtr<nsINode> selNode = selection->GetRangeAt(0)->GetStartContainer();
|
nsCOMPtr<nsINode> selNode = selection->GetRangeAt(0)->GetStartContainer();
|
||||||
|
nsCOMPtr<nsIContent> selChild = selection->GetRangeAt(0)->GetChildAtStartOffset();
|
||||||
int32_t selOffset = selection->GetRangeAt(0)->StartOffset();
|
int32_t selOffset = selection->GetRangeAt(0)->StartOffset();
|
||||||
NS_ENSURE_STATE(selNode);
|
NS_ENSURE_STATE(selNode);
|
||||||
|
|
||||||
|
@ -722,7 +723,7 @@ TextEditor::InsertLineBreak()
|
||||||
|
|
||||||
// insert a linefeed character
|
// insert a linefeed character
|
||||||
rv = InsertTextImpl(NS_LITERAL_STRING("\n"), address_of(selNode),
|
rv = InsertTextImpl(NS_LITERAL_STRING("\n"), address_of(selNode),
|
||||||
&selOffset, doc);
|
address_of(selChild), &selOffset, doc);
|
||||||
if (!selNode) {
|
if (!selNode) {
|
||||||
rv = NS_ERROR_NULL_POINTER; // don't return here, so DidDoAction is called
|
rv = NS_ERROR_NULL_POINTER; // don't return here, so DidDoAction is called
|
||||||
}
|
}
|
||||||
|
|
|
@ -234,6 +234,7 @@ WSRunObject::InsertBreak(nsCOMPtr<nsINode>* aInOutParent,
|
||||||
nsresult
|
nsresult
|
||||||
WSRunObject::InsertText(const nsAString& aStringToInsert,
|
WSRunObject::InsertText(const nsAString& aStringToInsert,
|
||||||
nsCOMPtr<nsINode>* aInOutParent,
|
nsCOMPtr<nsINode>* aInOutParent,
|
||||||
|
nsCOMPtr<nsIContent>* aInOutChildAtOffset,
|
||||||
int32_t* aInOutOffset,
|
int32_t* aInOutOffset,
|
||||||
nsIDocument* aDoc)
|
nsIDocument* aDoc)
|
||||||
{
|
{
|
||||||
|
@ -356,7 +357,8 @@ WSRunObject::InsertText(const nsAString& aStringToInsert,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ready, aim, fire!
|
// Ready, aim, fire!
|
||||||
mHTMLEditor->InsertTextImpl(theString, aInOutParent, aInOutOffset, aDoc);
|
mHTMLEditor->InsertTextImpl(theString, aInOutParent, aInOutChildAtOffset,
|
||||||
|
aInOutOffset, aDoc);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -224,6 +224,7 @@ public:
|
||||||
// trailingws before {aInOutParent,aInOutOffset} needs to be removed.
|
// trailingws before {aInOutParent,aInOutOffset} needs to be removed.
|
||||||
nsresult InsertText(const nsAString& aStringToInsert,
|
nsresult InsertText(const nsAString& aStringToInsert,
|
||||||
nsCOMPtr<nsINode>* aInOutNode,
|
nsCOMPtr<nsINode>* aInOutNode,
|
||||||
|
nsCOMPtr<nsIContent>* aInOutChildAtOffset,
|
||||||
int32_t* aInOutOffset,
|
int32_t* aInOutOffset,
|
||||||
nsIDocument* aDoc);
|
nsIDocument* aDoc);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script>
|
||||||
|
try { o1 = document.createElement('style'); } catch(e) { }
|
||||||
|
try { o2 = document.createElement('output') } catch(e) { }
|
||||||
|
try { o3 = document.createElement('input') } catch(e) { }
|
||||||
|
try { o4 = document.createElement('script'); } catch(e) { }
|
||||||
|
try { o5 = o2.cloneNode(false); } catch(e) { }
|
||||||
|
try { document.documentElement.appendChild(o1) } catch(e) { }
|
||||||
|
try { o1.outerHTML = '<a contenteditable=\'true\'>'; } catch(e) { }
|
||||||
|
try { document.documentElement.appendChild(o3) } catch(e) { }
|
||||||
|
try { o7 = document.createTextNode(' '); } catch(e) { }
|
||||||
|
try { o4.appendChild(o7) } catch(e) { }
|
||||||
|
try { document.documentElement.appendChild(o4) } catch(e) { }
|
||||||
|
try { o6 = window.getSelection() } catch(e) { }
|
||||||
|
try { o3.select() } catch(e) { }
|
||||||
|
try { document.replaceChild(document.documentElement, document.documentElement); } catch(e) { }
|
||||||
|
try { o6.setBaseAndExtent(o7, 0, o5, 0) } catch(e) { }
|
||||||
|
try { document.designMode = 'on'; } catch(e) { }
|
||||||
|
try { document.execCommand('insertimage', false, 'http://localhost/') } catch(e) { }
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
</html>
|
|
@ -80,6 +80,7 @@ load 1366176.html
|
||||||
load 1375131.html
|
load 1375131.html
|
||||||
load 1381541.html
|
load 1381541.html
|
||||||
load 1383755.html
|
load 1383755.html
|
||||||
|
load 1388075.html
|
||||||
load 1402469.html
|
load 1402469.html
|
||||||
load 1402904.html
|
load 1402904.html
|
||||||
load 1405747.html
|
load 1405747.html
|
||||||
|
|
|
@ -174,7 +174,6 @@ struct TextureFactoryIdentifier
|
||||||
bool mSupportsTextureBlitting;
|
bool mSupportsTextureBlitting;
|
||||||
bool mSupportsPartialUploads;
|
bool mSupportsPartialUploads;
|
||||||
bool mSupportsComponentAlpha;
|
bool mSupportsComponentAlpha;
|
||||||
bool mSupportsBackdropCopyForComponentAlpha;
|
|
||||||
bool mUsingAdvancedLayers;
|
bool mUsingAdvancedLayers;
|
||||||
SyncHandle mSyncHandle;
|
SyncHandle mSyncHandle;
|
||||||
|
|
||||||
|
@ -193,7 +192,6 @@ struct TextureFactoryIdentifier
|
||||||
, mSupportsTextureBlitting(aSupportsTextureBlitting)
|
, mSupportsTextureBlitting(aSupportsTextureBlitting)
|
||||||
, mSupportsPartialUploads(aSupportsPartialUploads)
|
, mSupportsPartialUploads(aSupportsPartialUploads)
|
||||||
, mSupportsComponentAlpha(aSupportsComponentAlpha)
|
, mSupportsComponentAlpha(aSupportsComponentAlpha)
|
||||||
, mSupportsBackdropCopyForComponentAlpha(true)
|
|
||||||
, mUsingAdvancedLayers(false)
|
, mUsingAdvancedLayers(false)
|
||||||
, mSyncHandle(aSyncHandle)
|
, mSyncHandle(aSyncHandle)
|
||||||
{}
|
{}
|
||||||
|
|
|
@ -1352,8 +1352,7 @@ ContainerLayer::DefaultComputeSupportsComponentAlphaChildren(bool* aNeedsSurface
|
||||||
if (HasOpaqueAncestorLayer(this) &&
|
if (HasOpaqueAncestorLayer(this) &&
|
||||||
GetEffectiveTransform().Is2D(&transform) &&
|
GetEffectiveTransform().Is2D(&transform) &&
|
||||||
!gfx::ThebesMatrix(transform).HasNonIntegerTranslation() &&
|
!gfx::ThebesMatrix(transform).HasNonIntegerTranslation() &&
|
||||||
blendMode == gfx::CompositionOp::OP_OVER &&
|
blendMode == gfx::CompositionOp::OP_OVER)
|
||||||
Manager()->SupportsBackdropCopyForComponentAlpha())
|
|
||||||
{
|
{
|
||||||
mSupportsComponentAlphaChildren = true;
|
mSupportsComponentAlphaChildren = true;
|
||||||
needsSurfaceCopy = true;
|
needsSurfaceCopy = true;
|
||||||
|
|
|
@ -360,12 +360,6 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual bool BlendingRequiresIntermediateSurface() { return false; }
|
virtual bool BlendingRequiresIntermediateSurface() { return false; }
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if this LayerManager supports component alpha layers in
|
|
||||||
* situations that require a copy of the backdrop.
|
|
||||||
*/
|
|
||||||
virtual bool SupportsBackdropCopyForComponentAlpha() { return true; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CONSTRUCTION PHASE ONLY
|
* CONSTRUCTION PHASE ONLY
|
||||||
* Set the root layer. The root layer is initially null. If there is
|
* Set the root layer. The root layer is initially null. If there is
|
||||||
|
|
|
@ -825,13 +825,6 @@ ClientLayerManager::AreComponentAlphaLayersEnabled()
|
||||||
LayerManager::AreComponentAlphaLayersEnabled();
|
LayerManager::AreComponentAlphaLayersEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
ClientLayerManager::SupportsBackdropCopyForComponentAlpha()
|
|
||||||
{
|
|
||||||
const TextureFactoryIdentifier& ident = AsShadowForwarder()->GetTextureFactoryIdentifier();
|
|
||||||
return ident.mSupportsBackdropCopyForComponentAlpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ClientLayerManager::SetIsFirstPaint()
|
ClientLayerManager::SetIsFirstPaint()
|
||||||
{
|
{
|
||||||
|
|
|
@ -201,7 +201,6 @@ public:
|
||||||
const mozilla::TimeStamp& aCompositeEnd) override;
|
const mozilla::TimeStamp& aCompositeEnd) override;
|
||||||
|
|
||||||
virtual bool AreComponentAlphaLayersEnabled() override;
|
virtual bool AreComponentAlphaLayersEnabled() override;
|
||||||
virtual bool SupportsBackdropCopyForComponentAlpha() override;
|
|
||||||
|
|
||||||
// Log APZ test data for the current paint. We supply the paint sequence
|
// Log APZ test data for the current paint. We supply the paint sequence
|
||||||
// number ourselves, and take care of calling APZTestData::StartNewPaint()
|
// number ourselves, and take care of calling APZTestData::StartNewPaint()
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "mozilla/gfx/GPUProcessManager.h"
|
#include "mozilla/gfx/GPUProcessManager.h"
|
||||||
#include "mozilla/gfx/Logging.h"
|
#include "mozilla/gfx/Logging.h"
|
||||||
#include "mozilla/mozalloc.h" // for operator new, etc
|
#include "mozilla/mozalloc.h" // for operator new, etc
|
||||||
|
#include "mozilla/Telemetry.h"
|
||||||
#include "nsAutoPtr.h"
|
#include "nsAutoPtr.h"
|
||||||
#include "nsDebug.h" // for NS_RUNTIMEABORT
|
#include "nsDebug.h" // for NS_RUNTIMEABORT
|
||||||
#include "nsIObserver.h" // for nsIObserver
|
#include "nsIObserver.h" // for nsIObserver
|
||||||
|
@ -94,6 +95,8 @@ CompositorBridgeChild::CompositorBridgeChild(CompositorManagerChild *aManager)
|
||||||
, mOutstandingAsyncPaints(0)
|
, mOutstandingAsyncPaints(0)
|
||||||
, mOutstandingAsyncEndTransaction(false)
|
, mOutstandingAsyncEndTransaction(false)
|
||||||
, mIsWaitingForPaint(false)
|
, mIsWaitingForPaint(false)
|
||||||
|
, mSlowFlushCount(0)
|
||||||
|
, mTotalFlushCount(0)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
}
|
}
|
||||||
|
@ -1154,13 +1157,35 @@ CompositorBridgeChild::FlushAsyncPaints()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
MonitorAutoLock lock(mPaintLock);
|
Maybe<TimeStamp> start;
|
||||||
while (mIsWaitingForPaint) {
|
if (XRE_IsContentProcess() && gfx::gfxVars::UseOMTP()) {
|
||||||
lock.Wait();
|
start = Some(TimeStamp::Now());
|
||||||
}
|
}
|
||||||
|
|
||||||
// It's now safe to free any TextureClients that were used during painting.
|
{
|
||||||
mTextureClientsForAsyncPaint.Clear();
|
MonitorAutoLock lock(mPaintLock);
|
||||||
|
while (mIsWaitingForPaint) {
|
||||||
|
lock.Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's now safe to free any TextureClients that were used during painting.
|
||||||
|
mTextureClientsForAsyncPaint.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start) {
|
||||||
|
float ms = (TimeStamp::Now() - start.value()).ToMilliseconds();
|
||||||
|
|
||||||
|
// Anything above 200us gets recorded.
|
||||||
|
if (ms >= 0.2) {
|
||||||
|
mSlowFlushCount++;
|
||||||
|
Telemetry::Accumulate(Telemetry::GFX_OMTP_PAINT_WAIT_TIME, int32_t(ms));
|
||||||
|
}
|
||||||
|
mTotalFlushCount++;
|
||||||
|
|
||||||
|
double ratio = double(mSlowFlushCount) / double(mTotalFlushCount);
|
||||||
|
Telemetry::ScalarSet(Telemetry::ScalarID::GFX_OMTP_PAINT_WAIT_RATIO,
|
||||||
|
uint32_t(ratio * 100 * 100));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -388,6 +388,9 @@ private:
|
||||||
// paint thread completes. This is R/W on both the main and paint threads, and
|
// paint thread completes. This is R/W on both the main and paint threads, and
|
||||||
// must be accessed within the paint lock.
|
// must be accessed within the paint lock.
|
||||||
bool mIsWaitingForPaint;
|
bool mIsWaitingForPaint;
|
||||||
|
|
||||||
|
uintptr_t mSlowFlushCount;
|
||||||
|
uintptr_t mTotalFlushCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace layers
|
} // namespace layers
|
||||||
|
|
|
@ -307,7 +307,6 @@ struct ParamTraits<mozilla::layers::TextureFactoryIdentifier>
|
||||||
WriteParam(aMsg, aParam.mSupportsTextureBlitting);
|
WriteParam(aMsg, aParam.mSupportsTextureBlitting);
|
||||||
WriteParam(aMsg, aParam.mSupportsPartialUploads);
|
WriteParam(aMsg, aParam.mSupportsPartialUploads);
|
||||||
WriteParam(aMsg, aParam.mSupportsComponentAlpha);
|
WriteParam(aMsg, aParam.mSupportsComponentAlpha);
|
||||||
WriteParam(aMsg, aParam.mSupportsBackdropCopyForComponentAlpha);
|
|
||||||
WriteParam(aMsg, aParam.mUsingAdvancedLayers);
|
WriteParam(aMsg, aParam.mUsingAdvancedLayers);
|
||||||
WriteParam(aMsg, aParam.mSyncHandle);
|
WriteParam(aMsg, aParam.mSyncHandle);
|
||||||
}
|
}
|
||||||
|
@ -321,7 +320,6 @@ struct ParamTraits<mozilla::layers::TextureFactoryIdentifier>
|
||||||
ReadParam(aMsg, aIter, &aResult->mSupportsTextureBlitting) &&
|
ReadParam(aMsg, aIter, &aResult->mSupportsTextureBlitting) &&
|
||||||
ReadParam(aMsg, aIter, &aResult->mSupportsPartialUploads) &&
|
ReadParam(aMsg, aIter, &aResult->mSupportsPartialUploads) &&
|
||||||
ReadParam(aMsg, aIter, &aResult->mSupportsComponentAlpha) &&
|
ReadParam(aMsg, aIter, &aResult->mSupportsComponentAlpha) &&
|
||||||
ReadParam(aMsg, aIter, &aResult->mSupportsBackdropCopyForComponentAlpha) &&
|
|
||||||
ReadParam(aMsg, aIter, &aResult->mUsingAdvancedLayers) &&
|
ReadParam(aMsg, aIter, &aResult->mUsingAdvancedLayers) &&
|
||||||
ReadParam(aMsg, aIter, &aResult->mSyncHandle);
|
ReadParam(aMsg, aIter, &aResult->mSyncHandle);
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -21,7 +21,8 @@ using namespace gfx;
|
||||||
ContainerLayerMLGPU::ContainerLayerMLGPU(LayerManagerMLGPU* aManager)
|
ContainerLayerMLGPU::ContainerLayerMLGPU(LayerManagerMLGPU* aManager)
|
||||||
: ContainerLayer(aManager, nullptr),
|
: ContainerLayer(aManager, nullptr),
|
||||||
LayerMLGPU(aManager),
|
LayerMLGPU(aManager),
|
||||||
mInvalidateEntireSurface(false)
|
mInvalidateEntireSurface(false),
|
||||||
|
mSurfaceCopyNeeded(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +36,8 @@ ContainerLayerMLGPU::~ContainerLayerMLGPU()
|
||||||
bool
|
bool
|
||||||
ContainerLayerMLGPU::OnPrepareToRender(FrameBuilder* aBuilder)
|
ContainerLayerMLGPU::OnPrepareToRender(FrameBuilder* aBuilder)
|
||||||
{
|
{
|
||||||
|
mView = nullptr;
|
||||||
|
|
||||||
if (!UseIntermediateSurface()) {
|
if (!UseIntermediateSurface()) {
|
||||||
// Set this so we invalidate the entire cached render target (if any)
|
// Set this so we invalidate the entire cached render target (if any)
|
||||||
// if our container uses an intermediate surface again later.
|
// if our container uses an intermediate surface again later.
|
||||||
|
@ -67,6 +70,19 @@ ContainerLayerMLGPU::OnPrepareToRender(FrameBuilder* aBuilder)
|
||||||
mRenderTarget = nullptr;
|
mRenderTarget = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note that if a surface copy is needed, we always redraw the
|
||||||
|
// whole surface (on-demand). This is a rare case - the old
|
||||||
|
// Compositor already does this - and it saves us having to
|
||||||
|
// do much more complicated invalidation.
|
||||||
|
bool surfaceCopyNeeded = false;
|
||||||
|
DefaultComputeSupportsComponentAlphaChildren(&surfaceCopyNeeded);
|
||||||
|
if (surfaceCopyNeeded != mSurfaceCopyNeeded ||
|
||||||
|
surfaceCopyNeeded)
|
||||||
|
{
|
||||||
|
mInvalidateEntireSurface = true;
|
||||||
|
}
|
||||||
|
mSurfaceCopyNeeded = surfaceCopyNeeded;
|
||||||
|
|
||||||
gfx::IntRect viewport(gfx::IntPoint(0, 0), mTargetSize);
|
gfx::IntRect viewport(gfx::IntPoint(0, 0), mTargetSize);
|
||||||
if (!mRenderTarget ||
|
if (!mRenderTarget ||
|
||||||
!gfxPrefs::AdvancedLayersUseInvalidation() ||
|
!gfxPrefs::AdvancedLayersUseInvalidation() ||
|
||||||
|
|
|
@ -13,6 +13,7 @@ namespace mozilla {
|
||||||
namespace layers {
|
namespace layers {
|
||||||
|
|
||||||
class MLGDevice;
|
class MLGDevice;
|
||||||
|
class RenderViewMLGPU;
|
||||||
|
|
||||||
class ContainerLayerMLGPU final : public ContainerLayer
|
class ContainerLayerMLGPU final : public ContainerLayer
|
||||||
, public LayerMLGPU
|
, public LayerMLGPU
|
||||||
|
@ -53,6 +54,17 @@ public:
|
||||||
mInvalidRect.SetEmpty();
|
mInvalidRect.SetEmpty();
|
||||||
}
|
}
|
||||||
bool IsContentOpaque() override;
|
bool IsContentOpaque() override;
|
||||||
|
bool NeedsSurfaceCopy() const {
|
||||||
|
return mSurfaceCopyNeeded;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderViewMLGPU* GetRenderView() const {
|
||||||
|
return mView;
|
||||||
|
}
|
||||||
|
void SetRenderView(RenderViewMLGPU* aView) {
|
||||||
|
MOZ_ASSERT(!mView);
|
||||||
|
mView = aView;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool OnPrepareToRender(FrameBuilder* aBuilder) override;
|
bool OnPrepareToRender(FrameBuilder* aBuilder) override;
|
||||||
|
@ -71,6 +83,11 @@ private:
|
||||||
// is in layer coordinates.
|
// is in layer coordinates.
|
||||||
gfx::IntRect mInvalidRect;
|
gfx::IntRect mInvalidRect;
|
||||||
bool mInvalidateEntireSurface;
|
bool mInvalidateEntireSurface;
|
||||||
|
bool mSurfaceCopyNeeded;
|
||||||
|
|
||||||
|
// This is only valid for intermediate surfaces while an instance of
|
||||||
|
// FrameBuilder is live.
|
||||||
|
RenderViewMLGPU* mView;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace layers
|
} // namespace layers
|
||||||
|
|
|
@ -183,7 +183,6 @@ LayerManagerMLGPU::GetTextureFactoryIdentifier()
|
||||||
if (mDevice) {
|
if (mDevice) {
|
||||||
ident = mDevice->GetTextureFactoryIdentifier();
|
ident = mDevice->GetTextureFactoryIdentifier();
|
||||||
}
|
}
|
||||||
ident.mSupportsBackdropCopyForComponentAlpha = SupportsBackdropCopyForComponentAlpha();
|
|
||||||
ident.mUsingAdvancedLayers = true;
|
ident.mUsingAdvancedLayers = true;
|
||||||
return ident;
|
return ident;
|
||||||
}
|
}
|
||||||
|
@ -525,12 +524,6 @@ LayerManagerMLGPU::BlendingRequiresIntermediateSurface()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
LayerManagerMLGPU::SupportsBackdropCopyForComponentAlpha()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
LayerManagerMLGPU::EndTransaction(DrawPaintedLayerCallback aCallback,
|
LayerManagerMLGPU::EndTransaction(DrawPaintedLayerCallback aCallback,
|
||||||
void* aCallbackData,
|
void* aCallbackData,
|
||||||
|
|
|
@ -50,7 +50,6 @@ public:
|
||||||
|
|
||||||
bool AreComponentAlphaLayersEnabled() override;
|
bool AreComponentAlphaLayersEnabled() override;
|
||||||
bool BlendingRequiresIntermediateSurface() override;
|
bool BlendingRequiresIntermediateSurface() override;
|
||||||
bool SupportsBackdropCopyForComponentAlpha() override;
|
|
||||||
|
|
||||||
// HostLayerManager methods
|
// HostLayerManager methods
|
||||||
void ForcePresent() override;
|
void ForcePresent() override;
|
||||||
|
|
|
@ -305,6 +305,11 @@ ShaderRenderPass::ExecuteRendering()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Change the blend state if needed.
|
||||||
|
if (Maybe<MLGBlendState> blendState = GetBlendState()) {
|
||||||
|
mDevice->SetBlendState(blendState.value());
|
||||||
|
}
|
||||||
|
|
||||||
mDevice->SetPSConstantBuffer(0, &mPSBuffer0);
|
mDevice->SetPSConstantBuffer(0, &mPSBuffer0);
|
||||||
if (MaskOperation* mask = GetMask()) {
|
if (MaskOperation* mask = GetMask()) {
|
||||||
mDevice->SetPSTexture(kMaskLayerTextureSlot, mask->GetTexture());
|
mDevice->SetPSTexture(kMaskLayerTextureSlot, mask->GetTexture());
|
||||||
|
@ -994,5 +999,48 @@ RenderViewPass::SetupPipeline()
|
||||||
mDevice->SetSamplerMode(kDefaultSamplerSlot, SamplerMode::LinearClamp);
|
mDevice->SetSamplerMode(kDefaultSamplerSlot, SamplerMode::LinearClamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RenderViewPass::ExecuteRendering()
|
||||||
|
{
|
||||||
|
if (mAssignedLayer->NeedsSurfaceCopy()) {
|
||||||
|
RenderWithBackdropCopy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TexturedRenderPass::ExecuteRendering();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RenderViewPass::RenderWithBackdropCopy()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mAssignedLayer->NeedsSurfaceCopy());
|
||||||
|
|
||||||
|
DebugOnly<Matrix> transform2d;
|
||||||
|
const Matrix4x4& transform = mAssignedLayer->GetEffectiveTransform();
|
||||||
|
MOZ_ASSERT(transform.Is2D(&transform2d) &&
|
||||||
|
!gfx::ThebesMatrix(transform2d).HasNonIntegerTranslation());
|
||||||
|
|
||||||
|
IntRect visible = mAssignedLayer->GetShadowVisibleRegion().GetBounds().ToUnknownRect();
|
||||||
|
visible += IntPoint::Truncate(transform._41, transform._42);
|
||||||
|
visible -= mParentView->GetTargetOffset();
|
||||||
|
|
||||||
|
RefPtr<MLGTexture> dest = mAssignedLayer->GetRenderTarget()->GetTexture();
|
||||||
|
RefPtr<MLGTexture> source = mParentView->GetRenderTarget()->GetTexture();
|
||||||
|
|
||||||
|
// Clamp the rect so that we don't read pixels outside the source texture, or
|
||||||
|
// write pixels outside the destination texture.
|
||||||
|
visible = visible.Intersect(IntRect(IntPoint(0, 0), source->GetSize()));
|
||||||
|
visible = visible.Intersect(IntRect(visible.TopLeft(), dest->GetSize()));
|
||||||
|
|
||||||
|
mDevice->CopyTexture(dest, IntPoint(0, 0), source, visible);
|
||||||
|
|
||||||
|
RenderViewMLGPU* childView = mAssignedLayer->GetRenderView();
|
||||||
|
childView->RenderAfterBackdropCopy();
|
||||||
|
|
||||||
|
mParentView->RestoreDeviceState();
|
||||||
|
|
||||||
|
TexturedRenderPass::ExecuteRendering();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace layers
|
} // namespace layers
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -464,8 +464,10 @@ private:
|
||||||
bool AddToPass(LayerMLGPU* aItem, ItemInfo& aInfo) override;
|
bool AddToPass(LayerMLGPU* aItem, ItemInfo& aInfo) override;
|
||||||
void SetupPipeline() override;
|
void SetupPipeline() override;
|
||||||
bool OnPrepareBuffers() override;
|
bool OnPrepareBuffers() override;
|
||||||
|
void ExecuteRendering() override;
|
||||||
float GetOpacity() const override;
|
float GetOpacity() const override;
|
||||||
bool PrepareBlendState();
|
bool PrepareBlendState();
|
||||||
|
void RenderWithBackdropCopy();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ConstantBufferSection mBlendConstants;
|
ConstantBufferSection mBlendConstants;
|
||||||
|
|
|
@ -62,6 +62,8 @@ RenderViewMLGPU::RenderViewMLGPU(FrameBuilder* aBuilder,
|
||||||
this,
|
this,
|
||||||
aContainer->GetLayer(),
|
aContainer->GetLayer(),
|
||||||
Stringify(mInvalidBounds).c_str());
|
Stringify(mInvalidBounds).c_str());
|
||||||
|
|
||||||
|
mContainer->SetRenderView(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderViewMLGPU::RenderViewMLGPU(FrameBuilder* aBuilder, RenderViewMLGPU* aParent)
|
RenderViewMLGPU::RenderViewMLGPU(FrameBuilder* aBuilder, RenderViewMLGPU* aParent)
|
||||||
|
@ -72,6 +74,7 @@ RenderViewMLGPU::RenderViewMLGPU(FrameBuilder* aBuilder, RenderViewMLGPU* aParen
|
||||||
mFinishedBuilding(false),
|
mFinishedBuilding(false),
|
||||||
mCurrentLayerBufferIndex(kInvalidResourceIndex),
|
mCurrentLayerBufferIndex(kInvalidResourceIndex),
|
||||||
mCurrentMaskRectBufferIndex(kInvalidResourceIndex),
|
mCurrentMaskRectBufferIndex(kInvalidResourceIndex),
|
||||||
|
mCurrentDepthMode(MLGDepthTestMode::Disabled),
|
||||||
mNextSortIndex(1),
|
mNextSortIndex(1),
|
||||||
mUseDepthBuffer(gfxPrefs::AdvancedLayersEnableDepthBuffer()),
|
mUseDepthBuffer(gfxPrefs::AdvancedLayersEnableDepthBuffer()),
|
||||||
mDepthBufferNeedsClear(false)
|
mDepthBufferNeedsClear(false)
|
||||||
|
@ -111,11 +114,23 @@ RenderViewMLGPU::AddChild(RenderViewMLGPU* aParent)
|
||||||
void
|
void
|
||||||
RenderViewMLGPU::Render()
|
RenderViewMLGPU::Render()
|
||||||
{
|
{
|
||||||
// We render tiles front-to-back, depth-first, to minimize render target switching.
|
// We render views depth-first to minimize render target switching.
|
||||||
for (const auto& child : mChildren) {
|
for (const auto& child : mChildren) {
|
||||||
child->Render();
|
child->Render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the view requires a surface copy (of its backdrop), then we delay
|
||||||
|
// rendering it until it is added to a batch.
|
||||||
|
if (mContainer && mContainer->NeedsSurfaceCopy()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ExecuteRendering();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RenderViewMLGPU::RenderAfterBackdropCopy()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mContainer && mContainer->NeedsSurfaceCopy());
|
||||||
ExecuteRendering();
|
ExecuteRendering();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,26 +400,19 @@ RenderViewMLGPU::ExecuteRendering()
|
||||||
if (!mTarget) {
|
if (!mTarget) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: we unbind slot 0 (which is where the render target could have been
|
|
||||||
// bound on a previous frame). Otherwise we trigger D3D11_DEVICE_PSSETSHADERRESOURCES_HAZARD.
|
|
||||||
mDevice->UnsetPSTexture(0);
|
|
||||||
mDevice->SetRenderTarget(mTarget);
|
|
||||||
mDevice->SetViewport(IntRect(IntPoint(0, 0), mTarget->GetSize()));
|
|
||||||
mDevice->SetScissorRect(Some(mInvalidBounds));
|
|
||||||
|
|
||||||
if (!mWorldConstants.IsValid()) {
|
if (!mWorldConstants.IsValid()) {
|
||||||
gfxWarning() << "Failed to allocate constant buffer for world transform";
|
gfxWarning() << "Failed to allocate constant buffer for world transform";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mDevice->SetVSConstantBuffer(kWorldConstantBufferSlot, &mWorldConstants);
|
|
||||||
|
SetDeviceState();
|
||||||
|
|
||||||
// If using the depth buffer, clear it (if needed) and enable writes.
|
// If using the depth buffer, clear it (if needed) and enable writes.
|
||||||
if (mUseDepthBuffer) {
|
if (mUseDepthBuffer) {
|
||||||
if (mDepthBufferNeedsClear) {
|
if (mDepthBufferNeedsClear) {
|
||||||
mDevice->ClearDepthBuffer(mTarget);
|
mDevice->ClearDepthBuffer(mTarget);
|
||||||
}
|
}
|
||||||
mDevice->SetDepthTestMode(MLGDepthTestMode::Write);
|
SetDepthTestMode(MLGDepthTestMode::Write);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opaque items, rendered front-to-back.
|
// Opaque items, rendered front-to-back.
|
||||||
|
@ -415,7 +423,7 @@ RenderViewMLGPU::ExecuteRendering()
|
||||||
if (mUseDepthBuffer) {
|
if (mUseDepthBuffer) {
|
||||||
// From now on we might be rendering transparent pixels, so we disable
|
// From now on we might be rendering transparent pixels, so we disable
|
||||||
// writing to the z-buffer.
|
// writing to the z-buffer.
|
||||||
mDevice->SetDepthTestMode(MLGDepthTestMode::ReadOnly);
|
SetDepthTestMode(MLGDepthTestMode::ReadOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear any pixels that are not occluded, and therefore might require
|
// Clear any pixels that are not occluded, and therefore might require
|
||||||
|
@ -466,14 +474,37 @@ RenderViewMLGPU::ExecutePass(RenderPassMLGPU* aPass)
|
||||||
mDevice->SetVSConstantBuffer(kMaskBufferSlot, §ion);
|
mDevice->SetVSConstantBuffer(kMaskBufferSlot, §ion);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change the blend state if needed.
|
|
||||||
if (Maybe<MLGBlendState> blendState = aPass->GetBlendState()) {
|
|
||||||
mDevice->SetBlendState(blendState.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
aPass->ExecuteRendering();
|
aPass->ExecuteRendering();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RenderViewMLGPU::SetDeviceState()
|
||||||
|
{
|
||||||
|
// Note: we unbind slot 0 (which is where the render target could have been
|
||||||
|
// bound on a previous frame). Otherwise we trigger D3D11_DEVICE_PSSETSHADERRESOURCES_HAZARD.
|
||||||
|
mDevice->UnsetPSTexture(0);
|
||||||
|
mDevice->SetRenderTarget(mTarget);
|
||||||
|
mDevice->SetViewport(IntRect(IntPoint(0, 0), mTarget->GetSize()));
|
||||||
|
mDevice->SetScissorRect(Some(mInvalidBounds));
|
||||||
|
mDevice->SetVSConstantBuffer(kWorldConstantBufferSlot, &mWorldConstants);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RenderViewMLGPU::SetDepthTestMode(MLGDepthTestMode aMode)
|
||||||
|
{
|
||||||
|
mDevice->SetDepthTestMode(aMode);
|
||||||
|
mCurrentDepthMode = aMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RenderViewMLGPU::RestoreDeviceState()
|
||||||
|
{
|
||||||
|
SetDeviceState();
|
||||||
|
mDevice->SetDepthTestMode(mCurrentDepthMode);
|
||||||
|
mCurrentLayerBufferIndex = kInvalidResourceIndex;
|
||||||
|
mCurrentMaskRectBufferIndex = kInvalidResourceIndex;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t
|
int32_t
|
||||||
RenderViewMLGPU::PrepareDepthBuffer()
|
RenderViewMLGPU::PrepareDepthBuffer()
|
||||||
{
|
{
|
||||||
|
@ -514,6 +545,11 @@ RenderViewMLGPU::PrepareDepthBuffer()
|
||||||
void
|
void
|
||||||
RenderViewMLGPU::PrepareClears()
|
RenderViewMLGPU::PrepareClears()
|
||||||
{
|
{
|
||||||
|
// We don't do any clearing if we're copying from a source backdrop.
|
||||||
|
if (mContainer && mContainer->NeedsSurfaceCopy()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the list of rects to clear. If using the depth buffer, we don't
|
// Get the list of rects to clear. If using the depth buffer, we don't
|
||||||
// care if it's accurate since the GPU will do occlusion testing for us.
|
// care if it's accurate since the GPU will do occlusion testing for us.
|
||||||
// If not using the depth buffer, we subtract out the occluded region.
|
// If not using the depth buffer, we subtract out the occluded region.
|
||||||
|
|
|
@ -52,6 +52,11 @@ public:
|
||||||
return mUseDepthBuffer;
|
return mUseDepthBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Render after having previously delayed rendering due to the view
|
||||||
|
// requiring a backdrop copy.
|
||||||
|
void RenderAfterBackdropCopy();
|
||||||
|
void RestoreDeviceState();
|
||||||
|
|
||||||
// The size and render target cannot be read until the view has finished
|
// The size and render target cannot be read until the view has finished
|
||||||
// building, since we try to right-size the render target to the visible
|
// building, since we try to right-size the render target to the visible
|
||||||
// region.
|
// region.
|
||||||
|
@ -72,6 +77,8 @@ private:
|
||||||
void AddItemBackToFront(LayerMLGPU* aLayer, ItemInfo& aItem);
|
void AddItemBackToFront(LayerMLGPU* aLayer, ItemInfo& aItem);
|
||||||
|
|
||||||
void PrepareClears();
|
void PrepareClears();
|
||||||
|
void SetDeviceState();
|
||||||
|
void SetDepthTestMode(MLGDepthTestMode aMode);
|
||||||
|
|
||||||
void ExecutePass(RenderPassMLGPU* aPass);
|
void ExecutePass(RenderPassMLGPU* aPass);
|
||||||
|
|
||||||
|
@ -124,6 +131,9 @@ private:
|
||||||
size_t mCurrentLayerBufferIndex;
|
size_t mCurrentLayerBufferIndex;
|
||||||
size_t mCurrentMaskRectBufferIndex;
|
size_t mCurrentMaskRectBufferIndex;
|
||||||
|
|
||||||
|
// This state is saved locally so it can be restored in RestoreDeviceState.
|
||||||
|
MLGDepthTestMode mCurrentDepthMode;
|
||||||
|
|
||||||
// Depth-buffer tracking.
|
// Depth-buffer tracking.
|
||||||
int32_t mNextSortIndex;
|
int32_t mNextSortIndex;
|
||||||
bool mUseDepthBuffer;
|
bool mUseDepthBuffer;
|
||||||
|
|
|
@ -79,11 +79,5 @@ StackingContextHelper::ToRelativeLayoutRect(const LayoutDeviceRect& aRect) const
|
||||||
PixelCastJustification::WebRenderHasUnitResolution) - mOrigin));
|
PixelCastJustification::WebRenderHasUnitResolution) - mOrigin));
|
||||||
}
|
}
|
||||||
|
|
||||||
wr::LayoutPoint
|
|
||||||
StackingContextHelper::ToRelativeLayoutPoint(const LayerPoint& aPoint) const
|
|
||||||
{
|
|
||||||
return wr::ToLayoutPoint(aPoint - mOrigin);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace layers
|
} // namespace layers
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -62,7 +62,11 @@ public:
|
||||||
wr::LayoutRect ToRelativeLayoutRect(const LayerRect& aRect) const;
|
wr::LayoutRect ToRelativeLayoutRect(const LayerRect& aRect) const;
|
||||||
wr::LayoutRect ToRelativeLayoutRect(const LayoutDeviceRect& aRect) const;
|
wr::LayoutRect ToRelativeLayoutRect(const LayoutDeviceRect& aRect) const;
|
||||||
// Same but for points
|
// Same but for points
|
||||||
wr::LayoutPoint ToRelativeLayoutPoint(const LayerPoint& aPoint) const;
|
wr::LayoutPoint ToRelativeLayoutPoint(const LayerPoint& aPoint) const
|
||||||
|
{
|
||||||
|
return wr::ToLayoutPoint(aPoint - mOrigin);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Export the inherited scale
|
// Export the inherited scale
|
||||||
gfx::Size GetInheritedScale() const { return mScale; }
|
gfx::Size GetInheritedScale() const { return mScale; }
|
||||||
|
|
|
@ -1370,37 +1370,38 @@ js::IdToStringOrSymbol(JSContext* cx, HandleId id, MutableHandleValue result)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ES6 draft rev 25 (2014 May 22) 19.1.2.8.1 */
|
// ES2018 draft rev c164be80f7ea91de5526b33d54e5c9321ed03d3f
|
||||||
|
// 19.1.2.10.1 Runtime Semantics: GetOwnPropertyKeys ( O, Type )
|
||||||
bool
|
bool
|
||||||
js::GetOwnPropertyKeys(JSContext* cx, const JS::CallArgs& args, unsigned flags)
|
js::GetOwnPropertyKeys(JSContext* cx, const JS::CallArgs& args, unsigned flags)
|
||||||
{
|
{
|
||||||
// Steps 1-2.
|
// Step 1.
|
||||||
RootedObject obj(cx, ToObject(cx, args.get(0)));
|
RootedObject obj(cx, ToObject(cx, args.get(0)));
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Steps 3-10.
|
// Steps 2-4.
|
||||||
AutoIdVector keys(cx);
|
AutoIdVector keys(cx);
|
||||||
if (!GetPropertyKeys(cx, obj, flags, &keys))
|
if (!GetPropertyKeys(cx, obj, flags, &keys))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Step 11.
|
// Step 5 (Inlined CreateArrayFromList).
|
||||||
AutoValueVector vals(cx);
|
RootedArrayObject array(cx, NewDenseFullyAllocatedArray(cx, keys.length()));
|
||||||
if (!vals.resize(keys.length()))
|
if (!array)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
array->ensureDenseInitializedLength(cx, 0, keys.length());
|
||||||
|
|
||||||
|
RootedValue val(cx);
|
||||||
for (size_t i = 0, len = keys.length(); i < len; i++) {
|
for (size_t i = 0, len = keys.length(); i < len; i++) {
|
||||||
MOZ_ASSERT_IF(JSID_IS_SYMBOL(keys[i]), flags & JSITER_SYMBOLS);
|
MOZ_ASSERT_IF(JSID_IS_SYMBOL(keys[i]), flags & JSITER_SYMBOLS);
|
||||||
MOZ_ASSERT_IF(!JSID_IS_SYMBOL(keys[i]), !(flags & JSITER_SYMBOLSONLY));
|
MOZ_ASSERT_IF(!JSID_IS_SYMBOL(keys[i]), !(flags & JSITER_SYMBOLSONLY));
|
||||||
if (!IdToStringOrSymbol(cx, keys[i], vals[i]))
|
if (!IdToStringOrSymbol(cx, keys[i], &val))
|
||||||
return false;
|
return false;
|
||||||
|
array->initDenseElement(i, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject* aobj = NewDenseCopiedArray(cx, vals.length(), vals.begin());
|
args.rval().setObject(*array);
|
||||||
if (!aobj)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
args.rval().setObject(*aobj);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1734,9 +1734,9 @@ class ASTSerializer
|
||||||
return StringValue(atom ? atom : cx->names().empty);
|
return StringValue(atom ? atom : cx->names().empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
BinaryOperator binop(ParseNodeKind kind, JSOp op);
|
BinaryOperator binop(ParseNodeKind kind);
|
||||||
UnaryOperator unop(ParseNodeKind kind, JSOp op);
|
UnaryOperator unop(ParseNodeKind kind);
|
||||||
AssignmentOperator aop(JSOp op);
|
AssignmentOperator aop(ParseNodeKind kind);
|
||||||
|
|
||||||
bool statements(ParseNode* pn, NodeVector& elts);
|
bool statements(ParseNode* pn, NodeVector& elts);
|
||||||
bool expressions(ParseNode* pn, NodeVector& elts);
|
bool expressions(ParseNode* pn, NodeVector& elts);
|
||||||
|
@ -1843,34 +1843,34 @@ class ASTSerializer
|
||||||
} /* anonymous namespace */
|
} /* anonymous namespace */
|
||||||
|
|
||||||
AssignmentOperator
|
AssignmentOperator
|
||||||
ASTSerializer::aop(JSOp op)
|
ASTSerializer::aop(ParseNodeKind kind)
|
||||||
{
|
{
|
||||||
switch (op) {
|
switch (kind) {
|
||||||
case JSOP_NOP:
|
case PNK_ASSIGN:
|
||||||
return AOP_ASSIGN;
|
return AOP_ASSIGN;
|
||||||
case JSOP_ADD:
|
case PNK_ADDASSIGN:
|
||||||
return AOP_PLUS;
|
return AOP_PLUS;
|
||||||
case JSOP_SUB:
|
case PNK_SUBASSIGN:
|
||||||
return AOP_MINUS;
|
return AOP_MINUS;
|
||||||
case JSOP_MUL:
|
case PNK_MULASSIGN:
|
||||||
return AOP_STAR;
|
return AOP_STAR;
|
||||||
case JSOP_DIV:
|
case PNK_DIVASSIGN:
|
||||||
return AOP_DIV;
|
return AOP_DIV;
|
||||||
case JSOP_MOD:
|
case PNK_MODASSIGN:
|
||||||
return AOP_MOD;
|
return AOP_MOD;
|
||||||
case JSOP_POW:
|
case PNK_POWASSIGN:
|
||||||
return AOP_POW;
|
return AOP_POW;
|
||||||
case JSOP_LSH:
|
case PNK_LSHASSIGN:
|
||||||
return AOP_LSH;
|
return AOP_LSH;
|
||||||
case JSOP_RSH:
|
case PNK_RSHASSIGN:
|
||||||
return AOP_RSH;
|
return AOP_RSH;
|
||||||
case JSOP_URSH:
|
case PNK_URSHASSIGN:
|
||||||
return AOP_URSH;
|
return AOP_URSH;
|
||||||
case JSOP_BITOR:
|
case PNK_BITORASSIGN:
|
||||||
return AOP_BITOR;
|
return AOP_BITOR;
|
||||||
case JSOP_BITXOR:
|
case PNK_BITXORASSIGN:
|
||||||
return AOP_BITXOR;
|
return AOP_BITXOR;
|
||||||
case JSOP_BITAND:
|
case PNK_BITANDASSIGN:
|
||||||
return AOP_BITAND;
|
return AOP_BITAND;
|
||||||
default:
|
default:
|
||||||
return AOP_ERR;
|
return AOP_ERR;
|
||||||
|
@ -1878,7 +1878,7 @@ ASTSerializer::aop(JSOp op)
|
||||||
}
|
}
|
||||||
|
|
||||||
UnaryOperator
|
UnaryOperator
|
||||||
ASTSerializer::unop(ParseNodeKind kind, JSOp op)
|
ASTSerializer::unop(ParseNodeKind kind)
|
||||||
{
|
{
|
||||||
if (IsDeleteKind(kind))
|
if (IsDeleteKind(kind))
|
||||||
return UNOP_DELETE;
|
return UNOP_DELETE;
|
||||||
|
@ -1886,19 +1886,18 @@ ASTSerializer::unop(ParseNodeKind kind, JSOp op)
|
||||||
if (IsTypeofKind(kind))
|
if (IsTypeofKind(kind))
|
||||||
return UNOP_TYPEOF;
|
return UNOP_TYPEOF;
|
||||||
|
|
||||||
if (kind == PNK_AWAIT)
|
switch (kind) {
|
||||||
|
case PNK_AWAIT:
|
||||||
return UNOP_AWAIT;
|
return UNOP_AWAIT;
|
||||||
|
case PNK_NEG:
|
||||||
switch (op) {
|
|
||||||
case JSOP_NEG:
|
|
||||||
return UNOP_NEG;
|
return UNOP_NEG;
|
||||||
case JSOP_POS:
|
case PNK_POS:
|
||||||
return UNOP_POS;
|
return UNOP_POS;
|
||||||
case JSOP_NOT:
|
case PNK_NOT:
|
||||||
return UNOP_NOT;
|
return UNOP_NOT;
|
||||||
case JSOP_BITNOT:
|
case PNK_BITNOT:
|
||||||
return UNOP_BITNOT;
|
return UNOP_BITNOT;
|
||||||
case JSOP_VOID:
|
case PNK_VOID:
|
||||||
return UNOP_VOID;
|
return UNOP_VOID;
|
||||||
default:
|
default:
|
||||||
return UNOP_ERR;
|
return UNOP_ERR;
|
||||||
|
@ -1906,7 +1905,7 @@ ASTSerializer::unop(ParseNodeKind kind, JSOp op)
|
||||||
}
|
}
|
||||||
|
|
||||||
BinaryOperator
|
BinaryOperator
|
||||||
ASTSerializer::binop(ParseNodeKind kind, JSOp op)
|
ASTSerializer::binop(ParseNodeKind kind)
|
||||||
{
|
{
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case PNK_LSH:
|
case PNK_LSH:
|
||||||
|
@ -2632,7 +2631,7 @@ ASTSerializer::leftAssociate(ParseNode* pn, MutableHandleValue dst)
|
||||||
if (!builder.logicalExpression(lor, left, right, &subpos, &left))
|
if (!builder.logicalExpression(lor, left, right, &subpos, &left))
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
BinaryOperator op = binop(pn->getKind(), pn->getOp());
|
BinaryOperator op = binop(pn->getKind());
|
||||||
LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
|
LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
|
||||||
|
|
||||||
if (!builder.binaryExpression(op, left, right, &subpos, &left))
|
if (!builder.binaryExpression(op, left, right, &subpos, &left))
|
||||||
|
@ -2676,7 +2675,7 @@ ASTSerializer::rightAssociate(ParseNode* pn, MutableHandleValue dst)
|
||||||
|
|
||||||
TokenPos subpos(pn->pn_pos.begin, next->pn_pos.end);
|
TokenPos subpos(pn->pn_pos.begin, next->pn_pos.end);
|
||||||
|
|
||||||
BinaryOperator op = binop(pn->getKind(), pn->getOp());
|
BinaryOperator op = binop(pn->getKind());
|
||||||
LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
|
LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
|
||||||
|
|
||||||
if (!builder.binaryExpression(op, left, right, &subpos, &right))
|
if (!builder.binaryExpression(op, left, right, &subpos, &right))
|
||||||
|
@ -2887,7 +2886,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
|
||||||
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
|
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
|
||||||
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
|
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
|
||||||
|
|
||||||
AssignmentOperator op = aop(pn->getOp());
|
AssignmentOperator op = aop(pn->getKind());
|
||||||
LOCAL_ASSERT(op > AOP_ERR && op < AOP_LIMIT);
|
LOCAL_ASSERT(op > AOP_ERR && op < AOP_LIMIT);
|
||||||
|
|
||||||
RootedValue lhs(cx), rhs(cx);
|
RootedValue lhs(cx), rhs(cx);
|
||||||
|
@ -2936,7 +2935,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
|
||||||
case PNK_NEG: {
|
case PNK_NEG: {
|
||||||
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
|
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
|
||||||
|
|
||||||
UnaryOperator op = unop(pn->getKind(), pn->getOp());
|
UnaryOperator op = unop(pn->getKind());
|
||||||
LOCAL_ASSERT(op > UNOP_ERR && op < UNOP_LIMIT);
|
LOCAL_ASSERT(op > UNOP_ERR && op < UNOP_LIMIT);
|
||||||
|
|
||||||
RootedValue expr(cx);
|
RootedValue expr(cx);
|
||||||
|
@ -3486,10 +3485,8 @@ ASTSerializer::functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector&
|
||||||
ParseNode* pnstart = pnbody->pn_head;
|
ParseNode* pnstart = pnbody->pn_head;
|
||||||
|
|
||||||
// Skip over initial yield in generator.
|
// Skip over initial yield in generator.
|
||||||
if (pnstart && pnstart->isKind(PNK_INITIALYIELD)) {
|
if (pnstart && pnstart->isKind(PNK_INITIALYIELD))
|
||||||
MOZ_ASSERT(pnstart->getOp() == JSOP_INITIALYIELD);
|
|
||||||
pnstart = pnstart->pn_next;
|
pnstart = pnstart->pn_next;
|
||||||
}
|
|
||||||
|
|
||||||
// Async arrow with expression body is converted into STATEMENTLIST
|
// Async arrow with expression body is converted into STATEMENTLIST
|
||||||
// to insert initial yield.
|
// to insert initial yield.
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
#include "mozilla/Unused.h"
|
#include "mozilla/Unused.h"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
#include "jscntxt.h"
|
#include "jscntxt.h"
|
||||||
|
@ -4737,6 +4739,118 @@ DisableForEach(JSContext* cx, unsigned argc, Value* vp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
GetTimeZone(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
{
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
RootedObject callee(cx, &args.callee());
|
||||||
|
|
||||||
|
if (args.length() != 0) {
|
||||||
|
ReportUsageErrorASCII(cx, callee, "Wrong number of arguments");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto getTimeZone = [](std::time_t* now) -> const char* {
|
||||||
|
std::tm local{};
|
||||||
|
#if defined(_WIN32)
|
||||||
|
_tzset();
|
||||||
|
if (localtime_s(&local, now) == 0)
|
||||||
|
return _tzname[local.tm_isdst > 0];
|
||||||
|
#else
|
||||||
|
tzset();
|
||||||
|
#if defined(HAVE_LOCALTIME_R)
|
||||||
|
if (localtime_r(now, &local)) {
|
||||||
|
#else
|
||||||
|
std::tm* localtm = std::localtime(now);
|
||||||
|
if (localtm) {
|
||||||
|
*local = *localtm;
|
||||||
|
#endif /* HAVE_LOCALTIME_R */
|
||||||
|
|
||||||
|
#if defined(HAVE_TM_ZONE_TM_GMTOFF)
|
||||||
|
return local.tm_zone;
|
||||||
|
#else
|
||||||
|
return tzname[local.tm_isdst > 0];
|
||||||
|
#endif /* HAVE_TM_ZONE_TM_GMTOFF */
|
||||||
|
}
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
return nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::time_t now = std::time(nullptr);
|
||||||
|
if (now != static_cast<std::time_t>(-1)) {
|
||||||
|
if (const char* tz = getTimeZone(&now)) {
|
||||||
|
JSString* str = JS_NewStringCopyZ(cx, tz);
|
||||||
|
if (!str)
|
||||||
|
return false;
|
||||||
|
args.rval().setString(str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
args.rval().setUndefined();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
SetTimeZone(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
{
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
RootedObject callee(cx, &args.callee());
|
||||||
|
|
||||||
|
if (args.length() != 1) {
|
||||||
|
ReportUsageErrorASCII(cx, callee, "Wrong number of arguments");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!args[0].isString() && !args[0].isUndefined()) {
|
||||||
|
ReportUsageErrorASCII(cx, callee, "First argument should be a string or undefined");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto setTimeZone = [](const char* value) {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
return _putenv_s("TZ", value) == 0;
|
||||||
|
#else
|
||||||
|
return setenv("TZ", value, true) == 0;
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
};
|
||||||
|
|
||||||
|
auto unsetTimeZone = []() {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
return _putenv_s("TZ", "") == 0;
|
||||||
|
#else
|
||||||
|
return unsetenv("TZ") == 0;
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
};
|
||||||
|
|
||||||
|
if (args[0].isString() && !args[0].toString()->empty()) {
|
||||||
|
JSAutoByteString timeZone;
|
||||||
|
if (!timeZone.encodeLatin1(cx, args[0].toString()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!setTimeZone(timeZone.ptr())) {
|
||||||
|
JS_ReportErrorASCII(cx, "Failed to set 'TZ' environment variable");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!unsetTimeZone()) {
|
||||||
|
JS_ReportErrorASCII(cx, "Failed to unset 'TZ' environment variable");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
_tzset();
|
||||||
|
#else
|
||||||
|
tzset();
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
JS::ResetTimeZone();
|
||||||
|
|
||||||
|
args.rval().setUndefined();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(FUZZING) && defined(__AFL_COMPILER)
|
#if defined(FUZZING) && defined(__AFL_COMPILER)
|
||||||
static bool
|
static bool
|
||||||
AflLoop(JSContext* cx, unsigned argc, Value* vp)
|
AflLoop(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
@ -5414,6 +5528,10 @@ gc::ZealModeHelpText),
|
||||||
"isLegacyIterator(value)",
|
"isLegacyIterator(value)",
|
||||||
" Returns whether the value is considered is a legacy iterator.\n"),
|
" Returns whether the value is considered is a legacy iterator.\n"),
|
||||||
|
|
||||||
|
JS_FN_HELP("getTimeZone", GetTimeZone, 0, 0,
|
||||||
|
"getTimeZone()",
|
||||||
|
" Get the current time zone.\n"),
|
||||||
|
|
||||||
JS_FS_HELP_END
|
JS_FS_HELP_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5432,6 +5550,12 @@ static const JSFunctionSpecWithHelp FuzzingUnsafeTestingFunctions[] = {
|
||||||
"getErrorNotes(error)",
|
"getErrorNotes(error)",
|
||||||
" Returns an array of error notes."),
|
" Returns an array of error notes."),
|
||||||
|
|
||||||
|
JS_FN_HELP("setTimeZone", SetTimeZone, 1, 0,
|
||||||
|
"setTimeZone(tzname)",
|
||||||
|
" Set the 'TZ' environment variable to the given time zone and applies the new time zone.\n"
|
||||||
|
" An empty string or undefined resets the time zone to its default value.\n"
|
||||||
|
" NOTE: The input string is not validated and will be passed verbatim to setenv()."),
|
||||||
|
|
||||||
JS_FS_HELP_END
|
JS_FS_HELP_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -6148,6 +6148,7 @@ bool
|
||||||
BytecodeEmitter::emitDeclarationList(ParseNode* declList)
|
BytecodeEmitter::emitDeclarationList(ParseNode* declList)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(declList->isArity(PN_LIST));
|
MOZ_ASSERT(declList->isArity(PN_LIST));
|
||||||
|
MOZ_ASSERT(declList->isOp(JSOP_NOP));
|
||||||
|
|
||||||
ParseNode* next;
|
ParseNode* next;
|
||||||
for (ParseNode* decl = declList->pn_head; decl; decl = next) {
|
for (ParseNode* decl = declList->pn_head; decl; decl = next) {
|
||||||
|
@ -6226,9 +6227,32 @@ EmitAssignmentRhs(BytecodeEmitter* bce, ParseNode* rhs, uint8_t offset)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static inline JSOp
|
||||||
BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs)
|
CompoundAssignmentParseNodeKindToJSOp(ParseNodeKind pnk)
|
||||||
{
|
{
|
||||||
|
switch (pnk) {
|
||||||
|
case PNK_ASSIGN: return JSOP_NOP;
|
||||||
|
case PNK_ADDASSIGN: return JSOP_ADD;
|
||||||
|
case PNK_SUBASSIGN: return JSOP_SUB;
|
||||||
|
case PNK_BITORASSIGN: return JSOP_BITOR;
|
||||||
|
case PNK_BITXORASSIGN: return JSOP_BITXOR;
|
||||||
|
case PNK_BITANDASSIGN: return JSOP_BITAND;
|
||||||
|
case PNK_LSHASSIGN: return JSOP_LSH;
|
||||||
|
case PNK_RSHASSIGN: return JSOP_RSH;
|
||||||
|
case PNK_URSHASSIGN: return JSOP_URSH;
|
||||||
|
case PNK_MULASSIGN: return JSOP_MUL;
|
||||||
|
case PNK_DIVASSIGN: return JSOP_DIV;
|
||||||
|
case PNK_MODASSIGN: return JSOP_MOD;
|
||||||
|
case PNK_POWASSIGN: return JSOP_POW;
|
||||||
|
default: MOZ_CRASH("unexpected compound assignment op");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BytecodeEmitter::emitAssignment(ParseNode* lhs, ParseNodeKind pnk, ParseNode* rhs)
|
||||||
|
{
|
||||||
|
JSOp op = CompoundAssignmentParseNodeKindToJSOp(pnk);
|
||||||
|
|
||||||
// Name assignments are handled separately because choosing ops and when
|
// Name assignments are handled separately because choosing ops and when
|
||||||
// to emit BINDNAME is involved and should avoid duplication.
|
// to emit BINDNAME is involved and should avoid duplication.
|
||||||
if (lhs->isKind(PNK_NAME)) {
|
if (lhs->isKind(PNK_NAME)) {
|
||||||
|
@ -6254,8 +6278,10 @@ BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit the compound assignment op if there is one.
|
// Emit the compound assignment op if there is one.
|
||||||
if (op != JSOP_NOP && !bce->emit1(op))
|
if (op != JSOP_NOP) {
|
||||||
return false;
|
if (!bce->emit1(op))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
@ -6454,7 +6480,7 @@ ParseNode::getConstantValue(JSContext* cx, AllowConstantObjects allowObjects,
|
||||||
count = pn_count - 1;
|
count = pn_count - 1;
|
||||||
pn = pn_head->pn_next;
|
pn = pn_head->pn_next;
|
||||||
} else {
|
} else {
|
||||||
MOZ_ASSERT(isOp(JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
|
MOZ_ASSERT(!(pn_xflags & PNX_NONCONST));
|
||||||
count = pn_count;
|
count = pn_count;
|
||||||
pn = pn_head;
|
pn = pn_head;
|
||||||
}
|
}
|
||||||
|
@ -6485,7 +6511,6 @@ ParseNode::getConstantValue(JSContext* cx, AllowConstantObjects allowObjects,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case PNK_OBJECT: {
|
case PNK_OBJECT: {
|
||||||
MOZ_ASSERT(isOp(JSOP_NEWINIT));
|
|
||||||
MOZ_ASSERT(!(pn_xflags & PNX_NONCONST));
|
MOZ_ASSERT(!(pn_xflags & PNX_NONCONST));
|
||||||
|
|
||||||
if (allowObjects == DontAllowObjects) {
|
if (allowObjects == DontAllowObjects) {
|
||||||
|
@ -7137,7 +7162,7 @@ BytecodeEmitter::emitInitializeForInOrOfTarget(ParseNode* forHead)
|
||||||
// initialization is just assigning the iteration value to a target
|
// initialization is just assigning the iteration value to a target
|
||||||
// expression.
|
// expression.
|
||||||
if (!parser.isDeclarationList(target))
|
if (!parser.isDeclarationList(target))
|
||||||
return emitAssignment(target, JSOP_NOP, nullptr); // ... ITERVAL
|
return emitAssignment(target, PNK_ASSIGN, nullptr); // ... ITERVAL
|
||||||
|
|
||||||
// Otherwise, per-loop initialization is (possibly) declaration
|
// Otherwise, per-loop initialization is (possibly) declaration
|
||||||
// initialization. If the declaration is a lexical declaration, it must be
|
// initialization. If the declaration is a lexical declaration, it must be
|
||||||
|
@ -7862,7 +7887,7 @@ BytecodeEmitter::emitComprehensionForOf(ParseNode* pn)
|
||||||
|
|
||||||
// Notice: Comprehension for-of doesn't perform IteratorClose, since it's
|
// Notice: Comprehension for-of doesn't perform IteratorClose, since it's
|
||||||
// not in the spec.
|
// not in the spec.
|
||||||
if (!emitAssignment(loopVariableName, JSOP_NOP, nullptr)) // ITER VALUE
|
if (!emitAssignment(loopVariableName, PNK_ASSIGN, nullptr)) // ITER VALUE
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Remove VALUE from the stack to release it.
|
// Remove VALUE from the stack to release it.
|
||||||
|
@ -7986,7 +8011,7 @@ BytecodeEmitter::emitComprehensionForIn(ParseNode* pn)
|
||||||
|
|
||||||
// Emit code to assign the enumeration value to the left hand side, but
|
// Emit code to assign the enumeration value to the left hand side, but
|
||||||
// also leave it on the stack.
|
// also leave it on the stack.
|
||||||
if (!emitAssignment(forHead->pn_kid2, JSOP_NOP, nullptr))
|
if (!emitAssignment(forHead->pn_kid2, PNK_ASSIGN, nullptr))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* The stack should be balanced around the assignment opcode sequence. */
|
/* The stack should be balanced around the assignment opcode sequence. */
|
||||||
|
@ -8688,7 +8713,7 @@ bool
|
||||||
BytecodeEmitter::emitYield(ParseNode* pn)
|
BytecodeEmitter::emitYield(ParseNode* pn)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(sc->isFunctionBox());
|
MOZ_ASSERT(sc->isFunctionBox());
|
||||||
MOZ_ASSERT(pn->getOp() == JSOP_YIELD);
|
MOZ_ASSERT(pn->isKind(PNK_YIELD));
|
||||||
|
|
||||||
bool needsIteratorResult = sc->asFunctionBox()->needsIteratorResult();
|
bool needsIteratorResult = sc->asFunctionBox()->needsIteratorResult();
|
||||||
if (needsIteratorResult) {
|
if (needsIteratorResult) {
|
||||||
|
@ -8738,7 +8763,7 @@ bool
|
||||||
BytecodeEmitter::emitAwait(ParseNode* pn)
|
BytecodeEmitter::emitAwait(ParseNode* pn)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(sc->isFunctionBox());
|
MOZ_ASSERT(sc->isFunctionBox());
|
||||||
MOZ_ASSERT(pn->getOp() == JSOP_AWAIT);
|
MOZ_ASSERT(pn->isKind(PNK_AWAIT));
|
||||||
|
|
||||||
if (!emitTree(pn->pn_kid))
|
if (!emitTree(pn->pn_kid))
|
||||||
return false;
|
return false;
|
||||||
|
@ -9675,6 +9700,41 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn, ValueUsage valueUsage /* = ValueUs
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const JSOp ParseNodeKindToJSOp[] = {
|
||||||
|
JSOP_OR,
|
||||||
|
JSOP_AND,
|
||||||
|
JSOP_BITOR,
|
||||||
|
JSOP_BITXOR,
|
||||||
|
JSOP_BITAND,
|
||||||
|
JSOP_STRICTEQ,
|
||||||
|
JSOP_EQ,
|
||||||
|
JSOP_STRICTNE,
|
||||||
|
JSOP_NE,
|
||||||
|
JSOP_LT,
|
||||||
|
JSOP_LE,
|
||||||
|
JSOP_GT,
|
||||||
|
JSOP_GE,
|
||||||
|
JSOP_INSTANCEOF,
|
||||||
|
JSOP_IN,
|
||||||
|
JSOP_LSH,
|
||||||
|
JSOP_RSH,
|
||||||
|
JSOP_URSH,
|
||||||
|
JSOP_ADD,
|
||||||
|
JSOP_SUB,
|
||||||
|
JSOP_MUL,
|
||||||
|
JSOP_DIV,
|
||||||
|
JSOP_MOD,
|
||||||
|
JSOP_POW
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline JSOp
|
||||||
|
BinaryOpParseNodeKindToJSOp(ParseNodeKind pnk)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(pnk >= PNK_BINOP_FIRST);
|
||||||
|
MOZ_ASSERT(pnk <= PNK_BINOP_LAST);
|
||||||
|
return ParseNodeKindToJSOp[pnk - PNK_BINOP_FIRST];
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BytecodeEmitter::emitRightAssociative(ParseNode* pn)
|
BytecodeEmitter::emitRightAssociative(ParseNode* pn)
|
||||||
{
|
{
|
||||||
|
@ -9702,7 +9762,7 @@ BytecodeEmitter::emitLeftAssociative(ParseNode* pn)
|
||||||
// Left-associative operator chain.
|
// Left-associative operator chain.
|
||||||
if (!emitTree(pn->pn_head))
|
if (!emitTree(pn->pn_head))
|
||||||
return false;
|
return false;
|
||||||
JSOp op = pn->getOp();
|
JSOp op = BinaryOpParseNodeKindToJSOp(pn->getKind());
|
||||||
ParseNode* nextExpr = pn->pn_head->pn_next;
|
ParseNode* nextExpr = pn->pn_head->pn_next;
|
||||||
do {
|
do {
|
||||||
if (!emitTree(nextExpr))
|
if (!emitTree(nextExpr))
|
||||||
|
@ -9717,6 +9777,7 @@ bool
|
||||||
BytecodeEmitter::emitLogical(ParseNode* pn)
|
BytecodeEmitter::emitLogical(ParseNode* pn)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(pn->isArity(PN_LIST));
|
MOZ_ASSERT(pn->isArity(PN_LIST));
|
||||||
|
MOZ_ASSERT(pn->isKind(PNK_OR) || pn->isKind(PNK_AND));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* JSOP_OR converts the operand on the stack to boolean, leaves the original
|
* JSOP_OR converts the operand on the stack to boolean, leaves the original
|
||||||
|
@ -9734,7 +9795,7 @@ BytecodeEmitter::emitLogical(ParseNode* pn)
|
||||||
ParseNode* pn2 = pn->pn_head;
|
ParseNode* pn2 = pn->pn_head;
|
||||||
if (!emitTree(pn2))
|
if (!emitTree(pn2))
|
||||||
return false;
|
return false;
|
||||||
JSOp op = pn->getOp();
|
JSOp op = pn->isKind(PNK_OR) ? JSOP_OR : JSOP_AND;
|
||||||
JumpList jump;
|
JumpList jump;
|
||||||
if (!emitJump(op, &jump))
|
if (!emitJump(op, &jump))
|
||||||
return false;
|
return false;
|
||||||
|
@ -10237,20 +10298,28 @@ BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline JSOp
|
||||||
|
UnaryOpParseNodeKindToJSOp(ParseNodeKind pnk)
|
||||||
|
{
|
||||||
|
switch (pnk) {
|
||||||
|
case PNK_THROW: return JSOP_THROW;
|
||||||
|
case PNK_VOID: return JSOP_VOID;
|
||||||
|
case PNK_NOT: return JSOP_NOT;
|
||||||
|
case PNK_BITNOT: return JSOP_BITNOT;
|
||||||
|
case PNK_POS: return JSOP_POS;
|
||||||
|
case PNK_NEG: return JSOP_NEG;
|
||||||
|
default: MOZ_CRASH("unexpected unary op");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BytecodeEmitter::emitUnary(ParseNode* pn)
|
BytecodeEmitter::emitUnary(ParseNode* pn)
|
||||||
{
|
{
|
||||||
if (!updateSourceCoordNotes(pn->pn_pos.begin))
|
if (!updateSourceCoordNotes(pn->pn_pos.begin))
|
||||||
return false;
|
return false;
|
||||||
|
if (!emitTree(pn->pn_kid))
|
||||||
/* Unary op, including unary +/-. */
|
|
||||||
JSOp op = pn->getOp();
|
|
||||||
ParseNode* pn2 = pn->pn_kid;
|
|
||||||
|
|
||||||
if (!emitTree(pn2))
|
|
||||||
return false;
|
return false;
|
||||||
|
return emit1(UnaryOpParseNodeKindToJSOp(pn->getKind()));
|
||||||
return emit1(op);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -10973,7 +11042,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
|
||||||
case PNK_DIVASSIGN:
|
case PNK_DIVASSIGN:
|
||||||
case PNK_MODASSIGN:
|
case PNK_MODASSIGN:
|
||||||
case PNK_POWASSIGN:
|
case PNK_POWASSIGN:
|
||||||
if (!emitAssignment(pn->pn_left, pn->getOp(), pn->pn_right))
|
if (!emitAssignment(pn->pn_left, pn->getKind(), pn->pn_right))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -759,7 +759,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
||||||
|
|
||||||
MOZ_MUST_USE bool emitCallSiteObject(ParseNode* pn);
|
MOZ_MUST_USE bool emitCallSiteObject(ParseNode* pn);
|
||||||
MOZ_MUST_USE bool emitTemplateString(ParseNode* pn);
|
MOZ_MUST_USE bool emitTemplateString(ParseNode* pn);
|
||||||
MOZ_MUST_USE bool emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs);
|
MOZ_MUST_USE bool emitAssignment(ParseNode* lhs, ParseNodeKind pnk, ParseNode* rhs);
|
||||||
|
|
||||||
MOZ_MUST_USE bool emitReturn(ParseNode* pn);
|
MOZ_MUST_USE bool emitReturn(ParseNode* pn);
|
||||||
MOZ_MUST_USE bool emitStatement(ParseNode* pn);
|
MOZ_MUST_USE bool emitStatement(ParseNode* pn);
|
||||||
|
|
|
@ -97,7 +97,7 @@ class FullParseHandler
|
||||||
|
|
||||||
ParseNode* newComputedName(ParseNode* expr, uint32_t begin, uint32_t end) {
|
ParseNode* newComputedName(ParseNode* expr, uint32_t begin, uint32_t end) {
|
||||||
TokenPos pos(begin, end);
|
TokenPos pos(begin, end);
|
||||||
return new_<UnaryNode>(PNK_COMPUTED_NAME, JSOP_NOP, pos, expr);
|
return new_<UnaryNode>(PNK_COMPUTED_NAME, pos, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newObjectLiteralPropertyName(JSAtom* atom, const TokenPos& pos) {
|
ParseNode* newObjectLiteralPropertyName(JSAtom* atom, const TokenPos& pos) {
|
||||||
|
@ -181,69 +181,69 @@ class FullParseHandler
|
||||||
ParseNode* newDelete(uint32_t begin, ParseNode* expr) {
|
ParseNode* newDelete(uint32_t begin, ParseNode* expr) {
|
||||||
if (expr->isKind(PNK_NAME)) {
|
if (expr->isKind(PNK_NAME)) {
|
||||||
expr->setOp(JSOP_DELNAME);
|
expr->setOp(JSOP_DELNAME);
|
||||||
return newUnary(PNK_DELETENAME, JSOP_NOP, begin, expr);
|
return newUnary(PNK_DELETENAME, begin, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expr->isKind(PNK_DOT))
|
if (expr->isKind(PNK_DOT))
|
||||||
return newUnary(PNK_DELETEPROP, JSOP_NOP, begin, expr);
|
return newUnary(PNK_DELETEPROP, begin, expr);
|
||||||
|
|
||||||
if (expr->isKind(PNK_ELEM))
|
if (expr->isKind(PNK_ELEM))
|
||||||
return newUnary(PNK_DELETEELEM, JSOP_NOP, begin, expr);
|
return newUnary(PNK_DELETEELEM, begin, expr);
|
||||||
|
|
||||||
return newUnary(PNK_DELETEEXPR, JSOP_NOP, begin, expr);
|
return newUnary(PNK_DELETEEXPR, begin, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newTypeof(uint32_t begin, ParseNode* kid) {
|
ParseNode* newTypeof(uint32_t begin, ParseNode* kid) {
|
||||||
|
return newUnary(kid->isKind(PNK_NAME) ? PNK_TYPEOFNAME : PNK_TYPEOFEXPR, begin, kid);
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseNode* newUnary(ParseNodeKind kind, uint32_t begin, ParseNode* kid) {
|
||||||
TokenPos pos(begin, kid->pn_pos.end);
|
TokenPos pos(begin, kid->pn_pos.end);
|
||||||
ParseNodeKind kind = kid->isKind(PNK_NAME) ? PNK_TYPEOFNAME : PNK_TYPEOFEXPR;
|
return new_<UnaryNode>(kind, pos, kid);
|
||||||
return new_<UnaryNode>(kind, JSOP_NOP, pos, kid);
|
|
||||||
}
|
|
||||||
|
|
||||||
ParseNode* newNullary(ParseNodeKind kind, JSOp op, const TokenPos& pos) {
|
|
||||||
return new_<NullaryNode>(kind, op, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
ParseNode* newUnary(ParseNodeKind kind, JSOp op, uint32_t begin, ParseNode* kid) {
|
|
||||||
TokenPos pos(begin, kid ? kid->pn_pos.end : begin + 1);
|
|
||||||
return new_<UnaryNode>(kind, op, pos, kid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newUpdate(ParseNodeKind kind, uint32_t begin, ParseNode* kid) {
|
ParseNode* newUpdate(ParseNodeKind kind, uint32_t begin, ParseNode* kid) {
|
||||||
TokenPos pos(begin, kid->pn_pos.end);
|
TokenPos pos(begin, kid->pn_pos.end);
|
||||||
return new_<UnaryNode>(kind, JSOP_NOP, pos, kid);
|
return new_<UnaryNode>(kind, pos, kid);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newSpread(uint32_t begin, ParseNode* kid) {
|
ParseNode* newSpread(uint32_t begin, ParseNode* kid) {
|
||||||
TokenPos pos(begin, kid->pn_pos.end);
|
TokenPos pos(begin, kid->pn_pos.end);
|
||||||
return new_<UnaryNode>(PNK_SPREAD, JSOP_NOP, pos, kid);
|
return new_<UnaryNode>(PNK_SPREAD, pos, kid);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newArrayPush(uint32_t begin, ParseNode* kid) {
|
ParseNode* newArrayPush(uint32_t begin, ParseNode* kid) {
|
||||||
TokenPos pos(begin, kid->pn_pos.end);
|
TokenPos pos(begin, kid->pn_pos.end);
|
||||||
return new_<UnaryNode>(PNK_ARRAYPUSH, JSOP_ARRAYPUSH, pos, kid);
|
return new_<UnaryNode>(PNK_ARRAYPUSH, pos, kid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
ParseNode* newBinary(ParseNodeKind kind, ParseNode* left, ParseNode* right,
|
ParseNode* newBinary(ParseNodeKind kind, ParseNode* left, ParseNode* right,
|
||||||
JSOp op = JSOP_NOP)
|
JSOp op = JSOP_NOP)
|
||||||
{
|
{
|
||||||
TokenPos pos(left->pn_pos.begin, right->pn_pos.end);
|
TokenPos pos(left->pn_pos.begin, right->pn_pos.end);
|
||||||
return new_<BinaryNode>(kind, op, pos, left, right);
|
return new_<BinaryNode>(kind, op, pos, left, right);
|
||||||
}
|
}
|
||||||
ParseNode* appendOrCreateList(ParseNodeKind kind, ParseNode* left, ParseNode* right,
|
|
||||||
ParseContext* pc, JSOp op = JSOP_NOP)
|
|
||||||
{
|
|
||||||
return ParseNode::appendOrCreateList(kind, op, left, right, this, pc);
|
|
||||||
}
|
|
||||||
|
|
||||||
ParseNode* newTernary(ParseNodeKind kind,
|
public:
|
||||||
ParseNode* first, ParseNode* second, ParseNode* third,
|
ParseNode* appendOrCreateList(ParseNodeKind kind, ParseNode* left, ParseNode* right,
|
||||||
JSOp op = JSOP_NOP)
|
ParseContext* pc)
|
||||||
{
|
{
|
||||||
return new_<TernaryNode>(kind, op, first, second, third);
|
return ParseNode::appendOrCreateList(kind, left, right, this, pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expressions
|
// Expressions
|
||||||
|
|
||||||
|
ParseNode* newGeneratorComprehension(ParseNode* genfn, const TokenPos& pos) {
|
||||||
|
MOZ_ASSERT(pos.begin <= genfn->pn_pos.begin);
|
||||||
|
MOZ_ASSERT(genfn->pn_pos.end <= pos.end);
|
||||||
|
ParseNode* result = new_<ListNode>(PNK_GENEXP, JSOP_CALL, pos);
|
||||||
|
if (!result)
|
||||||
|
return null();
|
||||||
|
result->append(genfn);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
ParseNode* newArrayComprehension(ParseNode* body, const TokenPos& pos) {
|
ParseNode* newArrayComprehension(ParseNode* body, const TokenPos& pos) {
|
||||||
MOZ_ASSERT(pos.begin <= body->pn_pos.begin);
|
MOZ_ASSERT(pos.begin <= body->pn_pos.begin);
|
||||||
MOZ_ASSERT(body->pn_pos.end <= pos.end);
|
MOZ_ASSERT(body->pn_pos.end <= pos.end);
|
||||||
|
@ -255,11 +255,7 @@ class FullParseHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newArrayLiteral(uint32_t begin) {
|
ParseNode* newArrayLiteral(uint32_t begin) {
|
||||||
ParseNode* literal = new_<ListNode>(PNK_ARRAY, TokenPos(begin, begin + 1));
|
return new_<ListNode>(PNK_ARRAY, TokenPos(begin, begin + 1));
|
||||||
// Later in this stack: remove dependency on this opcode.
|
|
||||||
if (literal)
|
|
||||||
literal->setOp(JSOP_NEWINIT);
|
|
||||||
return literal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_MUST_USE bool addElision(ParseNode* literal, const TokenPos& pos) {
|
MOZ_MUST_USE bool addElision(ParseNode* literal, const TokenPos& pos) {
|
||||||
|
@ -287,19 +283,19 @@ class FullParseHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newCall(const TokenPos& pos) {
|
ParseNode* newCall(const TokenPos& pos) {
|
||||||
return newList(PNK_CALL, pos, JSOP_CALL);
|
return new_<ListNode>(PNK_CALL, JSOP_CALL, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseNode* newSuperCall(ParseNode* callee) {
|
||||||
|
return new_<ListNode>(PNK_SUPERCALL, JSOP_SUPERCALL, callee);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newTaggedTemplate(const TokenPos& pos) {
|
ParseNode* newTaggedTemplate(const TokenPos& pos) {
|
||||||
return newList(PNK_TAGGED_TEMPLATE, pos, JSOP_CALL);
|
return new_<ListNode>(PNK_TAGGED_TEMPLATE, JSOP_CALL, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newObjectLiteral(uint32_t begin) {
|
ParseNode* newObjectLiteral(uint32_t begin) {
|
||||||
ParseNode* literal = new_<ListNode>(PNK_OBJECT, TokenPos(begin, begin + 1));
|
return new_<ListNode>(PNK_OBJECT, TokenPos(begin, begin + 1));
|
||||||
// Later in this stack: remove dependency on this opcode.
|
|
||||||
if (literal)
|
|
||||||
literal->setOp(JSOP_NEWINIT);
|
|
||||||
return literal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newClass(ParseNode* name, ParseNode* heritage, ParseNode* methodBlock,
|
ParseNode* newClass(ParseNode* name, ParseNode* heritage, ParseNode* methodBlock,
|
||||||
|
@ -320,7 +316,7 @@ class FullParseHandler
|
||||||
return new_<NullaryNode>(PNK_POSHOLDER, pos);
|
return new_<NullaryNode>(PNK_POSHOLDER, pos);
|
||||||
}
|
}
|
||||||
ParseNode* newSuperBase(ParseNode* thisName, const TokenPos& pos) {
|
ParseNode* newSuperBase(ParseNode* thisName, const TokenPos& pos) {
|
||||||
return new_<UnaryNode>(PNK_SUPERBASE, JSOP_NOP, pos, thisName);
|
return new_<UnaryNode>(PNK_SUPERBASE, pos, thisName);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_MUST_USE bool addPrototypeMutation(ParseNode* literal, uint32_t begin, ParseNode* expr) {
|
MOZ_MUST_USE bool addPrototypeMutation(ParseNode* literal, uint32_t begin, ParseNode* expr) {
|
||||||
|
@ -328,7 +324,7 @@ class FullParseHandler
|
||||||
// singleton objects will have Object.prototype as their [[Prototype]].
|
// singleton objects will have Object.prototype as their [[Prototype]].
|
||||||
setListFlag(literal, PNX_NONCONST);
|
setListFlag(literal, PNX_NONCONST);
|
||||||
|
|
||||||
ParseNode* mutation = newUnary(PNK_MUTATEPROTO, JSOP_NOP, begin, expr);
|
ParseNode* mutation = newUnary(PNK_MUTATEPROTO, begin, expr);
|
||||||
if (!mutation)
|
if (!mutation)
|
||||||
return false;
|
return false;
|
||||||
literal->append(mutation);
|
literal->append(mutation);
|
||||||
|
@ -378,7 +374,7 @@ class FullParseHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_MUST_USE bool addObjectMethodDefinition(ParseNode* literal, ParseNode* key, ParseNode* fn,
|
MOZ_MUST_USE bool addObjectMethodDefinition(ParseNode* literal, ParseNode* key, ParseNode* fn,
|
||||||
JSOp op)
|
AccessorType atype)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(literal->isArity(PN_LIST));
|
MOZ_ASSERT(literal->isArity(PN_LIST));
|
||||||
MOZ_ASSERT(key->isKind(PNK_NUMBER) ||
|
MOZ_ASSERT(key->isKind(PNK_NUMBER) ||
|
||||||
|
@ -387,7 +383,7 @@ class FullParseHandler
|
||||||
key->isKind(PNK_COMPUTED_NAME));
|
key->isKind(PNK_COMPUTED_NAME));
|
||||||
literal->pn_xflags |= PNX_NONCONST;
|
literal->pn_xflags |= PNX_NONCONST;
|
||||||
|
|
||||||
ParseNode* propdef = newBinary(PNK_COLON, key, fn, op);
|
ParseNode* propdef = newBinary(PNK_COLON, key, fn, AccessorTypeToJSOp(atype));
|
||||||
if (!propdef)
|
if (!propdef)
|
||||||
return false;
|
return false;
|
||||||
literal->append(propdef);
|
literal->append(propdef);
|
||||||
|
@ -395,7 +391,7 @@ class FullParseHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_MUST_USE bool addClassMethodDefinition(ParseNode* methodList, ParseNode* key, ParseNode* fn,
|
MOZ_MUST_USE bool addClassMethodDefinition(ParseNode* methodList, ParseNode* key, ParseNode* fn,
|
||||||
JSOp op, bool isStatic)
|
AccessorType atype, bool isStatic)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(methodList->isKind(PNK_CLASSMETHODLIST));
|
MOZ_ASSERT(methodList->isKind(PNK_CLASSMETHODLIST));
|
||||||
MOZ_ASSERT(key->isKind(PNK_NUMBER) ||
|
MOZ_ASSERT(key->isKind(PNK_NUMBER) ||
|
||||||
|
@ -403,7 +399,7 @@ class FullParseHandler
|
||||||
key->isKind(PNK_STRING) ||
|
key->isKind(PNK_STRING) ||
|
||||||
key->isKind(PNK_COMPUTED_NAME));
|
key->isKind(PNK_COMPUTED_NAME));
|
||||||
|
|
||||||
ParseNode* classMethod = new_<ClassMethod>(key, fn, op, isStatic);
|
ParseNode* classMethod = new_<ClassMethod>(key, fn, AccessorTypeToJSOp(atype), isStatic);
|
||||||
if (!classMethod)
|
if (!classMethod)
|
||||||
return false;
|
return false;
|
||||||
methodList->append(classMethod);
|
methodList->append(classMethod);
|
||||||
|
@ -412,22 +408,22 @@ class FullParseHandler
|
||||||
|
|
||||||
ParseNode* newInitialYieldExpression(uint32_t begin, ParseNode* gen) {
|
ParseNode* newInitialYieldExpression(uint32_t begin, ParseNode* gen) {
|
||||||
TokenPos pos(begin, begin + 1);
|
TokenPos pos(begin, begin + 1);
|
||||||
return new_<UnaryNode>(PNK_INITIALYIELD, JSOP_INITIALYIELD, pos, gen);
|
return new_<UnaryNode>(PNK_INITIALYIELD, pos, gen);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newYieldExpression(uint32_t begin, ParseNode* value) {
|
ParseNode* newYieldExpression(uint32_t begin, ParseNode* value) {
|
||||||
TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
|
TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
|
||||||
return new_<UnaryNode>(PNK_YIELD, JSOP_YIELD, pos, value);
|
return new_<UnaryNode>(PNK_YIELD, pos, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newYieldStarExpression(uint32_t begin, ParseNode* value) {
|
ParseNode* newYieldStarExpression(uint32_t begin, ParseNode* value) {
|
||||||
TokenPos pos(begin, value->pn_pos.end);
|
TokenPos pos(begin, value->pn_pos.end);
|
||||||
return new_<UnaryNode>(PNK_YIELD_STAR, JSOP_NOP, pos, value);
|
return new_<UnaryNode>(PNK_YIELD_STAR, pos, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newAwaitExpression(uint32_t begin, ParseNode* value) {
|
ParseNode* newAwaitExpression(uint32_t begin, ParseNode* value) {
|
||||||
TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
|
TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
|
||||||
return new_<UnaryNode>(PNK_AWAIT, JSOP_AWAIT, pos, value);
|
return new_<UnaryNode>(PNK_AWAIT, pos, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Statements
|
// Statements
|
||||||
|
@ -500,7 +496,7 @@ class FullParseHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newEmptyStatement(const TokenPos& pos) {
|
ParseNode* newEmptyStatement(const TokenPos& pos) {
|
||||||
return new_<UnaryNode>(PNK_SEMI, JSOP_NOP, pos, (ParseNode*) nullptr);
|
return new_<UnaryNode>(PNK_SEMI, pos, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newImportDeclaration(ParseNode* importSpecSet,
|
ParseNode* newImportDeclaration(ParseNode* importSpecSet,
|
||||||
|
@ -513,8 +509,12 @@ class FullParseHandler
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ParseNode* newImportSpec(ParseNode* importNameNode, ParseNode* bindingName) {
|
||||||
|
return newBinary(PNK_IMPORT_SPEC, importNameNode, bindingName);
|
||||||
|
}
|
||||||
|
|
||||||
ParseNode* newExportDeclaration(ParseNode* kid, const TokenPos& pos) {
|
ParseNode* newExportDeclaration(ParseNode* kid, const TokenPos& pos) {
|
||||||
return new_<UnaryNode>(PNK_EXPORT, JSOP_NOP, pos, kid);
|
return new_<UnaryNode>(PNK_EXPORT, pos, kid);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newExportFromDeclaration(uint32_t begin, ParseNode* exportSpecSet,
|
ParseNode* newExportFromDeclaration(uint32_t begin, ParseNode* exportSpecSet,
|
||||||
|
@ -532,15 +532,23 @@ class FullParseHandler
|
||||||
return new_<BinaryNode>(PNK_EXPORT_DEFAULT, JSOP_NOP, pos, kid, maybeBinding);
|
return new_<BinaryNode>(PNK_EXPORT_DEFAULT, JSOP_NOP, pos, kid, maybeBinding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ParseNode* newExportSpec(ParseNode* bindingName, ParseNode* exportName) {
|
||||||
|
return newBinary(PNK_EXPORT_SPEC, bindingName, exportName);
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseNode* newExportBatchSpec(const TokenPos& pos) {
|
||||||
|
return new_<NullaryNode>(PNK_EXPORT_BATCH_SPEC, JSOP_NOP, pos);
|
||||||
|
}
|
||||||
|
|
||||||
ParseNode* newExprStatement(ParseNode* expr, uint32_t end) {
|
ParseNode* newExprStatement(ParseNode* expr, uint32_t end) {
|
||||||
MOZ_ASSERT(expr->pn_pos.end <= end);
|
MOZ_ASSERT(expr->pn_pos.end <= end);
|
||||||
return new_<UnaryNode>(PNK_SEMI, JSOP_NOP, TokenPos(expr->pn_pos.begin, end), expr);
|
return new_<UnaryNode>(PNK_SEMI, TokenPos(expr->pn_pos.begin, end), expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newIfStatement(uint32_t begin, ParseNode* cond, ParseNode* thenBranch,
|
ParseNode* newIfStatement(uint32_t begin, ParseNode* cond, ParseNode* thenBranch,
|
||||||
ParseNode* elseBranch)
|
ParseNode* elseBranch)
|
||||||
{
|
{
|
||||||
ParseNode* pn = new_<TernaryNode>(PNK_IF, JSOP_NOP, cond, thenBranch, elseBranch);
|
ParseNode* pn = new_<TernaryNode>(PNK_IF, cond, thenBranch, elseBranch);
|
||||||
if (!pn)
|
if (!pn)
|
||||||
return null();
|
return null();
|
||||||
pn->pn_pos.begin = begin;
|
pn->pn_pos.begin = begin;
|
||||||
|
@ -590,14 +598,14 @@ class FullParseHandler
|
||||||
ParseNode* newForHead(ParseNode* init, ParseNode* test, ParseNode* update,
|
ParseNode* newForHead(ParseNode* init, ParseNode* test, ParseNode* update,
|
||||||
const TokenPos& pos)
|
const TokenPos& pos)
|
||||||
{
|
{
|
||||||
return new_<TernaryNode>(PNK_FORHEAD, JSOP_NOP, init, test, update, pos);
|
return new_<TernaryNode>(PNK_FORHEAD, init, test, update, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newForInOrOfHead(ParseNodeKind kind, ParseNode* target, ParseNode* iteratedExpr,
|
ParseNode* newForInOrOfHead(ParseNodeKind kind, ParseNode* target, ParseNode* iteratedExpr,
|
||||||
const TokenPos& pos)
|
const TokenPos& pos)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(kind == PNK_FORIN || kind == PNK_FOROF);
|
MOZ_ASSERT(kind == PNK_FORIN || kind == PNK_FOROF);
|
||||||
return new_<TernaryNode>(kind, JSOP_NOP, target, nullptr, iteratedExpr, pos);
|
return new_<TernaryNode>(kind, target, nullptr, iteratedExpr, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newSwitchStatement(uint32_t begin, ParseNode* discriminant, ParseNode* caseList) {
|
ParseNode* newSwitchStatement(uint32_t begin, ParseNode* discriminant, ParseNode* caseList) {
|
||||||
|
@ -619,11 +627,11 @@ class FullParseHandler
|
||||||
|
|
||||||
ParseNode* newReturnStatement(ParseNode* expr, const TokenPos& pos) {
|
ParseNode* newReturnStatement(ParseNode* expr, const TokenPos& pos) {
|
||||||
MOZ_ASSERT_IF(expr, pos.encloses(expr->pn_pos));
|
MOZ_ASSERT_IF(expr, pos.encloses(expr->pn_pos));
|
||||||
return new_<UnaryNode>(PNK_RETURN, JSOP_RETURN, pos, expr);
|
return new_<UnaryNode>(PNK_RETURN, pos, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newExpressionBody(ParseNode* expr) {
|
ParseNode* newExpressionBody(ParseNode* expr) {
|
||||||
return new_<UnaryNode>(PNK_RETURN, JSOP_RETURN, expr->pn_pos, expr);
|
return new_<UnaryNode>(PNK_RETURN, expr->pn_pos, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newWithStatement(uint32_t begin, ParseNode* expr, ParseNode* body) {
|
ParseNode* newWithStatement(uint32_t begin, ParseNode* expr, ParseNode* body) {
|
||||||
|
@ -637,13 +645,13 @@ class FullParseHandler
|
||||||
|
|
||||||
ParseNode* newThrowStatement(ParseNode* expr, const TokenPos& pos) {
|
ParseNode* newThrowStatement(ParseNode* expr, const TokenPos& pos) {
|
||||||
MOZ_ASSERT(pos.encloses(expr->pn_pos));
|
MOZ_ASSERT(pos.encloses(expr->pn_pos));
|
||||||
return new_<UnaryNode>(PNK_THROW, JSOP_THROW, pos, expr);
|
return new_<UnaryNode>(PNK_THROW, pos, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newTryStatement(uint32_t begin, ParseNode* body, ParseNode* catchList,
|
ParseNode* newTryStatement(uint32_t begin, ParseNode* body, ParseNode* catchList,
|
||||||
ParseNode* finallyBlock) {
|
ParseNode* finallyBlock) {
|
||||||
TokenPos pos(begin, (finallyBlock ? finallyBlock : catchList)->pn_pos.end);
|
TokenPos pos(begin, (finallyBlock ? finallyBlock : catchList)->pn_pos.end);
|
||||||
return new_<TernaryNode>(PNK_TRY, JSOP_NOP, body, catchList, finallyBlock, pos);
|
return new_<TernaryNode>(PNK_TRY, body, catchList, finallyBlock, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newDebuggerStatement(const TokenPos& pos) {
|
ParseNode* newDebuggerStatement(const TokenPos& pos) {
|
||||||
|
@ -717,7 +725,7 @@ class FullParseHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
Node newNewExpression(uint32_t begin, ParseNode* ctor) {
|
Node newNewExpression(uint32_t begin, ParseNode* ctor) {
|
||||||
ParseNode* newExpr = newList(PNK_NEW, begin, JSOP_NEW);
|
ParseNode* newExpr = new_<ListNode>(PNK_NEW, JSOP_NEW, TokenPos(begin, begin + 1));
|
||||||
if (!newExpr)
|
if (!newExpr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
@ -725,10 +733,8 @@ class FullParseHandler
|
||||||
return newExpr;
|
return newExpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newAssignment(ParseNodeKind kind, ParseNode* lhs, ParseNode* rhs,
|
ParseNode* newAssignment(ParseNodeKind kind, ParseNode* lhs, ParseNode* rhs) {
|
||||||
JSOp op)
|
return newBinary(kind, lhs, rhs);
|
||||||
{
|
|
||||||
return newBinary(kind, lhs, rhs, op);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isUnparenthesizedYieldExpression(ParseNode* node) {
|
bool isUnparenthesizedYieldExpression(ParseNode* node) {
|
||||||
|
@ -800,28 +806,28 @@ class FullParseHandler
|
||||||
return kind == PNK_VAR || kind == PNK_LET || kind == PNK_CONST;
|
return kind == PNK_VAR || kind == PNK_LET || kind == PNK_CONST;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newList(ParseNodeKind kind, const TokenPos& pos, JSOp op = JSOP_NOP) {
|
ParseNode* newList(ParseNodeKind kind, const TokenPos& pos) {
|
||||||
MOZ_ASSERT(!isDeclarationKind(kind));
|
MOZ_ASSERT(!isDeclarationKind(kind));
|
||||||
return new_<ListNode>(kind, op, pos);
|
return new_<ListNode>(kind, JSOP_NOP, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ParseNode* newList(ParseNodeKind kind, uint32_t begin, JSOp op = JSOP_NOP) {
|
ParseNode* newList(ParseNodeKind kind, uint32_t begin) {
|
||||||
return newList(kind, TokenPos(begin, begin + 1), op);
|
return newList(kind, TokenPos(begin, begin + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ParseNode* newList(ParseNodeKind kind, const T& begin, JSOp op = JSOP_NOP) = delete;
|
ParseNode* newList(ParseNodeKind kind, const T& begin) = delete;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ParseNode* newList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) {
|
ParseNode* newList(ParseNodeKind kind, ParseNode* kid) {
|
||||||
MOZ_ASSERT(!isDeclarationKind(kind));
|
MOZ_ASSERT(!isDeclarationKind(kind));
|
||||||
return new_<ListNode>(kind, op, kid);
|
return new_<ListNode>(kind, JSOP_NOP, kid);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newDeclarationList(ParseNodeKind kind, const TokenPos& pos, JSOp op) {
|
ParseNode* newDeclarationList(ParseNodeKind kind, const TokenPos& pos) {
|
||||||
MOZ_ASSERT(isDeclarationKind(kind));
|
MOZ_ASSERT(isDeclarationKind(kind));
|
||||||
return new_<ListNode>(kind, op, pos);
|
return new_<ListNode>(kind, JSOP_NOP, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isDeclarationList(ParseNode* node) {
|
bool isDeclarationList(ParseNode* node) {
|
||||||
|
@ -839,7 +845,7 @@ class FullParseHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* newCommaExpressionList(ParseNode* kid) {
|
ParseNode* newCommaExpressionList(ParseNode* kid) {
|
||||||
return newList(PNK_COMMA, kid, JSOP_NOP);
|
return new_<ListNode>(PNK_COMMA, JSOP_NOP, kid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addList(ParseNode* list, ParseNode* kid) {
|
void addList(ParseNode* list, ParseNode* kid) {
|
||||||
|
@ -943,7 +949,7 @@ FullParseHandler::addCatchBlock(ParseNode* catchList, ParseNode* lexicalScope,
|
||||||
ParseNode* catchName, ParseNode* catchGuard,
|
ParseNode* catchName, ParseNode* catchGuard,
|
||||||
ParseNode* catchBody)
|
ParseNode* catchBody)
|
||||||
{
|
{
|
||||||
ParseNode* catchpn = newTernary(PNK_CATCH, catchName, catchGuard, catchBody);
|
ParseNode* catchpn = new_<TernaryNode>(PNK_CATCH, catchName, catchGuard, catchBody);
|
||||||
if (!catchpn)
|
if (!catchpn)
|
||||||
return false;
|
return false;
|
||||||
catchList->append(lexicalScope);
|
catchList->append(lexicalScope);
|
||||||
|
@ -956,7 +962,7 @@ FullParseHandler::setLastFunctionFormalParameterDefault(ParseNode* funcpn,
|
||||||
ParseNode* defaultValue)
|
ParseNode* defaultValue)
|
||||||
{
|
{
|
||||||
ParseNode* arg = funcpn->pn_body->last();
|
ParseNode* arg = funcpn->pn_body->last();
|
||||||
ParseNode* pn = newBinary(PNK_ASSIGN, arg, defaultValue, JSOP_NOP);
|
ParseNode* pn = newBinary(PNK_ASSIGN, arg, defaultValue);
|
||||||
if (!pn)
|
if (!pn)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -571,7 +571,7 @@ ParseNodeAllocator::allocNode()
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode*
|
ParseNode*
|
||||||
ParseNode::appendOrCreateList(ParseNodeKind kind, JSOp op, ParseNode* left, ParseNode* right,
|
ParseNode::appendOrCreateList(ParseNodeKind kind, ParseNode* left, ParseNode* right,
|
||||||
FullParseHandler* handler, ParseContext* pc)
|
FullParseHandler* handler, ParseContext* pc)
|
||||||
{
|
{
|
||||||
// The asm.js specification is written in ECMAScript grammar terms that
|
// The asm.js specification is written in ECMAScript grammar terms that
|
||||||
|
@ -593,9 +593,7 @@ ParseNode::appendOrCreateList(ParseNodeKind kind, JSOp op, ParseNode* left, Pars
|
||||||
// processed with a left fold because (+) is left-associative.
|
// processed with a left fold because (+) is left-associative.
|
||||||
//
|
//
|
||||||
if (left->isKind(kind) &&
|
if (left->isKind(kind) &&
|
||||||
left->isOp(op) &&
|
(kind == PNK_POW ? !left->pn_parens : left->isBinaryOperation()))
|
||||||
(CodeSpec[op].format & JOF_LEFTASSOC ||
|
|
||||||
(kind == PNK_POW && !left->pn_parens)))
|
|
||||||
{
|
{
|
||||||
ListNode* list = &left->as<ListNode>();
|
ListNode* list = &left->as<ListNode>();
|
||||||
|
|
||||||
|
@ -606,7 +604,7 @@ ParseNode::appendOrCreateList(ParseNodeKind kind, JSOp op, ParseNode* left, Pars
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseNode* list = handler->new_<ListNode>(kind, op, left);
|
ParseNode* list = handler->new_<ListNode>(kind, JSOP_NOP, left);
|
||||||
if (!list)
|
if (!list)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче