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
# XCode project cruft
/*.xcodeproj/
embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/project.xcworkspace/xcuserdata
embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/xcuserdata

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

@ -107,6 +107,7 @@ GPATH
^mobile/android/gradle/.gradle
# XCode project cruft
^[^/]*\.xcodeproj/
^embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/project.xcworkspace/xcuserdata
^embedding/ios/GeckoEmbed/GeckoEmbed.xcodeproj/xcuserdata

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

@ -1336,6 +1336,13 @@ HyperTextAccessible::SetSelectionRange(int32_t aStartPos, int32_t aEndPos)
domSel->RemoveRange(domSel->GetRangeAt(idx));
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
// not focusable. That happens when selection is set within hypertext
// 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) {
switch (evt.command) {
case "Back":

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

@ -25,6 +25,10 @@ const CHROMEROOT = croot;
var gApp = document.getElementById("bundle_brand").getString("brandShortName");
var gVersion = Services.appinfo.version;
function waitForTick() {
return new Promise(resolve => executeSoon(resolve));
}
function getObserverTopic(aNotificationId) {
let topic = aNotificationId;
if (topic == "xpinstall-disabled")
@ -69,6 +73,7 @@ async function waitForProgressNotification(aPanelOpen = false, aExpectedCount =
await observerPromise;
await panelEventPromise;
await waitForTick();
info("Saw a notification");
ok(PopupNotifications.isPanelOpen, "Panel should be open");
@ -114,6 +119,7 @@ async function waitForNotification(aId, aExpectedCount = 1) {
await observerPromise;
await panelEventPromise;
await waitForTick();
info("Saw a " + aId + " notification");
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;
info("Got opened tab");
let otherTabClosePromise = BrowserTestUtils.tabRemoved(openedTab);
let windowClosedPromise = BrowserTestUtils.windowClosed(win);
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");
info("If we timeout now, the window failed to close - that shouldn't happen!");
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 identityRect =
this.DOMWindowUtils.getBoundsWithoutFlushing(identityIcon);
this.siteIconStart = popupDirection == "rtl" ? identityRect.right
: identityRect.left;
if (popupDirection == "rtl") {
this.siteIconStart = documentRect.right - identityRect.right;
} else {
this.siteIconStart = identityRect.left;
}
} else {
// Reset the alignment so that the site icons are positioned
// 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;
if (this.siteIconStart) {
let rect = this.DOMWindowUtils.getBoundsWithoutFlushing(window.document.documentElement);
let padding = popupDirection == "rtl" ? rect.right - this.siteIconStart
: this.siteIconStart;
this.searchSuggestionsNotification.style.paddingInlineStart = padding + "px";
this.searchSuggestionsNotification.style.paddingInlineStart =
this.siteIconStart + "px";
} else {
this.searchSuggestionsNotification.style.removeProperty("padding-inline-start");
}

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

@ -266,6 +266,12 @@
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"],
.searchbar-textbox[focused="true"] {
border-color: -moz-mac-focusring;

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

@ -6,7 +6,8 @@
const { CanvasFrameAnonymousContentHelper, getCSSStyleRules,
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 {
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) {
// No event handling if the highlighter is hidden
if (this.areShapesHidden()) {
@ -702,7 +724,10 @@ class ShapesHighlighter extends AutoRefreshHighlighter {
* in percentages relative to the element.
*/
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;
pageY -= top;
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 1304437.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-2.html
pref(dom.IntersectionObserver.enabled,true) load 1332939.html

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

