Merge mozilla-central to inbound. r=merge a=merge CLOSED TREE

This commit is contained in:
shindli 2017-12-22 23:58:07 +02:00
Родитель ff19deaa32 bdec02b3ec
Коммит 7356e0ba3b
36 изменённых файлов: 998 добавлений и 396 удалений

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

@ -11,19 +11,17 @@
xmlns:xbl="http://www.mozilla.org/xbl">
<binding id="ctrlTab-preview" extends="chrome://global/content/bindings/button.xml#button-base">
<content pack="center">
<xul:stack>
<xul:vbox class="ctrlTab-preview-inner" align="center" pack="center"
xbl:inherits="width=canvaswidth">
<xul:hbox class="tabPreview-canvas" xbl:inherits="style=canvasstyle">
<children/>
</xul:hbox>
<xul:label xbl:inherits="value=label" crop="end" class="plain"/>
</xul:vbox>
<xul:vbox class="ctrlTab-preview-inner">
<xul:hbox class="ctrlTab-canvas" xbl:inherits="style=canvasstyle,width=canvaswidth">
<children/>
</xul:hbox>
<xul:hbox class="ctrlTab-favicon-container" xbl:inherits="hidden=noicon">
<xul:image class="ctrlTab-favicon" xbl:inherits="src=image"/>
</xul:hbox>
</xul:stack>
<xul:label class="ctrlTab-label plain" xbl:inherits="value=label" crop="end"/>
</xul:vbox>
</content>
<handlers>
<handler event="mouseover" action="ctrlTab._mouseOverFocus(this);"/>
<handler event="command" action="ctrlTab.pick(this);"/>

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

@ -912,35 +912,6 @@ html|*#fullscreen-exit-button {
/* ::::: Ctrl-Tab Panel ::::: */
.ctrlTab-preview > html|img,
.ctrlTab-preview > html|canvas {
min-width: inherit;
max-width: inherit;
min-height: inherit;
max-height: inherit;
}
.ctrlTab-favicon-container {
-moz-box-align: start;
%ifdef XP_MACOSX
-moz-box-pack: end;
%else
-moz-box-pack: start;
%endif
}
.ctrlTab-favicon {
width: 16px;
height: 16px;
}
/* Apply crisp rendering for favicons at exactly 2dppx resolution */
@media (resolution: 2dppx) {
.ctrlTab-favicon {
image-rendering: -moz-crisp-edges;
}
}
.ctrlTab-preview {
-moz-binding: url("chrome://browser/content/browser-tabPreviews.xml#ctrlTab-preview");
}

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

@ -245,7 +245,7 @@
icon="save" id="imagesaveasbutton"
oncommand="saveMedia();"/>
</hbox>
<vbox id="imagecontainerbox" class="inset iframe" flex="1" pack="center">
<vbox id="imagecontainerbox" flex="1" pack="center">
<hbox id="theimagecontainer" pack="center">
<image id="thepreviewimage"/>
</hbox>

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

@ -22,8 +22,10 @@
}
#topBar {
-moz-appearance: listbox;
margin: 8px 8px 0;
border-bottom: 1px solid ThreeDShadow;
padding-inline-start: 10px;
background-color: -moz-Field;
color: -moz-FieldText;
}
#generalTab {
@ -51,8 +53,8 @@
padding-right: 2px;
}
deck {
padding: 10px 10px 10px 10px;
#mainDeck {
padding: 10px;
}
/* Misc */
@ -67,7 +69,7 @@ tree {
textbox {
background: transparent !important;
border: none;
padding: 0px;
padding: 0;
margin-top: 1px;
-moz-appearance: none;
}
@ -76,14 +78,11 @@ textbox.header {
margin-inline-start: 0;
}
.iframe {
#imagecontainerbox {
margin: .5em;
background: white;
overflow: auto;
}
.fixedsize {
height: 8.5em;
border: 1px solid ThreeDLightShadow;
}
textbox[disabled] {
@ -162,11 +161,6 @@ treechildren::-moz-tree-cell-text(broken) {
color: graytext;
}
#mediaPreviewBox .inset {
-moz-appearance: listbox;
margin-bottom: 0;
}
/* Feeds Tab */
#feedPanel {
margin-left: 2px;
@ -183,7 +177,7 @@ treechildren::-moz-tree-cell-text(broken) {
padding-inline-start: 7px;
padding-inline-end: 7px;
min-height: 25px;
border-bottom: 1px dotted #C0C0C0;
border-bottom: 1px dotted ThreeDShadow;
color: -moz-FieldText;
}
@ -194,11 +188,6 @@ treechildren::-moz-tree-cell-text(broken) {
#feedListbox {
margin-bottom: 0;
border: 2px solid;
-moz-border-top-colors: ThreeDShadow ThreeDDarkShadow;
-moz-border-right-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-left-colors: ThreeDShadow ThreeDDarkShadow;
}
.feedTitle {
@ -206,31 +195,18 @@ treechildren::-moz-tree-cell-text(broken) {
}
/* Permissions Tab */
#permPanel {
margin-left: 6px;
margin-right: 6px;
}
#permList {
-moz-appearance: listbox;
margin-top: .5em;
margin: .5em;
overflow: auto;
border: 2px solid;
-moz-border-top-colors: ThreeDShadow ThreeDDarkShadow;
-moz-border-right-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-left-colors: ThreeDShadow ThreeDDarkShadow;
background-color: -moz-field;
color: -moz-FieldText;
}
.permission {
padding-top: 6px;
padding-bottom: 6px;
padding-inline-start: 7px;
padding-inline-end: 7px;
padding: 6px 7px;
min-height: 25px;
border-bottom: 1px dotted #C0C0C0;
border-bottom: 1px dotted ThreeDShadow;
}
.permissionLabel {

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

@ -37,8 +37,8 @@
text-shadow: rgba(0, 0, 0, 0.4) 0 1px;
}
deck {
padding: 10px 10px 10px 10px;
#mainDeck {
padding: 10px;
}
/* Misc */
@ -53,7 +53,7 @@ tree {
textbox {
background: transparent !important;
border: none;
padding: 0px;
padding: 0;
margin-top: 1px;
-moz-appearance: none;
}
@ -62,14 +62,11 @@ textbox.header {
margin-inline-start: 0;
}
.iframe {
#imagecontainerbox {
margin: .5em;
background: white;
overflow: auto;
}
.fixedsize {
height: 8.5em;
border: 1px solid ThreeDLightShadow;
}
textbox[disabled] {
@ -146,7 +143,7 @@ treechildren::-moz-tree-cell-text(broken) {
padding-inline-start: 7px;
padding-inline-end: 7px;
min-height: 25px;
border-bottom: 1px dotted #C0C0C0;
border-bottom: 1px dotted ThreeDShadow;
}
#feedListbox richlistitem[selected="true"] {
@ -154,37 +151,22 @@ treechildren::-moz-tree-cell-text(broken) {
color: -moz-DialogText;
}
#feedListbox {
border: 2px solid;
-moz-border-top-colors: ThreeDShadow ThreeDDarkShadow;
-moz-border-right-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-left-colors: ThreeDShadow ThreeDDarkShadow;
}
.feedTitle {
font-weight: bold;
}
/* Permissions Tab */
#permList {
margin-top: .5em;
margin: .5em;
overflow: auto;
border: 2px solid;
-moz-border-top-colors: ThreeDShadow ThreeDDarkShadow;
-moz-border-right-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-left-colors: ThreeDShadow ThreeDDarkShadow;
background-color: -moz-field;
-moz-appearance: listbox;
color: -moz-fieldtext;
}
.permission {
padding-top: 6px;
padding-bottom: 6px;
padding-inline-start: 7px;
padding-inline-end: 7px;
padding: 6px 7px;
min-height: 25px;
border-bottom: 1px dotted #C0C0C0;
border-bottom: 1px dotted ThreeDShadow;
}
.permissionLabel {
@ -193,6 +175,7 @@ treechildren::-moz-tree-cell-text(broken) {
.permission:hover {
background-color: -moz-dialog;
color: -moz-DialogText;
}
/* Security Tab */

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

@ -11,7 +11,7 @@
%ifdef XP_MACOSX
-moz-window-shadow: none;
%endif
background: hsla(0,0%,33%,.85);
background: hsla(0,0%,40%,.85);
color: white;
border-style: none;
padding: 20px 10px 10px;
@ -21,19 +21,34 @@
text-shadow: 0 0 1px hsl(0,0%,12%), 0 0 2px hsl(0,0%,12%);
}
.ctrlTab-preview > html|img,
.ctrlTab-preview > html|canvas {
min-width: inherit;
max-width: inherit;
min-height: inherit;
max-height: inherit;
}
.ctrlTab-favicon-container {
position: relative;
-moz-box-pack: end;
}
.ctrlTab-favicon[src] {
background-color: white;
width: 20px;
height: 20px;
padding: 2px;
}
.ctrlTab-preview-inner > .tabPreview-canvas {
box-shadow: 1px 1px 2px hsl(0,0%,12%);
}
.ctrlTab-preview:not(#ctrlTab-showAll) > * > .ctrlTab-preview-inner > .tabPreview-canvas {
width: 42px;
height: 42px;
margin-top: -44px;
margin-bottom: 2px;
margin-inline-end: -6px;
padding: 5px;
background-color: #F9F9FA;
border-radius: 6px;
box-shadow: inset 0 0 0 1px rgba(0,0,0,.1);
}
.ctrlTab-preview:not(#ctrlTab-showAll) > .ctrlTab-preview-inner > .ctrlTab-canvas {
box-shadow: 1px 1px 2px hsl(0,0%,12%);
margin-bottom: 8px;
}
.ctrlTab-preview-inner {
@ -42,19 +57,23 @@
border-radius: .5em;
}
.ctrlTab-preview:not(#ctrlTab-showAll) > * > .ctrlTab-preview-inner {
.ctrlTab-preview:not(#ctrlTab-showAll) > .ctrlTab-preview-inner {
margin: -10px -10px 0;
}
#ctrlTab-showAll:not(:focus) > * > .ctrlTab-preview-inner {
#ctrlTab-showAll:not(:focus) > .ctrlTab-preview-inner {
background-color: rgba(255,255,255,.2);
}
.ctrlTab-preview:focus > * > .ctrlTab-preview-inner {
.ctrlTab-preview:focus > .ctrlTab-preview-inner {
color: white;
background-color: rgba(0,0,0,.6);
background-color: rgba(0,0,0,.75);
text-shadow: none;
border-color: white;
border-color: #45a1ff;
}
.ctrlTab-label {
text-align: center;
}
#ctrlTab-showAll {

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

@ -28,7 +28,7 @@
}
#topBar {
border-bottom: 2px groove ThreeDFace;
border-bottom: 1px solid ThreeDLightShadow;
padding-inline-start: 10px;
background-color: -moz-Field;
color: -moz-FieldText;
@ -38,7 +38,8 @@
-moz-image-region: rect(0px, 32px, 32px, 0px)
}
#generalTab:hover, #generalTab[selected="true"] {
#generalTab:hover,
#generalTab[selected="true"] {
-moz-image-region: rect(32px, 32px, 64px, 0px)
}
@ -46,7 +47,8 @@
-moz-image-region: rect(0px, 64px, 32px, 32px)
}
#mediaTab:hover, #mediaTab[selected="true"] {
#mediaTab:hover,
#mediaTab[selected="true"] {
-moz-image-region: rect(32px, 64px, 64px, 32px)
}
@ -54,7 +56,8 @@
-moz-image-region: rect(0px, 96px, 32px, 64px)
}
#feedTab:hover, #feedTab[selected="true"] {
#feedTab:hover,
#feedTab[selected="true"] {
-moz-image-region: rect(32px, 96px, 64px, 64px)
}
@ -62,7 +65,8 @@
-moz-image-region: rect(0px, 128px, 32px, 96px)
}
#permTab:hover, #permTab[selected="true"] {
#permTab:hover,
#permTab[selected="true"] {
-moz-image-region: rect(32px, 128px, 64px, 96px)
}
@ -70,12 +74,13 @@
-moz-image-region: rect(0px, 160px, 32px, 128px)
}
#securityTab:hover, #securityTab[selected="true"] {
#securityTab:hover,
#securityTab[selected="true"] {
-moz-image-region: rect(32px, 160px, 64px, 128px)
}
deck {
padding: 10px 10px 10px 10px;
#mainDeck {
padding: 10px;
}
/* Misc */
@ -90,7 +95,7 @@ tree {
textbox {
background: transparent !important;
border: none;
padding: 0px;
padding: 0;
margin-top: 1px;
-moz-appearance: none;
}
@ -99,14 +104,11 @@ textbox.header {
margin-inline-start: 0;
}
.iframe {
#imagecontainerbox {
margin: .5em;
background: white;
overflow: auto;
}
.fixedsize {
height: 8.5em;
border: 1px solid ThreeDLightShadow;
}
textbox[disabled] {
@ -188,7 +190,7 @@ treechildren::-moz-tree-cell-text(broken) {
padding-inline-start: 7px;
padding-inline-end: 7px;
min-height: 25px;
border-bottom: 1px dotted #C0C0C0;
border-bottom: 1px dotted ThreeDShadow;
}
#feedListbox richlistitem[selected="true"] {
@ -196,37 +198,22 @@ treechildren::-moz-tree-cell-text(broken) {
color: -moz-DialogText;
}
#feedListbox {
border: 2px solid;
-moz-border-top-colors: ThreeDShadow ThreeDDarkShadow;
-moz-border-right-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-left-colors: ThreeDShadow ThreeDDarkShadow;
}
.feedTitle {
font-weight: bold;
}
/* Permissions Tab */
#permList {
margin-top: .5em;
margin: .5em;
overflow: auto;
border: 2px solid;
-moz-border-top-colors: ThreeDShadow ThreeDDarkShadow;
-moz-border-right-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow;
-moz-border-left-colors: ThreeDShadow ThreeDDarkShadow;
background-color: -moz-field;
-moz-appearance: listbox;
color: -moz-fieldtext;
}
.permission {
padding-top: 6px;
padding-bottom: 6px;
padding-inline-start: 7px;
padding-inline-end: 7px;
padding: 6px 7px;
min-height: 25px;
border-bottom: 1px dotted #C0C0C0;
border-bottom: 1px dotted ThreeDShadow;
}
.permissionLabel {
@ -235,6 +222,7 @@ treechildren::-moz-tree-cell-text(broken) {
.permission:hover {
background-color: -moz-dialog;
color: -moz-dialogText;
}
/* Security Tab */

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

@ -104,13 +104,7 @@ if test -z "$platform"; then
esac
fi
if test -z "$bucket"; then
case "$platform" in
win*) : ;;
*)
export CCACHE=ccache
esac
else
if test -n "$bucket"; then
mk_add_options "export SCCACHE_BUCKET=$bucket"
case "$master" in
*us[ew][12].mozilla.com*|*euc1.mozilla.com*)

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

