merge mozilla-central to autoland. r=merge a=merge

This commit is contained in:
Sebastian Hengst 2017-04-29 11:11:48 +02:00
commit f4f104e7e0
119 changed files with 1411 additions and 602 deletions

View File

@ -1,49 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.0.0.0"
processorArchitecture="*"
name="Firefox"
type="win32"
/>
<description>Firefox</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
<comInterfaceExternalProxyStub
iid="{618736E0-3C3D-11CF-810C-00AA00389B71}"
proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"
name="IAccessible"
tlbid="{1EA4DBF0-3C3B-11CF-810C-00AA00389B71}"
/>
<ms_asmv3:trustInfo xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3">
<ms_asmv3:security>
<ms_asmv3:requestedPrivileges>
<ms_asmv3:requestedExecutionLevel level="asInvoker" uiAccess="false" />
</ms_asmv3:requestedPrivileges>
</ms_asmv3:security>
</ms_asmv3:trustInfo>
<ms_asmv3:application xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3">
<ms_asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>True/PM</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2,PerMonitor</dpiAwareness>
</ms_asmv3:windowsSettings>
</ms_asmv3:application>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
</application>
</compatibility>
</assembly>

View File

@ -2059,6 +2059,34 @@
let getter;
let setter;
switch (name) {
case "audioMuted":
getter = () => {
return false;
};
break;
case "contentTitle":
getter = () => {
return SessionStore.getLazyTabValue(aTab, "title");
};
break;
case "currentURI":
getter = () => {
let url = SessionStore.getLazyTabValue(aTab, "url");
return Services.io.newURI(url);
};
break;
case "getTabBrowser":
getter = () => {
return () => {
return this;
};
};
break;
case "isRemoteBrowser":
getter = () => {
return browser.getAttribute("remote") == "true";
};
break;
case "permitUnload":
getter = () => {
return () => {
@ -2079,27 +2107,6 @@
};
};
break;
case "isRemoteBrowser":
getter = () => {
return browser.getAttribute("remote") == "true";
};
break;
case "audioMuted":
getter = () => {
return false;
};
break;
case "currentURI":
getter = () => {
let url = SessionStore.getLazyTabValue(aTab, "url");
return Services.io.newURI(url);
};
break;
case "contentTitle":
getter = () => {
return SessionStore.getLazyTabValue(aTab, "title");
};
break;
case "userTypedValue":
case "userTypedClear":
getter = () => {

View File

@ -1,3 +1,3 @@
[DEFAULT]
[browser_toolbariconcolor_restyles.js]
skip-if = os == "mac" && debug # Bug 1358356
skip-if = (os == "mac" || os == "win") && debug # Bug 1358356

View File

@ -989,7 +989,7 @@ html|span.ac-emphasize-text-url {
.ac-type-icon[type=keyword],
.ac-site-icon[type=searchengine] {
list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg);
/* uncomment after bug 1350010 lands: context-properties: fill; */
-moz-context-properties: fill;
fill: GrayText;
}

View File

@ -1766,7 +1766,7 @@ html|span.ac-emphasize-text-url {
.ac-type-icon[type=keyword],
.ac-site-icon[type=searchengine] {
list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg);
/* uncomment after bug 1350010 lands: context-properties: fill; */
-moz-context-properties: fill;
fill: GrayText;
}

View File

@ -38,6 +38,7 @@
-moz-appearance: none;
border-style: none;
list-style-image: url("chrome://browser/skin/page-action.svg");
-moz-context-properties: fill;
margin: 0;
padding: 0 6px;
fill: currentColor;

View File

@ -73,7 +73,7 @@
#urlbar[actiontype="searchengine"] > #identity-box > #identity-icon {
-moz-image-region: inherit;
list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg);
/* uncomment after bug 1350010 lands: context-properties: fill; */
-moz-context-properties: fill;
fill: GrayText;
width: 16px;
height: 16px;

View File

@ -184,12 +184,15 @@ toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-in-button {
#appMenu-new-window-button {
list-style-image: url(chrome://browser/skin/menu-icons/new-window.svg);
-moz-context-properties: fill;
}
#appMenu-private-window-button {
list-style-image: url(chrome://browser/skin/menu-icons/private-window.svg);
-moz-context-properties: fill;
}
#appMenu-print-button {
list-style-image: url(chrome://browser/skin/menu-icons/print.svg);
-moz-context-properties: fill;
}

View File

@ -1509,7 +1509,7 @@ html|span.ac-emphasize-text-url {
.ac-type-icon[type=keyword],
.ac-site-icon[type=searchengine] {
list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg);
/* uncomment after bug 1350010 lands: context-properties: fill; */
-moz-context-properties: fill;
fill: GrayText;
}

20
build/cargo-linker Executable file
View File

@ -0,0 +1,20 @@
#!/bin/sh
# If you want to use a custom linker with Cargo, Cargo requires that you
# specify it in Cargo.toml or via the matching environment variable.
# Passing extra options to the linker is possible with Cargo via
# RUSTFLAGS='-C link-args', but testing showed that doing this reliably
# was difficult.
#
# Our solution to these problems is to use this wrapper script. We pass
# in the LD and the LDFLAGS to use via environment variables. Note that
# we do *not* quote either MOZ_CARGO_WRAP variable:
#
# * MOZ_CARGO_WRAP_LD is equivalent to CC on Unix-y platforms, and CC
# frequently has additional arguments in addition to the compiler
# itself.
# * MOZ_CARGO_WRAP_LDFLAGS contains space-separated arguments to pass,
# and not quoting it ensures that either of those arguments is passed
# as a separate argument to the actual LD.
${MOZ_CARGO_WRAP_LD} ${MOZ_CARGO_WRAP_LDFLAGS} "$@"

View File

@ -223,6 +223,15 @@ rust_host_triple = rust_triple_alias(host)
set_config('RUST_TARGET', rust_target_triple)
set_config('RUST_HOST_TARGET', rust_host_triple)
@depends(rust_target_triple)
def rust_target_env_name(triple):
return triple.upper().replace('-','_')
# We need this to form various Cargo environment variables, as there is no
# uppercase function in make, and we don't want to shell out just for
# converting a string to uppercase.
set_config('RUST_TARGET_ENV_NAME', rust_target_env_name)
# Until we remove all the other Rust checks in old-configure.
add_old_configure_assignment('MOZ_RUST', rust_compiler)
add_old_configure_assignment('RUSTC', rustc)

View File

@ -963,7 +963,15 @@ else
environment_cleaner =
endif
CARGO_BUILD = env $(environment_cleaner) $(rustflags_override) \
# This function is intended to be called by:
#
# $(call CARGO_BUILD,EXTRA_ENV_VAR1=X EXTRA_ENV_VAR2=Y ...)
#
# but, given the idiosyncracies of make, can also be called without arguments:
#
# $(call CARGO_BUILD)
define CARGO_BUILD
env $(environment_cleaner) $(rustflags_override) \
CARGO_TARGET_DIR=$(CARGO_TARGET_DIR) \
RUSTC=$(RUSTC) \
MOZ_DIST=$(ABS_DIST) \
@ -972,7 +980,29 @@ CARGO_BUILD = env $(environment_cleaner) $(rustflags_override) \
PKG_CONFIG_ALLOW_CROSS=1 \
RUST_BACKTRACE=1 \
MOZ_TOPOBJDIR=$(topobjdir) \
$(1) \
$(CARGO) build $(cargo_build_flags)
endef
cargo_linker_env_var := CARGO_TARGET_$(RUST_TARGET_ENV_NAME)_LINKER
# Don't define a custom linker on Windows, as it's difficult to have a
# non-binary file that will get executed correctly by Cargo. We don't
# have to worry about a cross-compiling (besides x86-64 -> x86, which
# already works with the current setup) setup on Windows, and we don't
# have to pass in any special linker options on Windows.
ifneq (WINNT,$(OS_ARCH))
# Defining all of this for ASan builds results in crashes while running
# some crates's build scripts (!), so disable it for now.
ifndef MOZ_ASAN
target_cargo_env_vars := \
MOZ_CARGO_WRAP_LDFLAGS="$(LDFLAGS)" \
MOZ_CARGO_WRAP_LD="$(CC)" \
$(cargo_linker_env_var)=$(topsrcdir)/build/cargo-linker
endif # MOZ_ASAN
endif # ifneq WINNT
ifdef RUST_LIBRARY_FILE
@ -987,7 +1017,7 @@ endif
# build.
force-cargo-library-build:
$(REPORT_BUILD)
$(CARGO_BUILD) --lib $(cargo_target_flag) $(rust_features_flag)
$(call CARGO_BUILD,$(target_cargo_env_vars)) --lib $(cargo_target_flag) $(rust_features_flag)
$(RUST_LIBRARY_FILE): force-cargo-library-build
endif # RUST_LIBRARY_FILE
@ -1000,7 +1030,7 @@ endif
force-cargo-host-library-build:
$(REPORT_BUILD)
$(CARGO_BUILD) --lib $(cargo_host_flag) $(host_rust_features_flag)
$(call CARGO_BUILD) --lib $(cargo_host_flag) $(host_rust_features_flag)
$(HOST_RUST_LIBRARY_FILE): force-cargo-host-library-build
endif # HOST_RUST_LIBRARY_FILE
@ -1008,14 +1038,14 @@ endif # HOST_RUST_LIBRARY_FILE
ifdef RUST_PROGRAMS
force-cargo-program-build:
$(REPORT_BUILD)
$(CARGO_BUILD) $(addprefix --bin ,$(RUST_CARGO_PROGRAMS)) $(cargo_target_flag)
$(call CARGO_BUILD,$(target_cargo_env_vars)) $(addprefix --bin ,$(RUST_CARGO_PROGRAMS)) $(cargo_target_flag)
$(RUST_PROGRAMS): force-cargo-program-build
endif # RUST_PROGRAMS
ifdef HOST_RUST_PROGRAMS
force-cargo-host-program-build:
$(REPORT_BUILD)
$(CARGO_BUILD) $(addprefix --bin ,$(HOST_RUST_CARGO_PROGRAMS)) $(cargo_host_flag)
$(call CARGO_BUILD) $(addprefix --bin ,$(HOST_RUST_CARGO_PROGRAMS)) $(cargo_host_flag)
$(HOST_RUST_PROGRAMS): force-cargo-host-program-build
endif # HOST_RUST_PROGRAMS

View File

@ -83,7 +83,7 @@ select {
-moz-appearance: none; appearance: none;
background-color: var(--theme-toolbar-background);
background-image: var(--viewport-selection-arrow);
/* uncomment after bug 1350010 lands: context-properties: fill; */
-moz-context-properties: fill;
fill: currentColor;
color: var(--viewport-color);
background-position: 100% 50%;

View File

@ -1519,9 +1519,9 @@ function getFontPreviewData(font, doc, options) {
// Get the correct preview text measurements and set the canvas dimensions
ctx.font = fontValue;
ctx.fillStyle = fillStyle;
let textWidth = ctx.measureText(previewText).width;
let textWidth = Math.round(ctx.measureText(previewText).width);
canvas.width = textWidth * 2 + FONT_PREVIEW_OFFSET * 2;
canvas.width = textWidth * 2 + FONT_PREVIEW_OFFSET * 4;
canvas.height = previewFontSize * 3;
// we have to reset these after changing the canvas size

View File

@ -9,6 +9,7 @@ support-files =
doc_force_gc.html
doc_innerHTML.html
doc_perf.html
grid.html
inspectedwindow-reload-target.sjs
navigate-first.html
navigate-second.html
@ -53,6 +54,8 @@ skip-if = e10s # Bug 1183605 - devtools/server/tests/browser/ tests are still di
skip-if = e10s # Bug 1183605 - devtools/server/tests/browser/ tests are still disabled in E10S
[browser_canvasframe_helper_06.js]
skip-if = e10s # Bug 1183605 - devtools/server/tests/browser/ tests are still disabled in E10S
[browser_layout_getAllGrids.js]
[browser_layout_simple.js]
[browser_markers-cycle-collection.js]
[browser_markers-docloading-01.js]
[browser_markers-docloading-02.js]
@ -91,4 +94,4 @@ skip-if = e10s # Bug 1183605 - devtools/server/tests/browser/ tests are still di
[browser_timeline_actors.js]
[browser_timeline_iframes.js]
[browser_register_actor.js]
[browser_webextension_inspected_window.js]
[browser_webextension_inspected_window.js]

View File

@ -0,0 +1,133 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Check the output of getAllGrids for the LayoutActor
const GRID_FRAGMENT_DATA = {
areas: [
{
columnEnd: 3,
columnStart: 2,
name: "header",
rowEnd: 2,
rowStart: 1,
type: "explicit"
},
{
columnEnd: 2,
columnStart: 1,
name: "sidebar",
rowEnd: 3,
rowStart: 2,
type: "explicit"
},
{
columnEnd: 3,
columnStart: 2,
name: "content",
rowEnd: 3,
rowStart: 2,
type: "explicit"
}
],
cols: {
lines: [
{
breadth: 0,
names: ["col-1", "col-start-1", "sidebar-start"],
number: 1,
start: 0
},
{
breadth: 0,
names: ["col-2", "header-start", "sidebar-end", "content-start"],
number: 2,
start: 100
},
{
breadth: 0,
names: ["header-end", "content-end"],
number: 3,
start: 200
}
],
tracks: [
{
breadth: 100,
start: 0,
state: "static",
type: "explicit"
},
{
breadth: 100,
start: 100,
state: "static",
type: "explicit"
}
]
},
rows: {
lines: [
{
breadth: 0,
names: ["header-start"],
number: 1,
start: 0
},
{
breadth: 0,
names: ["header-end", "sidebar-start", "content-start"],
number: 2,
start: 100
},
{
breadth: 0,
names: ["sidebar-end", "content-end"],
number: 3,
start: 200
}
],
tracks: [
{
breadth: 100,
start: 0,
state: "static",
type: "explicit"
},
{
breadth: 100,
start: 100,
state: "static",
type: "explicit"
}
]
}
};
add_task(function* () {
let { client, walker, layout } = yield initLayoutFrontForUrl(MAIN_DOMAIN + "grid.html");
let grids = yield layout.getAllGrids(walker.rootNode, true);
let grid = grids[0];
let { gridFragments } = grid;
is(grids.length, 1, "One grid was returned.");
is(gridFragments.length, 1, "One grid fragment was returned.");
ok(Array.isArray(gridFragments), "An array of grid fragments was returned.");
Assert.deepEqual(gridFragments[0], GRID_FRAGMENT_DATA,
"Got the correct grid fragment data.");
info("Get the grid container node front.");
try {
let nodeFront = yield walker.getNodeFromActor(grids[0].actorID, ["containerEl"]);
ok(nodeFront, "Got the grid container node front.");
} catch (e) {
ok(false, "Did not get grid container node front.");
}
yield client.close();
gBrowser.removeCurrentTab();
});

View File

@ -0,0 +1,39 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Simple checks for the LayoutActor and GridActor
add_task(function* () {
let {client, walker, layout} = yield initLayoutFrontForUrl(
"data:text/html;charset=utf-8,<title>test</title><div></div>");
ok(layout, "The LayoutFront was created");
ok(layout.getAllGrids, "The getAllGrids method exists");
let didThrow = false;
try {
yield layout.getGrids(null);
} catch (e) {
didThrow = true;
}
ok(didThrow, "An exception was thrown for a missing NodeActor in getGrids");
didThrow = false;
try {
yield layout.getAllGrids(null);
} catch (e) {
didThrow = true;
}
ok(didThrow, "An exception was thrown for a missing NodeActor in getAllGrids");
let invalidNode = yield walker.querySelector(walker.rootNode, "title");
let grids = yield layout.getAllGrids(invalidNode, true);
ok(Array.isArray(grids), "An array of grids was returned");
is(grids.length, 0, "0 grids have been returned for the invalid node");
yield client.close();
gBrowser.removeCurrentTab();
});

View File

@ -0,0 +1,42 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Grid test page</title>
<style type='text/css'>
#grid {
display: grid;
grid-template-columns: [col-1 col-start-1] 100px [col-2] 100px;
grid-template-rows: 100px 100px;
grid-template-areas: ". header"
"sidebar content";
}
#cell1 {
grid-column: 1;
grid-row: 1;
}
#cell2 {
grid-column: 2;
grid-row: 1;
}
#cell3 {
grid-column: 1;
grid-row: 2;
}
#cell4 {
grid-column: 2;
grid-row: 2;
}
</style>
</head>
<body>
<div id="grid">
<div id="cell1">cell1</div>
<div id="cell2">cell2</div>
<div id="cell3">cell3</div>
<div id="cell4">cell4</div>
</div>
</body>
</html>

View File