@ -32,8 +32,6 @@ using mozilla::dom::Element;
AutoTArray<RefPtr<nsDOMMutationObserver>, 4>*
nsDOMMutationObserver::sScheduledMutationObservers = nullptr;
nsDOMMutationObserver* nsDOMMutationObserver::sCurrentObserver = nullptr;
uint32_t nsDOMMutationObserver::sMutationLevel = 0;
uint64_t nsDOMMutationObserver::sCount = 0;
@ -599,10 +597,32 @@ nsDOMMutationObserver::ScheduleForRun()
RescheduleForRun();
}
class MutationObserverMicroTask final : public MicroTaskRunnable
{
public:
virtual void Run(AutoSlowOperation& aAso) override
{
nsDOMMutationObserver::HandleMutations(aAso);
}
virtual bool Suppressed() override
{
return nsDOMMutationObserver::AllScheduledMutationObserversAreSuppressed();
}
};
void
nsDOMMutationObserver::RescheduleForRun()
{
if (!sScheduledMutationObservers) {
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
if (!ccjs) {
return;
}
RefPtr<MutationObserverMicroTask> momt =
new MutationObserverMicroTask();
ccjs->DispatchMicroTaskRunnable(momt.forget());
sScheduledMutationObservers = new AutoTArray<RefPtr<nsDOMMutationObserver>, 4>;
}
@ -864,37 +884,9 @@ nsDOMMutationObserver::HandleMutation()
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
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;
while (sScheduledMutationObservers) {
@ -902,20 +894,21 @@ nsDOMMutationObserver::HandleMutationsInternal()
sScheduledMutationObservers;
sScheduledMutationObservers = nullptr;
for (uint32_t i = 0; i < observers->Length(); ++i) {
sCurrentObserver = static_cast<nsDOMMutationObserver*>((*observers)[i]);
if (!sCurrentObserver->Suppressed()) {
sCurrentObserver->HandleMutation();
RefPtr<nsDOMMutationObserver> currentObserver =
static_cast<nsDOMMutationObserver*>((*observers)[i]);
if (!currentObserver->Suppressed()) {
currentObserver->HandleMutation();
} else {
if (!suppressedObservers) {
suppressedObservers = new nsTArray<RefPtr<nsDOMMutationObserver> >;
}
if (!suppressedObservers->Contains(sCurrentObserver)) {
suppressedObservers->AppendElement(sCurrentObserver);
if (!suppressedObservers->Contains(currentObserver)) {
suppressedObservers->AppendElement(currentObserver);
}
}
}
delete observers;
aso.CheckForInterrupt();
aAso.CheckForInterrupt();
}
if (suppressedObservers) {
@ -926,7 +919,6 @@ nsDOMMutationObserver::HandleMutationsInternal()
delete suppressedObservers;
suppressedObservers = nullptr;
}
sCurrentObserver = nullptr;
}
nsDOMMutationRecord*

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

@ -575,13 +575,29 @@ public:
}
// static methods
static void HandleMutations()
static void HandleMutations(mozilla::AutoSlowOperation& aAso)
{
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 LeaveMutationHandling();
@ -613,7 +629,7 @@ protected:
return mOwner && nsGlobalWindow::Cast(mOwner)->IsInSyncOperation();
}
static void HandleMutationsInternal();
static void HandleMutationsInternal(mozilla::AutoSlowOperation& aAso);
static void AddCurrentlyHandlingObserver(nsDOMMutationObserver* aObserver,
uint32_t aMutationLevel);
@ -641,7 +657,6 @@ protected:
static uint64_t sCount;
static AutoTArray<RefPtr<nsDOMMutationObserver>, 4>* sScheduledMutationObservers;
static nsDOMMutationObserver* sCurrentObserver;
static uint32_t sMutationLevel;
static AutoTArray<AutoTArray<RefPtr<nsDOMMutationObserver>, 4>, 4>*

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

@ -576,8 +576,6 @@ DumpString(const nsAString &str)
#define JS_OPTIONS_DOT_STR "javascript.options."
static const char js_options_dot_str[] = JS_OPTIONS_DOT_STR;
nsJSContext::nsJSContext(bool aGCOnDestruction,
nsIScriptGlobalObject* aGlobalObject)
: mWindowProxy(nullptr)

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

@ -21,9 +21,6 @@
#include "nsJSUtils.h"
#include "WorkerPrivate.h"
static const char kSetIntervalStr[] = "setInterval";
static const char kSetTimeoutStr[] = "setTimeout";
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::dom::workers;

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

@ -362,7 +362,7 @@ function testChildList5() {
is(records[5].previousSibling, c3, "");
is(records[5].nextSibling, c5, "");
observer.disconnect();
then(testAdoptNode);
then(testNestedMutations);
m = null;
});
m.observe(div, { childList: true, subtree: true });
@ -375,6 +375,37 @@ function testChildList5() {
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() {
var d1 = document.implementation.createHTMLDocument(null);
var d2 = document.implementation.createHTMLDocument(null);

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

@ -345,18 +345,19 @@ template<>
class Optional<nsAString>
{
public:
Optional() : mPassed(false) {}
Optional()
: mStr(nullptr)
{}
bool WasPassed() const
{
return mPassed;
return !!mStr;
}
void operator=(const nsAString* str)
{
MOZ_ASSERT(str);
mStr = str;
mPassed = true;
}
// If this code ever goes away, remove the comment pointing to it in the
@ -365,7 +366,6 @@ public:
{
MOZ_ASSERT(str);
mStr = reinterpret_cast<const nsString*>(str);
mPassed = true;
}
const nsAString& Value() const
@ -379,7 +379,6 @@ private:
Optional(const Optional& other) = delete;
const Optional &operator=(const Optional &other) = delete;
bool mPassed;
const nsAString* mStr;
};
@ -388,8 +387,9 @@ class NonNull
{
public:
NonNull()
: ptr(nullptr)
#ifdef DEBUG
: inited(false)
, inited(false)
#endif
{}

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

@ -19,6 +19,8 @@ namespace binding_detail {
// for small strings and a nsStringBuffer for longer strings.
struct FakeString {
FakeString() :
mData(nsString::char_traits::sEmptyBuffer),
mLength(0),
mDataFlags(nsString::DataFlags::TERMINATED),
mClassFlags(nsString::ClassFlags(0))
{

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

@ -2084,17 +2084,7 @@ ReadResponse(mozIStorageConnection* aConn, EntryId aEntryId,
rv = state->GetIsNull(6, &nullPadding);
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) {
#endif // NIGHTLY_BUILD
MOZ_DIAGNOSTIC_ASSERT(aSavedResponseOut->mValue.type() !=
ResponseType::Opaque);
aSavedResponseOut->mValue.paddingSize() =
@ -2113,20 +2103,6 @@ ReadResponse(mozIStorageConnection* aConn, EntryId aEntryId,
rv = state->GetBlobAsUTF8String(7, aSavedResponseOut->mValue.channelInfo().securityInfo());
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(
"SELECT "
"name, "

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

@ -389,19 +389,6 @@ WebGLContext::ValidateStencilParamsForDrawCall()
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
WebGLContext::InitAndValidateGL(FailureReason* const out_failReason)
{

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

@ -936,21 +936,6 @@ DoCompressedTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level,
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
DoCopyTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level, GLint xOffset,
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 916128-1.html
load 934939-1.html
load 989628.html
load 1099143-1.html
load 1161277-1.html
load 1183363.html
@ -38,10 +39,11 @@ load 1290628-1.html
load 1283113-1.html
load 1286458-1.html
load 1296410-1.html
load 1298576-1.html
load 1299062-1.html
load 1305085-1.html
load 1305312-1.html
load 1298576-1.html
load 1305850.html
load 1334366-1.html
load 1334647-1.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
[test_noprog_draw.html]
[test_pixel_pack_buffer.html]
skip-if = os == "win" && os_version == "10.0" # Bug 1302199
[test_privileged_exts.html]
[test_renderer_strings.html]
[test_sab_with_webgl.html]

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

@ -14,8 +14,6 @@
namespace mozilla {
namespace dom {
static const char16_t kReplacementChar = static_cast<char16_t>(0xFFFD);
void
TextDecoder::Init(const nsAString& aLabel, const bool aFatal,
ErrorResult& aRv)

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

@ -4277,7 +4277,8 @@ EventStateManager::GeneratePointerEnterExit(EventMessage aMessage,
/* static */ void
EventStateManager::UpdateLastRefPointOfMouseEvent(WidgetMouseEvent* aMouseEvent)
{
if (aMouseEvent->mMessage != eMouseMove) {
if (aMouseEvent->mMessage != eMouseMove &&
aMouseEvent->mMessage != ePointerMove) {
return;
}
@ -4310,10 +4311,15 @@ EventStateManager::ResetPointerToWindowCenterWhilePointerLocked(
WidgetMouseEvent* aMouseEvent)
{
MOZ_ASSERT(sIsPointerLocked);
if (aMouseEvent->mMessage != eMouseMove || !aMouseEvent->mWidget) {
if ((aMouseEvent->mMessage != eMouseMove &&
aMouseEvent->mMessage != ePointerMove) || !aMouseEvent->mWidget) {
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 window, dispatch a synthetic mousemove to return the pointer there.
// Doing this between "real" pointer moves gives the impression that the
@ -4323,7 +4329,7 @@ EventStateManager::ResetPointerToWindowCenterWhilePointerLocked(
LayoutDeviceIntPoint center =
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
// synthetic native mouse event to move the pointer back to the center
// of the window, to faciliate more movement. But first, record that
@ -4338,8 +4344,10 @@ EventStateManager::ResetPointerToWindowCenterWhilePointerLocked(
aMouseEvent->StopPropagation();
// Clear sSynthCenteringPoint so we don't cancel other events
// targeted at the center.
if (updateSynthCenteringPoint) {
sSynthCenteringPoint = kInvalidRefPoint;
}
}
}
/* static */ void

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

@ -124,7 +124,7 @@ UIEvent::GetMovementPoint()
}
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
// events except mousemove.
return nsIntPoint(0, 0);

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

@ -6,6 +6,10 @@ support-files =
../pointerevent_styles.css
../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]
support-files = pointerevent_pointerlock_after_pointercapture-manual.html
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)
, mURLList(aOther.mURLList)
, mHeaders(new InternalHeaders(*aOther.mHeaders))
, mBodyLength(InternalResponse::UNKNOWN_BODY_SIZE)
, mContentPolicyType(aOther.mContentPolicyType)
, mReferrer(aOther.mReferrer)
, mReferrerPolicy(aOther.mReferrerPolicy)

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

@ -227,9 +227,6 @@ const double HTMLInputElement::kMsPerDay = 24 * 60 * 60 * 1000;
{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.
// This class is used when the FilePicker finished its task (or when files and
// directories are set by some chrome/test only method).

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

@ -53,8 +53,6 @@ using namespace mozilla;
using namespace mozilla::dom;
using mozilla::layers::ScrollInputMethod;
static NS_DEFINE_CID(kTextEditorCID, NS_TEXTEDITOR_CID);
class MOZ_STACK_CLASS ValueSetter
{
public:

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

@ -189,8 +189,6 @@ cubeb_channel_layout sPreferredChannelLayout;
} // namespace
extern LazyLogModule gAudioStreamLog;
static const uint32_t CUBEB_NORMAL_LATENCY_MS = 100;
// Consevative default that can work on all platforms.
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.
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.
static const int AUDIO_DURATION_USECS = 40000;

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

@ -60,8 +60,6 @@ void MediaDeviceInfo::GetLabel(nsString& retval)
}
MediaDeviceKind Kind();
void GetLabel(nsString& retval);
void GetGroupId(nsString& retval);
} // namespace dom
} // 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] = {
"opus",
"vp8",

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

@ -9,10 +9,11 @@
namespace mozilla {
#ifdef DEBUG
extern LazyLogModule gMediaStreamGraphLog;
#define STREAM_LOG(type, msg) MOZ_LOG(gMediaStreamGraphLog, type, msg)
#ifdef DEBUG
void
StreamTracks::DumpTrackInfo() const
{

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

@ -23,7 +23,6 @@ static const int DEFAULT_CHANNELS = 1;
static const int DEFAULT_SAMPLING_RATE = 16000;
static const int DEFAULT_FRAME_WIDTH = 640;
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.
static const int AUDIO_INIT_FAILED_DURATION = 1;
// 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]
skip-if = toolkit == 'android' # Not supported on android
[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_mp4.html]
skip-if = toolkit == 'android' # Not supported on android
[test_Eviction_mp4.html]
skip-if = android_version == '15' # Not supported on Android(Bug 1358271)
[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]
skip-if = toolkit == 'android' # Not supported on android
[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]
skip-if = toolkit == 'android' # Not supported on android
[test_LiveSeekable.html]

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

@ -49,7 +49,6 @@
namespace mozilla {
extern already_AddRefed<PlatformDecoderModule> CreateAgnosticDecoderModule();
extern already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule();
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 1045650.html
load 1080986.html
load 1180881.html
load 1197935.html
load 1122218.html
load 1127188.html
load 1157994.html
load 1158427.html
load 1185176.html
load 1185192.html
load 1270303.html
load 1304948.html
load 1319486.html
load 1368490.html

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

@ -43,8 +43,6 @@ using namespace mozilla;
using namespace mozilla::plugins::parent;
using namespace mozilla::layers;
static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID);
NS_IMPL_ISUPPORTS(nsNPAPIPluginInstance, nsIAudioChannelAgentCallback)
nsNPAPIPluginInstance::nsNPAPIPluginInstance()

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

@ -615,17 +615,6 @@ PluginInstanceParent::RecvNPN_InvalidateRect(const NPRect& rect)
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
PluginInstanceParent::RecvRevokeCurrentDirectSurface()
{

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

@ -3838,6 +3838,13 @@ QuotaManager::GetQuotaObject(PersistenceType aPersistenceType,
return nullptr;
}
#if defined(NIGHTLY_BUILD)
{
MutexAutoLock autoLock(mQuotaMutex);
MOZ_DIAGNOSTIC_ASSERT(mTemporaryStorageInitialized);
}
#endif
nsString path;
nsresult rv = aFile->GetPath(path);
NS_ENSURE_SUCCESS(rv, nullptr);
@ -3923,6 +3930,13 @@ QuotaManager::GetQuotaObject(PersistenceType aPersistenceType,
{
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) {
*aFileSizeOut = 0;
}
@ -5242,7 +5256,14 @@ QuotaManager::EnsureOriginIsInitializedInternal(
NS_ENSURE_SUCCESS(rv, rv);
}
#if defined(NIGHTLY_BUILD)
{
MutexAutoLock autoLock(mQuotaMutex);
mTemporaryStorageInitialized = true;
}
#else
mTemporaryStorageInitialized = true;
#endif
CheckTemporaryStorageLimits();
}
@ -5328,7 +5349,16 @@ QuotaManager::ResetOrClearCompleted()
AssertIsOnIOThread();
mInitializedOrigins.Clear();
#if defined(NIGHTLY_BUILD)
{
MutexAutoLock autoLock(mQuotaMutex);
mTemporaryStorageInitialized = false;
}
#else
mTemporaryStorageInitialized = false;
#endif
mStorageInitialized = false;
ReleaseIOThreadObjects();

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

@ -224,14 +224,6 @@ nsCSPContext::permitsInternal(CSPDirective aDir,
nsAutoString violatedDirective;
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,
aContentLocation,
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_xhr.html
file_bug941404_xhr.html^headers^
file_frame_ancestors_ro.html
file_frame_ancestors_ro.html^headers^
file_hash_source.html
file_dual_header_testserver.sjs
file_hash_source.html^headers^
@ -246,6 +248,7 @@ skip-if = toolkit == 'android' # Times out, not sure why (bug 1008445)
[test_bug910139.html]
[test_bug909029.html]
[test_bug1229639.html]
[test_frame_ancestors_ro.html]
[test_policyuri_regression_from_multipolicy.html]
[test_nonce_source.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);
}
static const char kPermissionType[] = "cookie";
static const char kStorageEnabled[] = "dom.storage.enabled";
bool
LocalStorage::PrincipalEquals(nsIPrincipal* aPrincipal)
{

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

@ -14,6 +14,8 @@
namespace mozilla {
namespace dom {
static const char kStorageEnabled[] = "dom.storage.enabled";
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Storage, mWindow, mPrincipal)
NS_IMPL_CYCLE_COLLECTING_ADDREF(Storage)

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

@ -24,11 +24,6 @@
#include "mozilla/dom/BindingUtils.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 dom {

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

@ -64,8 +64,10 @@ DeleteRangeTransaction::DoTransaction()
if (startContainer == endContainer) {
// the selection begins and ends in the same node
nsIContent* startChild = rangeToDelete->GetChildAtStartOffset();
nsresult rv =
CreateTxnsToDeleteBetween(startContainer, startOffset, endOffset);
CreateTxnsToDeleteBetween(startContainer, startOffset,
startChild, endOffset);
NS_ENSURE_SUCCESS(rv, rv);
} else {
// the selection ends in a different node from where it started. delete
@ -122,6 +124,7 @@ DeleteRangeTransaction::GetTxnDescription(nsAString& aString)
nsresult
DeleteRangeTransaction::CreateTxnsToDeleteBetween(nsINode* aNode,
int32_t aStartOffset,
nsIContent* aChildAtStartOffset,
int32_t aEndOffset)
{
if (NS_WARN_IF(!mEditorBase)) {
@ -153,7 +156,7 @@ DeleteRangeTransaction::CreateTxnsToDeleteBetween(nsINode* aNode,
return NS_OK;
}
nsCOMPtr<nsIContent> child = aNode->GetChildAt(aStartOffset);
nsIContent* child = aChildAtStartOffset;
for (int32_t i = aStartOffset; i < aEndOffset; ++i) {
// Even if we detect invalid range, we should ignore it for removing
// specified range's nodes as far as possible.

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

@ -52,6 +52,7 @@ public:
protected:
nsresult CreateTxnsToDeleteBetween(nsINode* aNode,
int32_t aStartOffset,
nsIContent* aChildAtStartOffset,
int32_t aEndOffset);
nsresult CreateTxnsToDeleteNodesBetween(nsRange* aRangeToDelete);

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

@ -2391,13 +2391,14 @@ EditorBase::FindBetterInsertionPoint(nsCOMPtr<nsIDOMNode>& aNode,
int32_t& aOffset)
{
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
FindBetterInsertionPoint(node, aOffset);
FindBetterInsertionPoint(node, aOffset, nullptr);
aNode = do_QueryInterface(node);
}
void
EditorBase::FindBetterInsertionPoint(nsCOMPtr<nsINode>& aNode,
int32_t& aOffset)
int32_t& aOffset,
nsCOMPtr<nsIContent>* aSelChild)
{
if (aNode->IsNodeOfType(nsINode::eTEXT)) {
// There is no "better" insertion point.
@ -2424,6 +2425,9 @@ EditorBase::FindBetterInsertionPoint(nsCOMPtr<nsINode>& aNode,
node->GetFirstChild()->IsNodeOfType(nsINode::eTEXT)) {
aNode = node->GetFirstChild();
aOffset = 0;
if (aSelChild) {
*aSelChild = nullptr;
}
return;
}
@ -2439,6 +2443,9 @@ EditorBase::FindBetterInsertionPoint(nsCOMPtr<nsINode>& aNode,
NS_ENSURE_TRUE_VOID(node->Length() <= INT32_MAX);
aNode = child;
aOffset = static_cast<int32_t>(aNode->Length());
if (aSelChild) {
*aSelChild = nullptr;
}
return;
}
} else {
@ -2450,6 +2457,9 @@ EditorBase::FindBetterInsertionPoint(nsCOMPtr<nsINode>& aNode,
NS_ENSURE_TRUE_VOID(node->Length() <= INT32_MAX);
aNode = child;
aOffset = static_cast<int32_t>(aNode->Length());
if (aSelChild) {
*aSelChild = nullptr;
}
return;
}
child = child->GetPreviousSibling();
@ -2467,10 +2477,16 @@ EditorBase::FindBetterInsertionPoint(nsCOMPtr<nsINode>& aNode,
NS_ENSURE_TRUE_VOID(node->Length() <= INT32_MAX);
aNode = node->GetPreviousSibling();
aOffset = static_cast<int32_t>(aNode->Length());
if (aSelChild) {
*aSelChild = nullptr;
}
return;
}
if (node->GetParentNode() && node->GetParentNode() == root) {
if (aSelChild) {
*aSelChild = node->AsContent();
}
aNode = node->GetParentNode();
aOffset = 0;
return;
@ -2481,6 +2497,7 @@ EditorBase::FindBetterInsertionPoint(nsCOMPtr<nsINode>& aNode,
nsresult
EditorBase::InsertTextImpl(const nsAString& aStringToInsert,
nsCOMPtr<nsINode>* aInOutNode,
nsCOMPtr<nsIContent>* aInOutChildAtOffset,
int32_t* aInOutOffset,
nsIDocument* aDoc)
{
@ -2502,15 +2519,17 @@ EditorBase::InsertTextImpl(const nsAString& aStringToInsert,
nsCOMPtr<nsINode> node = *aInOutNode;
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
// element. Let's try to look for better insertion point in the nearest
// text node if there is.
FindBetterInsertionPoint(node, offset);
FindBetterInsertionPoint(node, offset, address_of(child));
// If a neighboring text node already exists, use that
if (!node->IsNodeOfType(nsINode::eTEXT)) {
nsIContent* child = node->GetChildAt(offset);
if (offset && child && child->GetPreviousSibling() &&
child->GetPreviousSibling()->IsNodeOfType(nsINode::eTEXT)) {
node = child->GetPreviousSibling();
@ -2566,6 +2585,7 @@ EditorBase::InsertTextImpl(const nsAString& aStringToInsert,
*aInOutNode = node;
*aInOutOffset = offset;
*aInOutChildAtOffset = nullptr;
return NS_OK;
}
@ -3278,6 +3298,7 @@ EditorBase::GetLengthOfDOMNode(nsIDOMNode* aNode,
nsIContent*
EditorBase::GetPriorNode(nsINode* aParentNode,
int32_t aOffset,
nsINode* aChildAtOffset,
bool aEditableNode,
bool aNoBlockCrossing)
{
@ -3294,8 +3315,8 @@ EditorBase::GetPriorNode(nsINode* aParentNode,
}
// else look before the child at 'aOffset'
if (nsIContent* child = aParentNode->GetChildAt(aOffset)) {
return GetPriorNode(child, aEditableNode, aNoBlockCrossing);
if (aChildAtOffset) {
return GetPriorNode(aChildAtOffset, aEditableNode, aNoBlockCrossing);
}
// 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*
EditorBase::GetNextNode(nsINode* aParentNode,
int32_t aOffset,
nsINode* aChildAtOffset,
bool aEditableNode,
bool aNoBlockCrossing)
{
@ -3326,15 +3348,16 @@ EditorBase::GetNextNode(nsINode* aParentNode,
}
// look at the child at 'aOffset'
nsIContent* child = aParentNode->GetChildAt(aOffset);
if (child) {
if (aNoBlockCrossing && IsBlockNode(child)) {
return child;
if (aChildAtOffset) {
if (aNoBlockCrossing && IsBlockNode(aChildAtOffset)) {
MOZ_ASSERT(aChildAtOffset->IsContent());
return aChildAtOffset->AsContent();
}
nsIContent* resultNode = GetLeftmostChild(child, aNoBlockCrossing);
nsIContent* resultNode = GetLeftmostChild(aChildAtOffset, aNoBlockCrossing);
if (!resultNode) {
return child;
MOZ_ASSERT(aChildAtOffset->IsContent());
return aChildAtOffset->AsContent();
}
if (!IsDescendantOfEditorRoot(resultNode)) {
@ -4078,8 +4101,12 @@ EditorBase::JoinNodeDeep(nsIContent& aLeftNode,
// Get new left and right nodes, and begin anew
parentNode = rightNodeToJoin;
leftNodeToJoin = parentNode->GetChildAt(length - 1);
rightNodeToJoin = parentNode->GetChildAt(length);
if (rightNodeToJoin) {
leftNodeToJoin = rightNodeToJoin->GetPreviousSibling();
} else {
leftNodeToJoin = nullptr;
}
// Skip over non-editable nodes
while (leftNodeToJoin && !IsEditable(leftNodeToJoin)) {
@ -4540,6 +4567,7 @@ EditorBase::CreateTxnForDeleteRange(nsRange* aRangeToDelete,
return nullptr;
}
nsIContent* child = aRangeToDelete->GetChildAtStartOffset();
int32_t offset = aRangeToDelete->StartOffset();
// 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
nsCOMPtr<nsINode> selectedNode;
if (aAction == ePrevious) {
selectedNode = GetPriorNode(node, offset, true);
selectedNode = GetPriorNode(node, offset, child, true);
} else if (aAction == eNext) {
selectedNode = GetNextNode(node, offset, true);
selectedNode = GetNextNode(node, offset, child, true);
}
while (selectedNode &&
@ -4958,7 +4986,7 @@ EditorBase::InitializeSelection(nsIDOMEventTarget* aFocusEventTarget)
NS_ENSURE_TRUE(firstRange, NS_ERROR_FAILURE);
nsCOMPtr<nsINode> startNode = firstRange->GetStartContainer();
int32_t startOffset = firstRange->StartOffset();
FindBetterInsertionPoint(startNode, startOffset);
FindBetterInsertionPoint(startNode, startOffset, nullptr);
Text* textNode = startNode->GetAsText();
MOZ_ASSERT(textNode,
"There must be text node if mIMETextLength is larger than 0");

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

@ -287,6 +287,7 @@ public:
virtual nsresult InsertTextImpl(const nsAString& aStringToInsert,
nsCOMPtr<nsINode>* aInOutNode,
nsCOMPtr<nsIContent>* aInOutChildAtOffset,
int32_t* aInOutOffset,
nsIDocument* aDoc);
nsresult InsertTextIntoTextNodeImpl(const nsAString& aStringToInsert,
@ -708,6 +709,7 @@ public:
*/
nsIContent* GetPriorNode(nsINode* aParentNode,
int32_t aOffset,
nsINode* aChildAtOffset,
bool aEditableNode,
bool aNoBlockCrossing = false);
@ -730,6 +732,7 @@ public:
*/
nsIContent* GetNextNode(nsINode* aParentNode,
int32_t aOffset,
nsINode* aChildAtOffset,
bool aEditableNode,
bool aNoBlockCrossing = false);
@ -1220,11 +1223,23 @@ public:
/**
* FindBetterInsertionPoint() tries to look for better insertion point which
* 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,
int32_t& aOffset);
void FindBetterInsertionPoint(nsCOMPtr<nsINode>& aNode,
int32_t& aOffset);
int32_t& aOffset,
nsCOMPtr<nsIContent>* aSelChild);
/**
* HideCaret() hides caret with nsCaret::AddForceHide() or may show carent

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

@ -854,6 +854,7 @@ HTMLEditRules::GetAlignment(bool* aMixed,
selection->GetRangeAt(0)->GetStartContainer());
OwningNonNull<nsINode> parent =
*selection->GetRangeAt(0)->GetStartContainer();
nsIContent* child = selection->GetRangeAt(0)->GetChildAtStartOffset();
int32_t offset = selection->GetRangeAt(0)->StartOffset();
// Is the selection collapsed?
@ -865,7 +866,7 @@ HTMLEditRules::GetAlignment(bool* aMixed,
nodeToExamine = parent;
} else if (parent->IsHTMLElement(nsGkAtoms::html) && offset == rootOffset) {
// 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 {
nsTArray<RefPtr<nsRange>> arrayOfRanges;
GetPromotedRanges(selection, arrayOfRanges, EditAction::align);
@ -1219,11 +1220,13 @@ HTMLEditRules::WillInsert(Selection& aSelection,
aSelection.GetRangeAt(0)->GetStartContainer());
OwningNonNull<nsINode> selNode =
*aSelection.GetRangeAt(0)->GetStartContainer();
nsIContent* selChild = aSelection.GetRangeAt(0)->GetChildAtStartOffset();
int32_t selOffset = aSelection.GetRangeAt(0)->StartOffset();
// Get prior node
nsCOMPtr<nsIContent> priorNode = htmlEditor->GetPriorHTMLNode(selNode,
selOffset);
selOffset,
selChild);
if (priorNode && TextEditUtils::IsMozBR(priorNode)) {
nsCOMPtr<Element> block1 = htmlEditor->GetBlock(selNode);
nsCOMPtr<Element> block2 = htmlEditor->GetBlockNodeParent(priorNode);
@ -1296,6 +1299,8 @@ HTMLEditRules::WillInsertText(EditAction aAction,
NS_ENSURE_STATE(mHTMLEditor);
NS_ENSURE_STATE(aSelection->GetRangeAt(0));
nsCOMPtr<nsINode> selNode = aSelection->GetRangeAt(0)->GetStartContainer();
nsCOMPtr<nsIContent> selChild =
aSelection->GetRangeAt(0)->GetChildAtStartOffset();
int32_t selOffset = aSelection->GetRangeAt(0)->StartOffset();
NS_ENSURE_STATE(selNode);
@ -1320,13 +1325,15 @@ HTMLEditRules::WillInsertText(EditAction aAction,
}
if (inString->IsEmpty()) {
rv = mHTMLEditor->InsertTextImpl(*inString, address_of(selNode),
address_of(selChild),
&selOffset, doc);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
} else {
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))) {
return rv;
}
@ -1398,6 +1405,7 @@ HTMLEditRules::WillInsertText(EditAction aAction,
} else {
NS_ENSURE_STATE(mHTMLEditor);
rv = mHTMLEditor->InsertTextImpl(subStr, address_of(curNode),
address_of(selChild),
&curOffset, doc);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -1430,7 +1438,8 @@ HTMLEditRules::WillInsertText(EditAction aAction,
// is it a tab?
if (subStr.Equals(tabStr)) {
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);
pos++;
}
@ -1441,8 +1450,10 @@ HTMLEditRules::WillInsertText(EditAction aAction,
nsIEditor::eNone);
NS_ENSURE_TRUE(br, NS_ERROR_FAILURE);
pos++;
selChild = br->GetNextSibling();;
} 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);
}
}
@ -1533,6 +1544,7 @@ HTMLEditRules::WillInsertBreak(Selection& aSelection,
aSelection.GetRangeAt(0)->GetStartContainer(),
NS_ERROR_FAILURE);
OwningNonNull<nsINode> node = *aSelection.GetRangeAt(0)->GetStartContainer();
nsIContent* child = aSelection.GetRangeAt(0)->GetChildAtStartOffset();
int32_t offset = aSelection.GetRangeAt(0)->StartOffset();
// Do nothing if the node is read-only
@ -1585,6 +1597,7 @@ HTMLEditRules::WillInsertBreak(Selection& aSelection,
return NS_ERROR_FAILURE;
}
node = *aSelection.GetRangeAt(0)->GetStartContainer();
child = aSelection.GetRangeAt(0)->GetChildAtStartOffset();
offset = aSelection.GetRangeAt(0)->StartOffset();
blockParent = mHTMLEditor->GetBlock(node);
@ -1638,8 +1651,8 @@ HTMLEditRules::WillInsertBreak(Selection& aSelection,
blockParent->IsAnyOfHTMLElements(nsGkAtoms::p, nsGkAtoms::div))) {
// Paragraphs: special rules to look for <br>s
nsresult rv =
ReturnInParagraph(&aSelection, GetAsDOMNode(blockParent),
GetAsDOMNode(node), offset, aCancel, aHandled);
ReturnInParagraph(&aSelection, blockParent, node,
offset, child, aCancel, aHandled);
NS_ENSURE_SUCCESS(rv, rv);
// Fall through, we may not have handled it in ReturnInParagraph()
}
@ -3596,6 +3609,7 @@ HTMLEditRules::MakeBasicBlock(Selection& aSelection, nsAtom& blockType)
aSelection.GetRangeAt(0)->GetStartContainer());
OwningNonNull<nsINode> container =
*aSelection.GetRangeAt(0)->GetStartContainer();
nsIContent* child = aSelection.GetRangeAt(0)->GetChildAtStartOffset();
int32_t offset = aSelection.GetRangeAt(0)->StartOffset();
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,
// which is visually bad.
nsCOMPtr<nsIContent> brNode =
htmlEditor->GetNextHTMLNode(container, offset);
htmlEditor->GetNextHTMLNode(container, offset, child);
if (brNode && brNode->IsHTMLElement(nsGkAtoms::br)) {
rv = htmlEditor->DeleteNode(brNode);
NS_ENSURE_SUCCESS(rv, rv);
@ -3631,7 +3645,7 @@ HTMLEditRules::MakeBasicBlock(Selection& aSelection, nsAtom& blockType)
} else {
// We are making a block. Consume a br, if needed.
nsCOMPtr<nsIContent> brNode =
htmlEditor->GetNextHTMLNode(container, offset, true);
htmlEditor->GetNextHTMLNode(container, offset, child, true);
if (brNode && brNode->IsHTMLElement(nsGkAtoms::br)) {
rv = htmlEditor->DeleteNode(brNode);
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
// creating extra lines, if possible.
nsCOMPtr<nsIContent> brContent =
htmlEditor->GetNextHTMLNode(parent, offset);
htmlEditor->GetNextHTMLNode(parent, offset, child);
if (brContent && TextEditUtils::IsBreak(brContent)) {
// 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
@ -5042,8 +5056,9 @@ HTMLEditRules::CheckForEmptyBlock(nsINode* aStartNode,
if (aAction == nsIEditor::eNext || aAction == nsIEditor::eNextWord ||
aAction == nsIEditor::eToEndOfLine) {
// Move to the start of the next node, if any
nsCOMPtr<nsIContent> nextNode = htmlEditor->GetNextNode(blockParent,
offset + 1, true);
nsINode* child = emptyBlock->GetNextSibling();
nsCOMPtr<nsIContent> nextNode =
htmlEditor->GetNextNode(blockParent, offset + 1, child, true);
if (nextNode) {
EditorDOMPoint pt = GetGoodSelPointForNode(*nextNode, aAction);
nsresult rv = aSelection->Collapse(pt.node, pt.offset);
@ -5059,6 +5074,7 @@ HTMLEditRules::CheckForEmptyBlock(nsINode* aStartNode,
// Move to the end of the previous node
nsCOMPtr<nsIContent> priorNode = htmlEditor->GetPriorNode(blockParent,
offset,
emptyBlock,
true);
if (priorNode) {
EditorDOMPoint pt = GetGoodSelPointForNode(*priorNode, aAction);
@ -5318,6 +5334,8 @@ HTMLEditRules::NormalizeSelection(Selection* inSelection)
if (NS_WARN_IF(!endNode)) {
return NS_ERROR_FAILURE;
}
nsIContent* startChild = range->GetChildAtStartOffset();
nsIContent* endChild = range->GetChildAtEndOffset();
uint32_t startOffset = range->StartOffset();
uint32_t endOffset = range->EndOffset();
@ -5355,7 +5373,8 @@ HTMLEditRules::NormalizeSelection(Selection* inSelection)
} else if (wsEndObj.mStartReason == WSType::thisBlock) {
// endpoint is just after start of this block
nsINode* child =
htmlEditor->GetPriorHTMLNode(endNode, static_cast<int32_t>(endOffset));
htmlEditor->GetPriorHTMLNode(endNode, static_cast<int32_t>(endOffset),
endChild);
if (child) {
int32_t offset = -1;
newEndNode = EditorBase::GetNodeLocation(child, &offset);
@ -5397,7 +5416,8 @@ HTMLEditRules::NormalizeSelection(Selection* inSelection)
// startpoint is just before end of this block
nsINode* child =
htmlEditor->GetNextHTMLNode(startNode,
static_cast<int32_t>(startOffset));
static_cast<int32_t>(startOffset),
startChild);
if (child) {
int32_t offset = -1;
newStartNode = EditorBase::GetNodeLocation(child, &offset);
@ -5493,6 +5513,7 @@ HTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere,
}
nsCOMPtr<nsINode> node = &aNode;
nsINode* child = node->GetChildAt(aOffset);
int32_t offset = aOffset;
// 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);
}
offset = node->GetParentNode()->IndexOf(node);
child = node;
node = node->GetParentNode();
}
// look back through any further inline nodes that aren't across a <br>
// from us, and that are enclosed in the same block.
nsCOMPtr<nsINode> priorNode =
htmlEditor->GetPriorHTMLNode(node, offset, true);
htmlEditor->GetPriorHTMLNode(node, offset, child, true);
while (priorNode && priorNode->GetParentNode() &&
!htmlEditor->IsVisibleBRElement(priorNode) &&
!IsBlockNode(*priorNode)) {
offset = priorNode->GetParentNode()->IndexOf(priorNode);
child = node;
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
// we are the first node in the container, and as long as we haven't hit
// the body node.
nsCOMPtr<nsIContent> nearNode =
htmlEditor->GetPriorHTMLNode(node, offset, true);
htmlEditor->GetPriorHTMLNode(node, offset, child, true);
while (!nearNode && !node->IsHTMLElement(nsGkAtoms::body) &&
node->GetParentNode()) {
// some cutoffs are here: we don't need to also include them in the
@ -5554,9 +5577,10 @@ HTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere,
break;
}
child = node;
node = parent;
offset = parentOffset;
nearNode = htmlEditor->GetPriorHTMLNode(node, offset, true);
nearNode = htmlEditor->GetPriorHTMLNode(node, offset, child, true);
}
return EditorDOMPoint(node, offset);
}
@ -5570,16 +5594,18 @@ HTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere,
}
// want to be after the text node
offset = 1 + node->GetParentNode()->IndexOf(node);
child = node;
node = node->GetParentNode();
}
// look ahead through any further inline nodes that aren't across a <br> from
// us, and that are enclosed in the same block.
nsCOMPtr<nsIContent> nextNode =
htmlEditor->GetNextHTMLNode(node, offset, true);
htmlEditor->GetNextHTMLNode(node, offset, child, true);
while (nextNode && !IsBlockNode(*nextNode) && nextNode->GetParentNode()) {
offset = 1 + nextNode->GetParentNode()->IndexOf(nextNode);
child = nextNode->GetNextSibling();
node = nextNode->GetParentNode();
if (htmlEditor->IsVisibleBRElement(nextNode)) {
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
// are the last node in the container, and as long as we haven't hit the body
// node.
nsCOMPtr<nsIContent> nearNode =
htmlEditor->GetNextHTMLNode(node, offset, true);
htmlEditor->GetNextHTMLNode(node, offset, child, true);
while (!nearNode && !node->IsHTMLElement(nsGkAtoms::body) &&
node->GetParentNode()) {
int32_t parentOffset = node->GetParentNode()->IndexOf(node);
@ -5623,10 +5649,11 @@ HTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere,
break;
}
child = node->GetNextSibling();
node = parent;
// we want to be AFTER nearNode
offset = parentOffset + 1;
nearNode = htmlEditor->GetNextHTMLNode(node, offset, true);
nearNode = htmlEditor->GetNextHTMLNode(node, offset, child, true);
}
return EditorDOMPoint(node, offset);
}
@ -6440,9 +6467,10 @@ HTMLEditRules::ReturnInHeader(Selection& aSelection,
*/
nsresult
HTMLEditRules::ReturnInParagraph(Selection* aSelection,
nsIDOMNode* aPara,
nsIDOMNode* aNode,
nsINode* aPara,
nsINode* aNode,
int32_t aOffset,
nsIContent* aChildAtOffset,
bool* aCancel,
bool* aHandled)
{
@ -6462,7 +6490,7 @@ HTMLEditRules::ReturnInParagraph(Selection* aSelection,
bool newBRneeded = false;
bool newSelNode = false;
nsCOMPtr<nsIContent> sibling;
nsCOMPtr<nsIDOMNode> selNode = aNode;
nsCOMPtr<nsIDOMNode> selNode = GetAsDOMNode(aNode);
int32_t selOffset = aOffset;
NS_ENSURE_STATE(mHTMLEditor);
@ -6500,7 +6528,7 @@ HTMLEditRules::ReturnInParagraph(Selection* aSelection,
return NS_ERROR_UNEXPECTED;
}
nsresult rv =
mHTMLEditor->SplitNode(aNode, aOffset, getter_AddRefs(tmp));
mHTMLEditor->SplitNode(selNode, aOffset, getter_AddRefs(tmp));
NS_ENSURE_SUCCESS(rv, rv);
selNode = tmp;
}
@ -6513,13 +6541,13 @@ HTMLEditRules::ReturnInParagraph(Selection* aSelection,
// is there a BR prior to it?
nsCOMPtr<nsIContent> nearNode;
NS_ENSURE_STATE(mHTMLEditor);
nearNode = mHTMLEditor->GetPriorHTMLNode(node, aOffset);
nearNode = mHTMLEditor->GetPriorHTMLNode(node, aOffset, aChildAtOffset);
NS_ENSURE_STATE(mHTMLEditor);
if (!nearNode || !mHTMLEditor->IsVisibleBRElement(nearNode) ||
TextEditUtils::HasMozAttr(GetAsDOMNode(nearNode))) {
// is there a BR after it?
NS_ENSURE_STATE(mHTMLEditor);
nearNode = mHTMLEditor->GetNextHTMLNode(node, aOffset);
nearNode = mHTMLEditor->GetNextHTMLNode(node, aOffset, aChildAtOffset);
NS_ENSURE_STATE(mHTMLEditor);
if (!nearNode || !mHTMLEditor->IsVisibleBRElement(nearNode) ||
TextEditUtils::HasMozAttr(GetAsDOMNode(nearNode))) {
@ -6546,7 +6574,8 @@ HTMLEditRules::ReturnInParagraph(Selection* aSelection,
}
}
*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
// the other conditionals.
nsCOMPtr<nsIContent> node =
htmlEditor->GetPriorHTMLNode(selNode, selOffset, true);
htmlEditor->GetPriorHTMLNode(selNode, selOffset, child, true);
if (node && node->IsHTMLElement(nsGkAtoms::br)) {
aSelection.SetInterlinePosition(true);
return;
@ -7537,12 +7566,14 @@ HTMLEditRules::AdjustSelection(Selection* aSelection,
EditorBase::GetStartNodeAndOffset(aSelection,
getter_AddRefs(selNode), &selOffset);
NS_ENSURE_SUCCESS(rv, rv);
nsINode* child = aSelection->GetRangeAt(0)->GetChildAtStartOffset();
temp = selNode;
// are we in an editable node?
NS_ENSURE_STATE(mHTMLEditor);
while (!mHTMLEditor->IsEditable(selNode)) {
// scan up the tree until we find an editable place to be
child = temp;
selNode = EditorBase::GetNodeLocation(temp, &selOffset);
NS_ENSURE_TRUE(selNode, NS_ERROR_FAILURE);
temp = selNode;
@ -7589,7 +7620,7 @@ HTMLEditRules::AdjustSelection(Selection* aSelection,
NS_ENSURE_STATE(mHTMLEditor);
nsCOMPtr<nsIContent> nearNode =
mHTMLEditor->GetPriorHTMLNode(selNode, selOffset);
mHTMLEditor->GetPriorHTMLNode(selNode, selOffset, child);
if (nearNode) {
// is nearNode also a descendant of same block?
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?
NS_ENSURE_STATE(mHTMLEditor);
nearNode = mHTMLEditor->GetPriorHTMLNode(selNode, selOffset, true);
nearNode = mHTMLEditor->GetPriorHTMLNode(selNode, selOffset, child, true);
if (nearNode && (TextEditUtils::IsBreak(nearNode) ||
EditorBase::IsTextNode(nearNode) ||
HTMLEditUtils::IsImage(nearNode) ||
@ -7637,7 +7668,7 @@ HTMLEditRules::AdjustSelection(Selection* aSelection,
return NS_OK;
}
NS_ENSURE_STATE(mHTMLEditor);
nearNode = mHTMLEditor->GetNextHTMLNode(selNode, selOffset, true);
nearNode = mHTMLEditor->GetNextHTMLNode(selNode, selOffset, child, true);
if (nearNode && (TextEditUtils::IsBreak(nearNode) ||
EditorBase::IsTextNode(nearNode) ||
nearNode->IsAnyOfHTMLElements(nsGkAtoms::img,
@ -7647,7 +7678,7 @@ HTMLEditRules::AdjustSelection(Selection* aSelection,
// look for a nearby text node.
// prefer the correct direction.
rv = FindNearSelectableNode(selNode, selOffset, aAction,
rv = FindNearSelectableNode(selNode, selOffset, child, aAction,
address_of(nearNode));
NS_ENSURE_SUCCESS(rv, rv);
@ -7666,6 +7697,7 @@ HTMLEditRules::AdjustSelection(Selection* aSelection,
nsresult
HTMLEditRules::FindNearSelectableNode(nsINode* aSelNode,
int32_t aSelOffset,
nsINode* aChildAtOffset,
nsIEditor::EDirection& aDirection,
nsCOMPtr<nsIContent>* outSelectableNode)
{
@ -7675,13 +7707,15 @@ HTMLEditRules::FindNearSelectableNode(nsINode* aSelNode,
nsCOMPtr<nsIContent> nearNode, curNode;
if (aDirection == nsIEditor::ePrevious) {
NS_ENSURE_STATE(mHTMLEditor);
nearNode = mHTMLEditor->GetPriorHTMLNode(aSelNode, aSelOffset);
nearNode = mHTMLEditor->GetPriorHTMLNode(aSelNode, aSelOffset,
aChildAtOffset);
if (NS_WARN_IF(!nearNode)) {
return NS_ERROR_FAILURE;
}
} else {
NS_ENSURE_STATE(mHTMLEditor);
nearNode = mHTMLEditor->GetNextHTMLNode(aSelNode, aSelOffset);
nearNode = mHTMLEditor->GetNextHTMLNode(aSelNode, aSelOffset,
aChildAtOffset);
if (NS_WARN_IF(!nearNode)) {
return NS_ERROR_FAILURE;
}
@ -7697,13 +7731,15 @@ HTMLEditRules::FindNearSelectableNode(nsINode* aSelNode,
if (aDirection == nsIEditor::ePrevious) {
NS_ENSURE_STATE(mHTMLEditor);
nearNode = mHTMLEditor->GetPriorHTMLNode(aSelNode, aSelOffset);
nearNode = mHTMLEditor->GetPriorHTMLNode(aSelNode, aSelOffset,
aChildAtOffset);
if (NS_WARN_IF(!nearNode)) {
return NS_ERROR_FAILURE;
}
} else {
NS_ENSURE_STATE(mHTMLEditor);
nearNode = mHTMLEditor->GetPriorHTMLNode(aSelNode, aSelOffset);
nearNode = mHTMLEditor->GetPriorHTMLNode(aSelNode, aSelOffset,
aChildAtOffset);
if (NS_WARN_IF(!nearNode)) {
return NS_ERROR_FAILURE;
}

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

@ -289,9 +289,10 @@ protected:
nsAtom& DefaultParagraphSeparator();
nsresult ReturnInHeader(Selection& aSelection, Element& aHeader,
nsINode& aNode, int32_t aOffset);
nsresult ReturnInParagraph(Selection* aSelection, nsIDOMNode* aHeader,
nsIDOMNode* aTextNode, int32_t aOffset,
bool* aCancel, bool* aHandled);
nsresult ReturnInParagraph(Selection* aSelection, nsINode* aHeader,
nsINode* aTextNode, int32_t aOffset,
nsIContent* aChildAtOffset, bool* aCancel,
bool* aHandled);
nsresult SplitParagraph(nsIDOMNode* aPara,
nsIContent* aBRNode,
Selection* aSelection,
@ -399,6 +400,7 @@ protected:
nsIEditor::EDirection aAction);
nsresult FindNearSelectableNode(nsINode* aSelNode,
int32_t aSelOffset,
nsINode* aChildAtOffset,
nsIEditor::EDirection& aDirection,
nsCOMPtr<nsIContent>* outSelectableNode);
/**

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

@ -3118,6 +3118,7 @@ HTMLEditor::DeleteText(nsGenericDOMDataNode& aCharData,
nsresult
HTMLEditor::InsertTextImpl(const nsAString& aStringToInsert,
nsCOMPtr<nsINode>* aInOutNode,
nsCOMPtr<nsIContent>* aInOutChildAtOffset,
int32_t* aInOutOffset,
nsIDocument* aDoc)
{
@ -3126,8 +3127,9 @@ HTMLEditor::InsertTextImpl(const nsAString& aStringToInsert,
return NS_ERROR_FAILURE;
}
return EditorBase::InsertTextImpl(aStringToInsert, aInOutNode, aInOutOffset,
aDoc);
return EditorBase::InsertTextImpl(aStringToInsert, aInOutNode,
aInOutChildAtOffset,
aInOutOffset, aDoc);
}
void
@ -3892,6 +3894,7 @@ HTMLEditor::GetPriorHTMLNode(nsIDOMNode* aNode,
nsIContent*
HTMLEditor::GetPriorHTMLNode(nsINode* aParent,
int32_t aOffset,
nsINode* aChildAtOffset,
bool aNoBlockCrossing)
{
MOZ_ASSERT(aParent);
@ -3900,7 +3903,7 @@ HTMLEditor::GetPriorHTMLNode(nsINode* aParent,
return nullptr;
}
return GetPriorNode(aParent, aOffset, true, aNoBlockCrossing);
return GetPriorNode(aParent, aOffset, aChildAtOffset, true, aNoBlockCrossing);
}
/**
@ -3942,9 +3945,11 @@ HTMLEditor::GetNextHTMLNode(nsIDOMNode* aNode,
nsIContent*
HTMLEditor::GetNextHTMLNode(nsINode* aParent,
int32_t aOffset,
nsINode* aChildAtOffset,
bool aNoBlockCrossing)
{
nsIContent* content = GetNextNode(aParent, aOffset, true, aNoBlockCrossing);
nsIContent* content = GetNextNode(aParent, aOffset, aChildAtOffset,
true, aNoBlockCrossing);
if (content && !IsDescendantOfEditorRoot(content)) {
return nullptr;
}

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

@ -313,6 +313,7 @@ public:
uint32_t aLength);
virtual nsresult InsertTextImpl(const nsAString& aStringToInsert,
nsCOMPtr<nsINode>* aInOutNode,
nsCOMPtr<nsIContent>* aInOutChildAtOffset,
int32_t* aInOutOffset,
nsIDocument* aDoc) override;
NS_IMETHOD_(bool) IsModifiableNode(nsIDOMNode* aNode) override;
@ -779,12 +780,14 @@ protected:
nsresult GetPriorHTMLNode(nsIDOMNode* inNode, nsCOMPtr<nsIDOMNode>* outNode,
bool bNoBlockCrossing = false);
nsIContent* GetPriorHTMLNode(nsINode* aParent, int32_t aOffset,
nsINode* aChildAtOffset,
bool aNoBlockCrossing = false);
nsIContent* GetNextHTMLNode(nsINode* aNode, bool aNoBlockCrossing = false);
nsresult GetNextHTMLNode(nsIDOMNode* inNode, nsCOMPtr<nsIDOMNode>* outNode,
bool bNoBlockCrossing = false);
nsIContent* GetNextHTMLNode(nsINode* aParent, int32_t aOffset,
nsINode* aChildAtOffset,
bool aNoBlockCrossing = false);
bool IsFirstEditableChild(nsINode* aNode);

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

@ -726,6 +726,8 @@ TextEditRules::WillInsertText(EditAction aAction,
// get the (collapsed) selection location
NS_ENSURE_STATE(aSelection->GetRangeAt(0));
nsCOMPtr<nsINode> selNode = aSelection->GetRangeAt(0)->GetStartContainer();
nsCOMPtr<nsIContent> selChild =
aSelection->GetRangeAt(0)->GetChildAtStartOffset();
int32_t selOffset = aSelection->GetRangeAt(0)->StartOffset();
NS_ENSURE_STATE(selNode);
@ -744,7 +746,8 @@ TextEditRules::WillInsertText(EditAction aAction,
if (aAction == EditAction::insertIMEText) {
NS_ENSURE_STATE(mTextEditor);
// 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
// the insertion point.
int32_t IMESelectionOffset =
@ -753,7 +756,7 @@ TextEditRules::WillInsertText(EditAction aAction,
selOffset = IMESelectionOffset;
}
rv = mTextEditor->InsertTextImpl(*outString, address_of(selNode),
&selOffset, doc);
address_of(selChild), &selOffset, doc);
NS_ENSURE_SUCCESS(rv, rv);
} else {
// aAction == EditAction::insertText; find where we are
@ -765,7 +768,7 @@ TextEditRules::WillInsertText(EditAction aAction,
AutoTransactionsConserveSelection dontChangeMySelection(mTextEditor);
rv = mTextEditor->InsertTextImpl(*outString, address_of(curNode),
&curOffset, doc);
address_of(selChild), &curOffset, doc);
NS_ENSURE_SUCCESS(rv, rv);
if (curNode) {

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

@ -551,7 +551,7 @@ TextEditor::ExtendSelectionForDelete(Selection* aSelection,
NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
// node might be anonymous DIV, so we find better text node
FindBetterInsertionPoint(node, offset);
FindBetterInsertionPoint(node, offset, nullptr);
if (IsTextNode(node)) {
const nsTextFragment* data = node->GetAsText()->GetText();
@ -704,6 +704,7 @@ TextEditor::InsertLineBreak()
// get the (collapsed) selection location
NS_ENSURE_STATE(selection->GetRangeAt(0));
nsCOMPtr<nsINode> selNode = selection->GetRangeAt(0)->GetStartContainer();
nsCOMPtr<nsIContent> selChild = selection->GetRangeAt(0)->GetChildAtStartOffset();
int32_t selOffset = selection->GetRangeAt(0)->StartOffset();
NS_ENSURE_STATE(selNode);
@ -722,7 +723,7 @@ TextEditor::InsertLineBreak()
// insert a linefeed character
rv = InsertTextImpl(NS_LITERAL_STRING("\n"), address_of(selNode),
&selOffset, doc);
address_of(selChild), &selOffset, doc);
if (!selNode) {
rv = NS_ERROR_NULL_POINTER; // don't return here, so DidDoAction is called
}

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

@ -234,6 +234,7 @@ WSRunObject::InsertBreak(nsCOMPtr<nsINode>* aInOutParent,
nsresult
WSRunObject::InsertText(const nsAString& aStringToInsert,
nsCOMPtr<nsINode>* aInOutParent,
nsCOMPtr<nsIContent>* aInOutChildAtOffset,
int32_t* aInOutOffset,
nsIDocument* aDoc)
{
@ -356,7 +357,8 @@ WSRunObject::InsertText(const nsAString& aStringToInsert,
}
// Ready, aim, fire!
mHTMLEditor->InsertTextImpl(theString, aInOutParent, aInOutOffset, aDoc);
mHTMLEditor->InsertTextImpl(theString, aInOutParent, aInOutChildAtOffset,
aInOutOffset, aDoc);
return NS_OK;
}

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

@ -224,6 +224,7 @@ public:
// trailingws before {aInOutParent,aInOutOffset} needs to be removed.
nsresult InsertText(const nsAString& aStringToInsert,
nsCOMPtr<nsINode>* aInOutNode,
nsCOMPtr<nsIContent>* aInOutChildAtOffset,
int32_t* aInOutOffset,
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 1381541.html
load 1383755.html
load 1388075.html
load 1402469.html
load 1402904.html
load 1405747.html

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

@ -174,7 +174,6 @@ struct TextureFactoryIdentifier
bool mSupportsTextureBlitting;
bool mSupportsPartialUploads;
bool mSupportsComponentAlpha;
bool mSupportsBackdropCopyForComponentAlpha;
bool mUsingAdvancedLayers;
SyncHandle mSyncHandle;
@ -193,7 +192,6 @@ struct TextureFactoryIdentifier
, mSupportsTextureBlitting(aSupportsTextureBlitting)
, mSupportsPartialUploads(aSupportsPartialUploads)
, mSupportsComponentAlpha(aSupportsComponentAlpha)
, mSupportsBackdropCopyForComponentAlpha(true)
, mUsingAdvancedLayers(false)
, mSyncHandle(aSyncHandle)
{}

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

@ -1352,8 +1352,7 @@ ContainerLayer::DefaultComputeSupportsComponentAlphaChildren(bool* aNeedsSurface
if (HasOpaqueAncestorLayer(this) &&
GetEffectiveTransform().Is2D(&transform) &&
!gfx::ThebesMatrix(transform).HasNonIntegerTranslation() &&
blendMode == gfx::CompositionOp::OP_OVER &&
Manager()->SupportsBackdropCopyForComponentAlpha())
blendMode == gfx::CompositionOp::OP_OVER)
{
mSupportsComponentAlphaChildren = true;
needsSurfaceCopy = true;

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

@ -360,12 +360,6 @@ public:
*/
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
* Set the root layer. The root layer is initially null. If there is

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

@ -825,13 +825,6 @@ ClientLayerManager::AreComponentAlphaLayersEnabled()
LayerManager::AreComponentAlphaLayersEnabled();
}
bool
ClientLayerManager::SupportsBackdropCopyForComponentAlpha()
{
const TextureFactoryIdentifier& ident = AsShadowForwarder()->GetTextureFactoryIdentifier();
return ident.mSupportsBackdropCopyForComponentAlpha;
}
void
ClientLayerManager::SetIsFirstPaint()
{

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

@ -201,7 +201,6 @@ public:
const mozilla::TimeStamp& aCompositeEnd) override;
virtual bool AreComponentAlphaLayersEnabled() override;
virtual bool SupportsBackdropCopyForComponentAlpha() override;
// Log APZ test data for the current paint. We supply the paint sequence
// number ourselves, and take care of calling APZTestData::StartNewPaint()

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

@ -29,6 +29,7 @@
#include "mozilla/gfx/GPUProcessManager.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/mozalloc.h" // for operator new, etc
#include "mozilla/Telemetry.h"
#include "nsAutoPtr.h"
#include "nsDebug.h" // for NS_RUNTIMEABORT
#include "nsIObserver.h" // for nsIObserver
@ -94,6 +95,8 @@ CompositorBridgeChild::CompositorBridgeChild(CompositorManagerChild *aManager)
, mOutstandingAsyncPaints(0)
, mOutstandingAsyncEndTransaction(false)
, mIsWaitingForPaint(false)
, mSlowFlushCount(0)
, mTotalFlushCount(0)
{
MOZ_ASSERT(NS_IsMainThread());
}
@ -1154,6 +1157,12 @@ CompositorBridgeChild::FlushAsyncPaints()
{
MOZ_ASSERT(NS_IsMainThread());
Maybe<TimeStamp> start;
if (XRE_IsContentProcess() && gfx::gfxVars::UseOMTP()) {
start = Some(TimeStamp::Now());
}
{
MonitorAutoLock lock(mPaintLock);
while (mIsWaitingForPaint) {
lock.Wait();
@ -1161,6 +1170,22 @@ CompositorBridgeChild::FlushAsyncPaints()
// It's now safe to free any TextureClients that were used during painting.
mTextureClientsForAsyncPaint.Clear();
}
if (start) {
float ms = (TimeStamp::Now() - start.value()).ToMilliseconds();
// Anything above 200us gets recorded.
if (ms >= 0.2) {
mSlowFlushCount++;
Telemetry::Accumulate(Telemetry::GFX_OMTP_PAINT_WAIT_TIME, int32_t(ms));
}
mTotalFlushCount++;
double ratio = double(mSlowFlushCount) / double(mTotalFlushCount);
Telemetry::ScalarSet(Telemetry::ScalarID::GFX_OMTP_PAINT_WAIT_RATIO,
uint32_t(ratio * 100 * 100));
}
}
void

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

@ -388,6 +388,9 @@ private:
// paint thread completes. This is R/W on both the main and paint threads, and
// must be accessed within the paint lock.
bool mIsWaitingForPaint;
uintptr_t mSlowFlushCount;
uintptr_t mTotalFlushCount;
};
} // namespace layers

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

@ -307,7 +307,6 @@ struct ParamTraits<mozilla::layers::TextureFactoryIdentifier>
WriteParam(aMsg, aParam.mSupportsTextureBlitting);
WriteParam(aMsg, aParam.mSupportsPartialUploads);
WriteParam(aMsg, aParam.mSupportsComponentAlpha);
WriteParam(aMsg, aParam.mSupportsBackdropCopyForComponentAlpha);
WriteParam(aMsg, aParam.mUsingAdvancedLayers);
WriteParam(aMsg, aParam.mSyncHandle);
}
@ -321,7 +320,6 @@ struct ParamTraits<mozilla::layers::TextureFactoryIdentifier>
ReadParam(aMsg, aIter, &aResult->mSupportsTextureBlitting) &&
ReadParam(aMsg, aIter, &aResult->mSupportsPartialUploads) &&
ReadParam(aMsg, aIter, &aResult->mSupportsComponentAlpha) &&
ReadParam(aMsg, aIter, &aResult->mSupportsBackdropCopyForComponentAlpha) &&
ReadParam(aMsg, aIter, &aResult->mUsingAdvancedLayers) &&
ReadParam(aMsg, aIter, &aResult->mSyncHandle);
return result;

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

@ -21,7 +21,8 @@ using namespace gfx;
ContainerLayerMLGPU::ContainerLayerMLGPU(LayerManagerMLGPU* aManager)
: ContainerLayer(aManager, nullptr),
LayerMLGPU(aManager),
mInvalidateEntireSurface(false)
mInvalidateEntireSurface(false),
mSurfaceCopyNeeded(false)
{
}
@ -35,6 +36,8 @@ ContainerLayerMLGPU::~ContainerLayerMLGPU()
bool
ContainerLayerMLGPU::OnPrepareToRender(FrameBuilder* aBuilder)
{
mView = nullptr;
if (!UseIntermediateSurface()) {
// Set this so we invalidate the entire cached render target (if any)
// if our container uses an intermediate surface again later.
@ -67,6 +70,19 @@ ContainerLayerMLGPU::OnPrepareToRender(FrameBuilder* aBuilder)
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);
if (!mRenderTarget ||
!gfxPrefs::AdvancedLayersUseInvalidation() ||

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

@ -13,6 +13,7 @@ namespace mozilla {
namespace layers {
class MLGDevice;
class RenderViewMLGPU;
class ContainerLayerMLGPU final : public ContainerLayer
, public LayerMLGPU
@ -53,6 +54,17 @@ public:
mInvalidRect.SetEmpty();
}
bool IsContentOpaque() override;
bool NeedsSurfaceCopy() const {
return mSurfaceCopyNeeded;
}
RenderViewMLGPU* GetRenderView() const {
return mView;
}
void SetRenderView(RenderViewMLGPU* aView) {
MOZ_ASSERT(!mView);
mView = aView;
}
protected:
bool OnPrepareToRender(FrameBuilder* aBuilder) override;
@ -71,6 +83,11 @@ private:
// is in layer coordinates.
gfx::IntRect mInvalidRect;
bool mInvalidateEntireSurface;
bool mSurfaceCopyNeeded;
// This is only valid for intermediate surfaces while an instance of
// FrameBuilder is live.
RenderViewMLGPU* mView;
};
} // namespace layers

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

@ -183,7 +183,6 @@ LayerManagerMLGPU::GetTextureFactoryIdentifier()
if (mDevice) {
ident = mDevice->GetTextureFactoryIdentifier();
}
ident.mSupportsBackdropCopyForComponentAlpha = SupportsBackdropCopyForComponentAlpha();
ident.mUsingAdvancedLayers = true;
return ident;
}
@ -525,12 +524,6 @@ LayerManagerMLGPU::BlendingRequiresIntermediateSurface()
return true;
}
bool
LayerManagerMLGPU::SupportsBackdropCopyForComponentAlpha()
{
return false;
}
void
LayerManagerMLGPU::EndTransaction(DrawPaintedLayerCallback aCallback,
void* aCallbackData,

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

@ -50,7 +50,6 @@ public:
bool AreComponentAlphaLayersEnabled() override;
bool BlendingRequiresIntermediateSurface() override;
bool SupportsBackdropCopyForComponentAlpha() override;
// HostLayerManager methods
void ForcePresent() override;

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

@ -305,6 +305,11 @@ ShaderRenderPass::ExecuteRendering()
return;
}
// Change the blend state if needed.
if (Maybe<MLGBlendState> blendState = GetBlendState()) {
mDevice->SetBlendState(blendState.value());
}
mDevice->SetPSConstantBuffer(0, &mPSBuffer0);
if (MaskOperation* mask = GetMask()) {
mDevice->SetPSTexture(kMaskLayerTextureSlot, mask->GetTexture());
@ -994,5 +999,48 @@ RenderViewPass::SetupPipeline()
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 mozilla

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

@ -464,8 +464,10 @@ private:
bool AddToPass(LayerMLGPU* aItem, ItemInfo& aInfo) override;
void SetupPipeline() override;
bool OnPrepareBuffers() override;
void ExecuteRendering() override;
float GetOpacity() const override;
bool PrepareBlendState();
void RenderWithBackdropCopy();
private:
ConstantBufferSection mBlendConstants;

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

@ -62,6 +62,8 @@ RenderViewMLGPU::RenderViewMLGPU(FrameBuilder* aBuilder,
this,
aContainer->GetLayer(),
Stringify(mInvalidBounds).c_str());
mContainer->SetRenderView(this);
}
RenderViewMLGPU::RenderViewMLGPU(FrameBuilder* aBuilder, RenderViewMLGPU* aParent)
@ -72,6 +74,7 @@ RenderViewMLGPU::RenderViewMLGPU(FrameBuilder* aBuilder, RenderViewMLGPU* aParen
mFinishedBuilding(false),
mCurrentLayerBufferIndex(kInvalidResourceIndex),
mCurrentMaskRectBufferIndex(kInvalidResourceIndex),
mCurrentDepthMode(MLGDepthTestMode::Disabled),
mNextSortIndex(1),
mUseDepthBuffer(gfxPrefs::AdvancedLayersEnableDepthBuffer()),
mDepthBufferNeedsClear(false)
@ -111,11 +114,23 @@ RenderViewMLGPU::AddChild(RenderViewMLGPU* aParent)
void
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) {
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();
}
@ -385,26 +400,19 @@ RenderViewMLGPU::ExecuteRendering()
if (!mTarget) {
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()) {
gfxWarning() << "Failed to allocate constant buffer for world transform";
return;
}
mDevice->SetVSConstantBuffer(kWorldConstantBufferSlot, &mWorldConstants);
SetDeviceState();
// If using the depth buffer, clear it (if needed) and enable writes.
if (mUseDepthBuffer) {
if (mDepthBufferNeedsClear) {
mDevice->ClearDepthBuffer(mTarget);
}
mDevice->SetDepthTestMode(MLGDepthTestMode::Write);
SetDepthTestMode(MLGDepthTestMode::Write);
}
// Opaque items, rendered front-to-back.
@ -415,7 +423,7 @@ RenderViewMLGPU::ExecuteRendering()
if (mUseDepthBuffer) {
// From now on we might be rendering transparent pixels, so we disable
// writing to the z-buffer.
mDevice->SetDepthTestMode(MLGDepthTestMode::ReadOnly);
SetDepthTestMode(MLGDepthTestMode::ReadOnly);
}
// Clear any pixels that are not occluded, and therefore might require
@ -466,14 +474,37 @@ RenderViewMLGPU::ExecutePass(RenderPassMLGPU* aPass)
mDevice->SetVSConstantBuffer(kMaskBufferSlot, &section);
}
// Change the blend state if needed.
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
RenderViewMLGPU::PrepareDepthBuffer()
{
@ -514,6 +545,11 @@ RenderViewMLGPU::PrepareDepthBuffer()
void
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
// 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.

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

@ -52,6 +52,11 @@ public:
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
// building, since we try to right-size the render target to the visible
// region.
@ -72,6 +77,8 @@ private:
void AddItemBackToFront(LayerMLGPU* aLayer, ItemInfo& aItem);
void PrepareClears();
void SetDeviceState();
void SetDepthTestMode(MLGDepthTestMode aMode);
void ExecutePass(RenderPassMLGPU* aPass);
@ -124,6 +131,9 @@ private:
size_t mCurrentLayerBufferIndex;
size_t mCurrentMaskRectBufferIndex;
// This state is saved locally so it can be restored in RestoreDeviceState.
MLGDepthTestMode mCurrentDepthMode;
// Depth-buffer tracking.
int32_t mNextSortIndex;
bool mUseDepthBuffer;

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

@ -79,11 +79,5 @@ StackingContextHelper::ToRelativeLayoutRect(const LayoutDeviceRect& aRect) const
PixelCastJustification::WebRenderHasUnitResolution) - mOrigin));
}
wr::LayoutPoint
StackingContextHelper::ToRelativeLayoutPoint(const LayerPoint& aPoint) const
{
return wr::ToLayoutPoint(aPoint - mOrigin);
}
} // namespace layers
} // namespace mozilla

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

@ -62,7 +62,11 @@ public:
wr::LayoutRect ToRelativeLayoutRect(const LayerRect& aRect) const;
wr::LayoutRect ToRelativeLayoutRect(const LayoutDeviceRect& aRect) const;
// 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
gfx::Size GetInheritedScale() const { return mScale; }

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

@ -1370,37 +1370,38 @@ js::IdToStringOrSymbol(JSContext* cx, HandleId id, MutableHandleValue result)
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
js::GetOwnPropertyKeys(JSContext* cx, const JS::CallArgs& args, unsigned flags)
{
// Steps 1-2.
// Step 1.
RootedObject obj(cx, ToObject(cx, args.get(0)));
if (!obj)
return false;
// Steps 3-10.
// Steps 2-4.
AutoIdVector keys(cx);
if (!GetPropertyKeys(cx, obj, flags, &keys))
return false;
// Step 11.
AutoValueVector vals(cx);
if (!vals.resize(keys.length()))
// Step 5 (Inlined CreateArrayFromList).
RootedArrayObject array(cx, NewDenseFullyAllocatedArray(cx, keys.length()));
if (!array)
return false;
array->ensureDenseInitializedLength(cx, 0, keys.length());
RootedValue val(cx);
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_SYMBOLSONLY));
if (!IdToStringOrSymbol(cx, keys[i], vals[i]))
if (!IdToStringOrSymbol(cx, keys[i], &val))
return false;
array->initDenseElement(i, val);
}
JSObject* aobj = NewDenseCopiedArray(cx, vals.length(), vals.begin());
if (!aobj)
return false;
args.rval().setObject(*aobj);
args.rval().setObject(*array);
return true;
}

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

@ -1734,9 +1734,9 @@ class ASTSerializer
return StringValue(atom ? atom : cx->names().empty);
}
BinaryOperator binop(ParseNodeKind kind, JSOp op);
UnaryOperator unop(ParseNodeKind kind, JSOp op);
AssignmentOperator aop(JSOp op);
BinaryOperator binop(ParseNodeKind kind);
UnaryOperator unop(ParseNodeKind kind);
AssignmentOperator aop(ParseNodeKind kind);
bool statements(ParseNode* pn, NodeVector& elts);
bool expressions(ParseNode* pn, NodeVector& elts);
@ -1843,34 +1843,34 @@ class ASTSerializer
} /* anonymous namespace */
AssignmentOperator
ASTSerializer::aop(JSOp op)
ASTSerializer::aop(ParseNodeKind kind)
{
switch (op) {
case JSOP_NOP:
switch (kind) {
case PNK_ASSIGN:
return AOP_ASSIGN;
case JSOP_ADD:
case PNK_ADDASSIGN:
return AOP_PLUS;
case JSOP_SUB:
case PNK_SUBASSIGN:
return AOP_MINUS;
case JSOP_MUL:
case PNK_MULASSIGN:
return AOP_STAR;
case JSOP_DIV:
case PNK_DIVASSIGN:
return AOP_DIV;
case JSOP_MOD:
case PNK_MODASSIGN:
return AOP_MOD;
case JSOP_POW:
case PNK_POWASSIGN:
return AOP_POW;
case JSOP_LSH:
case PNK_LSHASSIGN:
return AOP_LSH;
case JSOP_RSH:
case PNK_RSHASSIGN:
return AOP_RSH;
case JSOP_URSH:
case PNK_URSHASSIGN:
return AOP_URSH;
case JSOP_BITOR:
case PNK_BITORASSIGN:
return AOP_BITOR;
case JSOP_BITXOR:
case PNK_BITXORASSIGN:
return AOP_BITXOR;
case JSOP_BITAND:
case PNK_BITANDASSIGN:
return AOP_BITAND;
default:
return AOP_ERR;
@ -1878,7 +1878,7 @@ ASTSerializer::aop(JSOp op)
}
UnaryOperator
ASTSerializer::unop(ParseNodeKind kind, JSOp op)
ASTSerializer::unop(ParseNodeKind kind)
{
if (IsDeleteKind(kind))
return UNOP_DELETE;
@ -1886,19 +1886,18 @@ ASTSerializer::unop(ParseNodeKind kind, JSOp op)
if (IsTypeofKind(kind))
return UNOP_TYPEOF;
if (kind == PNK_AWAIT)
switch (kind) {
case PNK_AWAIT:
return UNOP_AWAIT;
switch (op) {
case JSOP_NEG:
case PNK_NEG:
return UNOP_NEG;
case JSOP_POS:
case PNK_POS:
return UNOP_POS;
case JSOP_NOT:
case PNK_NOT:
return UNOP_NOT;
case JSOP_BITNOT:
case PNK_BITNOT:
return UNOP_BITNOT;
case JSOP_VOID:
case PNK_VOID:
return UNOP_VOID;
default:
return UNOP_ERR;
@ -1906,7 +1905,7 @@ ASTSerializer::unop(ParseNodeKind kind, JSOp op)
}
BinaryOperator
ASTSerializer::binop(ParseNodeKind kind, JSOp op)
ASTSerializer::binop(ParseNodeKind kind)
{
switch (kind) {
case PNK_LSH:
@ -2632,7 +2631,7 @@ ASTSerializer::leftAssociate(ParseNode* pn, MutableHandleValue dst)
if (!builder.logicalExpression(lor, left, right, &subpos, &left))
return false;
} else {
BinaryOperator op = binop(pn->getKind(), pn->getOp());
BinaryOperator op = binop(pn->getKind());
LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
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);
BinaryOperator op = binop(pn->getKind(), pn->getOp());
BinaryOperator op = binop(pn->getKind());
LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
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_right->pn_pos));
AssignmentOperator op = aop(pn->getOp());
AssignmentOperator op = aop(pn->getKind());
LOCAL_ASSERT(op > AOP_ERR && op < AOP_LIMIT);
RootedValue lhs(cx), rhs(cx);
@ -2936,7 +2935,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
case PNK_NEG: {
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);
RootedValue expr(cx);
@ -3486,10 +3485,8 @@ ASTSerializer::functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector&
ParseNode* pnstart = pnbody->pn_head;
// Skip over initial yield in generator.
if (pnstart && pnstart->isKind(PNK_INITIALYIELD)) {
MOZ_ASSERT(pnstart->getOp() == JSOP_INITIALYIELD);
if (pnstart && pnstart->isKind(PNK_INITIALYIELD))
pnstart = pnstart->pn_next;
}
// Async arrow with expression body is converted into STATEMENTLIST
// to insert initial yield.

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

@ -13,6 +13,8 @@
#include "mozilla/Unused.h"
#include <cmath>
#include <cstdlib>
#include <ctime>
#include "jsapi.h"
#include "jscntxt.h"
@ -4737,6 +4739,118 @@ DisableForEach(JSContext* cx, unsigned argc, Value* vp)
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)
static bool
AflLoop(JSContext* cx, unsigned argc, Value* vp)
@ -5414,6 +5528,10 @@ gc::ZealModeHelpText),
"isLegacyIterator(value)",
" 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
};
@ -5432,6 +5550,12 @@ static const JSFunctionSpecWithHelp FuzzingUnsafeTestingFunctions[] = {
"getErrorNotes(error)",
" 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
};

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

@ -6148,6 +6148,7 @@ bool
BytecodeEmitter::emitDeclarationList(ParseNode* declList)
{
MOZ_ASSERT(declList->isArity(PN_LIST));
MOZ_ASSERT(declList->isOp(JSOP_NOP));
ParseNode* next;
for (ParseNode* decl = declList->pn_head; decl; decl = next) {
@ -6226,9 +6227,32 @@ EmitAssignmentRhs(BytecodeEmitter* bce, ParseNode* rhs, uint8_t offset)
return true;
}
bool
BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs)
static inline JSOp
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
// to emit BINDNAME is involved and should avoid duplication.
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.
if (op != JSOP_NOP && !bce->emit1(op))
if (op != JSOP_NOP) {
if (!bce->emit1(op))
return false;
}
return true;
};
@ -6454,7 +6480,7 @@ ParseNode::getConstantValue(JSContext* cx, AllowConstantObjects allowObjects,
count = pn_count - 1;
pn = pn_head->pn_next;
} else {
MOZ_ASSERT(isOp(JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
MOZ_ASSERT(!(pn_xflags & PNX_NONCONST));
count = pn_count;
pn = pn_head;
}
@ -6485,7 +6511,6 @@ ParseNode::getConstantValue(JSContext* cx, AllowConstantObjects allowObjects,
return true;
}
case PNK_OBJECT: {
MOZ_ASSERT(isOp(JSOP_NEWINIT));
MOZ_ASSERT(!(pn_xflags & PNX_NONCONST));
if (allowObjects == DontAllowObjects) {
@ -7137,7 +7162,7 @@ BytecodeEmitter::emitInitializeForInOrOfTarget(ParseNode* forHead)
// initialization is just assigning the iteration value to a target
// expression.
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
// 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
// not in the spec.
if (!emitAssignment(loopVariableName, JSOP_NOP, nullptr)) // ITER VALUE
if (!emitAssignment(loopVariableName, PNK_ASSIGN, nullptr)) // ITER VALUE
return false;
// 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
// also leave it on the stack.
if (!emitAssignment(forHead->pn_kid2, JSOP_NOP, nullptr))
if (!emitAssignment(forHead->pn_kid2, PNK_ASSIGN, nullptr))
return false;
/* The stack should be balanced around the assignment opcode sequence. */
@ -8688,7 +8713,7 @@ bool
BytecodeEmitter::emitYield(ParseNode* pn)
{
MOZ_ASSERT(sc->isFunctionBox());
MOZ_ASSERT(pn->getOp() == JSOP_YIELD);
MOZ_ASSERT(pn->isKind(PNK_YIELD));
bool needsIteratorResult = sc->asFunctionBox()->needsIteratorResult();
if (needsIteratorResult) {
@ -8738,7 +8763,7 @@ bool
BytecodeEmitter::emitAwait(ParseNode* pn)
{
MOZ_ASSERT(sc->isFunctionBox());
MOZ_ASSERT(pn->getOp() == JSOP_AWAIT);
MOZ_ASSERT(pn->isKind(PNK_AWAIT));
if (!emitTree(pn->pn_kid))
return false;
@ -9675,6 +9700,41 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn, ValueUsage valueUsage /* = ValueUs
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
BytecodeEmitter::emitRightAssociative(ParseNode* pn)
{
@ -9702,7 +9762,7 @@ BytecodeEmitter::emitLeftAssociative(ParseNode* pn)
// Left-associative operator chain.
if (!emitTree(pn->pn_head))
return false;
JSOp op = pn->getOp();
JSOp op = BinaryOpParseNodeKindToJSOp(pn->getKind());
ParseNode* nextExpr = pn->pn_head->pn_next;
do {
if (!emitTree(nextExpr))
@ -9717,6 +9777,7 @@ bool
BytecodeEmitter::emitLogical(ParseNode* pn)
{
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
@ -9734,7 +9795,7 @@ BytecodeEmitter::emitLogical(ParseNode* pn)
ParseNode* pn2 = pn->pn_head;
if (!emitTree(pn2))
return false;
JSOp op = pn->getOp();
JSOp op = pn->isKind(PNK_OR) ? JSOP_OR : JSOP_AND;
JumpList jump;
if (!emitJump(op, &jump))
return false;
@ -10237,20 +10298,28 @@ BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count)
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
BytecodeEmitter::emitUnary(ParseNode* pn)
{
if (!updateSourceCoordNotes(pn->pn_pos.begin))
return false;
/* Unary op, including unary +/-. */
JSOp op = pn->getOp();
ParseNode* pn2 = pn->pn_kid;
if (!emitTree(pn2))
if (!emitTree(pn->pn_kid))
return false;
return emit1(op);
return emit1(UnaryOpParseNodeKindToJSOp(pn->getKind()));
}
bool
@ -10973,7 +11042,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
case PNK_DIVASSIGN:
case PNK_MODASSIGN:
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;
break;

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

@ -759,7 +759,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitCallSiteObject(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 emitStatement(ParseNode* pn);

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

@ -97,7 +97,7 @@ class FullParseHandler
ParseNode* newComputedName(ParseNode* expr, uint32_t begin, uint32_t 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) {
@ -181,69 +181,69 @@ class FullParseHandler
ParseNode* newDelete(uint32_t begin, ParseNode* expr) {
if (expr->isKind(PNK_NAME)) {
expr->setOp(JSOP_DELNAME);
return newUnary(PNK_DELETENAME, JSOP_NOP, begin, expr);
return newUnary(PNK_DELETENAME, begin, expr);
}
if (expr->isKind(PNK_DOT))
return newUnary(PNK_DELETEPROP, JSOP_NOP, begin, expr);
return newUnary(PNK_DELETEPROP, begin, expr);
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) {
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);
ParseNodeKind kind = kid->isKind(PNK_NAME) ? PNK_TYPEOFNAME : PNK_TYPEOFEXPR;
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);
return new_<UnaryNode>(kind, pos, kid);
}
ParseNode* newUpdate(ParseNodeKind kind, uint32_t begin, ParseNode* kid) {
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) {
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) {
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,
JSOp op = JSOP_NOP)
{
TokenPos pos(left->pn_pos.begin, right->pn_pos.end);
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,
ParseNode* first, ParseNode* second, ParseNode* third,
JSOp op = JSOP_NOP)
public:
ParseNode* appendOrCreateList(ParseNodeKind kind, ParseNode* left, ParseNode* right,
ParseContext* pc)
{
return new_<TernaryNode>(kind, op, first, second, third);
return ParseNode::appendOrCreateList(kind, left, right, this, pc);
}
// 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) {
MOZ_ASSERT(pos.begin <= body->pn_pos.begin);
MOZ_ASSERT(body->pn_pos.end <= pos.end);
@ -255,11 +255,7 @@ class FullParseHandler
}
ParseNode* newArrayLiteral(uint32_t begin) {
ParseNode* literal = 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;
return new_<ListNode>(PNK_ARRAY, TokenPos(begin, begin + 1));
}
MOZ_MUST_USE bool addElision(ParseNode* literal, const TokenPos& pos) {
@ -287,19 +283,19 @@ class FullParseHandler
}
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) {
return newList(PNK_TAGGED_TEMPLATE, pos, JSOP_CALL);
return new_<ListNode>(PNK_TAGGED_TEMPLATE, JSOP_CALL, pos);
}
ParseNode* newObjectLiteral(uint32_t begin) {
ParseNode* literal = 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;
return new_<ListNode>(PNK_OBJECT, TokenPos(begin, begin + 1));
}
ParseNode* newClass(ParseNode* name, ParseNode* heritage, ParseNode* methodBlock,
@ -320,7 +316,7 @@ class FullParseHandler
return new_<NullaryNode>(PNK_POSHOLDER, 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) {
@ -328,7 +324,7 @@ class FullParseHandler
// singleton objects will have Object.prototype as their [[Prototype]].
setListFlag(literal, PNX_NONCONST);
ParseNode* mutation = newUnary(PNK_MUTATEPROTO, JSOP_NOP, begin, expr);
ParseNode* mutation = newUnary(PNK_MUTATEPROTO, begin, expr);
if (!mutation)
return false;
literal->append(mutation);
@ -378,7 +374,7 @@ class FullParseHandler
}
MOZ_MUST_USE bool addObjectMethodDefinition(ParseNode* literal, ParseNode* key, ParseNode* fn,
JSOp op)
AccessorType atype)
{
MOZ_ASSERT(literal->isArity(PN_LIST));
MOZ_ASSERT(key->isKind(PNK_NUMBER) ||
@ -387,7 +383,7 @@ class FullParseHandler
key->isKind(PNK_COMPUTED_NAME));
literal->pn_xflags |= PNX_NONCONST;
ParseNode* propdef = newBinary(PNK_COLON, key, fn, op);
ParseNode* propdef = newBinary(PNK_COLON, key, fn, AccessorTypeToJSOp(atype));
if (!propdef)
return false;
literal->append(propdef);
@ -395,7 +391,7 @@ class FullParseHandler
}
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(key->isKind(PNK_NUMBER) ||
@ -403,7 +399,7 @@ class FullParseHandler
key->isKind(PNK_STRING) ||
key->isKind(PNK_COMPUTED_NAME));
ParseNode* classMethod = new_<ClassMethod>(key, fn, op, isStatic);
ParseNode* classMethod = new_<ClassMethod>(key, fn, AccessorTypeToJSOp(atype), isStatic);
if (!classMethod)
return false;
methodList->append(classMethod);
@ -412,22 +408,22 @@ class FullParseHandler
ParseNode* newInitialYieldExpression(uint32_t begin, ParseNode* gen) {
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) {
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) {
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) {
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
@ -500,7 +496,7 @@ class FullParseHandler
}
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,
@ -513,8 +509,12 @@ class FullParseHandler
return pn;
}
ParseNode* newImportSpec(ParseNode* importNameNode, ParseNode* bindingName) {
return newBinary(PNK_IMPORT_SPEC, importNameNode, bindingName);
}
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,
@ -532,15 +532,23 @@ class FullParseHandler
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) {
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* elseBranch)
{
ParseNode* pn = new_<TernaryNode>(PNK_IF, JSOP_NOP, cond, thenBranch, elseBranch);
ParseNode* pn = new_<TernaryNode>(PNK_IF, cond, thenBranch, elseBranch);
if (!pn)
return null();
pn->pn_pos.begin = begin;
@ -590,14 +598,14 @@ class FullParseHandler
ParseNode* newForHead(ParseNode* init, ParseNode* test, ParseNode* update,
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,
const TokenPos& pos)
{
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) {
@ -619,11 +627,11 @@ class FullParseHandler
ParseNode* newReturnStatement(ParseNode* expr, const TokenPos& 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) {
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) {
@ -637,13 +645,13 @@ class FullParseHandler
ParseNode* newThrowStatement(ParseNode* expr, const TokenPos& 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* finallyBlock) {
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) {
@ -717,7 +725,7 @@ class FullParseHandler
}
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)
return nullptr;
@ -725,10 +733,8 @@ class FullParseHandler
return newExpr;
}
ParseNode* newAssignment(ParseNodeKind kind, ParseNode* lhs, ParseNode* rhs,
JSOp op)
{
return newBinary(kind, lhs, rhs, op);
ParseNode* newAssignment(ParseNodeKind kind, ParseNode* lhs, ParseNode* rhs) {
return newBinary(kind, lhs, rhs);
}
bool isUnparenthesizedYieldExpression(ParseNode* node) {
@ -800,28 +806,28 @@ class FullParseHandler
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));
return new_<ListNode>(kind, op, pos);
return new_<ListNode>(kind, JSOP_NOP, pos);
}
private:
ParseNode* newList(ParseNodeKind kind, uint32_t begin, JSOp op = JSOP_NOP) {
return newList(kind, TokenPos(begin, begin + 1), op);
ParseNode* newList(ParseNodeKind kind, uint32_t begin) {
return newList(kind, TokenPos(begin, begin + 1));
}
template<typename T>
ParseNode* newList(ParseNodeKind kind, const T& begin, JSOp op = JSOP_NOP) = delete;
ParseNode* newList(ParseNodeKind kind, const T& begin) = delete;
public:
ParseNode* newList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) {
ParseNode* newList(ParseNodeKind kind, ParseNode* kid) {
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));
return new_<ListNode>(kind, op, pos);
return new_<ListNode>(kind, JSOP_NOP, pos);
}
bool isDeclarationList(ParseNode* node) {
@ -839,7 +845,7 @@ class FullParseHandler
}
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) {
@ -943,7 +949,7 @@ FullParseHandler::addCatchBlock(ParseNode* catchList, ParseNode* lexicalScope,
ParseNode* catchName, ParseNode* catchGuard,
ParseNode* catchBody)
{
ParseNode* catchpn = newTernary(PNK_CATCH, catchName, catchGuard, catchBody);
ParseNode* catchpn = new_<TernaryNode>(PNK_CATCH, catchName, catchGuard, catchBody);
if (!catchpn)
return false;
catchList->append(lexicalScope);
@ -956,7 +962,7 @@ FullParseHandler::setLastFunctionFormalParameterDefault(ParseNode* funcpn,
ParseNode* defaultValue)
{
ParseNode* arg = funcpn->pn_body->last();
ParseNode* pn = newBinary(PNK_ASSIGN, arg, defaultValue, JSOP_NOP);
ParseNode* pn = newBinary(PNK_ASSIGN, arg, defaultValue);
if (!pn)
return false;

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

@ -571,7 +571,7 @@ ParseNodeAllocator::allocNode()
}
ParseNode*
ParseNode::appendOrCreateList(ParseNodeKind kind, JSOp op, ParseNode* left, ParseNode* right,
ParseNode::appendOrCreateList(ParseNodeKind kind, ParseNode* left, ParseNode* right,
FullParseHandler* handler, ParseContext* pc)
{
// 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.
//
if (left->isKind(kind) &&
left->isOp(op) &&
(CodeSpec[op].format & JOF_LEFTASSOC ||
(kind == PNK_POW && !left->pn_parens)))
(kind == PNK_POW ? !left->pn_parens : left->isBinaryOperation()))
{
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)
return nullptr;

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