This commit is contained in:
Ryan VanderMeulen 2017-10-11 17:53:30 -04:00
Родитель 90fa230f6d 876ae3e424
Коммит 833b27ac01
239 изменённых файлов: 3772 добавлений и 1513 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -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))
{ {

24
dom/cache/DBSchema.cpp поставляемый
Просмотреть файл

@ -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,9 +4344,11 @@ 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.
if (updateSynthCenteringPoint) {
sSynthCenteringPoint = kInvalidRefPoint; sSynthCenteringPoint = kInvalidRefPoint;
} }
} }
}
/* static */ void /* static */ void
EventStateManager::UpdateLastPointerPosition(WidgetMouseEvent* aMouseEvent) EventStateManager::UpdateLastPointerPosition(WidgetMouseEvent* aMouseEvent)

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

@ -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>

Двоичные данные
dom/media/test/crashtests/1180881.webm Normal file

Двоичный файл не отображается.

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

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<video src="1197935.mp4" autoplay></video>
</body>
</html>

Двоичные данные
dom/media/test/crashtests/1197935.mp4 Normal file

Двоичный файл не отображается.

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

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<video src="1270303.webm" autoplay></video>
</body>
</html>

Двоичные данные
dom/media/test/crashtests/1270303.webm Normal file

Двоичный файл не отображается.

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

@ -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();
#if defined(NIGHTLY_BUILD)
{
MutexAutoLock autoLock(mQuotaMutex);
mTemporaryStorageInitialized = false; 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,6 +1157,12 @@ CompositorBridgeChild::FlushAsyncPaints()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
Maybe<TimeStamp> start;
if (XRE_IsContentProcess() && gfx::gfxVars::UseOMTP()) {
start = Some(TimeStamp::Now());
}
{
MonitorAutoLock lock(mPaintLock); MonitorAutoLock lock(mPaintLock);
while (mIsWaitingForPaint) { while (mIsWaitingForPaint) {
lock.Wait(); lock.Wait();
@ -1163,6 +1172,22 @@ CompositorBridgeChild::FlushAsyncPaints()
mTextureClientsForAsyncPaint.Clear(); 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
CompositorBridgeChild::NotifyBeginAsyncPaint(CapturedPaintState* aState) CompositorBridgeChild::NotifyBeginAsyncPaint(CapturedPaintState* aState)
{ {

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

@ -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,12 +474,35 @@ RenderViewMLGPU::ExecutePass(RenderPassMLGPU* aPass)
mDevice->SetVSConstantBuffer(kMaskBufferSlot, &section); mDevice->SetVSConstantBuffer(kMaskBufferSlot, &section);
} }
// Change the blend state if needed. aPass->ExecuteRendering();
if (Maybe<MLGBlendState> blendState = aPass->GetBlendState()) {
mDevice->SetBlendState(blendState.value());
} }
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
@ -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) {
if (!bce->emit1(op))
return false; 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;

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