@ -65,6 +65,21 @@ function* initAnimationsFrontForUrl(url) {
return {inspector, walker, animations, client};
}
function* initLayoutFrontForUrl(url) {
const {InspectorFront} = require("devtools/shared/fronts/inspector");
yield addTab(url);
initDebuggerServer();
let client = new DebuggerClient(DebuggerServer.connectPipe());
let form = yield connectDebuggerClient(client);
let inspector = InspectorFront(client, form);
let walker = yield inspector.getWalker();
let layout = yield walker.getLayoutInspector();
return {inspector, walker, layout, client};
}
function initDebuggerServer() {
try {
// Sometimes debugger server does not get destroyed correctly by previous

View File

@ -925,6 +925,18 @@ exports.CSS_PROPERTIES = {
"unset"
]
},
"-moz-context-properties": {
"isInherited": true,
"subproperties": [
"-moz-context-properties"
],
"supports": [],
"values": [
"inherit",
"initial",
"unset"
]
},
"-moz-control-character-visibility": {
"isInherited": true,
"subproperties": [
@ -2941,6 +2953,7 @@ exports.CSS_PROPERTIES = {
"column-width",
"contain",
"content",
"-moz-context-properties",
"-moz-control-character-visibility",
"counter-increment",
"counter-reset",
@ -3370,6 +3383,7 @@ exports.CSS_PROPERTIES = {
"geometricprecision",
"grab",
"grabbing",
"grayscale",
"grid",
"groove",
"groupbox",

View File

@ -1116,7 +1116,7 @@ protected:
static nsGlobalWindow* GetOuterWindow(JSObject *proxy)
{
nsGlobalWindow* outerWindow = nsGlobalWindow::FromSupports(
static_cast<nsISupports*>(js::GetProxyExtra(proxy, 0).toPrivate()));
static_cast<nsISupports*>(js::GetProxyReservedSlot(proxy, 0).toPrivate()));
MOZ_ASSERT_IF(outerWindow, outerWindow->IsOuterWindow());
return outerWindow;
}
@ -1738,7 +1738,7 @@ nsGlobalWindow::~nsGlobalWindow()
if (IsOuterWindow()) {
JSObject *proxy = GetWrapperMaybeDead();
if (proxy) {
js::SetProxyExtra(proxy, 0, js::PrivateValue(nullptr));
js::SetProxyReservedSlot(proxy, 0, js::PrivateValue(nullptr));
}
// An outer window is destroyed with inner windows still possibly
@ -3160,7 +3160,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
NewOuterWindowProxy(cx, newInnerGlobal, thisChrome));
NS_ENSURE_TRUE(outer, NS_ERROR_FAILURE);
js::SetProxyExtra(outer, 0, js::PrivateValue(ToSupports(this)));
js::SetProxyReservedSlot(outer, 0, js::PrivateValue(ToSupports(this)));
// Inform the nsJSContext, which is the canonical holder of the outer.
mContext->SetWindowProxy(outer);
@ -3178,8 +3178,8 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
JS::Rooted<JSObject*> obj(cx, GetWrapperPreserveColor());
js::SetProxyExtra(obj, 0, js::PrivateValue(nullptr));
js::SetProxyExtra(outerObject, 0, js::PrivateValue(nullptr));
js::SetProxyReservedSlot(obj, 0, js::PrivateValue(nullptr));
js::SetProxyReservedSlot(outerObject, 0, js::PrivateValue(nullptr));
outerObject = xpc::TransplantObject(cx, obj, outerObject);
if (!outerObject) {
@ -3187,7 +3187,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
return NS_ERROR_FAILURE;
}
js::SetProxyExtra(outerObject, 0, js::PrivateValue(ToSupports(this)));
js::SetProxyReservedSlot(outerObject, 0, js::PrivateValue(ToSupports(this)));
SetWrapper(outerObject);

View File

@ -2205,9 +2205,9 @@ ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObjArg)
// NB: It's important to do this _after_ copying the properties to
// propertyHolder. Otherwise, an object with |foo.x === foo| will
// crash when JS_CopyPropertiesFrom tries to call wrap() on foo.x.
js::SetReservedOrProxyPrivateSlot(newobj, DOM_OBJECT_SLOT,
js::GetReservedOrProxyPrivateSlot(aObj, DOM_OBJECT_SLOT));
js::SetReservedOrProxyPrivateSlot(aObj, DOM_OBJECT_SLOT, JS::PrivateValue(nullptr));
js::SetReservedSlot(newobj, DOM_OBJECT_SLOT,
js::GetReservedSlot(aObj, DOM_OBJECT_SLOT));
js::SetReservedSlot(aObj, DOM_OBJECT_SLOT, JS::PrivateValue(nullptr));
aObj = xpc::TransplantObject(aCx, aObj, newobj);
if (!aObj) {

View File

@ -135,7 +135,7 @@ UnwrapDOMObject(JSObject* obj)
MOZ_ASSERT(IsDOMClass(js::GetObjectClass(obj)),
"Don't pass non-DOM objects to this function");
JS::Value val = js::GetReservedOrProxyPrivateSlot(obj, DOM_OBJECT_SLOT);
JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
return static_cast<T*>(val.toPrivate());
}
@ -150,7 +150,7 @@ UnwrapPossiblyNotInitializedDOMObject(JSObject* obj)
MOZ_ASSERT(IsDOMClass(js::GetObjectClass(obj)),
"Don't pass non-DOM objects to this function");
JS::Value val = js::GetReservedOrProxyPrivateSlot(obj, DOM_OBJECT_SLOT);
JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
if (val.isUndefined()) {
return nullptr;
}
@ -2679,8 +2679,7 @@ public:
~BindingJSObjectCreator()
{
if (mReflector) {
js::SetReservedOrProxyPrivateSlot(mReflector, DOM_OBJECT_SLOT,
JS::UndefinedValue());
js::SetReservedSlot(mReflector, DOM_OBJECT_SLOT, JS::UndefinedValue());
}
}
@ -2688,14 +2687,15 @@ public:
CreateProxyObject(JSContext* aCx, const js::Class* aClass,
const DOMProxyHandler* aHandler,
JS::Handle<JSObject*> aProto, T* aNative,
JS::Handle<JS::Value> aExpandoValue,
JS::MutableHandle<JSObject*> aReflector)
{
js::ProxyOptions options;
options.setClass(aClass);
JS::Rooted<JS::Value> proxyPrivateVal(aCx, JS::PrivateValue(aNative));
aReflector.set(js::NewProxyObject(aCx, aHandler, proxyPrivateVal, aProto,
aReflector.set(js::NewProxyObject(aCx, aHandler, aExpandoValue, aProto,
options));
if (aReflector) {
js::SetProxyReservedSlot(aReflector, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
mNative = aNative;
mReflector = aReflector;
}

View File

@ -3499,21 +3499,21 @@ def CreateBindingJSObject(descriptor, properties):
# We don't always need to root obj, but there are a variety
# of cases where we do, so for simplicity, just always root it.
if descriptor.proxy:
create = dedent(
if descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
expandoValue = "JS::PrivateValue(&aObject->mExpandoAndGeneration)"
else:
expandoValue = "JS::UndefinedValue()"
create = fill(
"""
JS::Rooted<JS::Value> expandoValue(aCx, ${expandoValue});
creator.CreateProxyObject(aCx, &sClass.mBase, DOMProxyHandler::getInstance(),
proto, aObject, aReflector);
proto, aObject, expandoValue, aReflector);
if (!aReflector) {
return false;
}
""")
if descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
create += dedent("""
js::SetProxyExtra(aReflector, JSPROXYSLOT_EXPANDO,
JS::PrivateValue(&aObject->mExpandoAndGeneration));
""")
""",
expandoValue=expandoValue)
else:
create = dedent(
"""
@ -11507,7 +11507,7 @@ class CGProxyUnwrap(CGAbstractMethod):
obj = js::UncheckedUnwrap(obj);
}
MOZ_ASSERT(IsProxy(obj));
return static_cast<${type}*>(js::GetProxyPrivate(obj).toPrivate());
return static_cast<${type}*>(js::GetProxyReservedSlot(obj, DOM_OBJECT_SLOT).toPrivate());
""",
type=self.descriptor.nativeType)

View File

@ -34,7 +34,7 @@ js::DOMProxyShadowsResult
DOMProxyShadows(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id)
{
JS::Rooted<JSObject*> expando(cx, DOMProxyHandler::GetExpandoObject(proxy));
JS::Value v = js::GetProxyExtra(proxy, JSPROXYSLOT_EXPANDO);
JS::Value v = js::GetProxyPrivate(proxy);
bool isOverrideBuiltins = !v.isObject() && !v.isUndefined();
if (expando) {
bool hasOwn;
@ -64,7 +64,7 @@ struct SetDOMProxyInformation
{
SetDOMProxyInformation() {
js::SetDOMProxyInformation((const void*) &DOMProxyHandler::family,
JSPROXYSLOT_EXPANDO, DOMProxyShadows);
DOMProxyShadows);
}
};
@ -75,7 +75,7 @@ void
DOMProxyHandler::ClearExternalRefsForWrapperRelease(JSObject* obj)
{
MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object");
JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
JS::Value v = js::GetProxyPrivate(obj);
if (v.isUndefined()) {
// No expando.
return;
@ -102,13 +102,13 @@ JSObject*
DOMProxyHandler::GetAndClearExpandoObject(JSObject* obj)
{
MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object");
JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
JS::Value v = js::GetProxyPrivate(obj);
if (v.isUndefined()) {
return nullptr;
}
if (v.isObject()) {
js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, UndefinedValue());
js::SetProxyPrivate(obj, UndefinedValue());
xpc::ObjectScope(obj)->RemoveDOMExpandoObject(obj);
} else {
js::ExpandoAndGeneration* expandoAndGeneration =
@ -142,7 +142,7 @@ JSObject*
DOMProxyHandler::EnsureExpandoObject(JSContext* cx, JS::Handle<JSObject*> obj)
{
NS_ASSERTION(IsDOMProxy(obj), "expected a DOM proxy object");
JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
JS::Value v = js::GetProxyPrivate(obj);
if (v.isObject()) {
return &v.toObject();
}
@ -178,7 +178,7 @@ DOMProxyHandler::EnsureExpandoObject(JSContext* cx, JS::Handle<JSObject*> obj)
}
cache->SetPreservingWrapper(true);
js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, ObjectValue(*expando));
js::SetProxyPrivate(obj, ObjectValue(*expando));
return expando;
}
@ -322,7 +322,7 @@ JSObject *
DOMProxyHandler::GetExpandoObject(JSObject *obj)
{
MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object");
JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
JS::Value v = js::GetProxyPrivate(obj);
if (v.isObject()) {
return &v.toObject();
}
@ -343,14 +343,12 @@ ShadowingDOMProxyHandler::trace(JSTracer* trc, JSObject* proxy) const
DOMProxyHandler::trace(trc, proxy);
MOZ_ASSERT(IsDOMProxy(proxy), "expected a DOM proxy object");
JS::Value v = js::GetProxyExtra(proxy, JSPROXYSLOT_EXPANDO);
JS::Value v = js::GetProxyPrivate(proxy);
MOZ_ASSERT(!v.isObject(), "Should not have expando object directly!");
if (v.isUndefined()) {
// This can happen if we GC while creating our object, before we get a
// chance to set up its JSPROXYSLOT_EXPANDO slot.
return;
}
// The proxy's private slot is set when we allocate the proxy,
// so it cannot be |undefined|.
MOZ_ASSERT(!v.isUndefined());
js::ExpandoAndGeneration* expandoAndGeneration =
static_cast<js::ExpandoAndGeneration*>(v.toPrivate());

View File

@ -14,35 +14,29 @@
#include "js/Proxy.h"
#include "nsString.h"
#define DOM_PROXY_OBJECT_SLOT js::PROXY_PRIVATE_SLOT
namespace mozilla {
namespace dom {
enum {
/**
* DOM proxies have an extra slot for the expando object at index
* JSPROXYSLOT_EXPANDO.
*
* The expando object is a plain JSObject whose properties correspond to
* "expandos" (custom properties set by the script author).
*
* The exact value stored in the JSPROXYSLOT_EXPANDO slot depends on whether
* the interface is annotated with the [OverrideBuiltins] extended attribute.
*
* If it is, the proxy is initialized with a PrivateValue, which contains a
* pointer to a js::ExpandoAndGeneration object; this contains a pointer to
* the actual expando object as well as the "generation" of the object. The
* proxy handler will trace the expando object stored in the
* js::ExpandoAndGeneration while the proxy itself is alive.
*
* If it is not, the proxy is initialized with an UndefinedValue. In
* EnsureExpandoObject, it is set to an ObjectValue that points to the
* expando object directly. (It is set back to an UndefinedValue only when
* the object is about to die.)
*/
JSPROXYSLOT_EXPANDO = 0
};
/**
* DOM proxies store the expando object in the private slot.
*
* The expando object is a plain JSObject whose properties correspond to
* "expandos" (custom properties set by the script author).
*
* The exact value stored in the proxy's private slot depends on whether the
* interface is annotated with the [OverrideBuiltins] extended attribute.
*
* If it is, the proxy is initialized with a PrivateValue, which contains a
* pointer to a js::ExpandoAndGeneration object; this contains a pointer to
* the actual expando object as well as the "generation" of the object. The
* proxy handler will trace the expando object stored in the
* js::ExpandoAndGeneration while the proxy itself is alive.
*
* If it is not, the proxy is initialized with an UndefinedValue. In
* EnsureExpandoObject, it is set to an ObjectValue that points to the
* expando object directly. (It is set back to an UndefinedValue only when
* the object is about to die.)
*/
template<typename T> struct Prefable;

View File

@ -23,6 +23,7 @@
#include "mozilla/Casting.h"
#include "mozilla/CycleCollectedJSRuntime.h"
#include "mozilla/EndianUtils.h"
#include "mozilla/ErrorNames.h"
#include "mozilla/LazyIdleThread.h"
#include "mozilla/Maybe.h"
#include "mozilla/Preferences.h"
@ -9468,6 +9469,7 @@ class Maintenance final
RefPtr<DirectoryLock> mDirectoryLock;
nsTArray<DirectoryInfo> mDirectoryInfos;
nsDataHashtable<nsStringHashKey, DatabaseMaintenance*> mDatabaseMaintenances;
nsresult mResultCode;
Atomic<bool> mAborted;
State mState;
@ -9475,6 +9477,7 @@ public:
explicit Maintenance(QuotaClient* aQuotaClient)
: mQuotaClient(aQuotaClient)
, mStartTime(PR_Now())
, mResultCode(NS_OK)
, mAborted(false)
, mState(State::Initial)
{
@ -18638,21 +18641,32 @@ Maintenance::DirectoryWork()
QuotaManager* quotaManager = QuotaManager::Get();
MOZ_ASSERT(quotaManager);
if (NS_WARN_IF(NS_FAILED(quotaManager->EnsureStorageIsInitialized()))) {
return NS_ERROR_FAILURE;
nsresult rv = quotaManager->EnsureStorageIsInitialized();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsIFile> storageDir = GetFileForPath(quotaManager->GetStoragePath());
MOZ_ASSERT(storageDir);
if (NS_WARN_IF(!storageDir)) {
return NS_ERROR_FAILURE;
}
bool exists;
MOZ_ALWAYS_SUCCEEDS(storageDir->Exists(&exists));
rv = storageDir->Exists(&exists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!exists) {
return NS_ERROR_NOT_AVAILABLE;
}
bool isDirectory;
MOZ_ALWAYS_SUCCEEDS(storageDir->IsDirectory(&isDirectory));
rv = storageDir->IsDirectory(&isDirectory);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (NS_WARN_IF(!isDirectory)) {
return NS_ERROR_FAILURE;
}
@ -18687,25 +18701,41 @@ Maintenance::DirectoryWork()
}
nsCOMPtr<nsIFile> persistenceDir;
MOZ_ALWAYS_SUCCEEDS(
storageDir->Clone(getter_AddRefs(persistenceDir)));
MOZ_ALWAYS_SUCCEEDS(
persistenceDir->Append(NS_ConvertASCIItoUTF16(persistenceTypeString)));
rv = storageDir->Clone(getter_AddRefs(persistenceDir));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = persistenceDir->Append(NS_ConvertASCIItoUTF16(persistenceTypeString));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = persistenceDir->Exists(&exists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ALWAYS_SUCCEEDS(persistenceDir->Exists(&exists));
if (!exists) {
continue;
}
MOZ_ALWAYS_SUCCEEDS(persistenceDir->IsDirectory(&isDirectory));
rv = persistenceDir->IsDirectory(&isDirectory);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (NS_WARN_IF(!isDirectory)) {
continue;
}
nsCOMPtr<nsISimpleEnumerator> persistenceDirEntries;
MOZ_ALWAYS_SUCCEEDS(
persistenceDir->GetDirectoryEntries(
getter_AddRefs(persistenceDirEntries)));
rv = persistenceDir->GetDirectoryEntries(
getter_AddRefs(persistenceDirEntries));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!persistenceDirEntries) {
continue;
}
@ -18717,46 +18747,76 @@ Maintenance::DirectoryWork()
}
bool persistenceDirHasMoreEntries;
MOZ_ALWAYS_SUCCEEDS(
persistenceDirEntries->HasMoreElements(&persistenceDirHasMoreEntries));
rv = persistenceDirEntries->HasMoreElements(
&persistenceDirHasMoreEntries);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!persistenceDirHasMoreEntries) {
break;
}
nsCOMPtr<nsISupports> persistenceDirEntry;
MOZ_ALWAYS_SUCCEEDS(
persistenceDirEntries->GetNext(getter_AddRefs(persistenceDirEntry)));
rv = persistenceDirEntries->GetNext(getter_AddRefs(persistenceDirEntry));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsIFile> originDir = do_QueryInterface(persistenceDirEntry);
MOZ_ASSERT(originDir);
MOZ_ASSERT(NS_SUCCEEDED(originDir->Exists(&exists)));
rv = originDir->Exists(&exists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ASSERT(exists);
MOZ_ALWAYS_SUCCEEDS(originDir->IsDirectory(&isDirectory));
rv = originDir->IsDirectory(&isDirectory);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!isDirectory) {
continue;
}
nsCOMPtr<nsIFile> idbDir;
MOZ_ALWAYS_SUCCEEDS(originDir->Clone(getter_AddRefs(idbDir)));
rv = originDir->Clone(getter_AddRefs(idbDir));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ALWAYS_SUCCEEDS(idbDir->Append(idbDirName));
rv = idbDir->Append(idbDirName);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = idbDir->Exists(&exists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ALWAYS_SUCCEEDS(idbDir->Exists(&exists));
if (!exists) {
continue;
}
MOZ_ALWAYS_SUCCEEDS(idbDir->IsDirectory(&isDirectory));
rv = idbDir->IsDirectory(&isDirectory);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (NS_WARN_IF(!isDirectory)) {
continue;
}
nsCOMPtr<nsISimpleEnumerator> idbDirEntries;
MOZ_ALWAYS_SUCCEEDS(
idbDir->GetDirectoryEntries(getter_AddRefs(idbDirEntries)));
rv = idbDir->GetDirectoryEntries(getter_AddRefs(idbDirEntries));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!idbDirEntries) {
continue;
}
@ -18772,31 +18832,46 @@ Maintenance::DirectoryWork()
}
bool idbDirHasMoreEntries;
MOZ_ALWAYS_SUCCEEDS(
idbDirEntries->HasMoreElements(&idbDirHasMoreEntries));
rv = idbDirEntries->HasMoreElements(&idbDirHasMoreEntries);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!idbDirHasMoreEntries) {
break;
}
nsCOMPtr<nsISupports> idbDirEntry;
MOZ_ALWAYS_SUCCEEDS(
idbDirEntries->GetNext(getter_AddRefs(idbDirEntry)));
rv = idbDirEntries->GetNext(getter_AddRefs(idbDirEntry));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsIFile> idbDirFile = do_QueryInterface(idbDirEntry);
MOZ_ASSERT(idbDirFile);
nsString idbFilePath;
MOZ_ALWAYS_SUCCEEDS(idbDirFile->GetPath(idbFilePath));
rv = idbDirFile->GetPath(idbFilePath);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!StringEndsWith(idbFilePath, sqliteExtension)) {
continue;
}
MOZ_ASSERT(NS_SUCCEEDED(idbDirFile->Exists(&exists)));
rv = idbDirFile->Exists(&exists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ASSERT(exists);
MOZ_ALWAYS_SUCCEEDS(idbDirFile->IsDirectory(&isDirectory));
rv = idbDirFile->IsDirectory(&isDirectory);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (isDirectory) {
continue;
}
@ -18925,8 +19000,19 @@ Maintenance::Finish()
AssertIsOnBackgroundThread();
MOZ_ASSERT(mState == State::Finishing);
if (NS_FAILED(mResultCode)) {
nsCString errorName;
GetErrorName(mResultCode, errorName);
IDB_WARNING("Maintenance finished with error: %s", errorName.get());
}
mDirectoryLock = nullptr;
// It can happen that we are only referenced by mCurrentMaintenance which is
// cleared in NoteFinishedMaintenance()
RefPtr<Maintenance> kungFuDeathGrip = this;
mQuotaClient->NoteFinishedMaintenance(this);
mState = State::Complete;
@ -18971,6 +19057,10 @@ Maintenance::Run()
}
if (NS_WARN_IF(NS_FAILED(rv)) && mState != State::Finishing) {
if (NS_SUCCEEDED(mResultCode)) {
mResultCode = rv;
}
// Must set mState before dispatching otherwise we will race with the owning
// thread.
mState = State::Finishing;
@ -18997,6 +19087,10 @@ Maintenance::DirectoryLockAcquired(DirectoryLock* aLock)
nsresult rv = DirectoryOpen();
if (NS_WARN_IF(NS_FAILED(rv))) {
if (NS_SUCCEEDED(mResultCode)) {
mResultCode = rv;
}
mState = State::Finishing;
Finish();
@ -19011,6 +19105,10 @@ Maintenance::DirectoryLockFailed()
MOZ_ASSERT(mState == State::DirectoryOpenPending);
MOZ_ASSERT(!mDirectoryLock);
if (NS_SUCCEEDED(mResultCode)) {
mResultCode = NS_ERROR_FAILURE;
}
mState = State::Finishing;
Finish();
}

View File

@ -11,9 +11,12 @@
#include "IndexedDatabase.h"
#define IDB_WARNING(x) \
mozilla::dom::indexedDB::ReportInternalError(__FILE__, __LINE__, x); \
NS_WARNING(x)
#define IDB_WARNING(...) \
do { \
nsPrintfCString s(__VA_ARGS__); \
mozilla::dom::indexedDB::ReportInternalError(__FILE__, __LINE__, s.get()); \
NS_WARNING(s.get()); \
} while (0)
#define IDB_REPORT_INTERNAL_ERR() \
mozilla::dom::indexedDB::ReportInternalError(__FILE__, __LINE__, \

View File

@ -5055,10 +5055,9 @@ ContentParent::ForceTabPaint(TabParent* aTabParent, uint64_t aLayerObserverEpoch
}
nsresult
ContentParent::TransmitPermissionsFor(nsIChannel* aChannel)
ContentParent::AboutToLoadDocumentForChild(nsIChannel* aChannel)
{
MOZ_ASSERT(aChannel);
#ifdef MOZ_PERMISSIONS
nsresult rv;
if (!aChannel->IsDocument()) {
@ -5078,7 +5077,6 @@ ContentParent::TransmitPermissionsFor(nsIChannel* aChannel)
rv = TransmitPermissionsForPrincipal(principal);
NS_ENSURE_SUCCESS(rv, rv);
#endif
return NS_OK;
}

View File

@ -652,7 +652,11 @@ public:
// Use the PHangMonitor channel to ask the child to repaint a tab.
void ForceTabPaint(TabParent* aTabParent, uint64_t aLayerObserverEpoch);
nsresult TransmitPermissionsFor(nsIChannel* aChannel);
// This function is called when we are about to load a document from an
// HTTP(S), FTP or wyciwyg channel for a content process. It is a useful
// place to start to kick off work as early as possible in response to such
// document loads.
nsresult AboutToLoadDocumentForChild(nsIChannel* aChannel);
nsresult TransmitPermissionsForPrincipal(nsIPrincipal* aPrincipal);

View File

@ -46,6 +46,7 @@ AndroidDynamicToolbarAnimator::AndroidDynamicToolbarAnimator()
, mControllerDragThresholdReached(false)
, mControllerCancelTouchTracking(false)
, mControllerDragChangedDirection(false)
, mControllerResetOnNextMove(false)
, mControllerStartTouch(0)
, mControllerPreviousTouch(0)
, mControllerTotalDistance(0)
@ -54,6 +55,7 @@ AndroidDynamicToolbarAnimator::AndroidDynamicToolbarAnimator()
, mControllerSurfaceHeight(0)
, mControllerCompositionHeight(0)
, mControllerLastDragDirection(0)
, mControllerTouchCount(0)
, mControllerLastEventTimeStamp(0)
, mControllerState(eNothingPending)
// Compositor thread only
@ -102,6 +104,22 @@ AndroidDynamicToolbarAnimator::ReceiveInputEvent(InputData& aEvent)
MultiTouchInput& multiTouch = aEvent.AsMultiTouchInput();
ScreenIntCoord currentTouch = 0;
switch (multiTouch.mType) {
case MultiTouchInput::MULTITOUCH_START:
mControllerTouchCount = multiTouch.mTouches.Length();
break;
case MultiTouchInput::MULTITOUCH_END:
case MultiTouchInput::MULTITOUCH_CANCEL:
mControllerTouchCount -= multiTouch.mTouches.Length();
break;
default:
break;
}
if (mControllerTouchCount > 1) {
mControllerResetOnNextMove = true;
}
if (mPinnedFlags || !GetTouchY(multiTouch, &currentTouch)) {
TranslateTouchEvent(multiTouch);
return nsEventStatus_eIgnore;
@ -121,6 +139,8 @@ AndroidDynamicToolbarAnimator::ReceiveInputEvent(InputData& aEvent)
}
break;
case MultiTouchInput::MULTITOUCH_MOVE: {
CheckForResetOnNextMove(currentTouch);
if ((mControllerState != eAnimationStartPending) &&
(mControllerState != eAnimationStopPending) &&
(currentToolbarState != eToolbarAnimating) &&
@ -150,7 +170,10 @@ AndroidDynamicToolbarAnimator::ReceiveInputEvent(InputData& aEvent)
}
case MultiTouchInput::MULTITOUCH_END:
case MultiTouchInput::MULTITOUCH_CANCEL:
HandleTouchEnd(currentToolbarState, currentTouch);
// last finger was lifted
if (mControllerTouchCount == 0) {
HandleTouchEnd(currentToolbarState, currentTouch);
}
break;
default:
break;
@ -514,6 +537,9 @@ void
AndroidDynamicToolbarAnimator::HandleTouchEnd(StaticToolbarState aCurrentToolbarState, ScreenIntCoord aCurrentTouch)
{
MOZ_ASSERT(APZThreadUtils::IsControllerThread());
// If there was no move before the reset flag was set and the touch ended, check for it here.
// if mControllerResetOnNextMove is true, it will be set to false here
CheckForResetOnNextMove(aCurrentTouch);
int32_t direction = mControllerLastDragDirection;
mControllerLastDragDirection = 0;
bool isRoot = mControllerScrollingRootContent;
@ -530,23 +556,41 @@ AndroidDynamicToolbarAnimator::HandleTouchEnd(StaticToolbarState aCurrentToolbar
// If the last touch didn't have a drag direction, use start of touch to find direction
if (!direction) {
direction = ((aCurrentTouch - mControllerStartTouch) > 0 ? MOVE_TOOLBAR_DOWN : MOVE_TOOLBAR_UP);
if (mControllerToolbarHeight == mControllerMaxToolbarHeight) {
direction = MOVE_TOOLBAR_DOWN;
} else if (mControllerToolbarHeight == 0) {
direction = MOVE_TOOLBAR_UP;
} else {
direction = ((aCurrentTouch - mControllerStartTouch) > 0 ? MOVE_TOOLBAR_DOWN : MOVE_TOOLBAR_UP);
}
// If there still isn't a direction, default to show just to be safe
if (!direction) {
direction = MOVE_TOOLBAR_DOWN;
}
}
bool dragThresholdReached = mControllerDragThresholdReached;
mControllerStartTouch = 0;
mControllerPreviousTouch = 0;
mControllerTotalDistance = 0;
mControllerDragThresholdReached = false;
mControllerLastEventTimeStamp = 0;
bool cancelTouchTracking = mControllerCancelTouchTracking;
mControllerCancelTouchTracking = false;
// Animation is in progress, bail out.
if (aCurrentToolbarState == eToolbarAnimating) {
return;
}
// Received a UI thread request to show or hide the snapshot during a touch.
// This overrides the touch event so just return
if (mControllerCancelTouchTracking) {
mControllerCancelTouchTracking = false;
// This overrides the touch event so just return.
if (cancelTouchTracking) {
return;
}
// The toolbar is already where it needs to be so just return.
if (((direction == MOVE_TOOLBAR_DOWN) && (mControllerToolbarHeight == mControllerMaxToolbarHeight)) ||
((direction == MOVE_TOOLBAR_UP) && (mControllerToolbarHeight == 0))) {
ShowToolbarIfNotVisible(aCurrentToolbarState);
return;
}
@ -571,15 +615,7 @@ AndroidDynamicToolbarAnimator::HandleTouchEnd(StaticToolbarState aCurrentToolbar
}
}
// This makes sure the snapshot is not left partially visible at the end of a touch.
if ((aCurrentToolbarState != eToolbarAnimating) && dragThresholdReached) {
if (((direction == MOVE_TOOLBAR_DOWN) && (mControllerToolbarHeight != mControllerMaxToolbarHeight)) ||
((direction == MOVE_TOOLBAR_UP) && (mControllerToolbarHeight != 0))) {
StartCompositorAnimation(direction, eAnimate, mControllerToolbarHeight);
}
} else {
ShowToolbarIfNotVisible(aCurrentToolbarState);
}
StartCompositorAnimation(direction, eAnimate, mControllerToolbarHeight);
}
void
@ -910,5 +946,17 @@ AndroidDynamicToolbarAnimator::NotifyControllerSnapshotFailed()
UpdateCompositorToolbarHeight(mControllerToolbarHeight);
}
void
AndroidDynamicToolbarAnimator::CheckForResetOnNextMove(ScreenIntCoord aCurrentTouch) {
MOZ_ASSERT(APZThreadUtils::IsControllerThread());
if (mControllerResetOnNextMove) {
mControllerTotalDistance = 0;
mControllerLastDragDirection = 0;
mControllerStartTouch = mControllerPreviousTouch = aCurrentTouch;
mControllerDragThresholdReached = false;
mControllerResetOnNextMove = false;
}
}
} // namespace layers
} // namespace mozilla

View File

@ -150,6 +150,7 @@ protected:
void TranslateTouchEvent(MultiTouchInput& aTouchEvent);
ScreenIntCoord GetFixedLayerMarginsBottom();
void NotifyControllerSnapshotFailed();
void CheckForResetOnNextMove(ScreenIntCoord aCurrentTouch);
// Read only Compositor and Controller threads after Initialize()
uint64_t mRootLayerTreeId;
@ -163,6 +164,9 @@ protected:
bool mControllerDragThresholdReached; // Set to true when the drag threshold has been passed in a single drag
bool mControllerCancelTouchTracking; // Set to true when the UI thread requests the toolbar be made visible
bool mControllerDragChangedDirection; // Set to true if the drag ever goes in more than one direction
bool mControllerResetOnNextMove; // Set to true if transitioning from multiple touches to a single touch source
// Causes mControllerStartTouch, mControllerPreviousTouch, mControllerTotalDistance,
// mControllerDragThresholdReached, and mControllerLastDragDirection to be reset on next move
ScreenIntCoord mControllerStartTouch; // The Y position where the touch started
ScreenIntCoord mControllerPreviousTouch; // The previous Y position of the touch
ScreenIntCoord mControllerTotalDistance; // Total distance travel during the current touch
@ -171,6 +175,7 @@ protected:
ScreenIntCoord mControllerSurfaceHeight; // Current height of the render surface
ScreenIntCoord mControllerCompositionHeight; // Current height of the visible page
int32_t mControllerLastDragDirection; // Direction of movement of the previous touch move event
int32_t mControllerTouchCount; // Counts the number of current touches.
uint32_t mControllerLastEventTimeStamp; // Time stamp for the previous touch event received
ControllerThreadState mControllerState; // Contains the expected pending state of the mToolbarState

View File

@ -1147,12 +1147,13 @@ LayerManagerComposite::RenderToolbar()
EffectChain effects;
effects.mPrimaryEffect = animator->GetToolbarEffect(mCompositor->AsCompositorOGL());
if (!effects.mPrimaryEffect) {
// No toolbar texture so just draw a red square
effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(1, 0, 0));
// If GetToolbarEffect returns null, nothing is rendered for the static snapshot of the toolbar.
// If the real toolbar chrome is not covering this portion of the surface, the clear color
// of the surface will be visible. On Android the clear color is the background color of the page.
if (effects.mPrimaryEffect) {
mCompositor->DrawQuad(gfx::Rect(0, 0, mRenderBounds.width, toolbarHeight),
IntRect(0, 0, mRenderBounds.width, toolbarHeight), effects, 1.0, gfx::Matrix4x4());
}
mCompositor->DrawQuad(gfx::Rect(0, 0, mRenderBounds.width, toolbarHeight),
IntRect(0, 0, mRenderBounds.width, toolbarHeight), effects, 1.0, gfx::Matrix4x4());
// Move the content down the surface by the toolbar's height so they don't overlap
gfx::Matrix4x4 mat = mCompositor->AsCompositorOGL()->GetProjMatrix();

View File

@ -123,7 +123,15 @@ CrossProcessCompositorBridgeParent::AllocPAPZCTreeManagerParent(const uint64_t&
MonitorAutoLock lock(*sIndirectLayerTreesLock);
CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[aLayersId];
MOZ_ASSERT(state.mParent);
// If the widget has shutdown its compositor, we may not have had a chance yet
// to unmap our layers id, and we could get here without a parent compositor.
// In this case return an empty APZCTM.
if (!state.mParent) {
RefPtr<APZCTreeManager> temp = new APZCTreeManager();
return new APZCTreeManagerParent(aLayersId, temp);
}
MOZ_ASSERT(!state.mApzcTreeManagerParent);
state.mApzcTreeManagerParent = new APZCTreeManagerParent(aLayersId, state.mParent->GetAPZCTreeManager());

View File

@ -2587,7 +2587,7 @@ gfxFont::GetShapedWord(DrawTarget *aDrawTarget,
CacheHashKey key(aText, aLength, aHash,
aRunScript,
aAppUnitsPerDevUnit,
aFlags);
aFlags, aRounding);
CacheHashEntry *entry = mWordCache->PutEntry(key);
if (!entry) {
@ -2621,7 +2621,7 @@ gfxFont::GetShapedWord(DrawTarget *aDrawTarget,
#endif
sw = gfxShapedWord::Create(aText, aLength, aRunScript, aAppUnitsPerDevUnit,
aFlags);
aFlags, aRounding);
entry->mShapedWord.reset(sw);
if (!sw) {
NS_WARNING("failed to create gfxShapedWord - expect missing text");
@ -2646,6 +2646,7 @@ gfxFont::CacheHashEntry::KeyEquals(const KeyTypePointer aKey) const
}
if (sw->GetLength() != aKey->mLength ||
sw->GetFlags() != aKey->mFlags ||
sw->GetRounding() != aKey->mRounding ||
sw->GetAppUnitsPerDevUnit() != aKey->mAppUnitsPerDevUnit ||
sw->GetScript() != aKey->mScript) {
return false;

View File

@ -1190,7 +1190,8 @@ public:
static gfxShapedWord* Create(const uint8_t *aText, uint32_t aLength,
Script aRunScript,
int32_t aAppUnitsPerDevUnit,
uint32_t aFlags) {
uint32_t aFlags,
gfxFontShaper::RoundingFlags aRounding) {
NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(),
"excessive length for gfxShapedWord!");
@ -1206,13 +1207,15 @@ public:
// Construct in the pre-allocated storage, using placement new
return new (storage) gfxShapedWord(aText, aLength, aRunScript,
aAppUnitsPerDevUnit, aFlags);
aAppUnitsPerDevUnit, aFlags,
aRounding);
}
static gfxShapedWord* Create(const char16_t *aText, uint32_t aLength,
Script aRunScript,
int32_t aAppUnitsPerDevUnit,
uint32_t aFlags) {
uint32_t aFlags,
gfxFontShaper::RoundingFlags aRounding) {
NS_ASSERTION(aLength <= gfxPlatform::GetPlatform()->WordCacheCharLimit(),
"excessive length for gfxShapedWord!");
@ -1224,7 +1227,8 @@ public:
LossyAppendUTF16toASCII(nsDependentSubstring(aText, aLength),
narrowText);
return Create((const uint8_t*)(narrowText.BeginReading()),
aLength, aRunScript, aAppUnitsPerDevUnit, aFlags);
aLength, aRunScript, aAppUnitsPerDevUnit, aFlags,
aRounding);
}
uint32_t size =
@ -1236,7 +1240,8 @@ public:
}
return new (storage) gfxShapedWord(aText, aLength, aRunScript,
aAppUnitsPerDevUnit, aFlags);
aAppUnitsPerDevUnit, aFlags,
aRounding);
}
// Override operator delete to properly free the object that was
@ -1272,6 +1277,10 @@ public:
return mScript;
}
gfxFontShaper::RoundingFlags GetRounding() const {
return mRounding;
}
void ResetAge() {
mAgeCounter = 0;
}
@ -1292,10 +1301,12 @@ private:
// Construct storage for a ShapedWord, ready to receive glyph data
gfxShapedWord(const uint8_t *aText, uint32_t aLength,
Script aRunScript,
int32_t aAppUnitsPerDevUnit, uint32_t aFlags)
int32_t aAppUnitsPerDevUnit, uint32_t aFlags,
gfxFontShaper::RoundingFlags aRounding)
: gfxShapedText(aLength, aFlags | gfxTextRunFactory::TEXT_IS_8BIT,
aAppUnitsPerDevUnit)
, mScript(aRunScript)
, mRounding(aRounding)
, mAgeCounter(0)
{
memset(mCharGlyphsStorage, 0, aLength * sizeof(CompressedGlyph));
@ -1305,9 +1316,11 @@ private:
gfxShapedWord(const char16_t *aText, uint32_t aLength,
Script aRunScript,
int32_t aAppUnitsPerDevUnit, uint32_t aFlags)
int32_t aAppUnitsPerDevUnit, uint32_t aFlags,
gfxFontShaper::RoundingFlags aRounding)
: gfxShapedText(aLength, aFlags, aAppUnitsPerDevUnit)
, mScript(aRunScript)
, mRounding(aRounding)
, mAgeCounter(0)
{
memset(mCharGlyphsStorage, 0, aLength * sizeof(CompressedGlyph));
@ -1318,6 +1331,8 @@ private:
Script mScript;
gfxFontShaper::RoundingFlags mRounding;
uint32_t mAgeCounter;
// The mCharGlyphsStorage array is actually a variable-size member;
@ -2032,18 +2047,23 @@ protected:
int32_t mAppUnitsPerDevUnit;
PLDHashNumber mHashKey;
bool mTextIs8Bit;
RoundingFlags mRounding;
CacheHashKey(const uint8_t *aText, uint32_t aLength,
uint32_t aStringHash,
Script aScriptCode, int32_t aAppUnitsPerDevUnit,
uint32_t aFlags)
uint32_t aFlags, RoundingFlags aRounding)
: mLength(aLength),
mFlags(aFlags),
mScript(aScriptCode),
mAppUnitsPerDevUnit(aAppUnitsPerDevUnit),
mHashKey(aStringHash + static_cast<int32_t>(aScriptCode) +
aAppUnitsPerDevUnit * 0x100 + aFlags * 0x10000),
mTextIs8Bit(true)
mHashKey(aStringHash
+ static_cast<int32_t>(aScriptCode)
+ aAppUnitsPerDevUnit * 0x100
+ aFlags * 0x10000
+ int(aRounding)),
mTextIs8Bit(true),
mRounding(aRounding)
{
NS_ASSERTION(aFlags & gfxTextRunFactory::TEXT_IS_8BIT,
"8-bit flag should have been set");
@ -2053,14 +2073,18 @@ protected:
CacheHashKey(const char16_t *aText, uint32_t aLength,
uint32_t aStringHash,
Script aScriptCode, int32_t aAppUnitsPerDevUnit,
uint32_t aFlags)
uint32_t aFlags, RoundingFlags aRounding)
: mLength(aLength),
mFlags(aFlags),
mScript(aScriptCode),
mAppUnitsPerDevUnit(aAppUnitsPerDevUnit),
mHashKey(aStringHash + static_cast<int32_t>(aScriptCode) +
aAppUnitsPerDevUnit * 0x100 + aFlags * 0x10000),
mTextIs8Bit(false)
mHashKey(aStringHash
+ static_cast<int32_t>(aScriptCode)
+ aAppUnitsPerDevUnit * 0x100
+ aFlags * 0x10000
+ int(aRounding)),
mTextIs8Bit(false),
mRounding(aRounding)
{
// We can NOT assert that TEXT_IS_8BIT is false in aFlags here,
// because this might be an 8bit-only word from a 16-bit textrun,

View File

@ -995,7 +995,7 @@ close DATA_TABLES;
print HEADER "namespace mozilla {\n";
print HEADER "namespace unicode {\n";
print HEADER "enum class Script {\n";
print HEADER "enum class Script : int16_t {\n";
for (my $i = 0; $i < scalar @scriptCodeToName; ++$i) {
print HEADER " ", $scriptCodeToName[$i], " = ", $i, ",\n";
}

View File

@ -11,7 +11,7 @@
*/
/*
* Created on Tue Nov 15 16:39:42 2016 from UCD data files with version info:
* Created on Tue Apr 4 21:22:17 2017 from UCD data files with version info:
*
# Unicode Character Database

View File

@ -11,7 +11,7 @@
*/
/*
* Created on Tue Nov 15 16:39:42 2016 from UCD data files with version info:
* Created on Tue Apr 4 21:22:17 2017 from UCD data files with version info:
*
# Unicode Character Database
@ -122,7 +122,7 @@ struct nsCharProps2 {
namespace mozilla {
namespace unicode {
enum class Script {
enum class Script : int16_t {
COMMON = 0,
INHERITED = 1,
ARABIC = 2,

View File

@ -1,49 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.0.0.0"
processorArchitecture="*"
name="plugin-container"
type="win32"
/>
<description>Firefox Runtime</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
<comInterfaceExternalProxyStub
iid="{618736E0-3C3D-11CF-810C-00AA00389B71}"
proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"
name="IAccessible"
tlbid="{1EA4DBF0-3C3B-11CF-810C-00AA00389B71}"
/>
<ms_asmv3:trustInfo xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3">
<ms_asmv3:security>
<ms_asmv3:requestedPrivileges>
<ms_asmv3:requestedExecutionLevel level="asInvoker" uiAccess="false" />
</ms_asmv3:requestedPrivileges>
</ms_asmv3:security>
</ms_asmv3:trustInfo>
<ms_asmv3:application xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3">
<ms_asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>True/PM</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2,PerMonitor</dpiAwareness>
</ms_asmv3:windowsSettings>
</ms_asmv3:application>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
</application>
</compatibility>
</assembly>

View File

@ -59,14 +59,14 @@ static inline AuxCPOWData*
AuxCPOWDataOf(JSObject* obj)
{
MOZ_ASSERT(IsCPOW(obj));
return static_cast<AuxCPOWData*>(GetProxyExtra(obj, 1).toPrivate());
return static_cast<AuxCPOWData*>(GetProxyReservedSlot(obj, 1).toPrivate());
}
static inline WrapperOwner*
OwnerOf(JSObject* obj)
{
MOZ_ASSERT(IsCPOW(obj));
return reinterpret_cast<WrapperOwner*>(GetProxyExtra(obj, 0).toPrivate());
return reinterpret_cast<WrapperOwner*>(GetProxyReservedSlot(obj, 0).toPrivate());
}
ObjectId
@ -1218,8 +1218,8 @@ WrapperOwner::fromRemoteObjectVariant(JSContext* cx, const RemoteObject& objVar)
objVar.isDOMObject(),
objVar.objectTag());
SetProxyExtra(obj, 0, PrivateValue(this));
SetProxyExtra(obj, 1, PrivateValue(aux));
SetProxyReservedSlot(obj, 0, PrivateValue(this));
SetProxyReservedSlot(obj, 1, PrivateValue(aux));
}
if (!JS_WrapObject(cx, &obj))

View File

@ -367,30 +367,71 @@ inline bool IsProxy(const JSObject* obj)
}
namespace detail {
const uint32_t PROXY_EXTRA_SLOTS = 2;
// Layout of the values stored by a proxy. Note that API clients require the
// private slot to be the first slot in the proxy's values, so that the private
// slot can be accessed in the same fashion as the first reserved slot, via
// {Get,Set}ReservedOrProxyPrivateSlot.
// Proxy slot layout
// -----------------
//
// Every proxy has a ProxyValueArray that contains the following Values:
//
// - The private slot.
// - The reserved slots. The number of slots is determined by the proxy's Class.
//
// Proxy objects store a pointer to the reserved slots (ProxyReservedSlots*).
// The ProxyValueArray and the private slot can be accessed using
// ProxyValueArray::fromReservedSlots or ProxyDataLayout::values.
//
// Storing a pointer to ProxyReservedSlots instead of ProxyValueArray has a
// number of advantages. In particular, it means js::GetReservedSlot and
// js::SetReservedSlot can be used with both proxies and native objects. This
// works because the ProxyReservedSlots* pointer is stored where native objects
// store their dynamic slots pointer.
struct ProxyReservedSlots
{
Value slots[1];
static inline int offsetOfPrivateSlot();
void init(size_t nreserved) {
for (size_t i = 0; i < nreserved; i++)
slots[i] = JS::UndefinedValue();
}
ProxyReservedSlots(const ProxyReservedSlots&) = delete;
void operator=(const ProxyReservedSlots&) = delete;
};
struct ProxyValueArray
{
Value privateSlot;
Value extraSlots[PROXY_EXTRA_SLOTS];
ProxyReservedSlots reservedSlots;
ProxyValueArray()
: privateSlot(JS::UndefinedValue())
{
for (size_t i = 0; i < PROXY_EXTRA_SLOTS; i++)
extraSlots[i] = JS::UndefinedValue();
void init(size_t nreserved) {
privateSlot = JS::UndefinedValue();
reservedSlots.init(nreserved);
}
static size_t offsetOfPrivateSlot() {
return offsetof(ProxyValueArray, privateSlot);
static size_t sizeOf(size_t nreserved) {
return offsetOfReservedSlots() + nreserved * sizeof(Value);
}
static MOZ_ALWAYS_INLINE ProxyValueArray* fromReservedSlots(ProxyReservedSlots* slots) {
uintptr_t p = reinterpret_cast<uintptr_t>(slots);
return reinterpret_cast<ProxyValueArray*>(p - offsetOfReservedSlots());
}
static size_t offsetOfReservedSlots() {
return offsetof(ProxyValueArray, reservedSlots);
}
ProxyValueArray(const ProxyValueArray&) = delete;
void operator=(const ProxyValueArray&) = delete;
};
/* static */ inline int
ProxyReservedSlots::offsetOfPrivateSlot()
{
return -int(ProxyValueArray::offsetOfReservedSlots()) + offsetof(ProxyValueArray, privateSlot);
}
// All proxies share the same data layout. Following the object's shape and
// type, the proxy has a ProxyDataLayout structure with a pointer to an array
// of values and the proxy's handler. This is designed both so that proxies can
@ -401,8 +442,12 @@ struct ProxyValueArray
// See GetReservedOrProxyPrivateSlot below.
struct ProxyDataLayout
{
ProxyValueArray* values;
ProxyReservedSlots* reservedSlots;
const BaseProxyHandler* handler;
MOZ_ALWAYS_INLINE ProxyValueArray* values() const {
return ProxyValueArray::fromReservedSlots(reservedSlots);
}
};
const uint32_t ProxyDataOffset = 2 * sizeof(void*);
@ -432,7 +477,7 @@ GetProxyHandler(const JSObject* obj)
inline const Value&
GetProxyPrivate(const JSObject* obj)
{
return detail::GetProxyDataLayout(obj)->values->privateSlot;
return detail::GetProxyDataLayout(obj)->values()->privateSlot;
}
inline JSObject*
@ -442,10 +487,10 @@ GetProxyTargetObject(JSObject* obj)
}
inline const Value&
GetProxyExtra(const JSObject* obj, size_t n)
GetProxyReservedSlot(const JSObject* obj, size_t n)
{
MOZ_ASSERT(n < detail::PROXY_EXTRA_SLOTS);
return detail::GetProxyDataLayout(obj)->values->extraSlots[n];
MOZ_ASSERT(n < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj)));
return detail::GetProxyDataLayout(obj)->reservedSlots->slots[n];
}
inline void
@ -458,10 +503,10 @@ JS_FRIEND_API(void)
SetValueInProxy(Value* slot, const Value& value);
inline void
SetProxyExtra(JSObject* obj, size_t n, const Value& extra)
SetProxyReservedSlot(JSObject* obj, size_t n, const Value& extra)
{
MOZ_ASSERT(n < detail::PROXY_EXTRA_SLOTS);
Value* vp = &detail::GetProxyDataLayout(obj)->values->extraSlots[n];
MOZ_ASSERT(n < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj)));
Value* vp = &detail::GetProxyDataLayout(obj)->reservedSlots->slots[n];
// Trigger a barrier before writing the slot.
if (vp->isGCThing() || extra.isGCThing())
@ -470,32 +515,24 @@ SetProxyExtra(JSObject* obj, size_t n, const Value& extra)
*vp = extra;
}
inline void
SetProxyPrivate(JSObject* obj, const Value& value)
{
Value* vp = &detail::GetProxyDataLayout(obj)->values()->privateSlot;
// Trigger a barrier before writing the slot.
if (vp->isGCThing() || value.isGCThing())
SetValueInProxy(vp, value);
else
*vp = value;
}
inline bool
IsScriptedProxy(const JSObject* obj)
{
return IsProxy(obj) && GetProxyHandler(obj)->isScripted();
}
inline const Value&
GetReservedOrProxyPrivateSlot(const JSObject* obj, size_t slot)
{
MOZ_ASSERT(slot == 0);
MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj)) || IsProxy(obj));
return reinterpret_cast<const shadow::Object*>(obj)->slotRef(slot);
}
inline void
SetReservedOrProxyPrivateSlot(JSObject* obj, size_t slot, const Value& value)
{
MOZ_ASSERT(slot == 0);
MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj)) || IsProxy(obj));
shadow::Object* sobj = reinterpret_cast<shadow::Object*>(obj);
if (sobj->slotRef(slot).isGCThing() || value.isGCThing())
SetReservedOrProxyPrivateSlotWithBarrier(obj, slot, value);
else
sobj->slotRef(slot) = value;
}
class MOZ_STACK_CLASS ProxyOptions {
protected:
/* protected constructor for subclass */

View File

@ -9607,6 +9607,21 @@ Parser<ParseHandler, CharT>::propertyName(YieldHandling yieldHandling,
return null();
break;
case TOK_STRING: {
propAtom.set(tokenStream.currentToken().atom());
uint32_t index;
if (propAtom->isIndex(&index)) {
propName = handler.newNumber(index, NoDecimal, pos());
if (!propName)
return null();
break;
}
propName = stringLiteral();
if (!propName)
return null();
break;
}
case TOK_LB:
propName = computedPropertyName(yieldHandling, maybeDecl, propList);
if (!propName)
@ -9620,7 +9635,7 @@ Parser<ParseHandler, CharT>::propertyName(YieldHandling yieldHandling,
}
propAtom.set(tokenStream.currentName());
// Do not look for accessor syntax on generators
// Do not look for accessor syntax on generator or async methods.
if (isGenerator || isAsync || !(ltok == TOK_GET || ltok == TOK_SET)) {
propName = handler.newObjectLiteralPropertyName(propAtom, pos());
if (!propName)
@ -9675,21 +9690,6 @@ Parser<ParseHandler, CharT>::propertyName(YieldHandling yieldHandling,
return null();
break;
}
case TOK_STRING: {
propAtom.set(tokenStream.currentToken().atom());
uint32_t index;
if (propAtom->isIndex(&index)) {
propName = handler.newNumber(index, NoDecimal, pos());
if (!propName)
return null();
break;
}
propName = stringLiteral();
if (!propName)
return null();
break;
}
}
TokenKind tt;
@ -9697,7 +9697,7 @@ Parser<ParseHandler, CharT>::propertyName(YieldHandling yieldHandling,
return null();
if (tt == TOK_COLON) {
if (isGenerator) {
if (isGenerator || isAsync) {
error(JSMSG_BAD_PROP_ID);
return null();
}
@ -9708,7 +9708,7 @@ Parser<ParseHandler, CharT>::propertyName(YieldHandling yieldHandling,
if (TokenKindIsPossibleIdentifierName(ltok) &&
(tt == TOK_COMMA || tt == TOK_RC || tt == TOK_ASSIGN))
{
if (isGenerator) {
if (isGenerator || isAsync) {
error(JSMSG_BAD_PROP_ID);
return null();
}

View File

@ -0,0 +1,15 @@
// |jit-test| --no-threads
"use strict";
function test() {
for (var k = 0; k < 35; ++k) {
try {
(function (x) {
(x ? 0 : ([y] = []));
})();
} catch (e) {}
}
}
for (var i = 0; i < 35; i++)
test();

View File

@ -1826,8 +1826,8 @@ BaselineCacheIRCompiler::emitLoadDOMExpandoValueGuardGeneration()
if (!addFailurePath(&failure))
return false;
masm.loadPtr(Address(obj, ProxyObject::offsetOfValues()), scratch);
Address expandoAddr(scratch, ProxyObject::offsetOfExtraSlotInValues(GetDOMProxyExpandoSlot()));
masm.loadPtr(Address(obj, ProxyObject::offsetOfReservedSlots()), scratch);
Address expandoAddr(scratch, detail::ProxyReservedSlots::offsetOfPrivateSlot());
// Load the ExpandoAndGeneration* in the output scratch register and guard
// it matches the proxy's ExpandoAndGeneration.

View File

@ -803,7 +803,7 @@ GetPropIRGenerator::tryAttachDOMProxyExpando(HandleObject obj, ObjOperandId objI
{
MOZ_ASSERT(IsCacheableDOMProxy(obj));
RootedValue expandoVal(cx_, GetProxyExtra(obj, GetDOMProxyExpandoSlot()));
RootedValue expandoVal(cx_, GetProxyPrivate(obj));
RootedObject expandoObj(cx_);
if (expandoVal.isObject()) {
expandoObj = &expandoVal.toObject();
@ -873,7 +873,7 @@ CheckDOMProxyExpandoDoesNotShadow(CacheIRWriter& writer, JSObject* obj, jsid id,
{
MOZ_ASSERT(IsCacheableDOMProxy(obj));
Value expandoVal = GetProxyExtra(obj, GetDOMProxyExpandoSlot());
Value expandoVal = GetProxyPrivate(obj);
ValOperandId expandoId;
if (!expandoVal.isObject() && !expandoVal.isUndefined()) {
@ -3164,7 +3164,7 @@ SetPropIRGenerator::tryAttachDOMProxyExpando(HandleObject obj, ObjOperandId objI
{
MOZ_ASSERT(IsCacheableDOMProxy(obj));
RootedValue expandoVal(cx_, GetProxyExtra(obj, GetDOMProxyExpandoSlot()));
RootedValue expandoVal(cx_, GetProxyPrivate(obj));
RootedObject expandoObj(cx_);
if (expandoVal.isObject()) {
expandoObj = &expandoVal.toObject();

View File

@ -1576,8 +1576,8 @@ CacheIRCompiler::emitLoadWrapperTarget()
Register obj = allocator.useRegister(masm, reader.objOperandId());
Register reg = allocator.defineRegister(masm, reader.objOperandId());
masm.loadPtr(Address(obj, ProxyObject::offsetOfValues()), reg);
masm.unboxObject(Address(reg, detail::ProxyValueArray::offsetOfPrivateSlot()), reg);
masm.loadPtr(Address(obj, ProxyObject::offsetOfReservedSlots()), reg);
masm.unboxObject(Address(reg, detail::ProxyReservedSlots::offsetOfPrivateSlot()), reg);
return true;
}
@ -1587,9 +1587,9 @@ CacheIRCompiler::emitLoadDOMExpandoValue()
Register obj = allocator.useRegister(masm, reader.objOperandId());
ValueOperand val = allocator.defineValueRegister(masm, reader.valOperandId());
masm.loadPtr(Address(obj, ProxyObject::offsetOfValues()), val.scratchReg());
masm.loadPtr(Address(obj, ProxyObject::offsetOfReservedSlots()), val.scratchReg());
masm.loadValue(Address(val.scratchReg(),
ProxyObject::offsetOfExtraSlotInValues(GetDOMProxyExpandoSlot())),
detail::ProxyReservedSlots::offsetOfPrivateSlot()),
val);
return true;
}
@ -1602,8 +1602,8 @@ CacheIRCompiler::emitLoadDOMExpandoValueIgnoreGeneration()
// Determine the expando's Address.
Register scratch = output.scratchReg();
masm.loadPtr(Address(obj, ProxyObject::offsetOfValues()), scratch);
Address expandoAddr(scratch, ProxyObject::offsetOfExtraSlotInValues(GetDOMProxyExpandoSlot()));
masm.loadPtr(Address(obj, ProxyObject::offsetOfReservedSlots()), scratch);
Address expandoAddr(scratch, detail::ProxyReservedSlots::offsetOfPrivateSlot());
#ifdef DEBUG
// Private values are stored as doubles, so assert we have a double.

View File

@ -1985,8 +1985,8 @@ IonCacheIRCompiler::emitLoadDOMExpandoValueGuardGeneration()
if (!addFailurePath(&failure))
return false;
masm.loadPtr(Address(obj, ProxyObject::offsetOfValues()), scratch1);
Address expandoAddr(scratch1, ProxyObject::offsetOfExtraSlotInValues(GetDOMProxyExpandoSlot()));
masm.loadPtr(Address(obj, ProxyObject::offsetOfReservedSlots()), scratch1);
Address expandoAddr(scratch1, detail::ProxyReservedSlots::offsetOfPrivateSlot());
// Guard the ExpandoAndGeneration* matches the proxy's ExpandoAndGeneration.
masm.loadValue(expandoAddr, output);

View File

@ -348,7 +348,8 @@ CloseLiveIteratorIon(JSContext* cx, const InlineFrameIterator& frame, JSTryNote*
for (unsigned i = 0; i < skipSlots; i++)
si.skip();
Value v = si.read();
MaybeReadFallback recover(cx, cx->activation()->asJit(), &frame.frame(), MaybeReadFallback::Fallback_DoNothing);
Value v = si.maybeRead(recover);
RootedObject iterObject(cx, &v.toObject());
if (isDestructuring) {

View File

@ -74,15 +74,15 @@ BEGIN_TEST(testBug604087)
JS::RootedObject c2wrapper(cx, wrap(cx, outerObj, compartment2));
CHECK(c2wrapper);
c2wrapper->as<js::ProxyObject>().setExtra(0, js::Int32Value(2));
c2wrapper->as<js::ProxyObject>().setReservedSlot(0, js::Int32Value(2));
JS::RootedObject c3wrapper(cx, wrap(cx, outerObj, compartment3));
CHECK(c3wrapper);
c3wrapper->as<js::ProxyObject>().setExtra(0, js::Int32Value(3));
c3wrapper->as<js::ProxyObject>().setReservedSlot(0, js::Int32Value(3));
JS::RootedObject c4wrapper(cx, wrap(cx, outerObj, compartment4));
CHECK(c4wrapper);
c4wrapper->as<js::ProxyObject>().setExtra(0, js::Int32Value(4));
c4wrapper->as<js::ProxyObject>().setReservedSlot(0, js::Int32Value(4));
compartment4 = c4wrapper = nullptr;
JS::RootedObject next(cx);

View File

@ -2824,10 +2824,10 @@ GetIndexedPropertiesInRange(JSContext* cx, HandleObject obj, uint32_t begin, uin
for (; !r.empty(); r.popFront()) {
Shape& shape = r.front();
jsid id = shape.propid();
if (!JSID_IS_INT(id))
uint32_t i;
if (!IdIsIndex(id, &i))
continue;
uint32_t i = uint32_t(JSID_TO_INT(id));
if (!(begin <= i && i < end))
continue;

View File

@ -546,14 +546,12 @@ js::GetOriginalEval(JSContext* cx, HandleObject scope, MutableHandleObject eval)
}
JS_FRIEND_API(void)
js::SetReservedOrProxyPrivateSlotWithBarrier(JSObject* obj, size_t slot, const js::Value& value)
js::SetReservedSlotWithBarrier(JSObject* obj, size_t slot, const js::Value& value)
{
if (IsProxy(obj)) {
MOZ_ASSERT(slot == 0);
obj->as<ProxyObject>().setSameCompartmentPrivate(value);
} else {
if (IsProxy(obj))
obj->as<ProxyObject>().setReservedSlot(slot, value);
else
obj->as<NativeObject>().setSlot(slot, value);
}
}
void
@ -1298,15 +1296,13 @@ js::GetDOMCallbacks(JSContext* cx)
}
static const void* gDOMProxyHandlerFamily = nullptr;
static uint32_t gDOMProxyExpandoSlot = 0;
static DOMProxyShadowsCheck gDOMProxyShadowsCheck;
JS_FRIEND_API(void)
js::SetDOMProxyInformation(const void* domProxyHandlerFamily, uint32_t domProxyExpandoSlot,
js::SetDOMProxyInformation(const void* domProxyHandlerFamily,
DOMProxyShadowsCheck domProxyShadowsCheck)
{
gDOMProxyHandlerFamily = domProxyHandlerFamily;
gDOMProxyExpandoSlot = domProxyExpandoSlot;
gDOMProxyShadowsCheck = domProxyShadowsCheck;
}
@ -1316,12 +1312,6 @@ js::GetDOMProxyHandlerFamily()
return gDOMProxyHandlerFamily;
}
uint32_t
js::GetDOMProxyExpandoSlot()
{
return gDOMProxyExpandoSlot;
}
DOMProxyShadowsCheck
js::GetDOMProxyShadowsCheck()
{

View File

@ -365,6 +365,7 @@ extern JS_FRIEND_DATA(const js::ObjectOps) ProxyObjectOps;
js::Class::NON_NATIVE | \
JSCLASS_IS_PROXY | \
JSCLASS_DELAY_METADATA_BUILDER | \
JSCLASS_HAS_RESERVED_SLOTS(2) | \
flags, \
&js::ProxyClassOps, \
JS_NULL_CLASS_SPEC, \
@ -722,6 +723,11 @@ GetObjectPrivate(JSObject* obj)
return *addr;
}
/**
* Get the value stored in an object's reserved slot. This can be used with
* both native objects and proxies, but if |obj| is known to be a proxy
* GetProxyReservedSlot is a bit more efficient.
*/
inline const JS::Value&
GetReservedSlot(JSObject* obj, size_t slot)
{
@ -730,15 +736,20 @@ GetReservedSlot(JSObject* obj, size_t slot)
}
JS_FRIEND_API(void)
SetReservedOrProxyPrivateSlotWithBarrier(JSObject* obj, size_t slot, const JS::Value& value);
SetReservedSlotWithBarrier(JSObject* obj, size_t slot, const JS::Value& value);
/**
* Store a value in an object's reserved slot. This can be used with
* both native objects and proxies, but if |obj| is known to be a proxy
* SetProxyReservedSlot is a bit more efficient.
*/
inline void
SetReservedSlot(JSObject* obj, size_t slot, const JS::Value& value)
{
MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj)));
shadow::Object* sobj = reinterpret_cast<shadow::Object*>(obj);
if (sobj->slotRef(slot).isGCThing() || value.isGCThing())
SetReservedOrProxyPrivateSlotWithBarrier(obj, slot, value);
SetReservedSlotWithBarrier(obj, slot, value);
else
sobj->slotRef(slot) = value;
}
@ -1289,11 +1300,10 @@ typedef enum DOMProxyShadowsResult {
typedef DOMProxyShadowsResult
(* DOMProxyShadowsCheck)(JSContext* cx, JS::HandleObject object, JS::HandleId id);
JS_FRIEND_API(void)
SetDOMProxyInformation(const void* domProxyHandlerFamily, uint32_t domProxyExpandoSlot,
SetDOMProxyInformation(const void* domProxyHandlerFamily,
DOMProxyShadowsCheck domProxyShadowsCheck);
const void* GetDOMProxyHandlerFamily();
uint32_t GetDOMProxyExpandoSlot();
DOMProxyShadowsCheck GetDOMProxyShadowsCheck();
inline bool DOMProxyIsShadowing(DOMProxyShadowsResult result) {
return result == Shadows ||

View File

@ -4677,7 +4677,7 @@ IsGrayListObject(JSObject* obj)
}
/* static */ unsigned
ProxyObject::grayLinkExtraSlot(JSObject* obj)
ProxyObject::grayLinkReservedSlot(JSObject* obj)
{
MOZ_ASSERT(IsGrayListObject(obj));
return 1;
@ -4688,7 +4688,7 @@ static void
AssertNotOnGrayList(JSObject* obj)
{
MOZ_ASSERT_IF(IsGrayListObject(obj),
GetProxyExtra(obj, ProxyObject::grayLinkExtraSlot(obj)).isUndefined());
GetProxyReservedSlot(obj, ProxyObject::grayLinkReservedSlot(obj)).isUndefined());
}
#endif
@ -4716,12 +4716,12 @@ CrossCompartmentPointerReferent(JSObject* obj)
static JSObject*
NextIncomingCrossCompartmentPointer(JSObject* prev, bool unlink)
{
unsigned slot = ProxyObject::grayLinkExtraSlot(prev);
JSObject* next = GetProxyExtra(prev, slot).toObjectOrNull();
unsigned slot = ProxyObject::grayLinkReservedSlot(prev);
JSObject* next = GetProxyReservedSlot(prev, slot).toObjectOrNull();
MOZ_ASSERT_IF(next, IsGrayListObject(next));
if (unlink)
SetProxyExtra(prev, slot, UndefinedValue());
SetProxyReservedSlot(prev, slot, UndefinedValue());
return next;
}
@ -4732,15 +4732,15 @@ js::DelayCrossCompartmentGrayMarking(JSObject* src)
MOZ_ASSERT(IsGrayListObject(src));
/* Called from MarkCrossCompartmentXXX functions. */
unsigned slot = ProxyObject::grayLinkExtraSlot(src);
unsigned slot = ProxyObject::grayLinkReservedSlot(src);
JSObject* dest = CrossCompartmentPointerReferent(src);
JSCompartment* comp = dest->compartment();
if (GetProxyExtra(src, slot).isUndefined()) {
SetProxyExtra(src, slot, ObjectOrNullValue(comp->gcIncomingGrayPointers));
if (GetProxyReservedSlot(src, slot).isUndefined()) {
SetProxyReservedSlot(src, slot, ObjectOrNullValue(comp->gcIncomingGrayPointers));
comp->gcIncomingGrayPointers = src;
} else {
MOZ_ASSERT(GetProxyExtra(src, slot).isObjectOrNull());
MOZ_ASSERT(GetProxyReservedSlot(src, slot).isObjectOrNull());
}
#ifdef DEBUG
@ -4809,12 +4809,12 @@ RemoveFromGrayList(JSObject* wrapper)
if (!IsGrayListObject(wrapper))
return false;
unsigned slot = ProxyObject::grayLinkExtraSlot(wrapper);
if (GetProxyExtra(wrapper, slot).isUndefined())
unsigned slot = ProxyObject::grayLinkReservedSlot(wrapper);
if (GetProxyReservedSlot(wrapper, slot).isUndefined())
return false; /* Not on our list. */
JSObject* tail = GetProxyExtra(wrapper, slot).toObjectOrNull();
SetProxyExtra(wrapper, slot, UndefinedValue());
JSObject* tail = GetProxyReservedSlot(wrapper, slot).toObjectOrNull();
SetProxyReservedSlot(wrapper, slot, UndefinedValue());
JSCompartment* comp = CrossCompartmentPointerReferent(wrapper)->compartment();
JSObject* obj = comp->gcIncomingGrayPointers;
@ -4824,10 +4824,10 @@ RemoveFromGrayList(JSObject* wrapper)
}
while (obj) {
unsigned slot = ProxyObject::grayLinkExtraSlot(obj);
JSObject* next = GetProxyExtra(obj, slot).toObjectOrNull();
unsigned slot = ProxyObject::grayLinkReservedSlot(obj);
JSObject* next = GetProxyReservedSlot(obj, slot).toObjectOrNull();
if (next == wrapper) {
SetProxyExtra(obj, slot, ObjectOrNullValue(tail));
SetProxyReservedSlot(obj, slot, ObjectOrNullValue(tail));
return true;
}
obj = next;

View File

@ -1125,12 +1125,14 @@ CopyProxyObject(JSContext* cx, Handle<ProxyObject*> from, Handle<ProxyObject*> t
to->setSameCompartmentPrivate(v);
}
MOZ_ASSERT(from->numReservedSlots() == to->numReservedSlots());
RootedValue v(cx);
for (size_t n = 0; n < js::detail::PROXY_EXTRA_SLOTS; n++) {
v = GetProxyExtra(from, n);
for (size_t n = 0; n < from->numReservedSlots(); n++) {
v = GetProxyReservedSlot(from, n);
if (!cx->compartment()->wrap(cx, &v))
return false;
SetProxyExtra(to, n, v);
SetProxyReservedSlot(to, n, v);
}
return true;
@ -1528,13 +1530,58 @@ JSObject::fixDictionaryShapeAfterSwap()
as<NativeObject>().shape_->listp = &as<NativeObject>().shape_;
}
static void
RemoveFromStoreBuffer(JSContext* cx, js::detail::ProxyValueArray* values)
static MOZ_MUST_USE bool
CopyProxyValuesBeforeSwap(ProxyObject* proxy, Vector<Value>& values)
{
StoreBuffer& sb = cx->zone()->group()->storeBuffer();
sb.unputValue(&values->privateSlot);
for (size_t i = 0; i < js::detail::PROXY_EXTRA_SLOTS; i++)
sb.unputValue(&values->extraSlots[i]);
MOZ_ASSERT(values.empty());
// Remove the GCPtrValues we're about to swap from the store buffer, to
// ensure we don't trace bogus values.
StoreBuffer& sb = proxy->zone()->group()->storeBuffer();
// Reserve space for the private slot and the reserved slots.
if (!values.reserve(1 + proxy->numReservedSlots()))
return false;
js::detail::ProxyValueArray* valArray = js::detail::GetProxyDataLayout(proxy)->values();
sb.unputValue(&valArray->privateSlot);
values.infallibleAppend(valArray->privateSlot);
for (size_t i = 0; i < proxy->numReservedSlots(); i++) {
sb.unputValue(&valArray->reservedSlots.slots[i]);
values.infallibleAppend(valArray->reservedSlots.slots[i]);
}
return true;
}
bool
ProxyObject::initExternalValueArrayAfterSwap(JSContext* cx, const Vector<Value>& values)
{
MOZ_ASSERT(getClass()->isProxy());
size_t nreserved = numReservedSlots();
// |values| contains the private slot and the reserved slots.
MOZ_ASSERT(values.length() == 1 + nreserved);
size_t nbytes = js::detail::ProxyValueArray::sizeOf(nreserved);
auto* valArray =
reinterpret_cast<js::detail::ProxyValueArray*>(cx->zone()->pod_malloc<uint8_t>(nbytes));
if (!valArray)
return false;
valArray->privateSlot = values[0];
for (size_t i = 0; i < nreserved; i++)
valArray->reservedSlots.slots[i] = values[i + 1];
// Note: we allocate external slots iff the proxy had an inline
// ProxyValueArray, so at this point reservedSlots points into the
// old object and we don't have to free anything.
data.reservedSlots = &valArray->reservedSlots;
return true;
}
/* Use this method with extreme caution. It trades the guts of two objects. */
@ -1640,16 +1687,13 @@ JSObject::swap(JSContext* cx, HandleObject a, HandleObject b)
ProxyObject* proxyA = a->is<ProxyObject>() ? &a->as<ProxyObject>() : nullptr;
ProxyObject* proxyB = b->is<ProxyObject>() ? &b->as<ProxyObject>() : nullptr;
Maybe<js::detail::ProxyValueArray> proxyAVals, proxyBVals;
if (aIsProxyWithInlineValues) {
js::detail::ProxyValueArray* values = js::detail::GetProxyDataLayout(proxyA)->values;
proxyAVals.emplace(*values);
RemoveFromStoreBuffer(cx, values);
if (!CopyProxyValuesBeforeSwap(proxyA, avals))
oomUnsafe.crash("CopyProxyValuesBeforeSwap");
}
if (bIsProxyWithInlineValues) {
js::detail::ProxyValueArray* values = js::detail::GetProxyDataLayout(proxyB)->values;
proxyBVals.emplace(*values);
RemoveFromStoreBuffer(cx, values);
if (!CopyProxyValuesBeforeSwap(proxyB, bvals))
oomUnsafe.crash("CopyProxyValuesBeforeSwap");
}
// Swap the main fields of the objects, whether they are native objects or proxies.
@ -1670,11 +1714,11 @@ JSObject::swap(JSContext* cx, HandleObject a, HandleObject b)
oomUnsafe.crash("fillInAfterSwap");
}
if (aIsProxyWithInlineValues) {
if (!b->as<ProxyObject>().initExternalValueArrayAfterSwap(cx, proxyAVals.ref()))
if (!b->as<ProxyObject>().initExternalValueArrayAfterSwap(cx, avals))
oomUnsafe.crash("initExternalValueArray");
}
if (bIsProxyWithInlineValues) {
if (!a->as<ProxyObject>().initExternalValueArrayAfterSwap(cx, proxyBVals.ref()))
if (!a->as<ProxyObject>().initExternalValueArrayAfterSwap(cx, bvals))
oomUnsafe.crash("initExternalValueArray");
}
}
@ -4078,11 +4122,11 @@ JSObject::debugCheckNewObject(ObjectGroup* group, Shape* shape, js::gc::AllocKin
MOZ_ASSERT(!group->compartment()->hasObjectPendingMetadata());
// Non-native classes cannot have reserved slots or private data, and the
// objects can't have any fixed slots, for compatibility with
// GetReservedOrProxyPrivateSlot.
// Non-native classes manage their own data and slots, so numFixedSlots and
// slotSpan are always 0. Note that proxy classes can have reserved slots
// but they're also not included in numFixedSlots/slotSpan.
if (!clasp->isNative()) {
MOZ_ASSERT(JSCLASS_RESERVED_SLOTS(clasp) == 0);
MOZ_ASSERT_IF(!clasp->isProxy(), JSCLASS_RESERVED_SLOTS(clasp) == 0);
MOZ_ASSERT(!clasp->hasPrivate());
MOZ_ASSERT_IF(shape, shape->numFixedSlots() == 0);
MOZ_ASSERT_IF(shape, shape->slotSpan() == 0);

View File

@ -685,14 +685,17 @@ ProxyObject::trace(JSTracer* trc, JSObject* obj)
// Note: If you add new slots here, make sure to change
// nuke() to cope.
TraceCrossCompartmentEdge(trc, obj, proxy->slotOfPrivate(), "private");
TraceEdge(trc, proxy->slotOfExtra(0), "extra0");
/*
* The GC can use the second reserved slot to link the cross compartment
* wrappers into a linked list, in which case we don't want to trace it.
*/
if (!proxy->is<CrossCompartmentWrapperObject>())
TraceEdge(trc, proxy->slotOfExtra(1), "extra1");
size_t nreserved = proxy->numReservedSlots();
for (size_t i = 0; i < nreserved; i++) {
/*
* The GC can use the second reserved slot to link the cross compartment
* wrappers into a linked list, in which case we don't want to trace it.
*/
if (proxy->is<CrossCompartmentWrapperObject>() && i == 1)
continue;
TraceEdge(trc, proxy->reservedSlotPtr(i), "proxy_reserved");
}
Proxy::trace(trc, obj);
}
@ -714,7 +717,7 @@ proxy_Finalize(FreeOp* fop, JSObject* obj)
obj->as<ProxyObject>().handler()->finalize(fop, obj);
if (!obj->as<ProxyObject>().usingInlineValueArray())
js_free(js::detail::GetProxyDataLayout(obj)->values);
js_free(js::detail::GetProxyDataLayout(obj)->values());
}
static void
@ -803,8 +806,8 @@ ProxyObject::renew(const BaseProxyHandler* handler, const Value& priv)
setHandler(handler);
setCrossCompartmentPrivate(priv);
setExtra(0, UndefinedValue());
setExtra(1, UndefinedValue());
for (size_t i = 0; i < numReservedSlots(); i++)
setReservedSlot(i, UndefinedValue());
}
JS_FRIEND_API(JSObject*)

View File

@ -130,7 +130,7 @@ IsCompatiblePropertyDescriptor(JSContext* cx, bool extensible, Handle<PropertyDe
ScriptedProxyHandler::handlerObject(const JSObject* proxy)
{
MOZ_ASSERT(proxy->as<ProxyObject>().handler() == &ScriptedProxyHandler::singleton);
return proxy->as<ProxyObject>().extra(ScriptedProxyHandler::HANDLER_EXTRA).toObjectOrNull();
return proxy->as<ProxyObject>().reservedSlot(ScriptedProxyHandler::HANDLER_EXTRA).toObjectOrNull();
}
// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 7.3.9 GetMethod,
@ -1287,7 +1287,7 @@ bool
ScriptedProxyHandler::isCallable(JSObject* obj) const
{
MOZ_ASSERT(obj->as<ProxyObject>().handler() == &ScriptedProxyHandler::singleton);
uint32_t callConstruct = obj->as<ProxyObject>().extra(IS_CALLCONSTRUCT_EXTRA).toPrivateUint32();
uint32_t callConstruct = obj->as<ProxyObject>().reservedSlot(IS_CALLCONSTRUCT_EXTRA).toPrivateUint32();
return !!(callConstruct & IS_CALLABLE);
}
@ -1295,7 +1295,7 @@ bool
ScriptedProxyHandler::isConstructor(JSObject* obj) const
{
MOZ_ASSERT(obj->as<ProxyObject>().handler() == &ScriptedProxyHandler::singleton);
uint32_t callConstruct = obj->as<ProxyObject>().extra(IS_CALLCONSTRUCT_EXTRA).toPrivateUint32();
uint32_t callConstruct = obj->as<ProxyObject>().reservedSlot(IS_CALLCONSTRUCT_EXTRA).toPrivateUint32();
return !!(callConstruct & IS_CONSTRUCTOR);
}
@ -1350,13 +1350,13 @@ ProxyCreate(JSContext* cx, CallArgs& args, const char* callerName)
// Step 9 (reordered).
Rooted<ProxyObject*> proxy(cx, &proxy_->as<ProxyObject>());
proxy->setExtra(ScriptedProxyHandler::HANDLER_EXTRA, ObjectValue(*handler));
proxy->setReservedSlot(ScriptedProxyHandler::HANDLER_EXTRA, ObjectValue(*handler));
// Step 7.
uint32_t callable = target->isCallable() ? ScriptedProxyHandler::IS_CALLABLE : 0;
uint32_t constructor = target->isConstructor() ? ScriptedProxyHandler::IS_CONSTRUCTOR : 0;
proxy->setExtra(ScriptedProxyHandler::IS_CALLCONSTRUCT_EXTRA,
PrivateUint32Value(callable | constructor));
proxy->setReservedSlot(ScriptedProxyHandler::IS_CALLCONSTRUCT_EXTRA,
PrivateUint32Value(callable | constructor));
// Step 10.
args.rval().setObject(*proxy);
@ -1388,7 +1388,7 @@ RevokeProxy(JSContext* cx, unsigned argc, Value* vp)
MOZ_ASSERT(p->is<ProxyObject>());
p->as<ProxyObject>().setSameCompartmentPrivate(NullValue());
p->as<ProxyObject>().setExtra(ScriptedProxyHandler::HANDLER_EXTRA, NullValue());
p->as<ProxyObject>().setReservedSlot(ScriptedProxyHandler::HANDLER_EXTRA, NullValue());
}
args.rval().setUndefined();

View File

@ -0,0 +1,21 @@
function assertSyntaxError(code) {
assertThrowsInstanceOf(() => { Function(code); }, SyntaxError, "Function:" + code);
assertThrowsInstanceOf(() => { eval(code); }, SyntaxError, "eval:" + code);
var ieval = eval;
assertThrowsInstanceOf(() => { ieval(code); }, SyntaxError, "indirect eval:" + code);
}
assertSyntaxError(`({async async: 0})`);
assertSyntaxError(`({async async})`);
assertSyntaxError(`({async async, })`);
assertSyntaxError(`({async async = 0} = {})`);
for (let decl of ["var", "let", "const"]) {
assertSyntaxError(`${decl} {async async: a} = {}`);
assertSyntaxError(`${decl} {async async} = {}`);
assertSyntaxError(`${decl} {async async, } = {}`);
assertSyntaxError(`${decl} {async async = 0} = {}`);
}
if (typeof reportCompare === "function")
reportCompare(true, true);

View File

@ -0,0 +1,18 @@
var array = [];
array[2**31 - 2] = "INT32_MAX - 1";
array[2**31 - 1] = "INT32_MAX";
array[2**31 - 0] = "INT32_MAX + 1";
array[2**32 - 2] = "UINT32_MAX - 1";
array[2**32 - 1] = "UINT32_MAX";
array[2**32 - 0] = "UINT32_MAX + 1";
var copy = array.slice();
assertEq(copy[2**31 - 2], "INT32_MAX - 1");
assertEq(copy[2**31 - 1], "INT32_MAX");
assertEq(copy[2**31 - 0], "INT32_MAX + 1");
assertEq(copy[2**32 - 2], "UINT32_MAX - 1");
assertEq(copy[2**32 - 1], undefined);
assertEq(copy[2**32 - 0], undefined);
if (typeof reportCompare === "function")
reportCompare(true, true);

View File

@ -2268,8 +2268,8 @@ DebugEnvironmentProxy::create(JSContext* cx, EnvironmentObject& env, HandleObjec
return nullptr;
DebugEnvironmentProxy* debugEnv = &obj->as<DebugEnvironmentProxy>();
debugEnv->setExtra(ENCLOSING_EXTRA, ObjectValue(*enclosing));
debugEnv->setExtra(SNAPSHOT_EXTRA, NullValue());
debugEnv->setReservedSlot(ENCLOSING_SLOT, ObjectValue(*enclosing));
debugEnv->setReservedSlot(SNAPSHOT_SLOT, NullValue());
return debugEnv;
}
@ -2283,13 +2283,13 @@ DebugEnvironmentProxy::environment() const
JSObject&
DebugEnvironmentProxy::enclosingEnvironment() const
{
return extra(ENCLOSING_EXTRA).toObject();
return reservedSlot(ENCLOSING_SLOT).toObject();
}
ArrayObject*
DebugEnvironmentProxy::maybeSnapshot() const
{
JSObject* obj = extra(SNAPSHOT_EXTRA).toObjectOrNull();
JSObject* obj = reservedSlot(SNAPSHOT_SLOT).toObjectOrNull();
return obj ? &obj->as<ArrayObject>() : nullptr;
}
@ -2297,7 +2297,7 @@ void
DebugEnvironmentProxy::initSnapshot(ArrayObject& o)
{
MOZ_ASSERT(maybeSnapshot() == nullptr);
setExtra(SNAPSHOT_EXTRA, ObjectValue(o));
setReservedSlot(SNAPSHOT_SLOT, ObjectValue(o));
}
bool

View File

@ -872,13 +872,13 @@ class DebugEnvironmentProxy : public ProxyObject
* The enclosing environment on the dynamic environment chain. This slot is analogous
* to the ENCLOSING_ENV_SLOT of a EnvironmentObject.
*/
static const unsigned ENCLOSING_EXTRA = 0;
static const unsigned ENCLOSING_SLOT = 0;
/*
* NullValue or a dense array holding the unaliased variables of a function
* frame that has been popped.
*/
static const unsigned SNAPSHOT_EXTRA = 1;
static const unsigned SNAPSHOT_SLOT = 1;
public:
static DebugEnvironmentProxy* create(JSContext* cx, EnvironmentObject& env,

View File

@ -15,12 +15,18 @@
using namespace js;
static gc::AllocKind
GetProxyGCObjectKind(const BaseProxyHandler* handler, const Value& priv)
GetProxyGCObjectKind(const Class* clasp, const BaseProxyHandler* handler, const Value& priv)
{
static_assert(sizeof(js::detail::ProxyValueArray) % sizeof(js::HeapSlot) == 0,
"ProxyValueArray must be a multiple of HeapSlot");
MOZ_ASSERT(clasp->isProxy());
uint32_t nslots = sizeof(js::detail::ProxyValueArray) / sizeof(HeapSlot);
uint32_t nreserved = JSCLASS_RESERVED_SLOTS(clasp);
MOZ_ASSERT(nreserved > 0);
MOZ_ASSERT(js::detail::ProxyValueArray::sizeOf(nreserved) % sizeof(Value) == 0,
"ProxyValueArray must be a multiple of Value");
uint32_t nslots = js::detail::ProxyValueArray::sizeOf(nreserved) / sizeof(Value);
MOZ_ASSERT(nslots <= NativeObject::MAX_FIXED_SLOTS);
gc::AllocKind kind = gc::GetGCObjectKind(nslots);
if (handler->finalizeInBackground(priv))
@ -68,7 +74,7 @@ ProxyObject::New(JSContext* cx, const BaseProxyHandler* handler, HandleValue pri
newKind = TenuredObject;
}
gc::AllocKind allocKind = GetProxyGCObjectKind(handler, priv);
gc::AllocKind allocKind = GetProxyGCObjectKind(clasp, handler, priv);
AutoSetNewObjectMetadata metadata(cx);
// Note: this will initialize the object's |data| to strange values, but we
@ -77,7 +83,10 @@ ProxyObject::New(JSContext* cx, const BaseProxyHandler* handler, HandleValue pri
JS_TRY_VAR_OR_RETURN_NULL(cx, proxy, create(cx, clasp, proto, allocKind, newKind));
proxy->setInlineValueArray();
new (proxy->data.values) detail::ProxyValueArray;
detail::ProxyValueArray* values = detail::GetProxyDataLayout(proxy)->values();
values->init(proxy->numReservedSlots());
proxy->data.handler = handler;
proxy->setCrossCompartmentPrivate(priv);
@ -93,7 +102,7 @@ ProxyObject::allocKindForTenure() const
{
MOZ_ASSERT(usingInlineValueArray());
Value priv = const_cast<ProxyObject*>(this)->private_();
return GetProxyGCObjectKind(data.handler, priv);
return GetProxyGCObjectKind(getClass(), data.handler, priv);
}
void
@ -133,7 +142,7 @@ ProxyObject::nuke()
setHandler(DeadObjectProxy<DeadProxyNotCallableNotConstructor>::singleton());
}
// The proxy's extra slots are not cleared and will continue to be
// The proxy's reserved slots are not cleared and will continue to be
// traced. This avoids the possibility of triggering write barriers while
// nuking proxies in dead compartments which could otherwise cause those
// compartments to be kept alive. Note that these are slots cannot hold
@ -190,19 +199,6 @@ ProxyObject::create(JSContext* cx, const Class* clasp, Handle<TaggedProto> proto
return pobj;
}
bool
ProxyObject::initExternalValueArrayAfterSwap(JSContext* cx, const detail::ProxyValueArray& src)
{
MOZ_ASSERT(getClass()->isProxy());
auto* values = cx->zone()->new_<detail::ProxyValueArray>(src);
if (!values)
return false;
data.values = values;
return true;
}
JS_FRIEND_API(void)
js::SetValueInProxy(Value* slot, const Value& value)
{

View File

@ -29,6 +29,8 @@ class ProxyObject : public ShapedObject
"proxy object size must match GC thing size");
static_assert(offsetof(ProxyObject, data) == detail::ProxyDataOffset,
"proxy object layout must match shadow interface");
static_assert(offsetof(ProxyObject, data.reservedSlots) == offsetof(shadow::Object, slots),
"Proxy reservedSlots must overlay native object slots field");
}
static JS::Result<ProxyObject*, JS::OOM&>
@ -46,12 +48,12 @@ class ProxyObject : public ShapedObject
return (void*)(uintptr_t(this) + sizeof(ProxyObject));
}
bool usingInlineValueArray() const {
return data.values == inlineDataStart();
return data.values() == inlineDataStart();
}
void setInlineValueArray() {
data.values = reinterpret_cast<detail::ProxyValueArray*>(inlineDataStart());
data.reservedSlots = &reinterpret_cast<detail::ProxyValueArray*>(inlineDataStart())->reservedSlots;
}
MOZ_MUST_USE bool initExternalValueArrayAfterSwap(JSContext* cx, const detail::ProxyValueArray& src);
MOZ_MUST_USE bool initExternalValueArrayAfterSwap(JSContext* cx, const Vector<Value>& values);
const Value& private_() {
return GetProxyPrivate(this);
@ -61,7 +63,7 @@ class ProxyObject : public ShapedObject
void setSameCompartmentPrivate(const Value& priv);
GCPtrValue* slotOfPrivate() {
return reinterpret_cast<GCPtrValue*>(&detail::GetProxyDataLayout(this)->values->privateSlot);
return reinterpret_cast<GCPtrValue*>(&detail::GetProxyDataLayout(this)->values()->privateSlot);
}
JSObject* target() const {
@ -76,31 +78,29 @@ class ProxyObject : public ShapedObject
SetProxyHandler(this, handler);
}
static size_t offsetOfValues() {
return offsetof(ProxyObject, data.values);
static size_t offsetOfReservedSlots() {
return offsetof(ProxyObject, data.reservedSlots);
}
static size_t offsetOfHandler() {
return offsetof(ProxyObject, data.handler);
}
static size_t offsetOfExtraSlotInValues(size_t slot) {
MOZ_ASSERT(slot < detail::PROXY_EXTRA_SLOTS);
return offsetof(detail::ProxyValueArray, extraSlots) + slot * sizeof(Value);
size_t numReservedSlots() const {
return JSCLASS_RESERVED_SLOTS(getClass());
}
const Value& reservedSlot(size_t n) const {
return GetProxyReservedSlot(const_cast<ProxyObject*>(this), n);
}
const Value& extra(size_t n) const {
return GetProxyExtra(const_cast<ProxyObject*>(this), n);
}
void setExtra(size_t n, const Value& extra) {
SetProxyExtra(this, n, extra);
void setReservedSlot(size_t n, const Value& extra) {
SetProxyReservedSlot(this, n, extra);
}
gc::AllocKind allocKindForTenure() const;
private:
GCPtrValue* slotOfExtra(size_t n) {
MOZ_ASSERT(n < detail::PROXY_EXTRA_SLOTS);
return reinterpret_cast<GCPtrValue*>(&detail::GetProxyDataLayout(this)->values->extraSlots[n]);
GCPtrValue* reservedSlotPtr(size_t n) {
return reinterpret_cast<GCPtrValue*>(&detail::GetProxyDataLayout(this)->reservedSlots->slots[n]);
}
static bool isValidProxyClass(const Class* clasp) {
@ -116,7 +116,7 @@ class ProxyObject : public ShapedObject
}
public:
static unsigned grayLinkExtraSlot(JSObject* obj);
static unsigned grayLinkReservedSlot(JSObject* obj);
void renew(const BaseProxyHandler* handler, const Value& priv);

View File

@ -114,7 +114,14 @@
* a single BaseShape.
*/
#define JSSLOT_FREE(clasp) JSCLASS_RESERVED_SLOTS(clasp)
MOZ_ALWAYS_INLINE size_t
JSSLOT_FREE(const js::Class* clasp)
{
// Proxy classes have reserved slots, but proxies manage their own slot
// layout.
MOZ_ASSERT(!clasp->isProxy());
return JSCLASS_RESERVED_SLOTS(clasp);
}
namespace js {
@ -919,7 +926,10 @@ class Shape : public gc::TenuredCell
uint32_t slotSpan(const Class* clasp) const {
MOZ_ASSERT(!inDictionary());
uint32_t free = JSSLOT_FREE(clasp);
// Proxy classes have reserved slots, but proxies manage their own slot
// layout. This means all non-native object shapes have nfixed == 0 and
// slotSpan == 0.
uint32_t free = clasp->isProxy() ? 0 : JSSLOT_FREE(clasp);
return hasMissingSlot() ? free : Max(free, maybeSlot() + 1);
}
@ -1324,11 +1334,6 @@ struct StackShape
uint32_t slot() const { MOZ_ASSERT(hasSlot() && !hasMissingSlot()); return slot_; }
uint32_t maybeSlot() const { return slot_; }
uint32_t slotSpan() const {
uint32_t free = JSSLOT_FREE(base->clasp_);
return hasMissingSlot() ? free : (maybeSlot() + 1);
}
void setSlot(uint32_t slot) {
MOZ_ASSERT(slot <= SHAPE_INVALID_SLOT);
slot_ = slot;

View File

@ -716,8 +716,8 @@ WrapCallable(JSContext* cx, HandleObject callable, HandleObject sandboxProtoProx
JSObject* obj = js::NewProxyObject(cx, &xpc::sandboxCallableProxyHandler,
priv, nullptr, options);
if (obj) {
js::SetProxyExtra(obj, SandboxCallableProxyHandler::SandboxProxySlot,
ObjectValue(*sandboxProtoProxy));
js::SetProxyReservedSlot(obj, SandboxCallableProxyHandler::SandboxProxySlot,
ObjectValue(*sandboxProtoProxy));
}
return obj;

View File

@ -1318,14 +1318,14 @@ bool CloneExpandoChain(JSContext* cx, JSObject* dstArg, JSObject* srcArg)
static JSObject*
GetHolder(JSObject* obj)
{
return &js::GetProxyExtra(obj, 0).toObject();
return &js::GetProxyReservedSlot(obj, 0).toObject();
}
JSObject*
XrayTraits::getHolder(JSObject* wrapper)
{
MOZ_ASSERT(WrapperFactory::IsXrayWrapper(wrapper));
js::Value v = js::GetProxyExtra(wrapper, 0);
js::Value v = js::GetProxyReservedSlot(wrapper, 0);
return v.isObject() ? &v.toObject() : nullptr;
}
@ -1337,7 +1337,7 @@ XrayTraits::ensureHolder(JSContext* cx, HandleObject wrapper)
return holder;
holder = createHolder(cx, wrapper); // virtual trap.
if (holder)
js::SetProxyExtra(wrapper, 0, ObjectValue(*holder));
js::SetProxyReservedSlot(wrapper, 0, ObjectValue(*holder));
return holder;
}

View File

@ -588,7 +588,7 @@ public:
static inline JSObject* getSandboxProxy(JS::Handle<JSObject*> proxy)
{
return &js::GetProxyExtra(proxy, SandboxProxySlot).toObject();
return &js::GetProxyReservedSlot(proxy, SandboxProxySlot).toObject();
}
};

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<script>
function draw(id, r, c) {
var txt = "TryToTaLLY-" + id + "__________" + r;
var ctx = document.getElementById(id).getContext('2d');
ctx.font = '15px Arial';
ctx.fillStyle = c;
if (r) {
ctx.save();
ctx.rotate(Math.PI / 4);
ctx.fillText(txt, 200, 0);
ctx.restore();
}
ctx.fillText(txt, 10, 20);
}
</script>
<style>
canvas { border: 1px solid silver; margin: 10px; }
</style>
</head>
<body>
<div style="float:left; transform: translate(300px, 150px) scale(3)">
<canvas id="c1" width="120" height="50"></canvas>
</div>
<script>
draw("c1", false, "red");
draw("c1", false, "green");
</script>
</body>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<script>
function draw(id, r, c) {
var txt = "TryToTaLLY-" + id + "__________" + r;
var ctx = document.getElementById(id).getContext('2d');
ctx.font = '15px Arial';
ctx.fillStyle = c;
if (r) {
ctx.save();
ctx.rotate(Math.PI / 4);
ctx.fillText(txt, 200, 0);
ctx.restore();
}
ctx.fillText(txt, 10, 20);
}
</script>
<style>
canvas { border: 1px solid silver; margin: 10px; }
</style>
</head>
<body>
<div style="float:left; transform: translate(300px, 150px) scale(3)">
<canvas id="c1" width="120" height="50"></canvas>
</div>
<script>
draw("c1", true, "red");
draw("c1", false, "green");
</script>
</body>

View File

@ -113,3 +113,4 @@ fuzzy-if(winWidget,94,1575) fuzzy-if(cocoaWidget,1,24) == 1304353-text-global-co
== text-indent-1b.html text-indent-1-ref.html
== 1347147-1.html 1347147-1-ref.html
== 1353000-1.html 1353000-1-ref.html

View File

@ -7,6 +7,7 @@
img {
width: 100px;
height: 100px;
-moz-context-properties: fill;
fill: lime;
}

View File

@ -7,6 +7,7 @@
img {
width: 100px;
height: 100px;
-moz-context-properties: fill;
fill: lime;
border: 1px solid black;
}

View File

@ -7,6 +7,7 @@
img {
width: 100px;
height: 100px;
-moz-context-properties: fill;
fill: rgb(0% 100% 0% / 50%);
}

View File

@ -7,6 +7,7 @@
img {
width: 100px;
height: 100px;
-moz-context-properties: fill;
fill: lime;
}

View File

@ -7,6 +7,7 @@
img {
width: 100px;
height: 100px;
-moz-context-properties: fill;
}
#img1 {

View File

@ -7,6 +7,7 @@
img {
width: 100px;
height: 100px;
-moz-context-properties: fill;
fill: lime;
}

View File

@ -1,10 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>Test context-fill when no context fill is provided</title>
<title>Test context-fill when no context fill value is provided</title>
<style>
img {
-moz-context-properties: fill;
width: 100px;
height: 100px;
}

View File

@ -8,6 +8,7 @@ div {
width: 100px;
height: 100px;
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><rect width='100%' height='100%' fill='context-fill red'/></svg>");
-moz-context-properties: fill;
fill: blue;
}

View File

@ -7,6 +7,7 @@
img {
width: 100px;
height: 100px;
-moz-context-properties: stroke;
stroke: lime;
}

View File

@ -7,6 +7,7 @@
img {
width: 100px;
height: 100px;
-moz-context-properties: stroke;
stroke: lime;
border: 1px solid black;
}

View File

@ -7,6 +7,7 @@
img {
width: 100px;
height: 100px;
-moz-context-properties: stroke;
stroke: rgb(0% 100% 0% / 50%);
}

View File

@ -7,6 +7,7 @@
img {
width: 100px;
height: 100px;
-moz-context-properties: stroke;
stroke: lime;
}

View File

@ -7,6 +7,7 @@
img {
width: 100px;
height: 100px;
-moz-context-properties: stroke;
}
#img1 {

View File

@ -7,6 +7,7 @@
img {
width: 100px;
height: 100px;
-moz-context-properties: stroke;
stroke: lime;
}

View File

@ -1,10 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>Test context-stroke when no context stroke is provided</title>
<title>Test context-stroke when no context stroke value is provided</title>
<style>
img {
-moz-context-properties: fill;
width: 100px;
height: 100px;
border: 1px solid black;

View File

@ -8,6 +8,7 @@ div {
width: 100px;
height: 100px;
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><rect x='5' y='5' width='90' height='90' fill='none' stroke='context-stroke red' stroke-width='10'/></svg>");
-moz-context-properties: stroke;
stroke: blue;
}

View File

@ -56,29 +56,29 @@ fuzzy(1,2) fuzzy-if(azureSkia,1,40000) == canvas-drawImage-alpha-2.html canvas-d
# Context paint tests (this feature is currently not part of any spec.)
# context-fill:
== context-fill-01.html blue100x100-ref.html
test-pref(svg.context-properties.content.enabled,true) == context-fill-01.html lime100x100-ref.html
== context-fill-02.html transparent100x100-w-border-ref.html
test-pref(svg.context-properties.content.enabled,true) == context-fill-02.html lime100x100-w-border-ref.html
test-pref(svg.context-properties.content.enabled,true) == context-fill-03.html lime100x100-50pct-ref.html
skip-if(stylo) == context-fill-01.html blue100x100-ref.html
skip-if(stylo) test-pref(svg.context-properties.content.enabled,true) == context-fill-01.html lime100x100-ref.html
skip-if(stylo) == context-fill-02.html transparent100x100-w-border-ref.html
skip-if(stylo) test-pref(svg.context-properties.content.enabled,true) == context-fill-02.html lime100x100-w-border-ref.html
skip-if(stylo) test-pref(svg.context-properties.content.enabled,true) == context-fill-03.html lime100x100-50pct-ref.html
# fuzz because on win8 the r & b components are off by one
fuzzy-if(winWidget,1,10000) test-pref(svg.context-properties.content.enabled,true) == context-fill-04.html lime100x100-50pct-ref.html
test-pref(svg.context-properties.content.enabled,true) == context-fill-05.html context-fill-or-stroke-05-ref.html
test-pref(svg.context-properties.content.enabled,true) == context-fill-06.html lime100x100-ref.html
test-pref(svg.context-properties.content.enabled,true) == context-fill-07.html context-fill-07-ref.html
test-pref(svg.context-properties.content.enabled,true) == context-fill-bg-image-01.html blue100x100-ref.html
skip-if(stylo) fuzzy-if(winWidget,1,10000) test-pref(svg.context-properties.content.enabled,true) == context-fill-04.html lime100x100-50pct-ref.html
skip-if(stylo) test-pref(svg.context-properties.content.enabled,true) == context-fill-05.html context-fill-or-stroke-05-ref.html
skip-if(stylo) test-pref(svg.context-properties.content.enabled,true) == context-fill-06.html lime100x100-ref.html
skip-if(stylo) test-pref(svg.context-properties.content.enabled,true) == context-fill-07.html context-fill-07-ref.html
skip-if(stylo) test-pref(svg.context-properties.content.enabled,true) == context-fill-bg-image-01.html blue100x100-ref.html
# context-stroke:
== context-stroke-01.html blue100x100-ref.html
test-pref(svg.context-properties.content.enabled,true) == context-stroke-01.html lime100x100-ref.html
== context-stroke-02.html transparent100x100-w-border-ref.html
test-pref(svg.context-properties.content.enabled,true) == context-stroke-02.html lime100x100-w-border-ref.html
test-pref(svg.context-properties.content.enabled,true) == context-stroke-03.html lime100x100-50pct-ref.html
skip-if(stylo) == context-stroke-01.html blue100x100-ref.html
skip-if(stylo) test-pref(svg.context-properties.content.enabled,true) == context-stroke-01.html lime100x100-ref.html
skip-if(stylo) == context-stroke-02.html transparent100x100-w-border-ref.html
skip-if(stylo) test-pref(svg.context-properties.content.enabled,true) == context-stroke-02.html lime100x100-w-border-ref.html
skip-if(stylo) test-pref(svg.context-properties.content.enabled,true) == context-stroke-03.html lime100x100-50pct-ref.html
# fuzz because on win8 the r & b components are off by one
fuzzy-if(winWidget,1,10000) test-pref(svg.context-properties.content.enabled,true) == context-stroke-04.html lime100x100-50pct-ref.html
test-pref(svg.context-properties.content.enabled,true) == context-stroke-05.html context-fill-or-stroke-05-ref.html
test-pref(svg.context-properties.content.enabled,true) == context-stroke-06.html lime100x100-ref.html
test-pref(svg.context-properties.content.enabled,true) == context-stroke-07.html context-stroke-07-ref.html
test-pref(svg.context-properties.content.enabled,true) == context-stroke-bg-image-01.html blue100x100-border-ref.html
skip-if(stylo) fuzzy-if(winWidget,1,10000) test-pref(svg.context-properties.content.enabled,true) == context-stroke-04.html lime100x100-50pct-ref.html
skip-if(stylo) test-pref(svg.context-properties.content.enabled,true) == context-stroke-05.html context-fill-or-stroke-05-ref.html
skip-if(stylo) test-pref(svg.context-properties.content.enabled,true) == context-stroke-06.html lime100x100-ref.html
skip-if(stylo) test-pref(svg.context-properties.content.enabled,true) == context-stroke-07.html context-stroke-07-ref.html
skip-if(stylo) test-pref(svg.context-properties.content.enabled,true) == context-stroke-bg-image-01.html blue100x100-border-ref.html
# Simple <img> tests
== img-simple-1.html lime100x100-ref.html

View File

@ -49,6 +49,7 @@ CSS_KEY(-moz-cellhighlighttext, _moz_cellhighlighttext)
CSS_KEY(-moz-center, _moz_center)
CSS_KEY(-moz-combobox, _moz_combobox)
CSS_KEY(-moz-comboboxtext, _moz_comboboxtext)
CSS_KEY(-moz-context-properties, _moz_context_properties)
CSS_KEY(-moz-block-height, _moz_block_height)
CSS_KEY(-moz-deck, _moz_deck)
CSS_KEY(-moz-default-background-color, _moz_default_background_color)

View File

@ -924,6 +924,7 @@ protected:
uint32_t& aVariantMask,
bool *aHadFinalWS);
bool ParseCalcTerm(nsCSSValue& aValue, uint32_t& aVariantMask);
bool ParseContextProperties();
bool RequireWhitespace();
// For "flex" shorthand property, defined in CSS Flexbox spec
@ -8064,6 +8065,50 @@ CSSParserImpl::ParseCounter(nsCSSValue& aValue)
return false;
}
bool
CSSParserImpl::ParseContextProperties()
{
nsCSSValue listValue;
nsCSSValueList* currentListValue = listValue.SetListValue();
bool first = true;
for (;;) {
const uint32_t variantMask = VARIANT_IDENTIFIER |
VARIANT_INHERIT |
VARIANT_NONE;
nsCSSValue value;
if (!ParseSingleTokenVariant(value, variantMask, nullptr)) {
return false;
}
if (value.GetUnit() != eCSSUnit_Ident) {
if (first) {
AppendValue(eCSSProperty__moz_context_properties, value);
return true;
} else {
return false;
}
}
value.AtomizeIdentValue();
nsIAtom* atom = value.GetAtomValue();
if (atom == nsGkAtoms::_default) {
return false;
}
currentListValue->mValue = Move(value);
if (!ExpectSymbol(',', true)) {
break;
}
currentListValue->mNext = new nsCSSValueList;
currentListValue = currentListValue->mNext;
first = false;
}
AppendValue(eCSSProperty__moz_context_properties, listValue);
return true;
}
bool
CSSParserImpl::ParseAttr(nsCSSValue& aValue)
{
@ -11708,6 +11753,8 @@ CSSParserImpl::ParsePropertyByFunction(nsCSSPropertyID aPropID)
return ParseBorderSide(kColumnRuleIDs, false);
case eCSSProperty_content:
return ParseContent();
case eCSSProperty__moz_context_properties:
return ParseContextProperties();
case eCSSProperty_counter_increment:
case eCSSProperty_counter_reset:
return ParseCounterData(aPropID);

View File

@ -1616,6 +1616,19 @@ CSS_PROP_CONTENT(
CSS_PROP_NO_OFFSET,
eStyleAnimType_Discrete)
#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
CSS_PROP_SVG(
// Only intended to be used internally by Mozilla, so prefixed.
-moz-context-properties,
_moz_context_properties,
CSS_PROP_DOMPROP_PREFIXED(ContextProperties),
CSS_PROPERTY_PARSE_FUNCTION |
CSS_PROPERTY_VALUE_LIST_USES_COMMAS |
CSS_PROPERTY_INTERNAL,
"",
0,
nullptr,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
CSS_PROP_TEXT(
-moz-control-character-visibility,
_moz_control_character_visibility,

View File

@ -6463,6 +6463,27 @@ nsComputedDOMStyle::DoGetMaskType()
return val.forget();
}
already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetContextProperties()
{
const nsTArray<nsCOMPtr<nsIAtom>>& contextProps = StyleSVG()->mContextProps;
if (contextProps.IsEmpty()) {
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
val->SetIdent(eCSSKeyword_none);
return val.forget();
}
RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
for (const nsIAtom* ident : contextProps) {
RefPtr<nsROCSSPrimitiveValue> property = new nsROCSSPrimitiveValue;
property->SetString(nsDependentAtomString(ident));
valueList->AppendCSSValue(property.forget());
}
return valueList.forget();
}
already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetPaintOrder()
{

View File

@ -600,6 +600,8 @@ private:
already_AddRefed<CSSValue> DoGetMaskType();
already_AddRefed<CSSValue> DoGetPaintOrder();
already_AddRefed<CSSValue> DoGetContextProperties();
/* Custom properties */
already_AddRefed<CSSValue> DoGetCustomProperty(const nsAString& aPropertyName);

View File

@ -287,6 +287,7 @@ COMPUTED_STYLE_PROP(_moz_box_flex, BoxFlex)
COMPUTED_STYLE_PROP(_moz_box_ordinal_group, BoxOrdinalGroup)
COMPUTED_STYLE_PROP(_moz_box_orient, BoxOrient)
COMPUTED_STYLE_PROP(_moz_box_pack, BoxPack)
COMPUTED_STYLE_PROP(_moz_context_properties, ContextProperties)
COMPUTED_STYLE_PROP(_moz_float_edge, FloatEdge)
COMPUTED_STYLE_PROP(_moz_force_broken_image_icon, ForceBrokenImageIcon)
COMPUTED_STYLE_PROP(_moz_image_region, ImageRegion)

View File

@ -9729,6 +9729,48 @@ nsRuleNode::ComputeSVGData(void* aStartStruct,
parentSVG->mTextAnchor,
NS_STYLE_TEXT_ANCHOR_START);
// -moz-context-properties:
const nsCSSValue* contextPropsValue = aRuleData->ValueForContextProperties();
switch (contextPropsValue->GetUnit()) {
case eCSSUnit_Null:
break;
case eCSSUnit_List:
case eCSSUnit_ListDep: {
svg->mContextProps.Clear();
svg->mContextPropsBits = 0;
for (const nsCSSValueList* item = contextPropsValue->GetListValue();
item; item = item->mNext)
{
nsIAtom* atom = item->mValue.GetAtomValue();
svg->mContextProps.AppendElement(atom);
if (atom == nsGkAtoms::fill) {
svg->mContextPropsBits |= NS_STYLE_CONTEXT_PROPERTY_FILL;
} else if (atom == nsGkAtoms::stroke) {
svg->mContextPropsBits |= NS_STYLE_CONTEXT_PROPERTY_STROKE;
}
}
break;
}
case eCSSUnit_Inherit:
svg->mContextProps.Clear();
svg->mContextProps.AppendElements(parentSVG->mContextProps);
svg->mContextPropsBits = parentSVG->mContextPropsBits;
conditions.SetUncacheable();
break;
case eCSSUnit_Initial:
case eCSSUnit_None:
case eCSSUnit_Unset:
svg->mContextProps.Clear();
svg->mContextPropsBits = 0;
break;
default:
MOZ_ASSERT(false, "unrecognized -moz-context-properties value");
}
COMPUTE_END_INHERITED(SVG, svg)
}

View File

@ -1053,6 +1053,10 @@ enum class StyleGridTrackBreadth : uint8_t {
// See nsStyleSVG
// -moz-context-properties
#define NS_STYLE_CONTEXT_PROPERTY_FILL (1 << 0)
#define NS_STYLE_CONTEXT_PROPERTY_STROKE (1 << 1)
// dominant-baseline
#define NS_STYLE_DOMINANT_BASELINE_AUTO 0
#define NS_STYLE_DOMINANT_BASELINE_USE_SCRIPT 1

View File

@ -876,6 +876,7 @@ nsStyleSVG::nsStyleSVG(const nsPresContext* aContext)
, mStrokeLinecap(NS_STYLE_STROKE_LINECAP_BUTT)
, mStrokeLinejoin(NS_STYLE_STROKE_LINEJOIN_MITER)
, mTextAnchor(NS_STYLE_TEXT_ANCHOR_START)
, mContextPropsBits(0)
, mContextFlags((eStyleSVGOpacitySource_Normal << FILL_OPACITY_SOURCE_SHIFT) |
(eStyleSVGOpacitySource_Normal << STROKE_OPACITY_SOURCE_SHIFT))
{
@ -894,6 +895,7 @@ nsStyleSVG::nsStyleSVG(const nsStyleSVG& aSource)
, mMarkerMid(aSource.mMarkerMid)
, mMarkerStart(aSource.mMarkerStart)
, mStrokeDasharray(aSource.mStrokeDasharray)
, mContextProps(aSource.mContextProps)
, mStrokeDashoffset(aSource.mStrokeDashoffset)
, mStrokeWidth(aSource.mStrokeWidth)
, mFillOpacity(aSource.mFillOpacity)
@ -908,6 +910,7 @@ nsStyleSVG::nsStyleSVG(const nsStyleSVG& aSource)
, mStrokeLinecap(aSource.mStrokeLinecap)
, mStrokeLinejoin(aSource.mStrokeLinejoin)
, mTextAnchor(aSource.mTextAnchor)
, mContextPropsBits(aSource.mContextPropsBits)
, mContextFlags(aSource.mContextFlags)
{
MOZ_COUNT_CTOR(nsStyleSVG);
@ -992,10 +995,17 @@ nsStyleSVG::CalcDifference(const nsStyleSVG& aNewData) const
mPaintOrder != aNewData.mPaintOrder ||
mShapeRendering != aNewData.mShapeRendering ||
mStrokeDasharray != aNewData.mStrokeDasharray ||
mContextFlags != aNewData.mContextFlags) {
mContextFlags != aNewData.mContextFlags ||
mContextPropsBits != aNewData.mContextPropsBits) {
return hint | nsChangeHint_RepaintFrame;
}
if (!hint) {
if (mContextProps != aNewData.mContextProps) {
hint = nsChangeHint_NeutralChange;
}
}
return hint;
}

View File

@ -3468,6 +3468,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleSVG
RefPtr<mozilla::css::URLValue> mMarkerMid; // [inherited]
RefPtr<mozilla::css::URLValue> mMarkerStart; // [inherited]
nsTArray<nsStyleCoord> mStrokeDasharray; // [inherited] coord, percent, factor
nsTArray<nsCOMPtr<nsIAtom>> mContextProps;
nsStyleCoord mStrokeDashoffset; // [inherited] coord, percent, factor
nsStyleCoord mStrokeWidth; // [inherited] coord, percent, factor
@ -3485,6 +3486,15 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleSVG
uint8_t mStrokeLinecap; // [inherited] see nsStyleConsts.h
uint8_t mStrokeLinejoin; // [inherited] see nsStyleConsts.h
uint8_t mTextAnchor; // [inherited] see nsStyleConsts.h
uint8_t mContextPropsBits; // [inherited] see nsStyleConsts.h.
// Stores a bitfield representation of
// the specified properties.
/// Returns true if style has been set to expose the computed values of
/// certain properties (such as 'fill') to the contents of any linked images.
bool ExposesContextProperties() const {
return bool(mContextPropsBits);
}
nsStyleSVGOpacitySource FillOpacitySource() const {
uint8_t value = (mContextFlags & FILL_OPACITY_SOURCE_MASK) >>

View File

@ -106,6 +106,7 @@ const char *gInaccessibleProperties[] = {
"-x-span",
"-x-system-font",
"-x-text-zoom",
"-moz-context-properties",
"-moz-control-character-visibility",
"-moz-script-level", // parsed by UA sheets only
"-moz-script-size-multiplier",

View File

@ -7872,4 +7872,13 @@ if (false) {
other_values: [ "none", "menu", "tooltip", "sheet" ],
invalid_values: []
};
gCSSProperties["-moz-context-properties"] = {
//domProp: "MozContextProperties",
inherited: true,
type: CSS_TYPE_LONGHAND,
initial_values: [ "none" ],
other_values: [ "fill", "stroke", "fill, stroke", "fill, stroke, fill", "fill, foo", "foo" ],
invalid_values: [ "default", "fill, auto", "all, stroke", "none, fill", "fill, none", "fill, default", "2px" ]
};
}

View File

@ -13,6 +13,7 @@
#include "nsContentUtils.h"
#include "nsIFrame.h"
#include "nsPresContext.h"
#include "nsStyleStruct.h"
namespace mozilla {
@ -30,6 +31,12 @@ SVGImageContext::MaybeStoreContextPaint(Maybe<SVGImageContext>& aContext,
sEnabledForContentCached = true;
}
if (!aFromFrame->StyleSVG()->ExposesContextProperties()) {
// Content must have '-moz-context-properties' set to the names of the
// properties it wants to expose to images it links to.
return;
}
if (!sEnabledForContent &&
!nsContentUtils::IsChromeDoc(aFromFrame->PresContext()->Document())) {
// Context paint is pref'ed off for content and this is a content doc.
@ -41,8 +48,6 @@ SVGImageContext::MaybeStoreContextPaint(Maybe<SVGImageContext>& aContext,
return;
}
// XXX return early if the 'context-properties' property is not set.
bool haveContextPaint = false;
RefPtr<SVGEmbeddingContextPaint> contextPaint = new SVGEmbeddingContextPaint();

Some files were not shown because too many files have changed in this diff Show More