@ -100,7 +100,7 @@
.requests-list-headers-wrapper {
position: sticky;
top: 0;
z-index: 1000;
z-index: 1;
width: 100%;
padding: 0;
}

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

@ -11,6 +11,7 @@
#include "mozilla/Base64.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/CycleCollectedJSRuntime.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/dom/IdleDeadline.h"
#include "mozilla/dom/UnionTypes.h"
@ -433,5 +434,32 @@ ChromeUtils::IsOriginAttributesEqual(const dom::OriginAttributesDictionary& aA,
aA.mPrivateBrowsingId == aB.mPrivateBrowsingId;
}
#ifdef NIGHTLY_BUILD
/* static */ void
ChromeUtils::GetRecentJSDevError(GlobalObject& aGlobal,
JS::MutableHandleValue aRetval,
ErrorResult& aRv)
{
aRetval.setUndefined();
auto runtime = CycleCollectedJSRuntime::Get();
MOZ_ASSERT(runtime);
auto cx = aGlobal.Context();
if (!runtime->GetRecentDevError(cx, aRetval)) {
aRv.NoteJSContextException(cx);
return;
}
}
/* static */ void
ChromeUtils::ClearRecentJSDevError(GlobalObject&)
{
auto runtime = CycleCollectedJSRuntime::Get();
MOZ_ASSERT(runtime);
runtime->ClearRecentDevError();
}
#endif // NIGHTLY_BUILD
} // namespace dom
} // namespace mozilla

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

@ -148,6 +148,12 @@ public:
IdleRequestCallback& callback,
const IdleRequestOptions& options,
ErrorResult& aRv);
static void GetRecentJSDevError(GlobalObject& aGlobal,
JS::MutableHandleValue aRetval,
ErrorResult& aRv);
static void ClearRecentJSDevError(GlobalObject& aGlobal);
};
} // namespace dom

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

@ -11000,7 +11000,7 @@ template <prototypes::ID PrototypeID, class NativeType, typename T>
static Result<Ok, nsresult>
ExtractExceptionValues(JSContext* aCx,
JS::HandleObject aObj,
nsACString& aSourceSpecOut,
nsAString& aSourceSpecOut,
uint32_t* aLineOut,
uint32_t* aColumnOut,
nsString& aMessageOut)
@ -11008,10 +11008,8 @@ ExtractExceptionValues(JSContext* aCx,
RefPtr<T> exn;
MOZ_TRY((UnwrapObject<PrototypeID, NativeType>(aObj, exn)));
nsAutoString filename;
exn->GetFilename(aCx, filename);
if (!filename.IsEmpty()) {
CopyUTF16toUTF8(filename, aSourceSpecOut);
exn->GetFilename(aCx, aSourceSpecOut);
if (!aSourceSpecOut.IsEmpty()) {
*aLineOut = exn->LineNumber(aCx);
*aColumnOut = exn->ColumnNumber();
}
@ -11032,6 +11030,19 @@ nsContentUtils::ExtractErrorValues(JSContext* aCx,
uint32_t* aLineOut,
uint32_t* aColumnOut,
nsString& aMessageOut)
{
nsAutoString sourceSpec;
ExtractErrorValues(aCx, aValue, sourceSpec, aLineOut, aColumnOut, aMessageOut);
CopyUTF16toUTF8(sourceSpec, aSourceSpecOut);
}
/* static */ void
nsContentUtils::ExtractErrorValues(JSContext* aCx,
JS::Handle<JS::Value> aValue,
nsAString& aSourceSpecOut,
uint32_t* aLineOut,
uint32_t* aColumnOut,
nsString& aMessageOut)
{
MOZ_ASSERT(aLineOut);
MOZ_ASSERT(aColumnOut);
@ -11053,7 +11064,7 @@ nsContentUtils::ExtractErrorValues(JSContext* aCx,
0); // window ID
if (!report->mFileName.IsEmpty()) {
CopyUTF16toUTF8(report->mFileName, aSourceSpecOut);
aSourceSpecOut = report->mFileName;
*aLineOut = report->mLineNumber;
*aColumnOut = report->mColumn;
}

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

@ -1136,6 +1136,14 @@ public:
static bool PrefetchPreloadEnabled(nsIDocShell* aDocShell);
static void
ExtractErrorValues(JSContext* aCx, JS::Handle<JS::Value> aValue,
nsAString& aSourceSpecOut, uint32_t *aLineOut,
uint32_t *aColumnOut, nsString& aMessageOut);
// Variant on `ExtractErrorValues` with a `nsACString`. This
// method is provided for backwards compatibility. Prefer the
// faster method above for your code.
static void
ExtractErrorValues(JSContext* aCx, JS::Handle<JS::Value> aValue,
nsACString& aSourceSpecOut, uint32_t *aLineOut,

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

@ -0,0 +1,56 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
function errors() {
return [
// The following two errors MUST NOT be captured.
new Error("This is an error: " + Math.random()),
new RangeError("This is a RangeError: " + Math.random()),
"This is a string: " + Math.random(),
null,
undefined,
Math.random(),
{},
// The following errors MUST be captured.
new TypeError("This is a TypeError: " + Math.random()),
new SyntaxError("This is a SyntaxError: " + Math.random()),
new ReferenceError("This is a ReferenceError: " + Math.random())
]
}
function isDeveloperError(e) {
if (e == null || typeof e != "object") {
return false;
}
return e.constructor == TypeError
|| e.constructor == SyntaxError
|| e.constructor == ReferenceError;
}
function run_test() {
ChromeUtils.clearRecentJSDevError();
Assert.equal(ChromeUtils.recentJSDevError, undefined);
for (let exn of errors()) {
ChromeUtils.clearRecentJSDevError();
try {
throw exn;
} catch (e) {
// Discard error.
}
if (isDeveloperError(exn)) {
Assert.equal(ChromeUtils.recentJSDevError.message, "" + exn);
} else {
Assert.equal(ChromeUtils.recentJSDevError, undefined);
}
ChromeUtils.clearRecentJSDevError();
Assert.equal(ChromeUtils.recentJSDevError, undefined);
}
};

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

@ -54,4 +54,7 @@ head = head_xml.js
[test_chromeutils_base64.js]
[test_generate_xpath.js]
head = head_xml.js
[test_js_dev_error_interceptor.js]
# This feature is implemented only in NIGHTLY.
run-if = nightly_build

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

@ -89,6 +89,40 @@ namespace ChromeUtils {
ArrayBuffer base64URLDecode(ByteString string,
Base64URLDecodeOptions options);
#ifdef NIGHTLY_BUILD
/**
* If the chrome code has thrown a JavaScript Dev Error
* in the current JSRuntime. the first such error, or `undefined`
* otherwise.
*
* A JavaScript Dev Error is an exception thrown by JavaScript
* code that matches both conditions:
* - it was thrown by chrome code;
* - it is either a `ReferenceError`, a `TypeError` or a `SyntaxError`.
*
* Such errors are stored regardless of whether they have been
* caught.
*
* This mechanism is designed to help ensure that the code of
* Firefox is free from Dev Errors, even if they are accidentally
* caught by clients.
*
* The object returned is not an exception. It has fields:
* - DOMString stack
* - DOMString filename
* - DOMString lineNumber
* - DOMString message
*/
[Throws]
readonly attribute any recentJSDevError;
/**
* Reset `recentJSDevError` to `undefined` for the current JSRuntime.
*/
void clearRecentJSDevError();
#endif // NIGHTLY_BUILD
/**
* IF YOU ADD NEW METHODS HERE, MAKE SURE THEY ARE THREAD-SAFE.
*/

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

@ -363,6 +363,7 @@ GENERATED_WEBIDL_FILES = [
]
PREPROCESSED_WEBIDL_FILES = [
'ChromeUtils.webidl',
'Navigator.webidl',
'Node.webidl',
'Window.webidl',
@ -425,7 +426,6 @@ WEBIDL_FILES = [
'CheckerboardReportService.webidl',
'ChildNode.webidl',
'ChromeNodeList.webidl',
'ChromeUtils.webidl',
'Client.webidl',
'Clients.webidl',
'ClipboardEvent.webidl',

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

@ -137,6 +137,13 @@ if CONFIG['ENABLE_STREAMS']:
'testReadableStream.cpp',
]
if CONFIG['NIGHTLY_BUILD']:
# The Error interceptor only exists on Nightly.
UNIFIED_SOURCES += [
'testErrorInterceptor.cpp',
]
if CONFIG['JS_BUILD_BINAST'] and CONFIG['JS_STANDALONE']:
# Standalone builds leave the source directory untouched,
# which lets us run tests with the data files intact.

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

@ -0,0 +1,143 @@
#include "jsapi.h"
#include "jsapi-tests/tests.h"
#include "vm/StringBuffer.h"
// Tests for JS_GetErrorInterceptorCallback and JS_SetErrorInterceptorCallback.
namespace {
const double EXN_VALUE = 3.14;
static JS::PersistentRootedString gLatestMessage;
// An interceptor that stores the error in `gLatestMessage`.
struct SimpleInterceptor: JSErrorInterceptor {
virtual void interceptError(JSContext* cx, const JS::Value& val) override {
js::StringBuffer buffer(cx);
if (!ValueToStringBuffer(cx, val, buffer))
MOZ_CRASH("Could not convert to string buffer");
gLatestMessage = buffer.finishString();
if (!gLatestMessage)
MOZ_CRASH("Could not convert to string");
}
};
bool equalStrings(JSContext* cx, JSString* a, JSString* b) {
int32_t result = 0;
if (!JS_CompareStrings(cx, a, b, &result))
MOZ_CRASH("Could not compare strings");
return result == 0;
}
}
BEGIN_TEST(testErrorInterceptor)
{
// Run the following snippets.
const char* SAMPLES[] = {
"throw new Error('I am an Error')\0",
"throw new TypeError('I am a TypeError')\0",
"throw new ReferenceError('I am a ReferenceError')\0",
"throw new SyntaxError('I am a SyntaxError')\0",
"throw 5\0",
"undefined[0]\0",
"foo[0]\0",
"b[\0",
};
// With the simpleInterceptor, we should end up with the following error:
const char* TO_STRING[] = {
"Error: I am an Error\0",
"TypeError: I am a TypeError\0",
"ReferenceError: I am a ReferenceError\0",
"SyntaxError: I am a SyntaxError\0",
"5\0",
"TypeError: undefined has no properties\0",
"ReferenceError: foo is not defined\0",
"SyntaxError: expected expression, got end of script\0",
};
MOZ_ASSERT(mozilla::ArrayLength(SAMPLES) == mozilla::ArrayLength(TO_STRING));
// Save original callback.
JSErrorInterceptor* original = JS_GetErrorInterceptorCallback(cx->runtime());
gLatestMessage.init(cx);
// Test without callback.
JS_SetErrorInterceptorCallback(cx->runtime(), nullptr);
CHECK(gLatestMessage == nullptr);
for (auto sample: SAMPLES) {
if (execDontReport(sample, __FILE__, __LINE__))
MOZ_CRASH("This sample should have failed");
CHECK(JS_IsExceptionPending(cx));
CHECK(gLatestMessage == nullptr);
JS_ClearPendingException(cx);
}
// Test with callback.
SimpleInterceptor simpleInterceptor;
JS_SetErrorInterceptorCallback(cx->runtime(), &simpleInterceptor);
// Test that we return the right callback.
CHECK_EQUAL(JS_GetErrorInterceptorCallback(cx->runtime()), &simpleInterceptor);
// This shouldn't cause any error.
EXEC("function bar() {}");
CHECK(gLatestMessage == nullptr);
// Test error throwing with a callback that succeeds.
for (size_t i = 0; i < mozilla::ArrayLength(SAMPLES); ++i) {
// This should cause the appropriate error.
if (execDontReport(SAMPLES[i], __FILE__, __LINE__))
MOZ_CRASH("This sample should have failed");
CHECK(JS_IsExceptionPending(cx));
// Check result of callback.
CHECK(gLatestMessage != nullptr);
CHECK(js::StringEqualsAscii(&gLatestMessage->asLinear(), TO_STRING[i]));
// Check the final error.
JS::RootedValue exn(cx);
CHECK(JS_GetPendingException(cx, &exn));
JS_ClearPendingException(cx);
js::StringBuffer buffer(cx);
CHECK(ValueToStringBuffer(cx, exn, buffer));
CHECK(equalStrings(cx, buffer.finishString(), gLatestMessage));
// Cleanup.
gLatestMessage = nullptr;
}
// Test again without callback.
JS_SetErrorInterceptorCallback(cx->runtime(), nullptr);
for (size_t i = 0; i < mozilla::ArrayLength(SAMPLES); ++i) {
if (execDontReport(SAMPLES[i], __FILE__, __LINE__))
MOZ_CRASH("This sample should have failed");
CHECK(JS_IsExceptionPending(cx));
// Check that the callback wasn't called.
CHECK(gLatestMessage == nullptr);
// Check the final error.
JS::RootedValue exn(cx);
CHECK(JS_GetPendingException(cx, &exn));
JS_ClearPendingException(cx);
js::StringBuffer buffer(cx);
CHECK(ValueToStringBuffer(cx, exn, buffer));
CHECK(js::StringEqualsAscii(buffer.finishString(), TO_STRING[i]));
// Cleanup.
gLatestMessage = nullptr;
}
// Cleanup
JS_SetErrorInterceptorCallback(cx->runtime(), original);
gLatestMessage = nullptr;
JS_ClearPendingException(cx);
return true;
}
END_TEST(testErrorInterceptor)

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

@ -653,6 +653,40 @@ JS_SetCompartmentNameCallback(JSContext* cx, JSCompartmentNameCallback callback)
cx->runtime()->compartmentNameCallback = callback;
}
#if defined(NIGHTLY_BUILD)
JS_PUBLIC_API(void)
JS_SetErrorInterceptorCallback(JSRuntime* rt, JSErrorInterceptor* callback)
{
rt->errorInterception.interceptor = callback;
}
JS_PUBLIC_API(JSErrorInterceptor*)
JS_GetErrorInterceptorCallback(JSRuntime* rt)
{
return rt->errorInterception.interceptor;
}
JS_PUBLIC_API(Maybe<JSExnType>)
JS_GetErrorType(const JS::Value& val)
{
// All errors are objects.
if (!val.isObject())
return mozilla::Nothing();
const JSObject& obj = val.toObject();
// All errors are `ErrorObject`.
if (!obj.is<js::ErrorObject>()) {
// Not one of the primitive errors.
return mozilla::Nothing();
}
const js::ErrorObject& err = obj.as<js::ErrorObject>();
return mozilla::Some(err.type());
}
#endif // defined(NIGHTLY_BUILD)
JS_PUBLIC_API(void)
JS_SetWrapObjectCallbacks(JSContext* cx, const JSWrapObjectCallbacks* callbacks)
{

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

@ -680,6 +680,18 @@ typedef void
using JSExternalStringSizeofCallback =
size_t (*)(JSString* str, mozilla::MallocSizeOf mallocSizeOf);
/**
* Callback used to intercept JavaScript errors.
*/
struct JSErrorInterceptor {
/**
* This method is called whenever an error has been raised from JS code.
*
* This method MUST be infallible.
*/
virtual void interceptError(JSContext* cx, const JS::Value& error) = 0;
};
/************************************************************************/
static MOZ_ALWAYS_INLINE JS::Value
@ -1327,6 +1339,33 @@ JS_SetWrapObjectCallbacks(JSContext* cx, const JSWrapObjectCallbacks* callbacks)
extern JS_PUBLIC_API(void)
JS_SetExternalStringSizeofCallback(JSContext* cx, JSExternalStringSizeofCallback callback);
#if defined(NIGHTLY_BUILD)
// Set a callback that will be called whenever an error
// is thrown in this runtime. This is designed as a mechanism
// for logging errors. Note that the VM makes no attempt to sanitize
// the contents of the error (so it may contain private data)
// or to sort out among errors (so it may not be the error you
// are interested in or for the component in which you are
// interested).
//
// If the callback sets a new error, this new error
// will replace the original error.
//
// May be `nullptr`.
extern JS_PUBLIC_API(void)
JS_SetErrorInterceptorCallback(JSRuntime*, JSErrorInterceptor* callback);
extern JS_PUBLIC_API(JSErrorInterceptor*)
JS_GetErrorInterceptorCallback(JSRuntime*);
// Examine a value to determine if it is one of the built-in Error types.
// If so, return the error type.
extern JS_PUBLIC_API(mozilla::Maybe<JSExnType>)
JS_GetErrorType(const JS::Value& val);
#endif // defined(NIGHTLY_BUILD)
extern JS_PUBLIC_API(void)
JS_SetCompartmentPrivate(JSCompartment* compartment, void* data);

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

@ -434,6 +434,31 @@ JSContext::minorGC(JS::gcreason::Reason reason)
inline void
JSContext::setPendingException(const js::Value& v)
{
#if defined(NIGHTLY_BUILD)
do {
// Do not intercept exceptions if we are already
// in the exception interceptor. That would lead
// to infinite recursion.
if (this->runtime()->errorInterception.isExecuting)
break;
// Check whether we have an interceptor at all.
if (!this->runtime()->errorInterception.interceptor)
break;
// Make sure that we do not call the interceptor from within
// the interceptor.
this->runtime()->errorInterception.isExecuting = true;
// The interceptor must be infallible.
const mozilla::DebugOnly<bool> wasExceptionPending = this->isExceptionPending();
this->runtime()->errorInterception.interceptor->interceptError(this, v);
MOZ_ASSERT(wasExceptionPending == this->isExceptionPending());
this->runtime()->errorInterception.isExecuting = false;
} while (false);
#endif // defined(NIGHTLY_BUILD)
// overRecursed_ is set after the fact by ReportOverRecursed.
this->overRecursed_ = false;
this->throwing = true;

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

@ -1081,6 +1081,30 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
void* wasmUnwindPC() const {
return wasmUnwindPC_;
}
public:
#if defined(NIGHTLY_BUILD)
// Support for informing the embedding of any error thrown.
// This mechanism is designed to let the embedding
// log/report/fail in case certain errors are thrown
// (e.g. SyntaxError, ReferenceError or TypeError
// in critical code).
struct ErrorInterceptionSupport {
ErrorInterceptionSupport()
: isExecuting(false)
, interceptor(nullptr)
{ }
// true if the error interceptor is currently executing,
// false otherwise. Used to avoid infinite loops.
bool isExecuting;
// if non-null, any call to `setPendingException`
// in this runtime will trigger the call to `interceptor`
JSErrorInterceptor* interceptor;
};
ErrorInterceptionSupport errorInterception;
#endif // defined(NIGHTLY_BUILD)
};
namespace js {

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

@ -1159,4 +1159,4 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
static const int32_t kUnknownId = -1;
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1522348268251000);
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1522434806681000);

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -8,7 +8,7 @@
/*****************************************************************************/
#include <stdint.h>
const PRTime gPreloadListExpirationTime = INT64_C(1524767455585000);
const PRTime gPreloadListExpirationTime = INT64_C(1524853993707000);
%%
0-1.party, 1
0.me.uk, 1
@ -656,7 +656,6 @@ academicexperts.us, 1
academie-de-police.ch, 1
academy4.net, 1
academytv.com.au, 1
acadianapatios.com, 1
acampar.com.br, 1
acaonegocios.com.br, 1
acara-yoga.de, 1
@ -2654,6 +2653,7 @@ azabani.com, 1
azamra.com, 1
azia.info, 1
azimut.fr, 1
azino777.ru, 1
azlk-team.ru, 1
azort.com, 1
azrazalea.net, 1
@ -4245,7 +4245,6 @@ bramvanaken.be, 1
bran.land, 1
bran.soy, 1
branch-bookkeeper.com, 1
branchzero.com, 1
brandbil.dk, 1
brandbuilderwebsites.com, 1
brandcodeconsulting.com, 1
@ -5427,7 +5426,6 @@ cheapssl.com.tr, 1
cheapticket.in, 1
cheapwritinghelp.com, 1
cheapwritingservice.com, 1
cheatturnitin.com, 1
chebwebb.com, 1
check.torproject.org, 0
checkecert.nl, 1
@ -5670,7 +5668,6 @@ ciderclub.com, 1
cie-theatre-montfaucon.ch, 1
cielbleu.org, 1
cielly.com, 1
cienbeaute-lidl.fr, 1
cifop-numerique.fr, 1
cig-dem.com, 1
cigar-cartel.com, 1
@ -5722,7 +5719,7 @@ cirugiasplasticas.com.mx, 1
cirujanooral.com, 1
cirurgicagervasio.com.br, 1
cirurgicalucena.com.br, 1
ciscodude.net, 0
ciscodude.net, 1
cisoaid.com, 1
ciss.ltd, 1
cisy.me, 1
@ -5893,7 +5890,6 @@ cloudcaprice.net, 1
cloudcloudcloud.cloud, 1
cloudflare.com, 1
cloudflareonazure.com, 1
cloudfren.com, 1
cloudia.org, 1
cloudily.com, 1
cloudimproved.com, 1
@ -6292,7 +6288,7 @@ concursopublico.com.br, 1
concursos.com.br, 1
concursosabertos.com.br, 1
condecom.com.br, 1
condepenalba.com, 1
condepenalba.com, 0
condesaelectronics.com, 1
condosforcash.com, 1
condroz-motors.be, 1
@ -7318,7 +7314,6 @@ davidschadlich.com, 1
davidscherzer.at, 1
davidschlachter.com, 1
davidstuff.net, 1
davie3.com, 1
davimun.org, 1
davisroi.com, 1
davo-usedcars.be, 1
@ -7630,6 +7625,7 @@ derehamcastles.co.uk, 1
derekkent.com, 1
derekseaman.com, 1
derekseaman.studio, 1
dergeilstestammderwelt.de, 1
derhil.de, 1
derivativeshub.pro, 1
derive.cc, 1
@ -7743,7 +7739,6 @@ devh.de, 1
devh.net, 1
deviant.email, 1
devillers-occasions.be, 1
devilshakerz.com, 1
deviltracks.net, 1
deviltraxxx.de, 1
devinfo.net, 0
@ -7846,6 +7841,7 @@ dicionarioetimologico.com.br, 1
dick.red, 1
dickieslife.com, 1
dickpics.ru, 1
dicoding.com, 1
didacte.com, 1
didche.net, 1
diddens.de, 1
@ -8021,7 +8017,7 @@ disconformity.net, 1
discord-chan.net, 1
discordapp.com, 1
discordghost.space, 1
discotek.club, 0
discotek.club, 1
discount24.de, 1
discountmania.eu, 1
discountmetaux.fr, 1
@ -8843,7 +8839,6 @@ echoworld.ch, 1
ecirtam.net, 1
eckel.co, 1
eclipse.ws, 1
ecnetworker.com, 1
eco-derattizzazione.it, 1
eco-work.it, 1
ecoccinelles.ch, 1
@ -11341,6 +11336,7 @@ g4w.co, 1
gaanbaksho.com.au, 1
gaasuper6.com, 1
gabemack.com, 1
gabethebabetv.com, 1
gabriel.to, 1
gabriele-kluge.de, 1
gabrielsimonet.ch, 1
@ -11681,6 +11677,7 @@ gerald-zojer.com, 1
geraldsonrealty.com, 1
gerardobsd.com, 1
gerardozamudio.mx, 1
geri.be, 1
germandarknes.net, 1
germansoldiers.net, 1
germanssky.de, 1
@ -12171,6 +12168,7 @@ graeber.com, 1
graetnew.com, 1
graf.re, 1
grafcaps.com, 1
graffen.dk, 1
grafmurr.de, 1
grahamofthewheels.com, 1
grailians.com, 1
@ -14070,7 +14068,6 @@ impact.health.nz, 1
impacter.eu, 1
impactfestival.be, 1
impactpub.ch, 1
impakho.com, 1
impas.se, 1
imperdin.com, 1
imperdintechnologies.com, 1
@ -14405,7 +14402,6 @@ internetpro.me, 1
internetradiocharts.de, 1
internetstaff.com, 1
internetzentrale.net, 1
internshipandwork.ru, 1
interociter-enterprises.com, 1
interracial.dating, 1
intersectraven.net, 1
@ -14692,7 +14688,6 @@ it-world.eu, 1
it.search.yahoo.com, 0
itactiq.com, 1
itactiq.info, 1
itad.top, 1
ital-gamma.be, 1
italia-store.com, 1
italiachegioca.com, 1
@ -14772,7 +14767,6 @@ itswincer.com, 1
ittop-gabon.com, 1
itzap.com.au, 1
ivanbenito.com, 1
ivancacic.com, 0
ivanilla.org, 1
ivanmeade.com, 1
ivanpolchenko.com, 1
@ -15615,6 +15609,7 @@ jutlander.dk, 1
juventusclublugano.ch, 1
juventusmania1897.com, 1
juwelierstoopman.nl, 1
juzgalo.com, 1
jva-wuerzburg.de, 1
jvanerp.nl, 1
jvbouncycastlehire.co.uk, 1
@ -15630,6 +15625,7 @@ jwolt-lx.com, 1
jwschuepfheim.ch, 1
jxir.de, 1
jyggen.com, 1
jym.fit, 1
jyoti-fairworks.org, 1
jzbk.org, 1
k-homes.net, 1
@ -15708,7 +15704,6 @@ kalsbouncies.com, 1
kaltenbrunner.it, 1
kalterersee.ch, 1
kamalame.co, 1
kamikaichimaru.com, 1
kamitech.ch, 1
kamixa.se, 1
kana.me, 1
@ -16342,7 +16337,6 @@ kokensupport.com, 1
koketteriet.se, 1
kokumoto.com, 1
koldanews.com, 1
kolin.org, 1
kolizaskrap.bg, 1
kolja-engelmann.de, 1
kolkataflowermall.com, 1
@ -16385,7 +16379,7 @@ konsertoversikt.no, 1
konst.se, 1
kontakthuman.hu, 1
kontaxis.org, 1
kontorhaus-schlachte.de, 0
kontorhaus-schlachte.de, 1
konventseliten.se, 1
konyalian.com, 1
konzertheld.de, 1
@ -17765,6 +17759,7 @@ loritaboegl.de, 1
losebellyfat.pro, 1
losless.fr, 1
loss.no, 1
lostandcash.com, 1
lostarq.com, 1
lostingames.de, 1
lostkeys.co.uk, 1
@ -17888,6 +17883,7 @@ lucysan.net, 1
ludikovsky.name, 1
ludovic-muller.fr, 1
ludwig.im, 1
ludwiggrill.de, 1
ludwigpro.net, 1
luehne.de, 1
luelistan.net, 1
@ -18311,7 +18307,6 @@ manneguiden.no, 1
mannford.com, 1
mannheimbloggt.tk, 1
manns-solutions.co.uk, 1
manns-solutions.ru, 1
mannschafft.ch, 1
mannsolutions.co.uk, 1
manoirdecontres.com, 1
@ -19815,7 +19810,7 @@ mplusm.eu, 1
mpn.poker, 1
mpnpokertour.com, 1
mpodraza.pl, 1
mpreserver.com, 0
mpreserver.com, 1
mpserver12.org, 1
mpsgarage.com.au, 1
mpsoundcraft.com, 1
@ -21360,7 +21355,6 @@ nystudio107.com, 1
nyxi.eu, 1
nyyu.tk, 1
nzb.cat, 0
nzmk.cz, 0
nzstudy.ac.nz, 1
o-loska.cz, 1
o-sp.com, 1
@ -21423,7 +21417,6 @@ ochsundjunior.ch, 1
ocim.ch, 1
ockendenhemming.co.uk, 1
ocloud.fr, 1
ocmeulebeke.be, 1
ocolere.ch, 1
ocotg.com, 1
ocrn.nl, 1
@ -23139,6 +23132,7 @@ poinsot.info, 1
pointaction.com, 1
pointagri.com, 1
pointhost.de, 1
pointiswunderland.de, 1
points4unitedway.com, 1
pointsixtyfive.com, 1
pointum.com, 1
@ -23626,7 +23620,6 @@ promoterms.com.au, 1
promotiongeeks.com, 0
pronto-intervento.net, 1
proobec.cz, 1
proofwiki.org, 1
proos.nl, 1
proovn.com, 1
propagandablog.de, 1
@ -23932,7 +23925,6 @@ qq-navi.com, 1
qqj.net, 1
qqvips.com, 1
qrcontagion.com, 1
qredo.com, 1
qrforex.com, 1
qrlfinancial.com, 1
qrpth.eu, 1
@ -24949,7 +24941,6 @@ roguetechhub.org, 1
rohanbassett.com, 1
rohedaten.de, 1
rohitagr.com, 1
rohlik.cz, 1
rointe.online, 1
roiscroll.com, 1
rokki.ch, 1
@ -25301,6 +25292,7 @@ sadbox.es, 1
sadbox.org, 1
sadhawkict.org, 1
sadmansh.com, 1
sadsu.com, 1
saengsook.com, 1
saengsuk.com, 1
safar.sk, 1
@ -25330,7 +25322,6 @@ safetyrisk.net, 1
safezone.cc, 1
safire.ac.za, 1
sagedocumentmanager.com, 1
sagemontchurch.org, 1
sagerus.com, 1
sagsmarseille.com, 1
sahar.io, 1
@ -25643,7 +25634,6 @@ schamlosharmlos.de, 1
schaper-sport.com, 1
schatmeester.be, 1
schatzibaers.de, 1
schau-rein.co.at, 1
schawe.me, 1
schd.io, 1
scheduleme.io, 1
@ -26283,7 +26273,6 @@ shan.io, 0
shanae.nl, 1
shanetully.com, 1
shanewadleigh.com, 1
shang-yu.cn, 1
shannoneichorn.com, 1
shansing.cn, 1
shansing.com, 1
@ -26715,7 +26704,6 @@ sinonimosonline.com, 1
sinonimosonline.com.br, 1
sinoscandinavia.se, 1
sinquin.eu, 1
sinsojb.me, 1
sint-joris.nl, 1
sinterama.biz, 1
sintesysglobal.com, 1
@ -26729,7 +26717,6 @@ sirbouncelot.co.uk, 1
sirena.co.jp, 1
sirenslove.com, 1
siriuspup.com, 1
siroop.ch, 1
sirtaptap.com, 1
sirtuins.com, 1
sistel.es, 1
@ -28244,7 +28231,6 @@ swfmax.com, 1
swift-devedge.de, 1
swiftconf.com, 1
swiftqueue.com, 1
swiggy.com, 1
swilly.org, 1
swimbee.nl, 1
swimturk.com.tr, 1
@ -28609,7 +28595,7 @@ teamnorthgermany.de, 1
teampaddymurphy.ch, 1
teampaddymurphy.ie, 1
teamtouring.net, 1
teamtrack.uk, 0
teamtrack.uk, 1
teamupturn.com, 1
teamupturn.org, 1
teamx-gaming.de, 1
@ -29304,6 +29290,7 @@ tianshili.me, 1
tianxicaipiao.com, 1
tianxicaipiao.win, 1
tianxicp.com, 1
tibbitshall.ca, 1
tibipg.com, 1
tibovanheule.site, 1
ticfleet.com, 1
@ -29576,6 +29563,7 @@ tollsjekk.no, 1
tom-geiger.de, 1
tom-kunze.de, 1
tom-maxwell.com, 1
tom.horse, 1
tomabrafix.de, 1
tomandshirley.com, 1
tomasjacik.cz, 1
@ -29943,7 +29931,7 @@ treasuredinheritanceministry.com, 1
treasurydirect.gov, 1
treasuryhunt.gov, 1
treasuryscams.gov, 1
treebaglia.xyz, 0
treebaglia.xyz, 1
treehousebydesign.com, 1
treehouseresort.nl, 1
trees.chat, 1
@ -30518,6 +30506,7 @@ unseen.tw, 1
unser-gartenforum.de, 1
unsuspicious.click, 1
unterfrankenclan.de, 1
unterkunft.guru, 1
unterschicht.tv, 1
untethereddog.com, 1
untoldstory.eu, 1
@ -30576,6 +30565,7 @@ urbanietz-immobilien.de, 1
urbanmelbourne.info, 1
urbannewsservice.com, 1
urbansparrow.in, 1
urbanstylestaging.com, 1
urbanwildlifealliance.org, 1
urbexdk.nl, 1
urcentral.com, 1
@ -31294,7 +31284,6 @@ voyageschine.com, 1
voyagesdetective.fr, 1
vozami.com, 1
vpc-display.com, 1
vpls.co.th, 1
vpn.ht, 1
vpnservice.nl, 1
vpnzoom.com, 1
@ -31494,7 +31483,6 @@ waterschaplimburg.nl, 1
watertrails.io, 1
waterworkscondos.com, 1
watsonwork.me, 1
wattechweb.com, 1
wave-ola.es, 1
wavesboardshop.com, 1
wavesoftime.com, 1
@ -31509,7 +31497,6 @@ waytt.cf, 0
waze.com, 1
wbci.us, 1
wbg-vs.de, 1
wbit.co.il, 1
wbt-solutions.ch, 1
wbt-solutions.net, 1
wbuntu.com, 1
@ -32053,7 +32040,6 @@ windhaven.nl, 0
windholz.us, 1
windowcleaningexperts.net, 1
windows10insider.com, 1
windowsforum.com, 1
windowsnerd.com, 1
windowstech.it, 1
windowwellcovers.com, 1
@ -32406,9 +32392,8 @@ wvg.myds.me, 1
wvw-8522.com, 1
wvw698.com, 1
wweforums.net, 1
wweichen.com.cn, 0
wweichen.com.cn, 1
wwgc2011.se, 1
wwv-8522.com, 1
www-33445.com, 1
www-49889.com, 1
www-62755.com, 1
@ -33203,7 +33188,6 @@ zaratan.fr, 1
zargaripour.com, 1
zarmarket.org, 1
zarpo.com.br, 1
zary.me, 1
zaufanatrzeciastrona.pl, 1
zavec.com.ec, 1
zavetaji.lv, 1
@ -33348,7 +33332,6 @@ zittingskalender.be, 1
zivava.ge, 1
zivmergers.com, 1
zivver.com, 1
zivy-ruzenec.cz, 0
zivyruzenec.cz, 0
zixiao.wang, 1
zk.gd, 1

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

@ -1382,7 +1382,7 @@ impl FragmentDisplayListBuilding for Fragment {
.map(|argument| argument.to_css_string())
.collect();
let mut draw_result = match state.layout_context.registered_painters.get(&name) {
let draw_result = match state.layout_context.registered_painters.get(&name) {
Some(painter) => {
debug!("Drawing a paint image {}({},{}).", name, size_in_px.width, size_in_px.height);
let properties = painter.properties().iter()
@ -1397,19 +1397,22 @@ impl FragmentDisplayListBuilding for Fragment {
},
};
let webrender_image = WebRenderImageInfo {
width: draw_result.width,
height: draw_result.height,
format: draw_result.format,
key: draw_result.image_key,
};
if let Ok(draw_result) = draw_result {
let webrender_image = WebRenderImageInfo {
width: draw_result.width,
height: draw_result.height,
format: draw_result.format,
key: draw_result.image_key,
};
for url in draw_result.missing_image_urls.drain(..) {
debug!("Requesting missing image URL {}.", url);
state.layout_context.get_webrender_image_for_url(self.node, url, UsePlaceholder::No);
for url in draw_result.missing_image_urls.into_iter() {
debug!("Requesting missing image URL {}.", url);
state.layout_context.get_webrender_image_for_url(self.node, url, UsePlaceholder::No);
}
Some(webrender_image)
} else {
None
}
Some(webrender_image)
}
fn build_display_list_for_background_gradient(&self,

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

@ -100,8 +100,8 @@ use script_layout_interface::rpc::{LayoutRPC, MarginStyleResponse, NodeOverflowR
use script_layout_interface::rpc::TextIndexResponse;
use script_layout_interface::wrapper_traits::LayoutNode;
use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
use script_traits::{DrawAPaintImageResult, PaintWorkletError};
use script_traits::{ScrollState, UntrustedNodeAddress};
use script_traits::DrawAPaintImageResult;
use script_traits::Painter;
use selectors::Element;
use servo_arc::Arc as ServoArc;
@ -1787,7 +1787,7 @@ impl Painter for RegisteredPainterImpl {
device_pixel_ratio: TypedScale<f32, CSSPixel, DevicePixel>,
properties: Vec<(Atom, String)>,
arguments: Vec<String>)
-> DrawAPaintImageResult
-> Result<DrawAPaintImageResult, PaintWorkletError>
{
self.painter.draw_a_paint_image(size, device_pixel_ratio, properties, arguments)
}

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

@ -45,9 +45,10 @@ use js::rust::Runtime;
use msg::constellation_msg::PipelineId;
use net_traits::image::base::PixelFormat;
use net_traits::image_cache::ImageCache;
use script_traits::DrawAPaintImageResult;
use script_traits::{DrawAPaintImageResult, PaintWorkletError};
use script_traits::Painter;
use servo_atoms::Atom;
use servo_config::prefs::PREFS;
use servo_url::ServoUrl;
use std::cell::Cell;
use std::collections::HashMap;
@ -58,6 +59,8 @@ use std::sync::Arc;
use std::sync::Mutex;
use std::sync::mpsc;
use std::sync::mpsc::Sender;
use std::thread;
use std::time::Duration;
use style_traits::CSSPixel;
use style_traits::DevicePixel;
use style_traits::SpeculativePainter;
@ -343,7 +346,7 @@ impl PaintWorkletGlobalScope {
device_pixel_ratio: TypedScale<f32, CSSPixel, DevicePixel>,
properties: Vec<(Atom, String)>,
arguments: Vec<String>)
-> DrawAPaintImageResult {
-> Result<DrawAPaintImageResult, PaintWorkletError> {
let name = self.name.clone();
let (sender, receiver) = mpsc::channel();
let task = PaintWorkletTask::DrawAPaintImage(name,
@ -354,7 +357,14 @@ impl PaintWorkletGlobalScope {
sender);
self.executor.lock().expect("Locking a painter.")
.schedule_a_worklet_task(WorkletTask::Paint(task));
receiver.recv().expect("Worklet thread died?")
let timeout = PREFS.get("dom.worklet.timeout_ms")
.as_u64()
.unwrap_or(10u64);
let timeout_duration = Duration::from_millis(timeout);
receiver.recv_timeout(timeout_duration)
.map_err(|e| PaintWorkletError::from(e))
}
}
Box::new(WorkletPainter {
@ -364,6 +374,60 @@ impl PaintWorkletGlobalScope {
}
}
/// Tasks which can be peformed by a paint worklet
pub enum PaintWorkletTask {
DrawAPaintImage(Atom,
TypedSize2D<f32, CSSPixel>,
TypedScale<f32, CSSPixel, DevicePixel>,
Vec<(Atom, String)>,
Vec<String>,
Sender<DrawAPaintImageResult>),
SpeculativelyDrawAPaintImage(Atom,
Vec<(Atom, String)>,
Vec<String>),
}
/// A paint definition
/// <https://drafts.css-houdini.org/css-paint-api/#paint-definition>
/// This type is dangerous, because it contains uboxed `Heap<JSVal>` values,
/// which can't be moved.
#[derive(JSTraceable, MallocSizeOf)]
#[must_root]
struct PaintDefinition {
class_constructor: Heap<JSVal>,
paint_function: Heap<JSVal>,
constructor_valid_flag: Cell<bool>,
context_alpha_flag: bool,
// TODO: this should be a list of CSS syntaxes.
input_arguments_len: usize,
// TODO: the spec calls for fresh rendering contexts each time a paint image is drawn,
// but to avoid having the primary worklet thread create a new renering context,
// we recycle them.
context: Dom<PaintRenderingContext2D>,
}
impl PaintDefinition {
fn new(class_constructor: HandleValue,
paint_function: HandleValue,
alpha: bool,
input_arguments_len: usize,
context: &PaintRenderingContext2D)
-> Box<PaintDefinition>
{
let result = Box::new(PaintDefinition {
class_constructor: Heap::default(),
paint_function: Heap::default(),
constructor_valid_flag: Cell::new(true),
context_alpha_flag: alpha,
input_arguments_len: input_arguments_len,
context: Dom::from_ref(context),
});
result.class_constructor.set(class_constructor.get());
result.paint_function.set(paint_function.get());
result
}
}
impl PaintWorkletGlobalScopeMethods for PaintWorkletGlobalScope {
#[allow(unsafe_code)]
#[allow(unrooted_must_root)]
@ -445,58 +509,14 @@ impl PaintWorkletGlobalScopeMethods for PaintWorkletGlobalScope {
Ok(())
}
}
/// Tasks which can be peformed by a paint worklet
pub enum PaintWorkletTask {
DrawAPaintImage(Atom,
TypedSize2D<f32, CSSPixel>,
TypedScale<f32, CSSPixel, DevicePixel>,
Vec<(Atom, String)>,
Vec<String>,
Sender<DrawAPaintImageResult>),
SpeculativelyDrawAPaintImage(Atom,
Vec<(Atom, String)>,
Vec<String>),
}
/// A paint definition
/// <https://drafts.css-houdini.org/css-paint-api/#paint-definition>
/// This type is dangerous, because it contains uboxed `Heap<JSVal>` values,
/// which can't be moved.
#[derive(JSTraceable, MallocSizeOf)]
#[must_root]
struct PaintDefinition {
class_constructor: Heap<JSVal>,
paint_function: Heap<JSVal>,
constructor_valid_flag: Cell<bool>,
context_alpha_flag: bool,
// TODO: this should be a list of CSS syntaxes.
input_arguments_len: usize,
// TODO: the spec calls for fresh rendering contexts each time a paint image is drawn,
// but to avoid having the primary worklet thread create a new renering context,
// we recycle them.
context: Dom<PaintRenderingContext2D>,
}
impl PaintDefinition {
fn new(class_constructor: HandleValue,
paint_function: HandleValue,
alpha: bool,
input_arguments_len: usize,
context: &PaintRenderingContext2D)
-> Box<PaintDefinition>
{
let result = Box::new(PaintDefinition {
class_constructor: Heap::default(),
paint_function: Heap::default(),
constructor_valid_flag: Cell::new(true),
context_alpha_flag: alpha,
input_arguments_len: input_arguments_len,
context: Dom::from_ref(context),
});
result.class_constructor.set(class_constructor.get());
result.paint_function.set(paint_function.get());
result
/// This is a blocking sleep function available in the paint worklet
/// global scope behind the dom.worklet.enabled +
/// dom.worklet.blockingsleep.enabled prefs. It is to be used only for
/// testing, e.g., timeouts, where otherwise one would need busy waiting
/// to make sure a certain timeout is triggered.
/// check-tidy: no specs after this line
fn Sleep(&self, ms: u64) {
thread::sleep(Duration::from_millis(ms));
}
}

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

@ -6,4 +6,8 @@
[Global=(Worklet,PaintWorklet), Pref="dom.worklet.enabled", Exposed=PaintWorklet]
interface PaintWorkletGlobalScope : WorkletGlobalScope {
[Throws] void registerPaint(DOMString name, VoidFunction paintCtor);
// This function is to be used only for testing, and should not be
// accessible outside of that use.
[Pref="dom.worklet.blockingsleep.enabled"]
void sleep(unsigned long long ms);
};

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

@ -869,7 +869,7 @@ pub trait Painter: SpeculativePainter {
zoom: TypedScale<f32, CSSPixel, DevicePixel>,
properties: Vec<(Atom, String)>,
arguments: Vec<String>)
-> DrawAPaintImageResult;
-> Result<DrawAPaintImageResult, PaintWorkletError>;
}
impl fmt::Debug for Painter {

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

@ -88,6 +88,17 @@ def get_digest_data(config, run, taskdesc):
if deps:
data.extend(sorted(deps.values()))
# If the task uses an in-tree docker image, we want it to influence
# the index path as well. Ideally, the content of the docker image itself
# should have an influence, but at the moment, we can't get that
# information here. So use the docker image name as a proxy. Not a lot of
# changes to docker images actually have an impact on the resulting
# toolchain artifact, so we'll just rely on such important changes to be
# accompanied with a docker image name change.
image = taskdesc['worker'].get('docker-image', {}).get('in-tree')
if image:
data.extend(image)
# Likewise script arguments should influence the index.
args = run.get('arguments')
if args:

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

@ -64,6 +64,10 @@
#include <gtk/gtkprivate.h>
#endif
#if defined(MOZ_WAYLAND)
#include <gdk/gdkwayland.h>
#endif
#include "nsGkAtoms.h"
#ifdef MOZ_ENABLE_STARTUP_NOTIFICATION
@ -1709,16 +1713,22 @@ nsWindow::GetNativeData(uint32_t aDataType)
#ifdef MOZ_X11
GdkDisplay* gdkDisplay = gdk_display_get_default();
if (GDK_IS_X11_DISPLAY(gdkDisplay)) {
return GDK_DISPLAY_XDISPLAY(gdkDisplay);
return GDK_DISPLAY_XDISPLAY(gdkDisplay);
}
#endif /* MOZ_X11 */
// Don't bother to return native display on Wayland as it's for
// X11 only NPAPI plugins.
return nullptr;
}
case NS_NATIVE_SHELLWIDGET:
return GetToplevelWidget();
case NS_NATIVE_SHAREABLE_WINDOW:
return (void *) GDK_WINDOW_XID(gdk_window_get_toplevel(mGdkWindow));
if (mIsX11Display) {
return (void *) GDK_WINDOW_XID(gdk_window_get_toplevel(mGdkWindow));
}
NS_WARNING("nsWindow::GetNativeData(): NS_NATIVE_SHAREABLE_WINDOW is not handled on Wayland!");
return nullptr;
case NS_RAW_NATIVE_IME_CONTEXT: {
void* pseudoIMEContext = GetPseudoIMEContext();
if (pseudoIMEContext) {
@ -2140,7 +2150,7 @@ nsWindow::OnExposeEvent(cairo_t *cr)
LOGDRAW(("sending expose event [%p] %p 0x%lx (rects follow):\n",
(void *)this, (void *)mGdkWindow,
gdk_x11_window_get_xid(mGdkWindow)));
mIsX11Display ? gdk_x11_window_get_xid(mGdkWindow) : 0));
// Our bounds may have changed after calling WillPaintWindow. Clip
// to the new bounds here. The region is relative to this
@ -3652,10 +3662,14 @@ nsWindow::Create(nsIWidget* aParent,
// which will use a Window with the override-redirect attribute
// (for temporary windows).
// For long-lived windows, their stacking order is managed by the
// window manager, as indicated by GTK_WINDOW_TOPLEVEL ...
GtkWindowType type =
mWindowType != eWindowType_popup || aInitData->mNoAutoHide ?
GTK_WINDOW_TOPLEVEL : GTK_WINDOW_POPUP;
// window manager, as indicated by GTK_WINDOW_TOPLEVEL.
// For Wayland we have to always use GTK_WINDOW_POPUP to control
// popup window position.
GtkWindowType type = GTK_WINDOW_TOPLEVEL;
if (mWindowType == eWindowType_popup) {
type = (mIsX11Display && aInitData->mNoAutoHide) ?
GTK_WINDOW_TOPLEVEL : GTK_WINDOW_POPUP;
}
mShell = gtk_window_new(type);
bool useAlphaVisual = (mWindowType == eWindowType_popup &&
@ -3727,9 +3741,11 @@ nsWindow::Create(nsIWidget* aParent,
#ifdef MOZ_X11
// ... but when the window manager offers focus through
// WM_TAKE_FOCUS, focus is requested on the parent window.
gtk_widget_realize(mShell);
gdk_window_add_filter(gtk_widget_get_window(mShell),
popup_take_focus_filter, nullptr);
if (mIsX11Display) {
gtk_widget_realize(mShell);
gdk_window_add_filter(gtk_widget_get_window(mShell),
popup_take_focus_filter, nullptr);
}
#endif
}
@ -3741,7 +3757,11 @@ nsWindow::Create(nsIWidget* aParent,
else {
switch (aInitData->mPopupHint) {
case ePopupTypeMenu:
gtkTypeHint = GDK_WINDOW_TYPE_HINT_POPUP_MENU;
// Use GDK_WINDOW_TYPE_HINT_UTILITY on Wayland which
// guides Gtk to create the popup as subsurface
// instead of xdg_shell popup (see Bug 1423598).
gtkTypeHint = mIsX11Display ? GDK_WINDOW_TYPE_HINT_POPUP_MENU :
GDK_WINDOW_TYPE_HINT_UTILITY;
break;
case ePopupTypeTooltip:
gtkTypeHint = GDK_WINDOW_TYPE_HINT_TOOLTIP;
@ -3793,9 +3813,12 @@ nsWindow::Create(nsIWidget* aParent,
* 2) We're running on Gtk+ and client side decorations
* are drawn by Gtk+ to mShell. Content is rendered to mContainer
* and we listen to the Gtk+ events on mContainer.
* 3) We're running on Wayland. All gecko content is rendered
* to mContainer and we listen to the Gtk+ events on mContainer.
*/
GtkStyleContext* style = gtk_widget_get_style_context(mShell);
drawToContainer =
!mIsX11Display ||
(mIsCSDAvailable && GetCSDSupportLevel() == CSD_SUPPORT_FLAT ) ||
gtk_style_context_has_class(style, "csd");
#endif
@ -4044,7 +4067,7 @@ nsWindow::Create(nsIWidget* aParent,
if (mShell) {
LOG(("\tmShell %p mContainer %p mGdkWindow %p 0x%lx\n",
mShell, mContainer, mGdkWindow,
gdk_x11_window_get_xid(mGdkWindow)));
mIsX11Display ? gdk_x11_window_get_xid(mGdkWindow) : 0));
} else if (mContainer) {
LOG(("\tmContainer %p mGdkWindow %p\n", mContainer, mGdkWindow));
}
@ -4789,6 +4812,12 @@ nsWindow::GrabPointer(guint32 aTime)
if (!mGdkWindow)
return;
if (!mIsX11Display) {
// Don't to the grab on Wayland as it causes a regression
// from Bug 1377084.
return;
}
gint retval;
retval = gdk_pointer_grab(mGdkWindow, TRUE,
(GdkEventMask)(GDK_BUTTON_PRESS_MASK |
@ -4822,6 +4851,13 @@ nsWindow::ReleaseGrabs(void)
LOG(("ReleaseGrabs\n"));
mRetryPointerGrab = false;
if (!mIsX11Display) {
// Don't to the ungrab on Wayland as it causes a regression
// from Bug 1377084.
return;
}
gdk_pointer_ungrab(GDK_CURRENT_TIME);
}
@ -7099,3 +7135,19 @@ nsWindow::IsComposited() const
(gdk_window_get_visual(mGdkWindow)
== gdk_screen_get_rgba_visual(gdkScreen));
}
#ifdef MOZ_WAYLAND
wl_display*
nsWindow::GetWaylandDisplay()
{
GdkDisplay* gdkDisplay = gdk_display_get_default();
return mIsX11Display ? nullptr :
gdk_wayland_display_get_wl_display(gdkDisplay);
}
wl_surface*
nsWindow::GetWaylandSurface()
{
return moz_container_get_wl_surface(MOZ_CONTAINER(mContainer));
}
#endif

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

@ -24,6 +24,9 @@
#ifdef MOZ_X11
#include <gdk/gdkx.h>
#endif /* MOZ_X11 */
#ifdef MOZ_WAYLAND
#include <gdk/gdkwayland.h>
#endif
#include "mozilla/widget/WindowSurface.h"
#include "mozilla/widget/WindowSurfaceProvider.h"
@ -348,8 +351,13 @@ public:
nsIObserver* aObserver) override;
#endif
#ifdef MOZ_X11
Display* XDisplay() { return mXDisplay; }
#endif
#ifdef MOZ_WAYLAND
wl_display* GetWaylandDisplay();
wl_surface* GetWaylandSurface();
#endif
virtual void GetCompositorWidgetInitData(mozilla::widget::CompositorWidgetInitData* aInitData) override;

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

@ -97,6 +97,11 @@
#include "nsThreadUtils.h"
#include "xpcpublic.h"
#ifdef NIGHTLY_BUILD
// For performance reasons, we make the JS Dev Error Interceptor a Nightly-only feature.
#define MOZ_JS_DEV_ERROR_INTERCEPTOR = 1
#endif // NIGHTLY_BUILD
using namespace mozilla;
using namespace mozilla::dom;
@ -556,11 +561,18 @@ CycleCollectedJSRuntime::CycleCollectedJSRuntime(JSContext* aCx)
js::SetScriptEnvironmentPreparer(aCx, &mEnvironmentPreparer);
JS::dbg::SetDebuggerMallocSizeOf(aCx, moz_malloc_size_of);
#ifdef MOZ_JS_DEV_ERROR_INTERCEPTOR
JS_SetErrorInterceptorCallback(mJSRuntime, &mErrorInterceptor);
#endif // MOZ_JS_DEV_ERROR_INTERCEPTOR
}
void
CycleCollectedJSRuntime::Shutdown(JSContext* cx)
{
#ifdef MOZ_JS_DEV_ERROR_INTERCEPTOR
mErrorInterceptor.Shutdown(mJSRuntime);
#endif // MOZ_JS_DEV_ERROR_INTERCEPTOR
JS_RemoveExtraGCRootsTracer(cx, TraceBlackJS, this);
JS_RemoveExtraGCRootsTracer(cx, TraceGrayJS, this);
#ifdef DEBUG
@ -1557,3 +1569,113 @@ CycleCollectedJSRuntime::Get()
}
return nullptr;
}
#ifdef MOZ_JS_DEV_ERROR_INTERCEPTOR
namespace js {
extern void DumpValue(const JS::Value& val);
}
void
CycleCollectedJSRuntime::ErrorInterceptor::Shutdown(JSRuntime* rt)
{
JS_SetErrorInterceptorCallback(rt, nullptr);
mThrownError.reset();
}
/* virtual */ void
CycleCollectedJSRuntime::ErrorInterceptor::interceptError(JSContext* cx, const JS::Value& exn)
{
if (mThrownError) {
// We already have an error, we don't need anything more.
return;
}
if (!nsContentUtils::ThreadsafeIsSystemCaller(cx)) {
// We are only interested in chrome code.
return;
}
const auto type = JS_GetErrorType(exn);
if (!type) {
// This is not one of the primitive error types.
return;
}
switch (*type) {
case JSExnType::JSEXN_REFERENCEERR:
case JSExnType::JSEXN_SYNTAXERR:
case JSExnType::JSEXN_TYPEERR:
break;
default:
// Not one of the errors we are interested in.
return;
}
// Now copy the details of the exception locally.
// While copying the details of an exception could be expensive, in most runs,
// this will be done at most once during the execution of the process, so the
// total cost should be reasonable.
JS::RootedValue value(cx, exn);
ErrorDetails details;
details.mType = *type;
// If `exn` isn't an exception object, `ExtractErrorValues` could end up calling
// `toString()`, which could in turn end up throwing an error. While this should
// work, we want to avoid that complex use case.
// Fortunately, we have already checked above that `exn` is an exception object,
// so nothing such should happen.
nsContentUtils::ExtractErrorValues(cx, value, details.mFilename, &details.mLine, &details.mColumn, details.mMessage);
nsAutoCString stack;
JS::UniqueChars buf = JS::FormatStackDump(cx, nullptr, /* showArgs = */ false, /* showLocals = */ false, /* showThisProps = */ false);
stack.Append(buf.get());
CopyUTF8toUTF16(buf.get(), details.mStack);
mThrownError.emplace(Move(details));
}
void
CycleCollectedJSRuntime::ClearRecentDevError()
{
mErrorInterceptor.mThrownError.reset();
}
bool
CycleCollectedJSRuntime::GetRecentDevError(JSContext*cx, JS::MutableHandle<JS::Value> error)
{
if (!mErrorInterceptor.mThrownError) {
return true;
}
// Create a copy of the exception.
JS::RootedObject obj(cx, JS_NewPlainObject(cx));
if (!obj) {
return false;
}
JS::RootedValue message(cx);
JS::RootedValue filename(cx);
JS::RootedValue stack(cx);
if (!ToJSValue(cx, mErrorInterceptor.mThrownError->mMessage, &message) ||
!ToJSValue(cx, mErrorInterceptor.mThrownError->mFilename, &filename) ||
!ToJSValue(cx, mErrorInterceptor.mThrownError->mStack, &stack)) {
return false;
}
// Build the object.
const auto FLAGS = JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT;
if (!JS_DefineProperty(cx, obj, "message", message, FLAGS) ||
!JS_DefineProperty(cx, obj, "fileName", filename, FLAGS) ||
!JS_DefineProperty(cx, obj, "lineNumber", mErrorInterceptor.mThrownError->mLine, FLAGS) ||
!JS_DefineProperty(cx, obj, "stack", stack, FLAGS)) {
return false;
}
// Pass the result.
error.setObject(*obj);
return true;
}
#endif // MOZ_JS_DEV_ERROR_INTERCEPTOR
#undef MOZ_JS_DEV_ERROR_INTERCEPTOR

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

@ -328,6 +328,11 @@ public:
void AddContext(CycleCollectedJSContext* aContext);
void RemoveContext(CycleCollectedJSContext* aContext);
#ifdef NIGHTLY_BUILD
bool GetRecentDevError(JSContext* aContext, JS::MutableHandle<JS::Value> aError);
void ClearRecentDevError();
#endif // defined(NIGHTLY_BUILD)
private:
LinkedList<CycleCollectedJSContext> mContexts;
@ -372,6 +377,37 @@ private:
#ifdef DEBUG
bool mShutdownCalled;
#endif
#ifdef NIGHTLY_BUILD
// Implementation of the error interceptor.
// Built on nightly only to avoid any possible performance impact on release
struct ErrorInterceptor final : public JSErrorInterceptor {
virtual void interceptError(JSContext* cx, const JS::Value& val) override;
void Shutdown(JSRuntime* rt);
// Copy of the details of the exception.
// We store this rather than the exception itself to avoid dealing with complicated
// garbage-collection scenarios, e.g. a JSContext being killed while we still hold
// onto an exception thrown from it.
struct ErrorDetails {
nsString mFilename;
nsString mMessage;
nsString mStack;
JSExnType mType;
uint32_t mLine;
uint32_t mColumn;
};
// If we have encountered at least one developer error,
// the first error we have encountered. Otherwise, or
// if we have reset since the latest error, `None`.
Maybe<ErrorDetails> mThrownError;
};
ErrorInterceptor mErrorInterceptor;
#endif // defined(NIGHTLY_BUILD)
};
void TraceScriptHolder(nsISupports* aHolder, JSTracer* aTracer);