зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound. a=merge CLOSED TREE
This commit is contained in:
Коммит
dee73f16c3
|
@ -190,3 +190,6 @@ tps_result\.json
|
|||
|
||||
# Ignore file generated by lalrpop at build time.
|
||||
^third_party/rust/lalrpop/src/parser/lrgrammar.rs
|
||||
|
||||
# Ignore the build directories of WebRender standalone builds.
|
||||
gfx/wr/target/
|
||||
|
|
|
@ -1123,6 +1123,7 @@ dependencies = [
|
|||
"encoding_glue 0.1.0",
|
||||
"env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"geckoservo 0.0.1",
|
||||
"gkrust_utils 0.1.0",
|
||||
"jsrust_shared 0.1.0",
|
||||
"kvstore 0.1.0",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1140,6 +1141,14 @@ dependencies = [
|
|||
"xpcom 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gkrust_utils"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nsstring 0.1.0",
|
||||
"uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gl_generator"
|
||||
version = "0.10.0"
|
||||
|
|
|
@ -36,6 +36,7 @@ exclude = [
|
|||
"media/mp4parse-rust/mp4parse",
|
||||
"media/mp4parse-rust/mp4parse_capi",
|
||||
"media/mp4parse-rust/mp4parse_fallible",
|
||||
"xpcom/rust/gkrust_utils",
|
||||
]
|
||||
|
||||
# Explicitly specify what our profiles use. The opt-level setting here is
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -253,19 +253,13 @@ panelview[mainview] > .panel-header {
|
|||
z-index: 2;
|
||||
}
|
||||
|
||||
/* The next 3 rules allow dragging tabs slightly outside of the tabstrip
|
||||
* to make it easier to drag tabs. */
|
||||
#navigator-toolbox[movingtab] > #titlebar > #TabsToolbar {
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
#navigator-toolbox[movingtab] #tabbrowser-tabs {
|
||||
/* Make it easier to drag tabs by expanding the drag area downwards. */
|
||||
#tabbrowser-tabs[movingtab] {
|
||||
padding-bottom: 15px;
|
||||
margin-bottom: -15px;
|
||||
}
|
||||
|
||||
#navigator-toolbox[movingtab] > #nav-bar {
|
||||
margin-top: -15px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -833,10 +833,14 @@ var gPrivacyPane = {
|
|||
* Initialize the starting state for the auto-start private browsing mode pref reverter.
|
||||
*/
|
||||
initAutoStartPrivateBrowsingReverter() {
|
||||
// We determine the mode in initializeHistoryMode, which is guaranteed to have been
|
||||
// called before now, so this is up-to-date.
|
||||
let mode = document.getElementById("historyMode");
|
||||
let autoStart = document.getElementById("privateBrowsingAutoStart");
|
||||
this._lastMode = mode.selectedIndex;
|
||||
this._lastCheckState = autoStart.hasAttribute("checked");
|
||||
// The value of the autostart pref, on the other hand, is gotten from Preferences,
|
||||
// which updates the DOM asynchronously, so we can't rely on the DOM. Get it directly
|
||||
// from the prefs.
|
||||
this._lastCheckState = Preferences.get("browser.privatebrowsing.autostart").value;
|
||||
},
|
||||
|
||||
_lastMode: null,
|
||||
|
|
|
@ -92,6 +92,7 @@ skip-if = os == 'win' && processor == "x86_64" && bits == 64 # bug 1522821
|
|||
[browser_telemetry.js]
|
||||
# Skip this test on Android as FHR and Telemetry are separate systems there.
|
||||
skip-if = !healthreport || !telemetry || (os == 'linux' && debug) || (os == 'android')
|
||||
[browser_warning_permanent_private_browsing.js]
|
||||
[browser_containers_name_input.js]
|
||||
run-if = nightly_build # Containers is enabled only on Nightly
|
||||
[browser_fluent.js]
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
function checkForPrompt(prefVal) {
|
||||
return async function() {
|
||||
await SpecialPowers.pushPrefEnv({set: [
|
||||
["privacy.history.custom", true],
|
||||
["browser.privatebrowsing.autostart", !prefVal],
|
||||
]});
|
||||
|
||||
await openPreferencesViaOpenPreferencesAPI("panePrivacy", { leaveOpen: true });
|
||||
let doc = gBrowser.contentDocument;
|
||||
is(doc.getElementById("historyMode").value, "custom", "Expect custom history mode");
|
||||
|
||||
// Stub out the prompt method as an easy way to check it was shown. We throw away
|
||||
// the tab straight after so don't need to bother restoring it.
|
||||
let promptFired = false;
|
||||
doc.defaultView.confirmRestartPrompt = () => {
|
||||
promptFired = true;
|
||||
return doc.defaultView.CONFIRM_RESTART_PROMPT_RESTART_NOW;
|
||||
};
|
||||
// Tick the checkbox and pretend the user did it:
|
||||
let checkbox = doc.getElementById("privateBrowsingAutoStart");
|
||||
checkbox.checked = prefVal;
|
||||
checkbox.doCommand();
|
||||
|
||||
// Now the prompt should have shown.
|
||||
ok(promptFired,
|
||||
`Expect a prompt when turning permanent private browsing ${prefVal ? "on" : "off"}!`);
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check we show the prompt if the permanent private browsing pref is false
|
||||
* and we flip the checkbox to true.
|
||||
*/
|
||||
add_task(checkForPrompt(true));
|
||||
|
||||
/**
|
||||
* Check it works in the other direction:
|
||||
*/
|
||||
add_task(checkForPrompt(false));
|
|
@ -69,7 +69,7 @@ class UrlbarView {
|
|||
* The currently selected result.
|
||||
*/
|
||||
get selectedResult() {
|
||||
if (!this.isOpen) {
|
||||
if (!this.isOpen || !this._selected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -279,13 +279,11 @@ inline bool BasePrincipal::FastEquals(nsIPrincipal* aOther) {
|
|||
// Two principals are considered to be equal if their origins are the same.
|
||||
// If the two principals are codebase principals, their origin attributes
|
||||
// (aka the origin suffix) must also match.
|
||||
// If the two principals are null principals, they're only equal if they're
|
||||
// the same object.
|
||||
if (Kind() == eNullPrincipal || Kind() == eSystemPrincipal) {
|
||||
if (Kind() == eSystemPrincipal) {
|
||||
return this == other;
|
||||
}
|
||||
|
||||
if (Kind() == eCodebasePrincipal) {
|
||||
if (Kind() == eCodebasePrincipal || Kind() == eNullPrincipal) {
|
||||
return mOriginNoSuffix == other->mOriginNoSuffix &&
|
||||
mOriginSuffix == other->mOriginSuffix;
|
||||
}
|
||||
|
@ -308,13 +306,6 @@ inline bool BasePrincipal::FastEqualsConsideringDomain(nsIPrincipal* aOther) {
|
|||
|
||||
inline bool BasePrincipal::FastSubsumes(nsIPrincipal* aOther) {
|
||||
// If two principals are equal, then they both subsume each other.
|
||||
// We deal with two special cases first:
|
||||
// Null principals only subsume each other if they are equal, and are only
|
||||
// equal if they're the same object.
|
||||
auto other = Cast(aOther);
|
||||
if (Kind() == eNullPrincipal && other->Kind() == eNullPrincipal) {
|
||||
return this == other;
|
||||
}
|
||||
if (FastEquals(aOther)) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -171,7 +171,9 @@ bool NullPrincipal::MayLoadInternal(nsIURI* aURI) {
|
|||
nsCOMPtr<nsIPrincipal> blobPrincipal;
|
||||
if (dom::BlobURLProtocolHandler::GetBlobURLPrincipal(
|
||||
aURI, getter_AddRefs(blobPrincipal))) {
|
||||
return blobPrincipal == this;
|
||||
MOZ_ASSERT(blobPrincipal);
|
||||
return SubsumesInternal(blobPrincipal,
|
||||
BasePrincipal::ConsiderDocumentDomain);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -87,7 +87,8 @@ class NullPrincipal final : public BasePrincipal {
|
|||
|
||||
bool SubsumesInternal(nsIPrincipal* aOther,
|
||||
DocumentDomainConsideration aConsideration) override {
|
||||
return aOther == this;
|
||||
MOZ_ASSERT(aOther);
|
||||
return FastEquals(aOther);
|
||||
}
|
||||
|
||||
bool MayLoadInternal(nsIURI* aURI) override;
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include "nsCRT.h"
|
||||
#include "nsIUUIDGenerator.h"
|
||||
|
||||
#include "mozilla/GkRustUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -27,18 +29,7 @@ NullPrincipalURI::NullPrincipalURI(const NullPrincipalURI& aOther) {
|
|||
}
|
||||
|
||||
nsresult NullPrincipalURI::Init() {
|
||||
// FIXME: bug 327161 -- make sure the uuid generator is reseeding-resistant.
|
||||
nsCOMPtr<nsIUUIDGenerator> uuidgen = services::GetUUIDGenerator();
|
||||
NS_ENSURE_TRUE(uuidgen, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
nsID id;
|
||||
nsresult rv = uuidgen->GenerateUUIDInPlace(&id);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mPath.SetLength(NSID_LENGTH - 1); // -1 because NSID_LENGTH counts the '\0'
|
||||
id.ToProvidedString(
|
||||
*reinterpret_cast<char(*)[NSID_LENGTH]>(mPath.BeginWriting()));
|
||||
|
||||
GkRustUtils::GenerateUUID(mPath);
|
||||
MOZ_ASSERT(mPath.Length() == NSID_LENGTH - 1);
|
||||
MOZ_ASSERT(strlen(mPath.get()) == NSID_LENGTH - 1);
|
||||
|
||||
|
|
|
@ -395,7 +395,7 @@ function addXULBrowserDecorations(browser) {
|
|||
if (browser.remoteType == undefined) {
|
||||
Object.defineProperty(browser, "remoteType", {
|
||||
get() {
|
||||
return this.getAttribute("remoteType");
|
||||
return this.messageManager.remoteType;
|
||||
},
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
|
|
|
@ -318,6 +318,10 @@ function tunnelToInnerBrowser(outer, inner) {
|
|||
// Reset @remote since this is now back to a regular, non-remote browser
|
||||
outer.setAttribute("remote", "false");
|
||||
outer.removeAttribute("remoteType");
|
||||
|
||||
// Stop forwarding remoteType to the inner browser
|
||||
delete outer.remoteType;
|
||||
|
||||
outer.construct();
|
||||
|
||||
// Delete browser window properties exposed on content's owner global
|
||||
|
@ -607,6 +611,10 @@ MessageManagerTunnel.prototype = {
|
|||
return this.innerParentMM.processMessageManager;
|
||||
},
|
||||
|
||||
get remoteType() {
|
||||
return this.innerParentMM.remoteType;
|
||||
},
|
||||
|
||||
loadFrameScript(url, ...args) {
|
||||
debug(`Calling loadFrameScript for ${url}`);
|
||||
|
||||
|
|
|
@ -158,7 +158,7 @@ class Browser extends PureComponent {
|
|||
mozbrowser: "true",
|
||||
noisolation: "true",
|
||||
remote: "true",
|
||||
remotetype: "web",
|
||||
remoteType: "web",
|
||||
src: "about:blank",
|
||||
usercontextid: userContextId,
|
||||
width: "100%",
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
"title": "Console",
|
||||
"environment": "development",
|
||||
"baseWorkerURL": "http://localhost:8000/public/build/",
|
||||
"defaultURL": "https://nchevobbe.github.io/demo/console-test-app.html",
|
||||
"host": "",
|
||||
"theme": "light",
|
||||
"dir": "ltr",
|
||||
"features": {
|
||||
},
|
||||
"logging": {
|
||||
"client": false,
|
||||
"firefoxProxy": false,
|
||||
"actions": false
|
||||
},
|
||||
"firefox": {
|
||||
"webSocketConnection": false,
|
||||
"host": "localhost",
|
||||
"webSocketPort": 8116,
|
||||
"tcpPort": 6080
|
||||
},
|
||||
"development": {
|
||||
"serverPort": 8000,
|
||||
"examplesPort": 7999
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ add_task(async function() {
|
|||
const jstermHistory = [
|
||||
`document`,
|
||||
`document
|
||||
.querySelectorAll("*")
|
||||
.querySelectorAll("span")
|
||||
.forEach(console.log)`,
|
||||
`Dog = "Snoopy"`,
|
||||
];
|
||||
|
|
|
@ -571,7 +571,7 @@ class ReactEventCollector extends MainEventCollector {
|
|||
if (props) {
|
||||
for (const [name, prop] of Object.entries(props)) {
|
||||
if (REACT_EVENT_NAMES.includes(name)) {
|
||||
const listener = prop.__reactBoundMethod || prop;
|
||||
const listener = prop && prop.__reactBoundMethod || prop;
|
||||
|
||||
if (typeof listener !== "function") {
|
||||
continue;
|
||||
|
@ -614,7 +614,7 @@ class ReactEventCollector extends MainEventCollector {
|
|||
if (value.memoizedProps) {
|
||||
return value.memoizedProps; // React 16
|
||||
}
|
||||
return value._currentElement.props; // React 15
|
||||
return value && value._currentElement && value._currentElement.props; // React 15
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -228,24 +228,6 @@ WebConsoleClient.prototype = {
|
|||
return this._client.request(packet);
|
||||
},
|
||||
|
||||
/**
|
||||
* Inspect the properties of an object.
|
||||
*
|
||||
* @param string actor
|
||||
* The WebConsoleObjectActor ID to send the request to.
|
||||
* @param function onResponse
|
||||
* The function invoked when the response is received.
|
||||
* @return request
|
||||
* Request object that implements both Promise and EventEmitter interfaces
|
||||
*/
|
||||
inspectObjectProperties: function(actor, onResponse) {
|
||||
const packet = {
|
||||
to: actor,
|
||||
type: "inspectProperties",
|
||||
};
|
||||
return this._client.request(packet, onResponse);
|
||||
},
|
||||
|
||||
/**
|
||||
* Evaluate a JavaScript expression.
|
||||
*
|
||||
|
|
|
@ -1079,22 +1079,6 @@ nsresult nsFrameLoader::SwapWithOtherRemoteLoader(
|
|||
return rv;
|
||||
}
|
||||
|
||||
// Swap the remoteType property as the frameloaders are being swapped
|
||||
nsAutoString ourRemoteType;
|
||||
if (!ourContent->GetAttr(kNameSpaceID_None, nsGkAtoms::RemoteType,
|
||||
ourRemoteType)) {
|
||||
ourRemoteType.AssignLiteral(DEFAULT_REMOTE_TYPE);
|
||||
}
|
||||
nsAutoString otherRemoteType;
|
||||
if (!otherContent->GetAttr(kNameSpaceID_None, nsGkAtoms::RemoteType,
|
||||
otherRemoteType)) {
|
||||
otherRemoteType.AssignLiteral(DEFAULT_REMOTE_TYPE);
|
||||
}
|
||||
ourContent->SetAttr(kNameSpaceID_None, nsGkAtoms::RemoteType, otherRemoteType,
|
||||
false);
|
||||
otherContent->SetAttr(kNameSpaceID_None, nsGkAtoms::RemoteType, ourRemoteType,
|
||||
false);
|
||||
|
||||
Unused << mRemoteBrowser->SendSwappedWithOtherRemoteLoader(
|
||||
ourContext.AsIPCTabContext());
|
||||
Unused << aOther->mRemoteBrowser->SendSwappedWithOtherRemoteLoader(
|
||||
|
|
|
@ -1171,8 +1171,14 @@ inline bool WrapNewBindingNonWrapperCachedObject(
|
|||
if (!JS_WrapObject(cx, &proto)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// cx and scope are same-compartment, but they might still be
|
||||
// different-Realm. Enter the Realm of scope, since that's
|
||||
// where we want to create our object.
|
||||
ar.emplace(cx, scope);
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(proto, js::IsObjectInContextCompartment(proto, cx));
|
||||
MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
|
||||
if (!value->WrapObject(cx, proto, &obj)) {
|
||||
return false;
|
||||
|
@ -1223,8 +1229,14 @@ inline bool WrapNewBindingNonWrapperCachedObject(
|
|||
if (!JS_WrapObject(cx, &proto)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// cx and scope are same-compartment, but they might still be
|
||||
// different-Realm. Enter the Realm of scope, since that's
|
||||
// where we want to create our object.
|
||||
ar.emplace(cx, scope);
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(proto, js::IsObjectInContextCompartment(proto, cx));
|
||||
MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
|
||||
if (!value->WrapObject(cx, proto, &obj)) {
|
||||
return false;
|
||||
|
|
|
@ -60,6 +60,10 @@ void ImageBitmapRenderingContext::TransferFromImageBitmap(
|
|||
return;
|
||||
}
|
||||
|
||||
if (aImageBitmap.IsWriteOnly() && mCanvasElement) {
|
||||
mCanvasElement->SetWriteOnly();
|
||||
}
|
||||
|
||||
Redraw(gfxRect(0, 0, mWidth, mHeight));
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ struct VideoFrameProperties
|
|||
{
|
||||
// Size of image data within the ShMem,
|
||||
// the ShMem is at least this large
|
||||
size_t bufferSize;
|
||||
uint32_t bufferSize;
|
||||
// From webrtc::VideoFrame
|
||||
uint32_t timeStamp;
|
||||
int64_t ntpTimeMs;
|
||||
|
|
|
@ -10,12 +10,14 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
size_t VideoFrameUtils::TotalRequiredBufferSize(
|
||||
uint32_t VideoFrameUtils::TotalRequiredBufferSize(
|
||||
const webrtc::VideoFrame& aVideoFrame) {
|
||||
auto i420 = aVideoFrame.video_frame_buffer()->ToI420();
|
||||
auto height = i420->height();
|
||||
return height * i420->StrideY() + ((height + 1) / 2) * i420->StrideU() +
|
||||
size_t size = height * i420->StrideY() + ((height + 1) / 2) * i420->StrideU() +
|
||||
((height + 1) / 2) * i420->StrideV();
|
||||
MOZ_RELEASE_ASSERT(size < std::numeric_limits<uint32_t>::max());
|
||||
return static_cast<uint32_t>(size);
|
||||
}
|
||||
|
||||
void VideoFrameUtils::InitFrameBufferProperties(
|
||||
|
|
|
@ -24,7 +24,7 @@ class VideoFrameUtils {
|
|||
public:
|
||||
// Returns the total number of bytes necessary to copy a VideoFrame's buffer
|
||||
// across all planes.
|
||||
static size_t TotalRequiredBufferSize(const webrtc::VideoFrame& frame);
|
||||
static uint32_t TotalRequiredBufferSize(const webrtc::VideoFrame& frame);
|
||||
|
||||
// Initializes a camera::VideoFrameProperties from a VideoFrameBuffer
|
||||
static void InitFrameBufferProperties(
|
||||
|
|
|
@ -443,7 +443,7 @@ nsresult MediaEngineWebRTCMicrophoneSource::Deallocate(
|
|||
const RefPtr<const AllocationHandle>&) {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
MOZ_ASSERT(mState == kStopped);
|
||||
MOZ_ASSERT(mState == kStopped || mState == kAllocated);
|
||||
|
||||
class EndTrackMessage : public ControlMessage {
|
||||
public:
|
||||
|
|
|
@ -98,7 +98,7 @@ union GfxVarValue
|
|||
|
||||
struct GfxVarUpdate
|
||||
{
|
||||
size_t index;
|
||||
uint32_t index;
|
||||
GfxVarValue value;
|
||||
};
|
||||
|
||||
|
|
|
@ -350,7 +350,7 @@ struct OpWindowOverlayChanged { };
|
|||
struct ShmemSection {
|
||||
Shmem shmem;
|
||||
uint32_t offset;
|
||||
size_t size;
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
struct CrossProcessSemaphoreDescriptor {
|
||||
|
|
|
@ -71,7 +71,7 @@ VertexInfo write_text_vertex(RectWithSize local_clip_rect,
|
|||
vec2 snap_bias) {
|
||||
// The offset to snap the glyph rect to a device pixel
|
||||
vec2 snap_offset = vec2(0.0);
|
||||
mat2 local_transform;
|
||||
mat2 local_transform = mat2(1.0);
|
||||
|
||||
#ifdef WR_FEATURE_GLYPH_TRANSFORM
|
||||
bool remove_subpx_offset = true;
|
||||
|
|
|
@ -214,4 +214,4 @@ To learn more about Fluent, follow the `Fluent for Firefox Developers`_ guide.
|
|||
.. _Pontoon: https://pontoon.mozilla.org/
|
||||
.. _hg.mozilla.org/l10n-central: https://hg.mozilla.org/l10n-central/
|
||||
.. _L10n Drivers Team: https://wiki.mozilla.org/L10n:Mozilla_Team
|
||||
.. _Fluent For Firefox Developers: ./l10n/docs/l10n/index.html
|
||||
.. _Fluent For Firefox Developers: ./l10n/l10n/fluent_tutorial.html
|
||||
|
|
|
@ -166,13 +166,23 @@ class L10nRegistryService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a source with the given known is already registered.
|
||||
*
|
||||
* @param {String} sourceName
|
||||
* @returns {boolean} whether or not a source by that name is known.
|
||||
*/
|
||||
hasSource(sourceName) {
|
||||
return this.sources.has(sourceName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new resource source to the L10nRegistry.
|
||||
*
|
||||
* @param {FileSource} source
|
||||
*/
|
||||
registerSource(source) {
|
||||
if (this.sources.has(source.name)) {
|
||||
if (this.hasSource(source.name)) {
|
||||
throw new Error(`Source with name "${source.name}" already registered.`);
|
||||
}
|
||||
this.sources.set(source.name, source);
|
||||
|
@ -192,7 +202,7 @@ class L10nRegistryService {
|
|||
* @param {FileSource} source
|
||||
*/
|
||||
updateSource(source) {
|
||||
if (!this.sources.has(source.name)) {
|
||||
if (!this.hasSource(source.name)) {
|
||||
throw new Error(`Source with name "${source.name}" is not registered.`);
|
||||
}
|
||||
this.sources.set(source.name, source);
|
||||
|
@ -233,7 +243,7 @@ class L10nRegistryService {
|
|||
_setSourcesFromSharedData() {
|
||||
let sources = Services.cpmm.sharedData.get("L10nRegistry:Sources");
|
||||
for (let [name, data] of sources.entries()) {
|
||||
if (!this.sources.has(name)) {
|
||||
if (!this.hasSource(name)) {
|
||||
const source = new FileSource(name, data.locales, data.prePath);
|
||||
this.registerSource(source);
|
||||
}
|
||||
|
|
|
@ -446,12 +446,12 @@ and the developer is not affected.
|
|||
__ https://unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html
|
||||
__ https://unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#bs
|
||||
|
||||
Partial Arguments
|
||||
-----------------
|
||||
Partially-formatted variables
|
||||
-----------------------------
|
||||
|
||||
When it comes to formatting data, Fluent allows the developer to provide
|
||||
a set of parameters for the formatter, and the localizer can fine tune some of them.
|
||||
This technique is called `partial arguments`__.
|
||||
This technique is called `partially-formatted variables`__.
|
||||
|
||||
For example, when formatting a date, the developer can just pass a JS :js:`Date` object,
|
||||
but its default formatting will be pretty expressive. In most cases, the developer
|
||||
|
@ -492,7 +492,7 @@ At the moment Fluent supports two formatters that match JS Intl API counterparts
|
|||
|
||||
With time more formatters will be added.
|
||||
|
||||
__ https://projectfluent.org/fluent/guide/functions.html#partial-arguments
|
||||
__ https://projectfluent.org/fluent/guide/functions.html#partially-formatted-variables
|
||||
__ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat
|
||||
__ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
|
||||
|
||||
|
|
|
@ -450,3 +450,12 @@ add_task(async function test_parallel_io() {
|
|||
L10nRegistry.sources.clear();
|
||||
L10nRegistry.load = originalLoad;
|
||||
});
|
||||
|
||||
add_task(async function test_hasSource() {
|
||||
equal(L10nRegistry.hasSource("gobbledygook"), false, "Non-existing source doesn't exist");
|
||||
equal(L10nRegistry.hasSource("app"), false, "hasSource returns true before registering a source");
|
||||
let oneSource = new FileSource("app", ["en-US"], "/{locale}/");
|
||||
L10nRegistry.registerSource(oneSource);
|
||||
equal(L10nRegistry.hasSource("app"), true, "hasSource returns true after registering a source");
|
||||
L10nRegistry.sources.clear();
|
||||
});
|
||||
|
|
|
@ -270,26 +270,6 @@ bool Pickle::ReadLength(PickleIterator* iter, int* result) const {
|
|||
return ((*result) >= 0);
|
||||
}
|
||||
|
||||
// Always written as a 64-bit value since the size for this type can
|
||||
// differ between architectures.
|
||||
bool Pickle::ReadSize(PickleIterator* iter, size_t* result) const {
|
||||
DCHECK(iter);
|
||||
|
||||
uint64_t big_result = 0;
|
||||
if (IteratorHasRoomFor(*iter, sizeof(big_result))) {
|
||||
iter->CopyInto(&big_result);
|
||||
UpdateIter(iter, sizeof(big_result));
|
||||
} else {
|
||||
if (!ReadBytesInto(iter, &big_result, sizeof(big_result))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
DCHECK(big_result <= std::numeric_limits<size_t>::max());
|
||||
*result = static_cast<size_t>(big_result);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Pickle::ReadInt32(PickleIterator* iter, int32_t* result) const {
|
||||
DCHECK(iter);
|
||||
|
||||
|
@ -581,15 +561,6 @@ bool Pickle::WriteULong(unsigned long value) {
|
|||
return WriteUInt64(uint64_t(value));
|
||||
}
|
||||
|
||||
bool Pickle::WriteSize(size_t value) {
|
||||
// Always written as a 64-bit value since the size for this type can
|
||||
// differ between architectures.
|
||||
#ifdef FUZZING
|
||||
mozilla::ipc::Faulty::instance().FuzzSize(&value);
|
||||
#endif
|
||||
return WriteUInt64(uint64_t(value));
|
||||
}
|
||||
|
||||
bool Pickle::WriteInt32(int32_t value) {
|
||||
#ifdef FUZZING
|
||||
mozilla::ipc::Faulty::instance().FuzzInt(&value);
|
||||
|
|
|
@ -100,7 +100,6 @@ class Pickle {
|
|||
MOZ_MUST_USE bool ReadLong(PickleIterator* iter, long* result) const;
|
||||
MOZ_MUST_USE bool ReadULong(PickleIterator* iter,
|
||||
unsigned long* result) const;
|
||||
MOZ_MUST_USE bool ReadSize(PickleIterator* iter, size_t* result) const;
|
||||
MOZ_MUST_USE bool ReadInt32(PickleIterator* iter, int32_t* result) const;
|
||||
MOZ_MUST_USE bool ReadUInt32(PickleIterator* iter, uint32_t* result) const;
|
||||
MOZ_MUST_USE bool ReadInt64(PickleIterator* iter, int64_t* result) const;
|
||||
|
@ -162,7 +161,6 @@ class Pickle {
|
|||
bool WriteInt(int value);
|
||||
bool WriteLong(long value);
|
||||
bool WriteULong(unsigned long value);
|
||||
bool WriteSize(size_t value);
|
||||
bool WriteInt32(int32_t value);
|
||||
bool WriteUInt32(uint32_t value);
|
||||
bool WriteInt64(int64_t value);
|
||||
|
|
|
@ -311,27 +311,10 @@ struct ParamTraitsFixed<uint64_t> {
|
|||
}
|
||||
};
|
||||
|
||||
// Other standard C types.
|
||||
|
||||
template <class P>
|
||||
struct ParamTraitsLibC : ParamTraitsFixed<P> {};
|
||||
|
||||
template <>
|
||||
struct ParamTraitsLibC<size_t> {
|
||||
typedef size_t param_type;
|
||||
static void Write(Message* m, const param_type& p) { m->WriteSize(p); }
|
||||
static bool Read(const Message* m, PickleIterator* iter, param_type* r) {
|
||||
return m->ReadSize(iter, r);
|
||||
}
|
||||
static void Log(const param_type& p, std::wstring* l) {
|
||||
l->append(StringPrintf(L"%u", p));
|
||||
}
|
||||
};
|
||||
|
||||
// std::* types.
|
||||
|
||||
template <class P>
|
||||
struct ParamTraitsStd : ParamTraitsLibC<P> {};
|
||||
struct ParamTraitsStd : ParamTraitsFixed<P> {};
|
||||
|
||||
template <>
|
||||
struct ParamTraitsStd<std::string> {
|
||||
|
|
|
@ -28,9 +28,7 @@ Types = (
|
|||
'intptr_t',
|
||||
'uintptr_t',
|
||||
|
||||
# stddef types
|
||||
'size_t',
|
||||
'ssize_t',
|
||||
# You may be tempted to add size_t. Do not! See bug 1525199.
|
||||
|
||||
# Mozilla types: "less" standard things we know how serialize/deserialize
|
||||
'nsresult',
|
||||
|
|
|
@ -132,7 +132,7 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext* cx, bool match_only)
|
|||
masm.Str(PseudoStackPointer64, vixl::MemOperand(sp, -16, vixl::PreIndex));
|
||||
|
||||
// Initialize the PSP from the SP.
|
||||
masm.initStackPtr();
|
||||
masm.initPseudoStackPtr();
|
||||
#endif
|
||||
|
||||
// Push non-volatile registers which might be modified by jitcode.
|
||||
|
|
|
@ -1500,6 +1500,12 @@ static Value FromSymbolPayload(uintptr_t payload) {
|
|||
return SymbolValue(reinterpret_cast<JS::Symbol*>(payload));
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
static Value FromBigIntPayload(uintptr_t payload) {
|
||||
return BigIntValue(reinterpret_cast<JS::BigInt*>(payload));
|
||||
}
|
||||
#endif
|
||||
|
||||
static Value FromTypedPayload(JSValueType type, uintptr_t payload) {
|
||||
switch (type) {
|
||||
case JSVAL_TYPE_INT32:
|
||||
|
@ -1510,6 +1516,10 @@ static Value FromTypedPayload(JSValueType type, uintptr_t payload) {
|
|||
return FromStringPayload(payload);
|
||||
case JSVAL_TYPE_SYMBOL:
|
||||
return FromSymbolPayload(payload);
|
||||
#ifdef ENABLE_BIGINT
|
||||
case JSVAL_TYPE_BIGINT:
|
||||
return FromBigIntPayload(payload);
|
||||
#endif
|
||||
case JSVAL_TYPE_OBJECT:
|
||||
return FromObjectPayload(payload);
|
||||
default:
|
||||
|
@ -1606,6 +1616,10 @@ Value SnapshotIterator::allocationValue(const RValueAllocation& alloc,
|
|||
return FromStringPayload(fromStack(alloc.stackOffset2()));
|
||||
case JSVAL_TYPE_SYMBOL:
|
||||
return FromSymbolPayload(fromStack(alloc.stackOffset2()));
|
||||
#ifdef ENABLE_BIGINT
|
||||
case JSVAL_TYPE_BIGINT:
|
||||
return FromBigIntPayload(fromStack(alloc.stackOffset2()));
|
||||
#endif
|
||||
case JSVAL_TYPE_OBJECT:
|
||||
return FromObjectPayload(fromStack(alloc.stackOffset2()));
|
||||
default:
|
||||
|
@ -1727,6 +1741,9 @@ void SnapshotIterator::writeAllocationValuePayload(
|
|||
break;
|
||||
case JSVAL_TYPE_STRING:
|
||||
case JSVAL_TYPE_SYMBOL:
|
||||
#ifdef ENABLE_BIGINT
|
||||
case JSVAL_TYPE_BIGINT:
|
||||
#endif
|
||||
case JSVAL_TYPE_OBJECT:
|
||||
WriteFrameSlot(fp_, alloc.stackOffset2(), uintptr_t(v.toGCThing()));
|
||||
break;
|
||||
|
|
|
@ -256,7 +256,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
|
|||
Mov(vixl::sp, GetStackPointer64());
|
||||
}
|
||||
}
|
||||
void initStackPtr() {
|
||||
void initPseudoStackPtr() {
|
||||
if (!GetStackPointer64().Is(vixl::sp)) {
|
||||
Mov(GetStackPointer64(), vixl::sp);
|
||||
}
|
||||
|
|
|
@ -649,9 +649,7 @@ bool JitRuntime::generateVMWrapper(JSContext* cx, MacroAssembler& masm,
|
|||
}
|
||||
|
||||
// SP is used to transfer stack across call boundaries.
|
||||
if (!masm.GetStackPointer64().Is(vixl::sp)) {
|
||||
masm.Mov(masm.GetStackPointer64(), vixl::sp);
|
||||
}
|
||||
masm.initPseudoStackPtr();
|
||||
|
||||
// Test for failure.
|
||||
switch (f.failType()) {
|
||||
|
|
|
@ -68,6 +68,7 @@ BEGIN_TEST(testJitRValueAlloc_TypedReg) {
|
|||
/* _(JSVAL_TYPE_MAGIC) */ \
|
||||
_(JSVAL_TYPE_STRING) \
|
||||
_(JSVAL_TYPE_SYMBOL) \
|
||||
IF_BIGINT(_(JSVAL_TYPE_BIGINT),) \
|
||||
/* _(JSVAL_TYPE_NULL) */ \
|
||||
_(JSVAL_TYPE_OBJECT)
|
||||
|
||||
|
@ -95,6 +96,7 @@ BEGIN_TEST(testJitRValueAlloc_TypedStack) {
|
|||
/* _(JSVAL_TYPE_MAGIC) */ \
|
||||
_(JSVAL_TYPE_STRING) \
|
||||
_(JSVAL_TYPE_SYMBOL) \
|
||||
IF_BIGINT(_(JSVAL_TYPE_BIGINT),) \
|
||||
/* _(JSVAL_TYPE_NULL) */ \
|
||||
_(JSVAL_TYPE_OBJECT)
|
||||
|
||||
|
|
|
@ -620,7 +620,7 @@ bool LCovRuntime::fillWithFilename(char* name, size_t length) {
|
|||
int len = snprintf(name, length, "%s/%" PRId64 "-%" PRIu32 "-%zu.info",
|
||||
outDir, timestamp, pid_, rid);
|
||||
if (len < 0 || size_t(len) >= length) {
|
||||
fprintf(stderr, "Warning: LCovRuntime::init: Cannot serialize file name.");
|
||||
fprintf(stderr, "Warning: LCovRuntime::init: Cannot serialize file name.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -635,7 +635,7 @@ void LCovRuntime::init() {
|
|||
|
||||
// If we cannot open the file, report a warning.
|
||||
if (!out_.init(name)) {
|
||||
fprintf(stderr, "Warning: LCovRuntime::init: Cannot open file named '%s'.",
|
||||
fprintf(stderr, "Warning: LCovRuntime::init: Cannot open file named '%s'.\n",
|
||||
name);
|
||||
}
|
||||
isEmpty_ = true;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -131,11 +131,14 @@ enum JSTryNoteKind {
|
|||
* Exception handling record.
|
||||
*/
|
||||
struct JSTryNote {
|
||||
uint8_t kind; /* one of JSTryNoteKind */
|
||||
uint32_t kind; /* one of JSTryNoteKind */
|
||||
uint32_t stackDepth; /* stack depth upon exception handler entry */
|
||||
uint32_t start; /* start of the try statement or loop relative
|
||||
to script->code() */
|
||||
uint32_t length; /* length of the try statement or loop */
|
||||
|
||||
template <js::XDRMode mode>
|
||||
js::XDRResult XDR(js::XDRState<mode>* xdr);
|
||||
};
|
||||
|
||||
namespace js {
|
||||
|
@ -167,6 +170,9 @@ struct ScopeNote {
|
|||
// relative to script->code().
|
||||
uint32_t length; // Bytecode length of scope.
|
||||
uint32_t parent; // Index of parent block scope in notes, or NoScopeNote.
|
||||
|
||||
template <js::XDRMode mode>
|
||||
js::XDRResult XDR(js::XDRState<mode>* xdr);
|
||||
};
|
||||
|
||||
class ScriptCounts {
|
||||
|
@ -452,6 +458,8 @@ struct SourceTypeTraits<char16_t> {
|
|||
}
|
||||
};
|
||||
|
||||
class ScriptSourceHolder;
|
||||
|
||||
class ScriptSource {
|
||||
friend class SourceCompressionTask;
|
||||
|
||||
|
@ -1003,11 +1011,6 @@ class ScriptSource {
|
|||
|
||||
void setCompressedSourceFromTask(SharedImmutableString compressed);
|
||||
|
||||
public:
|
||||
// XDR handling
|
||||
template <XDRMode mode>
|
||||
MOZ_MUST_USE XDRResult performXDR(XDRState<mode>* xdr);
|
||||
|
||||
private:
|
||||
// It'd be better to make this function take <XDRMode, Unit>, as both
|
||||
// specializations of this function contain nested Unit-parametrized
|
||||
|
@ -1095,6 +1098,11 @@ class ScriptSource {
|
|||
parseEnded_ = ReallyNow();
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
static MOZ_MUST_USE XDRResult
|
||||
XDR(XDRState<mode>* xdr, const mozilla::Maybe<JS::CompileOptions>& options,
|
||||
MutableHandle<ScriptSourceHolder> ss);
|
||||
|
||||
void trace(JSTracer* trc);
|
||||
};
|
||||
|
||||
|
@ -1120,6 +1128,8 @@ class ScriptSourceHolder {
|
|||
ss = newss;
|
||||
}
|
||||
ScriptSource* get() const { return ss; }
|
||||
|
||||
void trace(JSTracer* trc) { ss->trace(trc); }
|
||||
};
|
||||
|
||||
// [SMDOC] ScriptSourceObject
|
||||
|
@ -1409,6 +1419,13 @@ class alignas(JS::Value) PrivateScriptData final {
|
|||
uint32_t ntrynotes, uint32_t nscopenotes,
|
||||
uint32_t nresumeoffsets, uint32_t* dataSize);
|
||||
|
||||
template <XDRMode mode>
|
||||
static MOZ_MUST_USE XDRResult XDR(js::XDRState<mode>* xdr,
|
||||
js::HandleScript script,
|
||||
js::HandleScriptSourceObject sourceObject,
|
||||
js::HandleScope scriptEnclosingScope,
|
||||
js::HandleFunction fun);
|
||||
|
||||
void traceChildren(JSTracer* trc);
|
||||
};
|
||||
|
||||
|
@ -1478,6 +1495,10 @@ class SharedScriptData {
|
|||
return offsetof(SharedScriptData, natoms_);
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
static MOZ_MUST_USE XDRResult XDR(js::XDRState<mode>* xdr,
|
||||
js::HandleScript script);
|
||||
|
||||
private:
|
||||
SharedScriptData() = delete;
|
||||
SharedScriptData(const SharedScriptData&) = delete;
|
||||
|
@ -1805,6 +1826,16 @@ class JSScript : public js::gc::TenuredCell {
|
|||
js::HandleFunction fun,
|
||||
js::MutableHandleScript scriptp);
|
||||
|
||||
template <js::XDRMode mode>
|
||||
friend js::XDRResult js::SharedScriptData::XDR(js::XDRState<mode>* xdr,
|
||||
js::HandleScript script);
|
||||
|
||||
template <js::XDRMode mode>
|
||||
friend js::XDRResult js::PrivateScriptData::XDR(
|
||||
js::XDRState<mode>* xdr, js::HandleScript script,
|
||||
js::HandleScriptSourceObject sourceObject,
|
||||
js::HandleScope scriptEnclosingScope, js::HandleFunction fun);
|
||||
|
||||
friend bool js::detail::CopyScript(
|
||||
JSContext* cx, js::HandleScript src, js::HandleScript dst,
|
||||
js::MutableHandle<JS::GCVector<js::Scope*>> scopes);
|
||||
|
|
|
@ -1020,6 +1020,32 @@ template
|
|||
return static_cast<WithScope*>(scope);
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
/* static */ XDRResult WithScope::XDR(XDRState<mode>* xdr,
|
||||
HandleScope enclosing,
|
||||
MutableHandleScope scope) {
|
||||
JSContext* cx = xdr->cx();
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
scope.set(create(cx, enclosing));
|
||||
if (!scope) {
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template
|
||||
/* static */ XDRResult
|
||||
WithScope::XDR(XDRState<XDR_ENCODE>* xdr, HandleScope enclosing,
|
||||
MutableHandleScope scope);
|
||||
|
||||
template
|
||||
/* static */ XDRResult
|
||||
WithScope::XDR(XDRState<XDR_DECODE>* xdr, HandleScope enclosing,
|
||||
MutableHandleScope scope);
|
||||
|
||||
static const uint32_t EvalScopeEnvShapeFlags =
|
||||
BaseShape::QUALIFIED_VAROBJ | BaseShape::DELEGATE;
|
||||
|
||||
|
|
|
@ -773,6 +773,10 @@ class WithScope : public Scope {
|
|||
|
||||
public:
|
||||
static WithScope* create(JSContext* cx, HandleScope enclosing);
|
||||
|
||||
template <XDRMode mode>
|
||||
static XDRResult XDR(XDRState<mode>* xdr, HandleScope enclosing,
|
||||
MutableHandleScope scope);
|
||||
};
|
||||
|
||||
//
|
||||
|
|
|
@ -110,7 +110,7 @@ static const uintptr_t CLEAR_CONSTRUCTOR_CODE_TOKEN = 0x1;
|
|||
masm.Str(PseudoStackPointer64, vixl::MemOperand(sp, -16, vixl::PreIndex));
|
||||
|
||||
// Initialize the PSP from the SP.
|
||||
masm.initStackPtr();
|
||||
masm.initPseudoStackPtr();
|
||||
#endif
|
||||
|
||||
MOZ_ASSERT(propertiesReg.volatile_());
|
||||
|
|
|
@ -464,9 +464,10 @@ class XDRState : public XDRCoderBase {
|
|||
return fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
memcpy(ptr, *sp, len);
|
||||
MOZ_ASSERT(ptr[len-1] == '\0');
|
||||
} else {
|
||||
const uint8_t* ptr = buf.read(len);
|
||||
if (!ptr || ptr[len] != '\0') {
|
||||
if (!ptr || ptr[len-1] != '\0') {
|
||||
return fail(JS::TranscodeResult_Failure_BadDecode);
|
||||
}
|
||||
*sp = reinterpret_cast<const char*>(ptr);
|
||||
|
|
|
@ -1099,6 +1099,12 @@ void wasm::GenerateDirectCallFromJit(MacroAssembler& masm, const FuncExport& fe,
|
|||
masm.callJit(ImmPtr(callee));
|
||||
masm.assertStackAlignment(WasmStackAlignment);
|
||||
|
||||
#ifdef JS_CODEGEN_ARM64
|
||||
// WASM does not use the emulated stack pointer, so reinitialize it as it
|
||||
// might be clobbered either by WASM or by any C++ calls within.
|
||||
masm.initPseudoStackPtr();
|
||||
#endif
|
||||
|
||||
masm.branchPtr(Assembler::Equal, FramePointer, Imm32(wasm::FailFP),
|
||||
masm.exceptionLabel());
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@ import subprocess
|
|||
|
||||
CARGO_LOCK = mozpath.join(buildconfig.topsrcdir, "Cargo.lock")
|
||||
|
||||
# cbindgen_crate_path needs to match the crate name
|
||||
# EG: /xpcom/rust/gkrust_utils is the path for the "gkrust_utils" crate
|
||||
def generate(output, cbindgen_crate_path, *in_tree_dependencies):
|
||||
env = os.environ.copy()
|
||||
env['CARGO'] = str(buildconfig.substs['CARGO'])
|
||||
|
|
|
@ -329,8 +329,9 @@ void nsFontFaceLoader::Cancel() {
|
|||
mLoadTimer->Cancel();
|
||||
mLoadTimer = nullptr;
|
||||
}
|
||||
nsCOMPtr<nsIChannel> channel = mChannel.forget();
|
||||
channel->Cancel(NS_BINDING_ABORTED);
|
||||
if (nsCOMPtr<nsIChannel> channel = mChannel.forget()) {
|
||||
channel->Cancel(NS_BINDING_ABORTED);
|
||||
}
|
||||
}
|
||||
|
||||
StyleFontDisplay nsFontFaceLoader::GetFontDisplay() {
|
||||
|
|
|
@ -2993,9 +2993,10 @@ RefPtr<RTCStatsQueryPromise> PeerConnectionImpl::ExecuteStatsQuery_s(
|
|||
transportId = query->transportId;
|
||||
}
|
||||
auto report = std::move(query->report);
|
||||
auto now = query->now;
|
||||
|
||||
return aTransportHandler
|
||||
->GetIceStats(transportId, query->now, std::move(report))
|
||||
->GetIceStats(transportId, now, std::move(report))
|
||||
->Then(
|
||||
GetMainThreadSerialEventTarget(), __func__,
|
||||
[query = std::move(query)](
|
||||
|
|
|
@ -1458,7 +1458,7 @@ pref("javascript.options.strict", false);
|
|||
#ifdef DEBUG
|
||||
pref("javascript.options.strict.debug", false);
|
||||
#endif
|
||||
pref("javascript.options.unboxed_objects", true);
|
||||
pref("javascript.options.unboxed_objects", false);
|
||||
pref("javascript.options.baselinejit", true);
|
||||
//Duplicated in JitOptions - ensure both match.
|
||||
pref("javascript.options.baselinejit.threshold", 10);
|
||||
|
|
|
@ -728,25 +728,22 @@ inline nsresult NS_GetInnermostURIHost(nsIURI *aURI, nsACString &aHost) {
|
|||
// This block is optimized in order to avoid the overhead of calling
|
||||
// NS_GetInnermostURI() which incurs a lot of overhead in terms of
|
||||
// AddRef/Release calls.
|
||||
nsINestedURI *nestedURI = nullptr;
|
||||
nsresult rv = CallQueryInterface(aURI, &nestedURI);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(aURI);
|
||||
if (nestedURI) {
|
||||
// We have a nested URI!
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = nestedURI->GetInnermostURI(getter_AddRefs(uri));
|
||||
nsresult rv = nestedURI->GetInnermostURI(getter_AddRefs(uri));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_RELEASE(nestedURI);
|
||||
|
||||
rv = uri->GetAsciiHost(aHost);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
// We have a non-nested URI!
|
||||
rv = aURI->GetAsciiHost(aHost);
|
||||
nsresult rv = aURI->GetAsciiHost(aHost);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -1171,4 +1171,4 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
|
|||
|
||||
static const int32_t kUnknownId = -1;
|
||||
|
||||
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1558009037934000);
|
||||
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1558354645894000);
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -14,7 +14,7 @@ use crate::media_queries::Device;
|
|||
use crate::values::computed::basic_shape::ShapeRadius as ComputedShapeRadius;
|
||||
use crate::values::computed::FlexBasis as ComputedFlexBasis;
|
||||
use crate::values::computed::{Angle, ExtremumLength, Length, LengthPercentage};
|
||||
use crate::values::computed::{MaxLength as ComputedMaxLength, MozLength as ComputedMozLength};
|
||||
use crate::values::computed::{MaxSize as ComputedMaxSize, Size as ComputedSize};
|
||||
use crate::values::computed::{NonNegativeLengthPercentage, Percentage};
|
||||
use crate::values::computed::{Number, NumberOrPercentage};
|
||||
use crate::values::generics::basic_shape::ShapeRadius;
|
||||
|
@ -22,7 +22,7 @@ use crate::values::generics::box_::Perspective;
|
|||
use crate::values::generics::flex::FlexBasis;
|
||||
use crate::values::generics::gecko::ScrollSnapPoint;
|
||||
use crate::values::generics::grid::{TrackBreadth, TrackKeyword};
|
||||
use crate::values::generics::length::{LengthPercentageOrAuto, MaxLength, MozLength};
|
||||
use crate::values::generics::length::{LengthPercentageOrAuto, MaxSize, Size};
|
||||
use crate::values::generics::{CounterStyleOrNone, NonNegative};
|
||||
use crate::values::{Auto, Either, None_, Normal};
|
||||
use crate::Atom;
|
||||
|
@ -91,7 +91,7 @@ impl GeckoStyleCoordConvertible for ComputedFlexBasis {
|
|||
}
|
||||
|
||||
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
||||
if let Some(width) = ComputedMozLength::from_gecko_style_coord(coord) {
|
||||
if let Some(width) = ComputedSize::from_gecko_style_coord(coord) {
|
||||
return Some(FlexBasis::Width(width));
|
||||
}
|
||||
|
||||
|
@ -350,43 +350,43 @@ impl GeckoStyleCoordConvertible for ExtremumLength {
|
|||
}
|
||||
}
|
||||
|
||||
impl GeckoStyleCoordConvertible for ComputedMozLength {
|
||||
impl GeckoStyleCoordConvertible for ComputedSize {
|
||||
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
||||
match *self {
|
||||
MozLength::LengthPercentage(ref lpoa) => lpoa.to_gecko_style_coord(coord),
|
||||
MozLength::Auto => coord.set_value(CoordDataValue::Auto),
|
||||
MozLength::ExtremumLength(ref e) => e.to_gecko_style_coord(coord),
|
||||
Size::LengthPercentage(ref lpoa) => lpoa.to_gecko_style_coord(coord),
|
||||
Size::Auto => coord.set_value(CoordDataValue::Auto),
|
||||
Size::ExtremumLength(ref e) => e.to_gecko_style_coord(coord),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
||||
if let CoordDataValue::Auto = coord.as_value() {
|
||||
return Some(MozLength::Auto);
|
||||
return Some(Size::Auto);
|
||||
}
|
||||
if let Some(lp) = NonNegativeLengthPercentage::from_gecko_style_coord(coord) {
|
||||
return Some(MozLength::LengthPercentage(lp));
|
||||
return Some(Size::LengthPercentage(lp));
|
||||
}
|
||||
ExtremumLength::from_gecko_style_coord(coord).map(MozLength::ExtremumLength)
|
||||
ExtremumLength::from_gecko_style_coord(coord).map(Size::ExtremumLength)
|
||||
}
|
||||
}
|
||||
|
||||
impl GeckoStyleCoordConvertible for ComputedMaxLength {
|
||||
impl GeckoStyleCoordConvertible for ComputedMaxSize {
|
||||
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
||||
match *self {
|
||||
MaxLength::LengthPercentage(ref lpon) => lpon.to_gecko_style_coord(coord),
|
||||
MaxLength::None => coord.set_value(CoordDataValue::None),
|
||||
MaxLength::ExtremumLength(ref e) => e.to_gecko_style_coord(coord),
|
||||
MaxSize::LengthPercentage(ref lpon) => lpon.to_gecko_style_coord(coord),
|
||||
MaxSize::None => coord.set_value(CoordDataValue::None),
|
||||
MaxSize::ExtremumLength(ref e) => e.to_gecko_style_coord(coord),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
|
||||
if let CoordDataValue::None = coord.as_value() {
|
||||
return Some(MaxLength::None);
|
||||
return Some(MaxSize::None);
|
||||
}
|
||||
if let Some(lp) = NonNegativeLengthPercentage::from_gecko_style_coord(coord) {
|
||||
return Some(MaxLength::LengthPercentage(lp));
|
||||
return Some(MaxSize::LengthPercentage(lp));
|
||||
}
|
||||
ExtremumLength::from_gecko_style_coord(coord).map(MaxLength::ExtremumLength)
|
||||
ExtremumLength::from_gecko_style_coord(coord).map(MaxSize::ExtremumLength)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1390,8 +1390,8 @@ impl Clone for ${style_struct.gecko_struct_name} {
|
|||
"LengthOrNormal": impl_style_coord,
|
||||
"LengthPercentage": impl_simple,
|
||||
"LengthPercentageOrAuto": impl_style_coord,
|
||||
"MaxLength": impl_style_coord,
|
||||
"MozLength": impl_style_coord,
|
||||
"MaxSize": impl_style_coord,
|
||||
"Size": impl_style_coord,
|
||||
"MozScriptMinSize": impl_absolute_length,
|
||||
"MozScriptSizeMultiplier": impl_simple,
|
||||
"NonNegativeLengthPercentage": impl_simple,
|
||||
|
|
|
@ -244,65 +244,40 @@ ${helpers.predefined_type(
|
|||
if logical:
|
||||
spec = "https://drafts.csswg.org/css-logical-props/#propdef-%s"
|
||||
%>
|
||||
% if product == "gecko":
|
||||
// width, height, block-size, inline-size
|
||||
${helpers.predefined_type(
|
||||
size,
|
||||
"MozLength",
|
||||
"computed::MozLength::auto()",
|
||||
logical=logical,
|
||||
logical_group="size",
|
||||
allow_quirks=not logical,
|
||||
spec=spec % size,
|
||||
animation_value_type="MozLength",
|
||||
flags="GETCS_NEEDS_LAYOUT_FLUSH",
|
||||
servo_restyle_damage="reflow",
|
||||
)}
|
||||
// min-width, min-height, min-block-size, min-inline-size,
|
||||
${helpers.predefined_type(
|
||||
"min-%s" % size,
|
||||
"MozLength",
|
||||
"computed::MozLength::auto()",
|
||||
logical=logical,
|
||||
logical_group="min-size",
|
||||
allow_quirks=not logical,
|
||||
spec=spec % size,
|
||||
animation_value_type="MozLength",
|
||||
servo_restyle_damage="reflow",
|
||||
)}
|
||||
% else:
|
||||
// servo versions (no keyword support)
|
||||
${helpers.predefined_type(
|
||||
size,
|
||||
"NonNegativeLengthPercentageOrAuto",
|
||||
"computed::NonNegativeLengthPercentageOrAuto::auto()",
|
||||
spec=spec % size,
|
||||
logical_group="size",
|
||||
allow_quirks=not logical,
|
||||
animation_value_type="ComputedValue", logical = logical,
|
||||
servo_restyle_damage="reflow",
|
||||
)}
|
||||
${helpers.predefined_type(
|
||||
"min-%s" % size,
|
||||
"NonNegativeLengthPercentage",
|
||||
"computed::NonNegativeLengthPercentage::zero()",
|
||||
spec=spec % ("min-%s" % size),
|
||||
logical_group="min-size",
|
||||
animation_value_type="ComputedValue",
|
||||
logical=logical,
|
||||
allow_quirks=not logical,
|
||||
servo_restyle_damage="reflow",
|
||||
)}
|
||||
% endif
|
||||
// width, height, block-size, inline-size
|
||||
${helpers.predefined_type(
|
||||
size,
|
||||
"Size",
|
||||
"computed::Size::auto()",
|
||||
logical=logical,
|
||||
logical_group="size",
|
||||
allow_quirks=not logical,
|
||||
spec=spec % size,
|
||||
animation_value_type="Size",
|
||||
flags="GETCS_NEEDS_LAYOUT_FLUSH",
|
||||
servo_restyle_damage="reflow",
|
||||
)}
|
||||
// min-width, min-height, min-block-size, min-inline-size
|
||||
${helpers.predefined_type(
|
||||
"min-%s" % size,
|
||||
"Size",
|
||||
"computed::Size::auto()",
|
||||
logical=logical,
|
||||
logical_group="min-size",
|
||||
allow_quirks=not logical,
|
||||
spec=spec % size,
|
||||
animation_value_type="Size",
|
||||
servo_restyle_damage="reflow",
|
||||
)}
|
||||
${helpers.predefined_type(
|
||||
"max-%s" % size,
|
||||
"MaxLength",
|
||||
"computed::MaxLength::none()",
|
||||
"MaxSize",
|
||||
"computed::MaxSize::none()",
|
||||
logical=logical,
|
||||
logical_group="max-size",
|
||||
allow_quirks=not logical,
|
||||
spec=spec % size,
|
||||
animation_value_type="MaxLength",
|
||||
animation_value_type="MaxSize",
|
||||
servo_restyle_damage="reflow",
|
||||
)}
|
||||
% endfor
|
||||
|
|
|
@ -3016,7 +3016,7 @@ impl ComputedValuesInner {
|
|||
|
||||
/// Get the logical computed inline size.
|
||||
#[inline]
|
||||
pub fn content_inline_size(&self) -> computed::NonNegativeLengthPercentageOrAuto {
|
||||
pub fn content_inline_size(&self) -> computed::Size {
|
||||
let position_style = self.get_position();
|
||||
if self.writing_mode.is_vertical() {
|
||||
position_style.height
|
||||
|
@ -3027,35 +3027,35 @@ impl ComputedValuesInner {
|
|||
|
||||
/// Get the logical computed block size.
|
||||
#[inline]
|
||||
pub fn content_block_size(&self) -> computed::NonNegativeLengthPercentageOrAuto {
|
||||
pub fn content_block_size(&self) -> computed::Size {
|
||||
let position_style = self.get_position();
|
||||
if self.writing_mode.is_vertical() { position_style.width } else { position_style.height }
|
||||
}
|
||||
|
||||
/// Get the logical computed min inline size.
|
||||
#[inline]
|
||||
pub fn min_inline_size(&self) -> computed::NonNegativeLengthPercentage {
|
||||
pub fn min_inline_size(&self) -> computed::Size {
|
||||
let position_style = self.get_position();
|
||||
if self.writing_mode.is_vertical() { position_style.min_height } else { position_style.min_width }
|
||||
}
|
||||
|
||||
/// Get the logical computed min block size.
|
||||
#[inline]
|
||||
pub fn min_block_size(&self) -> computed::NonNegativeLengthPercentage {
|
||||
pub fn min_block_size(&self) -> computed::Size {
|
||||
let position_style = self.get_position();
|
||||
if self.writing_mode.is_vertical() { position_style.min_width } else { position_style.min_height }
|
||||
}
|
||||
|
||||
/// Get the logical computed max inline size.
|
||||
#[inline]
|
||||
pub fn max_inline_size(&self) -> computed::MaxLength {
|
||||
pub fn max_inline_size(&self) -> computed::MaxSize {
|
||||
let position_style = self.get_position();
|
||||
if self.writing_mode.is_vertical() { position_style.max_height } else { position_style.max_width }
|
||||
}
|
||||
|
||||
/// Get the logical computed max block size.
|
||||
#[inline]
|
||||
pub fn max_block_size(&self) -> computed::MaxLength {
|
||||
pub fn max_block_size(&self) -> computed::MaxSize {
|
||||
let position_style = self.get_position();
|
||||
if self.writing_mode.is_vertical() { position_style.max_width } else { position_style.max_height }
|
||||
}
|
||||
|
|
|
@ -4,23 +4,16 @@
|
|||
|
||||
//! Computed types for CSS values related to flexbox.
|
||||
|
||||
use crate::values::computed::Size;
|
||||
use crate::values::generics::flex::FlexBasis as GenericFlexBasis;
|
||||
|
||||
/// The `width` value type.
|
||||
#[cfg(feature = "servo")]
|
||||
pub type Width = crate::values::computed::NonNegativeLengthPercentageOrAuto;
|
||||
|
||||
/// The `width` value type.
|
||||
#[cfg(feature = "gecko")]
|
||||
pub type Width = crate::values::computed::MozLength;
|
||||
|
||||
/// A computed value for the `flex-basis` property.
|
||||
pub type FlexBasis = GenericFlexBasis<Width>;
|
||||
pub type FlexBasis = GenericFlexBasis<Size>;
|
||||
|
||||
impl FlexBasis {
|
||||
/// `auto`
|
||||
#[inline]
|
||||
pub fn auto() -> Self {
|
||||
GenericFlexBasis::Width(Width::auto())
|
||||
GenericFlexBasis::Width(Size::auto())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,7 @@ use super::{Context, Number, Percentage, ToComputedValue};
|
|||
use crate::values::animated::ToAnimatedValue;
|
||||
use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
|
||||
use crate::values::generics::length as generics;
|
||||
use crate::values::generics::length::{
|
||||
MaxLength as GenericMaxLength, MozLength as GenericMozLength,
|
||||
};
|
||||
use crate::values::generics::length::{MaxSize as GenericMaxSize, Size as GenericSize};
|
||||
use crate::values::generics::transform::IsZeroLength;
|
||||
use crate::values::generics::NonNegative;
|
||||
use crate::values::specified::length::ViewportPercentageLength;
|
||||
|
@ -580,12 +578,36 @@ impl NonNegativeLengthPercentage {
|
|||
}
|
||||
|
||||
#[cfg(feature = "servo")]
|
||||
impl MaxLength {
|
||||
impl MaxSize {
|
||||
/// Convert the computed value into used value.
|
||||
#[inline]
|
||||
pub fn to_used_value(&self, percentage_basis: Au) -> Option<Au> {
|
||||
match *self {
|
||||
GenericMaxLength::None => None,
|
||||
GenericMaxLength::LengthPercentage(ref lp) => Some(lp.to_used_value(percentage_basis)),
|
||||
GenericMaxSize::None => None,
|
||||
GenericMaxSize::LengthPercentage(ref lp) => Some(lp.to_used_value(percentage_basis)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Size {
|
||||
/// Convert the computed value into used value.
|
||||
#[inline]
|
||||
#[cfg(feature = "servo")]
|
||||
pub fn to_used_value(&self, percentage_basis: Au) -> Option<Au> {
|
||||
match *self {
|
||||
GenericSize::Auto => None,
|
||||
GenericSize::LengthPercentage(ref lp) => Some(lp.to_used_value(percentage_basis)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the computed value is absolute 0 or 0%.
|
||||
#[inline]
|
||||
pub fn is_definitely_zero(&self) -> bool {
|
||||
match *self {
|
||||
GenericSize::Auto => false,
|
||||
GenericSize::LengthPercentage(ref lp) => lp.is_definitely_zero(),
|
||||
#[cfg(feature = "gecko")]
|
||||
GenericSize::ExtremumLength(..) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -821,7 +843,7 @@ pub enum ExtremumLength {
|
|||
}
|
||||
|
||||
/// A computed value for `min-width`, `min-height`, `width` or `height` property.
|
||||
pub type MozLength = GenericMozLength<NonNegativeLengthPercentage>;
|
||||
pub type Size = GenericSize<NonNegativeLengthPercentage>;
|
||||
|
||||
/// A computed value for `max-width` or `min-height` property.
|
||||
pub type MaxLength = GenericMaxLength<NonNegativeLengthPercentage>;
|
||||
pub type MaxSize = GenericMaxSize<NonNegativeLengthPercentage>;
|
||||
|
|
|
@ -62,7 +62,7 @@ pub use self::gecko::ScrollSnapPoint;
|
|||
pub use self::image::{Gradient, GradientItem, Image, ImageLayer, LineDirection, MozImageRect};
|
||||
pub use self::length::{CSSPixelLength, ExtremumLength, NonNegativeLength};
|
||||
pub use self::length::{Length, LengthOrNumber, LengthPercentage};
|
||||
pub use self::length::{LengthPercentageOrAuto, MaxLength, MozLength};
|
||||
pub use self::length::{LengthPercentageOrAuto, MaxSize, Size};
|
||||
pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto};
|
||||
#[cfg(feature = "gecko")]
|
||||
pub use self::list::ListStyleType;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
//! Generic types for CSS values related to length.
|
||||
|
||||
use crate::parser::{Parse, ParserContext};
|
||||
#[cfg(feature = "gecko")]
|
||||
use crate::values::computed::ExtremumLength;
|
||||
use cssparser::Parser;
|
||||
use style_traits::ParseError;
|
||||
|
@ -76,7 +77,7 @@ impl<LengthPercentage: Parse> Parse for LengthPercentageOrAuto<LengthPercentage>
|
|||
|
||||
/// A generic value for the `width`, `height`, `min-width`, or `min-height` property.
|
||||
///
|
||||
/// Unlike `max-width` or `max-height` properties, a MozLength can be `auto`,
|
||||
/// Unlike `max-width` or `max-height` properties, a Size can be `auto`,
|
||||
/// and cannot be `none`.
|
||||
///
|
||||
/// Note that it only accepts non-negative values.
|
||||
|
@ -95,18 +96,25 @@ impl<LengthPercentage: Parse> Parse for LengthPercentageOrAuto<LengthPercentage>
|
|||
ToComputedValue,
|
||||
ToCss,
|
||||
)]
|
||||
pub enum MozLength<LengthPercentage> {
|
||||
pub enum Size<LengthPercentage> {
|
||||
LengthPercentage(LengthPercentage),
|
||||
Auto,
|
||||
#[cfg(feature = "gecko")]
|
||||
#[animation(error)]
|
||||
ExtremumLength(ExtremumLength),
|
||||
}
|
||||
|
||||
impl<LengthPercentage> MozLength<LengthPercentage> {
|
||||
impl<LengthPercentage> Size<LengthPercentage> {
|
||||
/// `auto` value.
|
||||
#[inline]
|
||||
pub fn auto() -> Self {
|
||||
MozLength::Auto
|
||||
Size::Auto
|
||||
}
|
||||
|
||||
/// Returns whether we're the auto value.
|
||||
#[inline]
|
||||
pub fn is_auto(&self) -> bool {
|
||||
matches!(*self, Size::Auto)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,7 +134,7 @@ impl<LengthPercentage> MozLength<LengthPercentage> {
|
|||
ToComputedValue,
|
||||
ToCss,
|
||||
)]
|
||||
pub enum MaxLength<LengthPercentage> {
|
||||
pub enum MaxSize<LengthPercentage> {
|
||||
LengthPercentage(LengthPercentage),
|
||||
None,
|
||||
#[cfg(feature = "gecko")]
|
||||
|
@ -134,10 +142,10 @@ pub enum MaxLength<LengthPercentage> {
|
|||
ExtremumLength(ExtremumLength),
|
||||
}
|
||||
|
||||
impl<LengthPercentage> MaxLength<LengthPercentage> {
|
||||
impl<LengthPercentage> MaxSize<LengthPercentage> {
|
||||
/// `none` value.
|
||||
#[inline]
|
||||
pub fn none() -> Self {
|
||||
MaxLength::None
|
||||
MaxSize::None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,26 +6,19 @@
|
|||
|
||||
use crate::parser::{Parse, ParserContext};
|
||||
use crate::values::generics::flex::FlexBasis as GenericFlexBasis;
|
||||
use crate::values::specified::Size;
|
||||
use cssparser::Parser;
|
||||
use style_traits::ParseError;
|
||||
|
||||
/// The `width` value type.
|
||||
#[cfg(feature = "servo")]
|
||||
pub type Width = crate::values::specified::NonNegativeLengthPercentageOrAuto;
|
||||
|
||||
/// The `width` value type.
|
||||
#[cfg(feature = "gecko")]
|
||||
pub type Width = crate::values::specified::MozLength;
|
||||
|
||||
/// A specified value for the `flex-basis` property.
|
||||
pub type FlexBasis = GenericFlexBasis<Width>;
|
||||
pub type FlexBasis = GenericFlexBasis<Size>;
|
||||
|
||||
impl Parse for FlexBasis {
|
||||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(width) = input.try(|i| Width::parse(context, i)) {
|
||||
if let Ok(width) = input.try(|i| Size::parse(context, i)) {
|
||||
return Ok(GenericFlexBasis::Width(width));
|
||||
}
|
||||
try_match_ident_ignore_ascii_case! { input,
|
||||
|
@ -38,12 +31,12 @@ impl FlexBasis {
|
|||
/// `auto`
|
||||
#[inline]
|
||||
pub fn auto() -> Self {
|
||||
GenericFlexBasis::Width(Width::auto())
|
||||
GenericFlexBasis::Width(Size::auto())
|
||||
}
|
||||
|
||||
/// `0%`
|
||||
#[inline]
|
||||
pub fn zero_percent() -> Self {
|
||||
GenericFlexBasis::Width(Width::zero_percent())
|
||||
GenericFlexBasis::Width(Size::zero_percent())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,11 +9,9 @@
|
|||
use super::{AllowQuirks, Number, Percentage, ToComputedValue};
|
||||
use crate::font_metrics::FontMetricsQueryResult;
|
||||
use crate::parser::{Parse, ParserContext};
|
||||
use crate::values::computed::{self, CSSPixelLength, Context, ExtremumLength};
|
||||
use crate::values::computed::{self, CSSPixelLength, Context};
|
||||
use crate::values::generics::length as generics;
|
||||
use crate::values::generics::length::{
|
||||
MaxLength as GenericMaxLength, MozLength as GenericMozLength,
|
||||
};
|
||||
use crate::values::generics::length::{MaxSize as GenericMaxSize, Size as GenericSize};
|
||||
use crate::values::generics::transform::IsZeroLength;
|
||||
use crate::values::generics::NonNegative;
|
||||
use crate::values::specified::calc::CalcNode;
|
||||
|
@ -1051,56 +1049,18 @@ impl LengthOrNumber {
|
|||
}
|
||||
|
||||
/// A specified value for `min-width`, `min-height`, `width` or `height` property.
|
||||
pub type MozLength = GenericMozLength<NonNegativeLengthPercentage>;
|
||||
pub type Size = GenericSize<NonNegativeLengthPercentage>;
|
||||
|
||||
impl Parse for MozLength {
|
||||
impl Parse for Size {
|
||||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
MozLength::parse_quirky(context, input, AllowQuirks::No)
|
||||
Size::parse_quirky(context, input, AllowQuirks::No)
|
||||
}
|
||||
}
|
||||
|
||||
impl MozLength {
|
||||
/// Parses, with quirks.
|
||||
pub fn parse_quirky<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
allow_quirks: AllowQuirks,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(l) = input.try(ExtremumLength::parse) {
|
||||
return Ok(GenericMozLength::ExtremumLength(l));
|
||||
}
|
||||
|
||||
if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
|
||||
return Ok(GenericMozLength::Auto);
|
||||
}
|
||||
|
||||
let length = NonNegativeLengthPercentage::parse_quirky(context, input, allow_quirks)?;
|
||||
Ok(GenericMozLength::LengthPercentage(length))
|
||||
}
|
||||
|
||||
/// Returns `0%`.
|
||||
#[inline]
|
||||
pub fn zero_percent() -> Self {
|
||||
GenericMozLength::LengthPercentage(NonNegativeLengthPercentage::zero_percent())
|
||||
}
|
||||
}
|
||||
|
||||
/// A specified value for `max-width` or `max-height` property.
|
||||
pub type MaxLength = GenericMaxLength<NonNegativeLengthPercentage>;
|
||||
|
||||
impl Parse for MaxLength {
|
||||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
MaxLength::parse_quirky(context, input, AllowQuirks::No)
|
||||
}
|
||||
}
|
||||
|
||||
impl MaxLength {
|
||||
impl Size {
|
||||
/// Parses, with quirks.
|
||||
pub fn parse_quirky<'i, 't>(
|
||||
context: &ParserContext,
|
||||
|
@ -1109,16 +1069,57 @@ impl MaxLength {
|
|||
) -> Result<Self, ParseError<'i>> {
|
||||
#[cfg(feature = "gecko")]
|
||||
{
|
||||
if let Ok(l) = input.try(ExtremumLength::parse) {
|
||||
return Ok(GenericMaxLength::ExtremumLength(l));
|
||||
if let Ok(l) = input.try(computed::ExtremumLength::parse) {
|
||||
return Ok(GenericSize::ExtremumLength(l));
|
||||
}
|
||||
}
|
||||
|
||||
if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
|
||||
return Ok(GenericSize::Auto);
|
||||
}
|
||||
|
||||
let length = NonNegativeLengthPercentage::parse_quirky(context, input, allow_quirks)?;
|
||||
Ok(GenericSize::LengthPercentage(length))
|
||||
}
|
||||
|
||||
/// Returns `0%`.
|
||||
#[inline]
|
||||
pub fn zero_percent() -> Self {
|
||||
GenericSize::LengthPercentage(NonNegativeLengthPercentage::zero_percent())
|
||||
}
|
||||
}
|
||||
|
||||
/// A specified value for `max-width` or `max-height` property.
|
||||
pub type MaxSize = GenericMaxSize<NonNegativeLengthPercentage>;
|
||||
|
||||
impl Parse for MaxSize {
|
||||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
MaxSize::parse_quirky(context, input, AllowQuirks::No)
|
||||
}
|
||||
}
|
||||
|
||||
impl MaxSize {
|
||||
/// Parses, with quirks.
|
||||
pub fn parse_quirky<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
allow_quirks: AllowQuirks,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
#[cfg(feature = "gecko")]
|
||||
{
|
||||
if let Ok(l) = input.try(computed::ExtremumLength::parse) {
|
||||
return Ok(GenericMaxSize::ExtremumLength(l));
|
||||
}
|
||||
}
|
||||
|
||||
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
return Ok(GenericMaxLength::None);
|
||||
return Ok(GenericMaxSize::None);
|
||||
}
|
||||
|
||||
let length = NonNegativeLengthPercentage::parse_quirky(context, input, allow_quirks)?;
|
||||
Ok(GenericMaxLength::LengthPercentage(length))
|
||||
Ok(GenericMaxSize::LengthPercentage(length))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ pub use self::image::{GradientItem, GradientKind, Image, ImageLayer, MozImageRec
|
|||
pub use self::length::{AbsoluteLength, CalcLengthPercentage, CharacterWidth};
|
||||
pub use self::length::{FontRelativeLength, Length, LengthOrNumber};
|
||||
pub use self::length::{LengthPercentage, LengthPercentageOrAuto};
|
||||
pub use self::length::{MaxLength, MozLength};
|
||||
pub use self::length::{MaxSize, Size};
|
||||
pub use self::length::{NoCalcLength, ViewportPercentageLength};
|
||||
pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto};
|
||||
#[cfg(feature = "gecko")]
|
||||
|
|
|
@ -4434,7 +4434,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(
|
|||
) {
|
||||
use style::properties::longhands::border_spacing::SpecifiedValue as BorderSpacing;
|
||||
use style::properties::{LonghandId, PropertyDeclaration};
|
||||
use style::values::generics::length::MozLength;
|
||||
use style::values::generics::length::Size;
|
||||
use style::values::generics::NonNegative;
|
||||
use style::values::generics::length::LengthPercentageOrAuto;
|
||||
use style::values::specified::length::NonNegativeLengthPercentage;
|
||||
|
@ -4447,8 +4447,8 @@ pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(
|
|||
let lp = LengthPercentage::Length(nocalc);
|
||||
let lp_or_auto = LengthPercentageOrAuto::LengthPercentage(lp.clone());
|
||||
let prop = match_wrap_declared! { long,
|
||||
Height => MozLength::LengthPercentage(NonNegative(lp)),
|
||||
Width => MozLength::LengthPercentage(NonNegative(lp)),
|
||||
Height => Size::LengthPercentage(NonNegative(lp)),
|
||||
Width => Size::LengthPercentage(NonNegative(lp)),
|
||||
BorderTopWidth => BorderSideWidth::Length(nocalc.into()),
|
||||
BorderRightWidth => BorderSideWidth::Length(nocalc.into()),
|
||||
BorderBottomWidth => BorderSideWidth::Length(nocalc.into()),
|
||||
|
@ -4497,7 +4497,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetLengthValue(
|
|||
use style::properties::longhands::_moz_script_min_size::SpecifiedValue as MozScriptMinSize;
|
||||
use style::properties::{LonghandId, PropertyDeclaration};
|
||||
use style::values::generics::NonNegative;
|
||||
use style::values::generics::length::MozLength;
|
||||
use style::values::generics::length::Size;
|
||||
use style::values::specified::length::NoCalcLength;
|
||||
use style::values::specified::length::{AbsoluteLength, FontRelativeLength};
|
||||
use style::values::specified::length::LengthPercentage;
|
||||
|
@ -4525,7 +4525,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetLengthValue(
|
|||
};
|
||||
|
||||
let prop = match_wrap_declared! { long,
|
||||
Width => MozLength::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
|
||||
Width => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
|
||||
FontSize => LengthPercentage::from(nocalc).into(),
|
||||
MozScriptMinSize => MozScriptMinSize(nocalc),
|
||||
};
|
||||
|
@ -4565,7 +4565,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(
|
|||
use style::properties::{LonghandId, PropertyDeclaration};
|
||||
use style::values::computed::Percentage;
|
||||
use style::values::generics::NonNegative;
|
||||
use style::values::generics::length::{MozLength, LengthPercentageOrAuto};
|
||||
use style::values::generics::length::{Size, LengthPercentageOrAuto};
|
||||
use style::values::specified::length::LengthPercentage;
|
||||
|
||||
let long = get_longhand_from_id!(property);
|
||||
|
@ -4574,8 +4574,8 @@ pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(
|
|||
let lp_or_auto = LengthPercentageOrAuto::LengthPercentage(lp.clone());
|
||||
|
||||
let prop = match_wrap_declared! { long,
|
||||
Height => MozLength::LengthPercentage(NonNegative(lp)),
|
||||
Width => MozLength::LengthPercentage(NonNegative(lp)),
|
||||
Height => Size::LengthPercentage(NonNegative(lp)),
|
||||
Width => Size::LengthPercentage(NonNegative(lp)),
|
||||
MarginTop => lp_or_auto,
|
||||
MarginRight => lp_or_auto,
|
||||
MarginBottom => lp_or_auto,
|
||||
|
@ -4593,14 +4593,14 @@ pub extern "C" fn Servo_DeclarationBlock_SetAutoValue(
|
|||
property: nsCSSPropertyID,
|
||||
) {
|
||||
use style::properties::{LonghandId, PropertyDeclaration};
|
||||
use style::values::generics::length::{LengthPercentageOrAuto, MozLength};
|
||||
use style::values::generics::length::{LengthPercentageOrAuto, Size};
|
||||
|
||||
let long = get_longhand_from_id!(property);
|
||||
let auto = LengthPercentageOrAuto::Auto;
|
||||
|
||||
let prop = match_wrap_declared! { long,
|
||||
Height => MozLength::auto(),
|
||||
Width => MozLength::auto(),
|
||||
Height => Size::auto(),
|
||||
Width => Size::auto(),
|
||||
MarginTop => auto,
|
||||
MarginRight => auto,
|
||||
MarginBottom => auto,
|
||||
|
|
|
@ -9,6 +9,10 @@ job-defaults:
|
|||
by-test-platform:
|
||||
android-hw.*: /builds/worker
|
||||
default: /home/cltbld
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
windows10-64-ux: ['try', 'mozilla-central']
|
||||
default: ['try', 'trunk', 'mozilla-beta']
|
||||
tier:
|
||||
by-test-platform:
|
||||
windows10-64-ccov/.*: 3
|
||||
|
@ -40,10 +44,6 @@ raptor-tp6-1-firefox:
|
|||
description: "Raptor tp6-1 on Firefox"
|
||||
try-name: raptor-tp6-1-firefox
|
||||
treeherder-symbol: Rap(tp6-1)
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
windows10-64-ux: ['try', 'mozilla-central']
|
||||
default: built-projects
|
||||
mozharness:
|
||||
extra-options:
|
||||
- --test=raptor-tp6-1
|
||||
|
@ -76,7 +76,6 @@ raptor-tp6-2-firefox:
|
|||
description: "Raptor tp6-2 on Firefox"
|
||||
try-name: raptor-tp6-2-firefox
|
||||
treeherder-symbol: Rap(tp6-2)
|
||||
run-on-projects: built-projects
|
||||
mozharness:
|
||||
extra-options:
|
||||
- --test=raptor-tp6-2
|
||||
|
@ -108,7 +107,6 @@ raptor-tp6-3-firefox:
|
|||
description: "Raptor tp6-3 on Firefox"
|
||||
try-name: raptor-tp6-3-firefox
|
||||
treeherder-symbol: Rap(tp6-3)
|
||||
run-on-projects: built-projects
|
||||
mozharness:
|
||||
extra-options:
|
||||
- --test=raptor-tp6-3
|
||||
|
@ -141,7 +139,6 @@ raptor-tp6-4-firefox:
|
|||
description: "Raptor tp6-4 on Firefox"
|
||||
try-name: raptor-tp6-4-firefox
|
||||
treeherder-symbol: Rap(tp6-4)
|
||||
run-on-projects: built-projects
|
||||
mozharness:
|
||||
extra-options:
|
||||
- --test=raptor-tp6-4
|
||||
|
@ -173,7 +170,6 @@ raptor-tp6-5-firefox:
|
|||
description: "Raptor tp6-5 on Firefox"
|
||||
try-name: raptor-tp6-5-firefox
|
||||
treeherder-symbol: Rap(tp6-5)
|
||||
run-on-projects: built-projects
|
||||
mozharness:
|
||||
extra-options:
|
||||
- --test=raptor-tp6-5
|
||||
|
@ -205,7 +201,6 @@ raptor-tp6-6-firefox:
|
|||
description: "Raptor tp6-6 on Firefox"
|
||||
try-name: raptor-tp6-6-firefox
|
||||
treeherder-symbol: Rap(tp6-6)
|
||||
run-on-projects: built-projects
|
||||
mozharness:
|
||||
extra-options:
|
||||
- --test=raptor-tp6-6
|
||||
|
@ -370,7 +365,6 @@ raptor-tp6m-1-geckoview:
|
|||
try-name: raptor-tp6m-1-geckoview
|
||||
treeherder-symbol: Rap(tp6m-1)
|
||||
target: geckoview_example.apk
|
||||
run-on-projects: built-projects
|
||||
tier: 2
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
@ -382,10 +376,6 @@ raptor-speedometer-firefox:
|
|||
description: "Raptor Speedometer on Firefox"
|
||||
try-name: raptor-speedometer-firefox
|
||||
treeherder-symbol: Rap(sp)
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
windows10-64-ux: ['try', 'mozilla-central']
|
||||
default: built-projects
|
||||
mozharness:
|
||||
extra-options:
|
||||
- --test=raptor-speedometer
|
||||
|
@ -409,7 +399,7 @@ raptor-speedometer-geckoview:
|
|||
target: geckoview_example.apk
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
android-hw.*: built-projects
|
||||
android-hw.*: ['try', 'trunk', 'mozilla-beta']
|
||||
max-run-time: 900
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
@ -442,7 +432,7 @@ raptor-speedometer-fennec:
|
|||
target: target.apk
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
android-hw.*: built-projects
|
||||
android-hw.*: ['try', 'trunk', 'mozilla-beta']
|
||||
tier: 3
|
||||
max-run-time: 900
|
||||
mozharness:
|
||||
|
@ -467,10 +457,6 @@ raptor-stylebench-firefox:
|
|||
description: "Raptor StyleBench on Firefox"
|
||||
try-name: raptor-stylebench-firefox
|
||||
treeherder-symbol: Rap(sb)
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
windows10-64-ux: ['try', 'mozilla-central']
|
||||
default: built-projects
|
||||
mozharness:
|
||||
extra-options:
|
||||
- --test=raptor-stylebench
|
||||
|
@ -502,10 +488,6 @@ raptor-motionmark-htmlsuite-firefox:
|
|||
description: "Raptor MotionMark HtmlSuite on Firefox"
|
||||
try-name: raptor-motionmark-htmlsuite-firefox
|
||||
treeherder-symbol: Rap(mm-h)
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
windows10-64-ux: ['try', 'mozilla-central']
|
||||
default: built-projects
|
||||
mozharness:
|
||||
extra-options:
|
||||
- --test=raptor-motionmark-htmlsuite
|
||||
|
@ -537,10 +519,6 @@ raptor-motionmark-animometer-firefox:
|
|||
description: "Raptor MotionMark Animometer on Firefox"
|
||||
try-name: raptor-motionmark-animometer-firefox
|
||||
treeherder-symbol: Rap(mm-a)
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
windows10-64-ux: ['try', 'mozilla-central']
|
||||
default: built-projects
|
||||
mozharness:
|
||||
extra-options:
|
||||
- --test=raptor-motionmark-animometer
|
||||
|
@ -572,10 +550,6 @@ raptor-webaudio-firefox:
|
|||
description: "Raptor WebAudio on Firefox"
|
||||
try-name: raptor-webaudio-firefox
|
||||
treeherder-symbol: Rap(wa)
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
windows10-64-ux: ['try', 'mozilla-central']
|
||||
default: built-projects
|
||||
mozharness:
|
||||
extra-options:
|
||||
- --test=raptor-webaudio
|
||||
|
@ -601,19 +575,11 @@ raptor-webaudio-chrome:
|
|||
extra-options:
|
||||
- --test=raptor-webaudio
|
||||
- --app=chrome
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
windows10-64-ux: ['try', 'mozilla-central']
|
||||
default: built-projects
|
||||
|
||||
raptor-sunspider-firefox:
|
||||
description: "Raptor SunSpider on Firefox"
|
||||
try-name: raptor-sunspider-firefox
|
||||
treeherder-symbol: Rap(ss)
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
windows10-64-ux: ['try', 'mozilla-central']
|
||||
default: built-projects
|
||||
mozharness:
|
||||
extra-options:
|
||||
- --test=raptor-sunspider
|
||||
|
@ -645,10 +611,6 @@ raptor-unity-webgl-firefox:
|
|||
description: "Raptor Unity WebGL on Firefox"
|
||||
try-name: raptor-unity-webgl-firefox
|
||||
treeherder-symbol: Rap(ugl)
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
windows10-64-ux: ['try', 'mozilla-central']
|
||||
default: built-projects
|
||||
mozharness:
|
||||
extra-options:
|
||||
- --test=raptor-unity-webgl
|
||||
|
@ -678,7 +640,7 @@ raptor-unity-webgl-geckoview:
|
|||
target: geckoview_example.apk
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
android-hw.*: built-projects
|
||||
android-hw.*: ['try', 'trunk', 'mozilla-beta']
|
||||
max-run-time: 900
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
@ -707,10 +669,6 @@ raptor-wasm-misc-firefox:
|
|||
description: "Raptor WASM Misc on Firefox"
|
||||
try-name: raptor-wasm-misc-firefox
|
||||
treeherder-symbol: Rap(wm)
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
windows10-64-ux: ['try', 'mozilla-central']
|
||||
default: built-projects
|
||||
mozharness:
|
||||
extra-options:
|
||||
- --test=raptor-wasm-misc
|
||||
|
@ -737,10 +695,6 @@ raptor-wasm-misc-baseline-firefox:
|
|||
description: "Raptor WASM Misc on Firefox with baseline JIT"
|
||||
try-name: raptor-wasm-misc-baseline-firefox
|
||||
treeherder-symbol: Rap(wm-b)
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
windows10-64-ux: ['try', 'mozilla-central']
|
||||
default: built-projects
|
||||
mozharness:
|
||||
extra-options:
|
||||
- --test=raptor-wasm-misc-baseline
|
||||
|
@ -767,10 +721,6 @@ raptor-wasm-misc-ion-firefox:
|
|||
description: "Raptor WASM Misc on Firefox with ION Monkey"
|
||||
try-name: raptor-wasm-misc-ion-firefox
|
||||
treeherder-symbol: Rap(wm-i)
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
windows10-64-ux: ['try', 'mozilla-central']
|
||||
default: built-projects
|
||||
mozharness:
|
||||
extra-options:
|
||||
- --test=raptor-wasm-misc-ion
|
||||
|
@ -811,10 +761,6 @@ raptor-assorted-dom-firefox:
|
|||
description: "Raptor Assorted-Dom on Firefox"
|
||||
try-name: raptor-assorted-dom-firefox
|
||||
treeherder-symbol: Rap(dom)
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
windows10-64-ux: ['try', 'mozilla-central']
|
||||
default: built-projects
|
||||
max-run-time:
|
||||
by-test-platform:
|
||||
.*-qr/.*: 2100
|
||||
|
@ -861,10 +807,6 @@ raptor-wasm-godot-firefox:
|
|||
description: "Raptor Wasm Godot on Firefox"
|
||||
try-name: raptor-wasm-godot-firefox
|
||||
treeherder-symbol: Rap(godot)
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
windows10-64-ux: ['try', 'mozilla-central']
|
||||
default: built-projects
|
||||
max-run-time:
|
||||
by-test-platform:
|
||||
.*-qr/.*: 2100
|
||||
|
@ -902,10 +844,6 @@ raptor-wasm-godot-baseline-firefox:
|
|||
description: "Raptor Wasm Godot on Firefox with baseline JIT"
|
||||
try-name: raptor-wasm-godot-baseline-firefox
|
||||
treeherder-symbol: Rap(godot-b)
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
windows10-64-ux: ['try', 'mozilla-central']
|
||||
default: built-projects
|
||||
max-run-time:
|
||||
by-test-platform:
|
||||
.*-qr/.*: 2100
|
||||
|
@ -931,10 +869,6 @@ raptor-wasm-godot-ion-firefox:
|
|||
description: "Raptor WASM godot on Firefox with ION Monkey"
|
||||
try-name: raptor-wasm-godot-ion-firefox
|
||||
treeherder-symbol: Rap(godot-i)
|
||||
run-on-projects:
|
||||
by-test-platform:
|
||||
windows10-64-ux: ['try', 'mozilla-central']
|
||||
default: built-projects
|
||||
max-run-time:
|
||||
by-test-platform:
|
||||
.*-qr/.*: 2100
|
||||
|
|
|
@ -297,10 +297,10 @@
|
|||
},
|
||||
"python-dateutil": {
|
||||
"hashes": [
|
||||
"sha256:063df5763652e21de43de7d9e00ccf239f953a832941e37be541614732cdfc93",
|
||||
"sha256:88f9287c0174266bb0d8cedd395cfba9c58e87e5ad86b2ce58859bc11be3cf02"
|
||||
"sha256:7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb",
|
||||
"sha256:c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e"
|
||||
],
|
||||
"version": "==2.7.5"
|
||||
"version": "==2.8.0"
|
||||
},
|
||||
"python-gnupg": {
|
||||
"hashes": [
|
||||
|
|
|
@ -12,9 +12,9 @@ import signal
|
|||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import urllib2
|
||||
import zipfile
|
||||
from collections import namedtuple
|
||||
from six.moves.urllib.request import urlopen
|
||||
|
||||
import mozfile
|
||||
import mozinfo
|
||||
|
@ -110,7 +110,9 @@ def check_for_crashes(dump_directory,
|
|||
sig=signature,
|
||||
out="\n".join(stackwalk_output),
|
||||
err="\n".join(info.stackwalk_errors))
|
||||
print(output.encode("utf-8"))
|
||||
if sys.stdout.encoding != 'UTF-8':
|
||||
output = output.encode('utf-8')
|
||||
print(output)
|
||||
|
||||
return crash_count
|
||||
|
||||
|
@ -179,7 +181,7 @@ class CrashInfo(object):
|
|||
self.remove_symbols = True
|
||||
self.logger.info("Downloading symbols from: %s" % self.symbols_path)
|
||||
# Get the symbols and write them to a temporary zipfile
|
||||
data = urllib2.urlopen(self.symbols_path)
|
||||
data = urlopen(self.symbols_path)
|
||||
with tempfile.TemporaryFile() as symbols_file:
|
||||
symbols_file.write(data.read())
|
||||
# extract symbols to a temporary directory (which we'll delete after
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
[DEFAULT]
|
||||
subsuite = mozbase
|
||||
skip-if = python == 3
|
||||
[test_basic.py]
|
||||
[test_java_exception.py]
|
||||
[test_save_path.py]
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import urlparse
|
||||
import zipfile
|
||||
import StringIO
|
||||
from six import BytesIO
|
||||
from six.moves.urllib.parse import urlunsplit
|
||||
|
||||
import mozhttpd
|
||||
import mozunit
|
||||
|
@ -34,7 +34,7 @@ def test_symbols_path_url(check_for_crashes, minidump_files):
|
|||
data = {"retrieved": False}
|
||||
|
||||
def make_zipfile():
|
||||
data = StringIO.StringIO()
|
||||
data = BytesIO()
|
||||
z = zipfile.ZipFile(data, 'w')
|
||||
z.writestr("symbols.txt", "abc/xyz")
|
||||
z.close()
|
||||
|
@ -51,8 +51,8 @@ def test_symbols_path_url(check_for_crashes, minidump_files):
|
|||
'path': '/symbols',
|
||||
'function': get_symbols}])
|
||||
httpd.start()
|
||||
symbol_url = urlparse.urlunsplit(('http', '%s:%d' % httpd.httpd.server_address,
|
||||
'/symbols', '', ''))
|
||||
symbol_url = urlunsplit(('http', '%s:%d' % httpd.httpd.server_address,
|
||||
'/symbols', '', ''))
|
||||
|
||||
assert 1 == check_for_crashes(symbols_path=symbol_url)
|
||||
assert data["retrieved"]
|
||||
|
|
|
@ -7,7 +7,7 @@ from __future__ import absolute_import
|
|||
from setuptools import setup, find_packages
|
||||
|
||||
PACKAGE_NAME = 'mozrunner'
|
||||
PACKAGE_VERSION = '7.2.0'
|
||||
PACKAGE_VERSION = '7.3.0'
|
||||
|
||||
desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
|
||||
|
||||
|
|
|
@ -606,11 +606,6 @@ class Output(object):
|
|||
|
||||
def output(self, test_names):
|
||||
"""output to file and perfherder data json """
|
||||
if self.summarized_results == {}:
|
||||
LOG.error("error: no summarized raptor results found for %s" %
|
||||
', '.join(test_names))
|
||||
return False
|
||||
|
||||
if os.environ['MOZ_UPLOAD_DIR']:
|
||||
# i.e. testing/mozharness/build/raptor.json locally; in production it will
|
||||
# be at /tasks/task_*/build/ (where it will be picked up by mozharness later
|
||||
|
@ -623,9 +618,13 @@ class Output(object):
|
|||
results_path = os.path.join(os.getcwd(), 'raptor.json')
|
||||
screenshot_path = os.path.join(os.getcwd(), 'screenshots.html')
|
||||
|
||||
with open(results_path, 'w') as f:
|
||||
for result in self.summarized_results:
|
||||
f.write("%s\n" % result)
|
||||
if self.summarized_results == {}:
|
||||
LOG.error("error: no summarized raptor results found for %s" %
|
||||
', '.join(test_names))
|
||||
else:
|
||||
with open(results_path, 'w') as f:
|
||||
for result in self.summarized_results:
|
||||
f.write("%s\n" % result)
|
||||
|
||||
if len(self.summarized_screenshots) > 0:
|
||||
with open(screenshot_path, 'w') as f:
|
||||
|
@ -633,6 +632,11 @@ class Output(object):
|
|||
f.write("%s\n" % result)
|
||||
LOG.info("screen captures can be found locally at: %s" % screenshot_path)
|
||||
|
||||
# now that we've checked for screen captures too, if there were no actual
|
||||
# test results we can bail out here
|
||||
if self.summarized_results == {}:
|
||||
return False
|
||||
|
||||
# when gecko_profiling, we don't want results ingested by Perfherder
|
||||
extra_opts = self.summarized_results['suites'][0].get('extraOptions', [])
|
||||
if 'gecko_profile' not in extra_opts:
|
||||
|
|
|
@ -396,9 +396,13 @@ async function nextCycle() {
|
|||
}
|
||||
}
|
||||
|
||||
function timeoutAlarmListener() {
|
||||
async function timeoutAlarmListener() {
|
||||
console.error("raptor-page-timeout on %s" % testURL);
|
||||
postToControlServer("raptor-page-timeout", [testName, testURL]);
|
||||
// take a screen capture
|
||||
if (screenCapture) {
|
||||
await getScreenCapture();
|
||||
}
|
||||
// call clean-up to shutdown gracefully
|
||||
cleanUp();
|
||||
}
|
||||
|
|
|
@ -121,17 +121,36 @@ bool GetParentPrincipalAndTrackingOrigin(
|
|||
return true;
|
||||
};
|
||||
|
||||
void CreatePermissionKey(const nsCString& aTrackingOrigin,
|
||||
nsACString& aPermissionKey) {
|
||||
MOZ_ASSERT(aPermissionKey.IsEmpty());
|
||||
|
||||
static const nsLiteralCString prefix =
|
||||
NS_LITERAL_CSTRING(ANTITRACKING_PERM_KEY "^");
|
||||
|
||||
aPermissionKey.SetCapacity(prefix.Length() + aTrackingOrigin.Length());
|
||||
aPermissionKey.Append(prefix);
|
||||
aPermissionKey.Append(aTrackingOrigin);
|
||||
}
|
||||
|
||||
void CreatePermissionKey(const nsCString& aTrackingOrigin,
|
||||
const nsCString& aGrantedOrigin,
|
||||
nsACString& aPermissionKey) {
|
||||
MOZ_ASSERT(aPermissionKey.IsEmpty());
|
||||
|
||||
if (aTrackingOrigin == aGrantedOrigin) {
|
||||
aPermissionKey =
|
||||
nsPrintfCString(ANTITRACKING_PERM_KEY "^%s", aTrackingOrigin.get());
|
||||
CreatePermissionKey(aTrackingOrigin, aPermissionKey);
|
||||
return;
|
||||
}
|
||||
|
||||
aPermissionKey = nsPrintfCString(ANTITRACKING_PERM_KEY "^%s^%s",
|
||||
aTrackingOrigin.get(), aGrantedOrigin.get());
|
||||
static const nsLiteralCString prefix =
|
||||
NS_LITERAL_CSTRING(ANTITRACKING_PERM_KEY "^");
|
||||
|
||||
aPermissionKey.SetCapacity(prefix.Length() + 1 + aTrackingOrigin.Length());
|
||||
aPermissionKey.Append(prefix);
|
||||
aPermissionKey.Append(aTrackingOrigin);
|
||||
aPermissionKey.AppendLiteral("^");
|
||||
aPermissionKey.Append(aGrantedOrigin);
|
||||
}
|
||||
|
||||
// This internal method returns ACCESS_DENY if the access is denied,
|
||||
|
@ -1021,7 +1040,7 @@ bool AntiTrackingCommon::IsStorageAccessPermission(nsIPermission* aPermission,
|
|||
// shorter permission key and will then do a prefix match on the type of the
|
||||
// input permission to see if it is a storage access permission or not.
|
||||
nsAutoCString permissionKey;
|
||||
CreatePermissionKey(origin, origin, permissionKey);
|
||||
CreatePermissionKey(origin, permissionKey);
|
||||
|
||||
nsAutoCString type;
|
||||
rv = aPermission->GetType(type);
|
||||
|
@ -1545,7 +1564,7 @@ bool AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(
|
|||
}
|
||||
|
||||
nsAutoCString type;
|
||||
CreatePermissionKey(origin, origin, type);
|
||||
CreatePermissionKey(origin, type);
|
||||
|
||||
nsPermissionManager* permManager = nsPermissionManager::GetInstance();
|
||||
if (NS_WARN_IF(!permManager)) {
|
||||
|
|
|
@ -20,12 +20,16 @@ AntiTracking.runTest("IndexedDB in workers",
|
|||
|
||||
await new Promise((resolve, reject) => {
|
||||
worker.onmessage = function(e) {
|
||||
if (e) {
|
||||
if (e.data) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
};
|
||||
|
||||
worker.onerror = function(e) {
|
||||
reject();
|
||||
};
|
||||
});
|
||||
},
|
||||
async _ => {
|
||||
|
@ -45,12 +49,16 @@ AntiTracking.runTest("IndexedDB in workers",
|
|||
|
||||
await new Promise((resolve, reject) => {
|
||||
worker.onmessage = function(e) {
|
||||
if (e) {
|
||||
if (e.data) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
};
|
||||
|
||||
worker.onerror = function(e) {
|
||||
reject();
|
||||
};
|
||||
});
|
||||
},
|
||||
async _ => {
|
||||
|
@ -88,12 +96,16 @@ AntiTracking.runTest("IndexedDB in workers and Storage Access API",
|
|||
|
||||
await new Promise((resolve, reject) => {
|
||||
worker.onmessage = function(e) {
|
||||
if (e) {
|
||||
if (e.data) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
};
|
||||
|
||||
worker.onerror = function(e) {
|
||||
reject();
|
||||
};
|
||||
});
|
||||
|
||||
/* import-globals-from storageAccessAPIHelpers.js */
|
||||
|
@ -114,12 +126,16 @@ AntiTracking.runTest("IndexedDB in workers and Storage Access API",
|
|||
|
||||
await new Promise((resolve, reject) => {
|
||||
worker.onmessage = function(e) {
|
||||
if (e) {
|
||||
if (e.data) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
};
|
||||
|
||||
worker.onerror = function(e) {
|
||||
reject();
|
||||
};
|
||||
});
|
||||
},
|
||||
async _ => {
|
||||
|
@ -142,12 +158,16 @@ AntiTracking.runTest("IndexedDB in workers and Storage Access API",
|
|||
|
||||
await new Promise((resolve, reject) => {
|
||||
worker.onmessage = function(e) {
|
||||
if (e) {
|
||||
if (e.data) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
};
|
||||
|
||||
worker.onerror = function(e) {
|
||||
reject();
|
||||
};
|
||||
});
|
||||
|
||||
/* import-globals-from storageAccessAPIHelpers.js */
|
||||
|
@ -160,12 +180,16 @@ AntiTracking.runTest("IndexedDB in workers and Storage Access API",
|
|||
|
||||
await new Promise((resolve, reject) => {
|
||||
worker.onmessage = function(e) {
|
||||
if (e) {
|
||||
if (e.data) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
};
|
||||
|
||||
worker.onerror = function(e) {
|
||||
reject();
|
||||
};
|
||||
});
|
||||
},
|
||||
async _ => {
|
||||
|
|
|
@ -40,12 +40,16 @@ AntiTracking.runTest("BroadcastChannel in workers",
|
|||
|
||||
await new Promise((resolve, reject) => {
|
||||
worker.onmessage = function(e) {
|
||||
if (e) {
|
||||
if (e.data) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
};
|
||||
|
||||
worker.onerror = function(e) {
|
||||
reject();
|
||||
};
|
||||
});
|
||||
},
|
||||
async _ => {
|
||||
|
@ -65,12 +69,16 @@ AntiTracking.runTest("BroadcastChannel in workers",
|
|||
|
||||
await new Promise((resolve, reject) => {
|
||||
worker.onmessage = function(e) {
|
||||
if (e) {
|
||||
if (e.data) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
};
|
||||
|
||||
worker.onerror = function(e) {
|
||||
reject();
|
||||
};
|
||||
});
|
||||
},
|
||||
async _ => {
|
||||
|
@ -157,12 +165,16 @@ AntiTracking.runTest("BroadcastChannel in workers and Storage Access API",
|
|||
|
||||
await new Promise((resolve, reject) => {
|
||||
worker.onmessage = function(e) {
|
||||
if (e) {
|
||||
if (e.data) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
};
|
||||
|
||||
worker.onerror = function(e) {
|
||||
reject();
|
||||
};
|
||||
});
|
||||
|
||||
/* import-globals-from storageAccessAPIHelpers.js */
|
||||
|
@ -184,12 +196,16 @@ AntiTracking.runTest("BroadcastChannel in workers and Storage Access API",
|
|||
|
||||
await new Promise((resolve, reject) => {
|
||||
worker.onmessage = function(e) {
|
||||
if (e) {
|
||||
if (e.data) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
};
|
||||
|
||||
worker.onerror = function(e) {
|
||||
reject();
|
||||
};
|
||||
});
|
||||
},
|
||||
async _ => {
|
||||
|
@ -212,12 +228,16 @@ AntiTracking.runTest("BroadcastChannel in workers and Storage Access API",
|
|||
|
||||
await new Promise((resolve, reject) => {
|
||||
worker.onmessage = function(e) {
|
||||
if (e) {
|
||||
if (e.data) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
};
|
||||
|
||||
worker.onerror = function(e) {
|
||||
reject();
|
||||
};
|
||||
});
|
||||
|
||||
/* import-globals-from storageAccessAPIHelpers.js */
|
||||
|
@ -230,12 +250,16 @@ AntiTracking.runTest("BroadcastChannel in workers and Storage Access API",
|
|||
|
||||
await new Promise((resolve, reject) => {
|
||||
worker.onmessage = function(e) {
|
||||
if (e) {
|
||||
if (e.data) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
};
|
||||
|
||||
worker.onerror = function(e) {
|
||||
reject();
|
||||
};
|
||||
});
|
||||
},
|
||||
async _ => {
|
||||
|
|
|
@ -316,899 +316,6 @@ add_task(async function test_userScripts_no_webext_apis() {
|
|||
await extension.unload();
|
||||
});
|
||||
|
||||
// A small utility function used to test the expected behaviors of the userScripts API method
|
||||
// wrapper.
|
||||
async function test_userScript_APIMethod({
|
||||
apiScript, userScript, userScriptMetadata, testFn,
|
||||
runtimeMessageListener,
|
||||
}) {
|
||||
async function backgroundScript(userScriptFn, scriptMetadata, messageListener) {
|
||||
await browser.userScripts.register({
|
||||
js: [{
|
||||
code: `(${userScriptFn})();`,
|
||||
}],
|
||||
runAt: "document_end",
|
||||
matches: ["http://localhost/*/file_sample.html"],
|
||||
scriptMetadata,
|
||||
});
|
||||
|
||||
if (messageListener) {
|
||||
browser.runtime.onMessage.addListener(messageListener);
|
||||
}
|
||||
|
||||
browser.test.sendMessage("background-ready");
|
||||
}
|
||||
|
||||
function notifyFinish(failureReason) {
|
||||
browser.test.assertEq(undefined, failureReason, "should be completed without errors");
|
||||
browser.test.sendMessage("test_userScript_APIMethod:done");
|
||||
}
|
||||
|
||||
function assertTrue(val, message) {
|
||||
browser.test.assertTrue(val, message);
|
||||
if (!val) {
|
||||
browser.test.sendMessage("test_userScript_APIMethod:done");
|
||||
throw message;
|
||||
}
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: [
|
||||
"http://localhost/*/file_sample.html",
|
||||
],
|
||||
user_scripts: {
|
||||
api_script: "api-script.js",
|
||||
},
|
||||
},
|
||||
// Defines a background script that receives all the needed test parameters.
|
||||
background: `
|
||||
const metadata = ${JSON.stringify(userScriptMetadata)};
|
||||
(${backgroundScript})(${userScript}, metadata, ${runtimeMessageListener})
|
||||
`,
|
||||
files: {
|
||||
"api-script.js": `(${apiScript})({
|
||||
assertTrue: ${assertTrue},
|
||||
notifyFinish: ${notifyFinish}
|
||||
})`,
|
||||
},
|
||||
});
|
||||
|
||||
// Load a page in a content process, register the user script and then load a
|
||||
// new page in the existing content process.
|
||||
let url = `${BASE_URL}/file_sample.html`;
|
||||
let contentPage = await ExtensionTestUtils.loadContentPage(`about:blank`);
|
||||
|
||||
await extension.startup();
|
||||
await extension.awaitMessage("background-ready");
|
||||
await contentPage.loadURL(url);
|
||||
|
||||
// Run any additional test-specific assertions.
|
||||
if (testFn) {
|
||||
await testFn({extension, contentPage, url});
|
||||
}
|
||||
|
||||
await extension.awaitMessage("test_userScript_APIMethod:done");
|
||||
|
||||
await extension.unload();
|
||||
await contentPage.close();
|
||||
}
|
||||
|
||||
add_task(async function test_apiScript_exports_simple_sync_method() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
const scriptMetadata = script.metadata;
|
||||
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIMethod(stringParam, numberParam, boolParam, nullParam, undefinedParam, arrayParam) {
|
||||
browser.test.assertEq("test-user-script-exported-apis", scriptMetadata.name,
|
||||
"Got the expected value for a string scriptMetadata property");
|
||||
browser.test.assertEq(null, scriptMetadata.nullProperty,
|
||||
"Got the expected value for a null scriptMetadata property");
|
||||
browser.test.assertTrue(scriptMetadata.arrayProperty &&
|
||||
scriptMetadata.arrayProperty.length === 1 &&
|
||||
scriptMetadata.arrayProperty[0] === "el1",
|
||||
"Got the expected value for an array scriptMetadata property");
|
||||
browser.test.assertTrue(scriptMetadata.objectProperty &&
|
||||
scriptMetadata.objectProperty.nestedProp === "nestedValue",
|
||||
"Got the expected value for an object scriptMetadata property");
|
||||
|
||||
browser.test.assertEq("param1", stringParam, "Got the expected string parameter value");
|
||||
browser.test.assertEq(123, numberParam, "Got the expected number parameter value");
|
||||
browser.test.assertEq(true, boolParam, "Got the expected boolean parameter value");
|
||||
browser.test.assertEq(null, nullParam, "Got the expected null parameter value");
|
||||
browser.test.assertEq(undefined, undefinedParam, "Got the expected undefined parameter value");
|
||||
|
||||
browser.test.assertEq(3, arrayParam.length, "Got the expected length on the array param");
|
||||
browser.test.assertTrue(arrayParam.includes(1),
|
||||
"Got the expected result when calling arrayParam.includes");
|
||||
|
||||
return "returned_value";
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function userScript() {
|
||||
const {assertTrue, notifyFinish, testAPIMethod} = this;
|
||||
|
||||
// Redefine the includes method on the Array prototype, to explicitly verify that the method
|
||||
// redefined in the userScript is not used when accessing arrayParam.includes from the API script.
|
||||
Array.prototype.includes = () => { // eslint-disable-line no-extend-native
|
||||
throw new Error("Unexpected prototype leakage");
|
||||
};
|
||||
const arrayParam = new Array(1, 2, 3); // eslint-disable-line no-array-constructor
|
||||
const result = testAPIMethod("param1", 123, true, null, undefined, arrayParam);
|
||||
|
||||
assertTrue(result === "returned_value", `userScript got an unexpected result value: ${result}`);
|
||||
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
const userScriptMetadata = {
|
||||
name: "test-user-script-exported-apis",
|
||||
arrayProperty: ["el1"],
|
||||
objectProperty: {nestedProp: "nestedValue"},
|
||||
nullProperty: null,
|
||||
};
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
userScriptMetadata,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_async_method() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIMethod(param, cb, cb2, objWithCb) {
|
||||
browser.test.assertEq("function", typeof cb, "Got a callback function parameter");
|
||||
browser.test.assertTrue(cb === cb2, "Got the same cloned function for the same function parameter");
|
||||
|
||||
browser.runtime.sendMessage(param).then(bgPageRes => {
|
||||
const cbResult = cb(script.export(bgPageRes));
|
||||
browser.test.sendMessage("user-script-callback-return", cbResult);
|
||||
});
|
||||
|
||||
return "resolved_value";
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
// Redefine Promise to verify that it doesn't break the WebExtensions internals
|
||||
// that are going to use them.
|
||||
const {Promise} = this;
|
||||
Promise.resolve = function() {
|
||||
throw new Error("Promise.resolve poisoning");
|
||||
};
|
||||
this.Promise = function() {
|
||||
throw new Error("Promise constructor poisoning");
|
||||
};
|
||||
|
||||
const {assertTrue, notifyFinish, testAPIMethod} = this;
|
||||
|
||||
const cb = (cbParam) => {
|
||||
return `callback param: ${JSON.stringify(cbParam)}`;
|
||||
};
|
||||
const cb2 = cb;
|
||||
const asyncAPIResult = await testAPIMethod("param3", cb, cb2);
|
||||
|
||||
assertTrue(asyncAPIResult === "resolved_value",
|
||||
`userScript got an unexpected resolved value: ${asyncAPIResult}`);
|
||||
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
async function runtimeMessageListener(param) {
|
||||
if (param !== "param3") {
|
||||
browser.test.fail(`Got an unexpected message: ${param}`);
|
||||
}
|
||||
|
||||
return {bgPageReply: true};
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
runtimeMessageListener,
|
||||
async testFn({extension}) {
|
||||
const res = await extension.awaitMessage("user-script-callback-return");
|
||||
equal(res, `callback param: ${JSON.stringify({bgPageReply: true})}`,
|
||||
"Got the expected userScript callback return value");
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_method_with_webpage_objects_params() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIMethod(windowParam, documentParam) {
|
||||
browser.test.assertEq(window, windowParam, "Got a reference to the native window as first param");
|
||||
browser.test.assertEq(window.document, documentParam,
|
||||
"Got a reference to the native document as second param");
|
||||
|
||||
// Return an uncloneable webpage object, which checks that if the returned object is from a principal
|
||||
// that is subsumed by the userScript sandbox principal, it is returned without being cloned.
|
||||
return windowParam;
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
const {assertTrue, notifyFinish, testAPIMethod} = this;
|
||||
|
||||
const result = testAPIMethod(window, document);
|
||||
|
||||
// We expect the returned value to be the uncloneable window object.
|
||||
assertTrue(result === window,
|
||||
`userScript got an unexpected returned value: ${result}`);
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_method_got_param_with_methods() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
const scriptGlobal = script.global;
|
||||
const ScriptFunction = scriptGlobal.Function;
|
||||
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIMethod(objWithMethods) {
|
||||
browser.test.assertEq("objPropertyValue", objWithMethods && objWithMethods.objProperty,
|
||||
"Got the expected property on the object passed as a parameter");
|
||||
browser.test.assertEq(undefined, typeof objWithMethods && objWithMethods.objMethod,
|
||||
"XrayWrapper should deny access to a callable property");
|
||||
|
||||
browser.test.assertTrue(
|
||||
objWithMethods && objWithMethods.wrappedJSObject &&
|
||||
objWithMethods.wrappedJSObject.objMethod instanceof ScriptFunction.wrappedJSObject,
|
||||
"The callable property is accessible on the wrappedJSObject");
|
||||
|
||||
browser.test.assertEq("objMethodResult: p1", objWithMethods && objWithMethods.wrappedJSObject &&
|
||||
objWithMethods.wrappedJSObject.objMethod("p1"),
|
||||
"Got the expected result when calling the method on the wrappedJSObject");
|
||||
return true;
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
const {assertTrue, notifyFinish, testAPIMethod} = this;
|
||||
|
||||
let result = testAPIMethod({
|
||||
objProperty: "objPropertyValue",
|
||||
objMethod(param) {
|
||||
return `objMethodResult: ${param}`;
|
||||
},
|
||||
});
|
||||
|
||||
assertTrue(result === true, `userScript got an unexpected returned value: ${result}`);
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_method_throws_errors() {
|
||||
function apiScript({notifyFinish}) {
|
||||
let proxyTrapsCount = 0;
|
||||
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
const scriptGlobals = {
|
||||
Error: script.global.Error,
|
||||
TypeError: script.global.TypeError,
|
||||
Proxy: script.global.Proxy,
|
||||
};
|
||||
|
||||
script.defineGlobals({
|
||||
notifyFinish,
|
||||
testAPIMethod(errorTestName, returnRejectedPromise) {
|
||||
let err;
|
||||
|
||||
switch (errorTestName) {
|
||||
case "apiScriptError":
|
||||
err = new Error(`${errorTestName} message`);
|
||||
break;
|
||||
case "apiScriptThrowsPlainString":
|
||||
err = `${errorTestName} message`;
|
||||
break;
|
||||
case "apiScriptThrowsNull":
|
||||
err = null;
|
||||
break;
|
||||
case "userScriptError":
|
||||
err = new scriptGlobals.Error(`${errorTestName} message`);
|
||||
break;
|
||||
case "userScriptTypeError":
|
||||
err = new scriptGlobals.TypeError(`${errorTestName} message`);
|
||||
break;
|
||||
case "userScriptProxyObject":
|
||||
let proxyTarget = script.export({
|
||||
name: "ProxyObject", message: "ProxyObject message",
|
||||
});
|
||||
let proxyHandlers = script.export({
|
||||
get(target, prop) {
|
||||
proxyTrapsCount++;
|
||||
switch (prop) {
|
||||
case "name":
|
||||
return "ProxyObjectGetName";
|
||||
case "message":
|
||||
return "ProxyObjectGetMessage";
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
getPrototypeOf() {
|
||||
proxyTrapsCount++;
|
||||
return scriptGlobals.TypeError;
|
||||
},
|
||||
});
|
||||
err = new scriptGlobals.Proxy(proxyTarget, proxyHandlers);
|
||||
break;
|
||||
default:
|
||||
browser.test.fail(`Unknown ${errorTestName} error testname`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (returnRejectedPromise) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
|
||||
throw err;
|
||||
},
|
||||
assertNoProxyTrapTriggered() {
|
||||
browser.test.assertEq(0, proxyTrapsCount, "Proxy traps should not be triggered");
|
||||
},
|
||||
resetProxyTrapCounter() {
|
||||
proxyTrapsCount = 0;
|
||||
},
|
||||
sendResults(results) {
|
||||
browser.test.sendMessage("test-results", results);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
const {
|
||||
assertNoProxyTrapTriggered,
|
||||
notifyFinish,
|
||||
resetProxyTrapCounter,
|
||||
sendResults,
|
||||
testAPIMethod,
|
||||
} = this;
|
||||
|
||||
let apiThrowResults = {};
|
||||
let apiThrowTestCases = [
|
||||
"apiScriptError",
|
||||
"apiScriptThrowsPlainString",
|
||||
"apiScriptThrowsNull",
|
||||
"userScriptError",
|
||||
"userScriptTypeError",
|
||||
"userScriptProxyObject",
|
||||
];
|
||||
for (let errorTestName of apiThrowTestCases) {
|
||||
try {
|
||||
testAPIMethod(errorTestName);
|
||||
} catch (err) {
|
||||
// We expect that no proxy traps have been triggered by the WebExtensions internals.
|
||||
if (errorTestName === "userScriptProxyObject") {
|
||||
assertNoProxyTrapTriggered();
|
||||
}
|
||||
|
||||
if (err instanceof Error) {
|
||||
apiThrowResults[errorTestName] = {name: err.name, message: err.message};
|
||||
} else {
|
||||
apiThrowResults[errorTestName] = {
|
||||
name: err && err.name,
|
||||
message: err && err.message,
|
||||
typeOf: typeof err,
|
||||
value: err,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sendResults(apiThrowResults);
|
||||
|
||||
resetProxyTrapCounter();
|
||||
|
||||
let apiRejectsResults = {};
|
||||
for (let errorTestName of apiThrowTestCases) {
|
||||
try {
|
||||
await testAPIMethod(errorTestName, true);
|
||||
} catch (err) {
|
||||
// We expect that no proxy traps have been triggered by the WebExtensions internals.
|
||||
if (errorTestName === "userScriptProxyObject") {
|
||||
assertNoProxyTrapTriggered();
|
||||
}
|
||||
|
||||
if (err instanceof Error) {
|
||||
apiRejectsResults[errorTestName] = {name: err.name, message: err.message};
|
||||
} else {
|
||||
apiRejectsResults[errorTestName] = {
|
||||
name: err && err.name,
|
||||
message: err && err.message,
|
||||
typeOf: typeof err,
|
||||
value: err,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sendResults(apiRejectsResults);
|
||||
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
async testFn({extension}) {
|
||||
const expectedResults = {
|
||||
// Any error not explicitly raised as a userScript objects or error instance is
|
||||
// expected to be turned into a generic error message.
|
||||
"apiScriptError": {name: "Error", message: "An unexpected apiScript error occurred"},
|
||||
|
||||
// When the api script throws a primitive value, we expect to receive it unmodified on
|
||||
// the userScript side.
|
||||
"apiScriptThrowsPlainString": {
|
||||
typeOf: "string", value: "apiScriptThrowsPlainString message",
|
||||
name: undefined, message: undefined,
|
||||
},
|
||||
"apiScriptThrowsNull": {
|
||||
typeOf: "object", value: null,
|
||||
name: undefined, message: undefined,
|
||||
},
|
||||
|
||||
// Error messages that the apiScript has explicitly created as userScript's Error
|
||||
// global instances are expected to be passing through unmodified.
|
||||
"userScriptError": {name: "Error", message: "userScriptError message"},
|
||||
"userScriptTypeError": {name: "TypeError", message: "userScriptTypeError message"},
|
||||
|
||||
// Error raised from the apiScript as userScript proxy objects are expected to
|
||||
// be passing through unmodified.
|
||||
"userScriptProxyObject": {
|
||||
typeOf: "object", name: "ProxyObjectGetName", message: "ProxyObjectGetMessage",
|
||||
},
|
||||
};
|
||||
|
||||
info("Checking results from errors raised from an apiScript exported function");
|
||||
|
||||
const apiThrowResults = await extension.awaitMessage("test-results");
|
||||
|
||||
for (let [key, expected] of Object.entries(expectedResults)) {
|
||||
Assert.deepEqual(apiThrowResults[key], expected,
|
||||
`Got the expected error object for test case "${key}"`);
|
||||
}
|
||||
|
||||
Assert.deepEqual(Object.keys(expectedResults).sort(),
|
||||
Object.keys(apiThrowResults).sort(),
|
||||
"the expected and actual test case names matches");
|
||||
|
||||
info("Checking expected results from errors raised from an apiScript exported function");
|
||||
|
||||
// Verify expected results from rejected promises returned from an apiScript exported function.
|
||||
const apiThrowRejections = await extension.awaitMessage("test-results");
|
||||
|
||||
for (let [key, expected] of Object.entries(expectedResults)) {
|
||||
Assert.deepEqual(apiThrowRejections[key], expected,
|
||||
`Got the expected rejected object for test case "${key}"`);
|
||||
}
|
||||
|
||||
Assert.deepEqual(Object.keys(expectedResults).sort(),
|
||||
Object.keys(apiThrowRejections).sort(),
|
||||
"the expected and actual test case names matches");
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_method_ensure_xraywrapped_proxy_in_params() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIMethod(...args) {
|
||||
// Proxies are opaque when wrapped in Xrays, and the proto of an opaque object
|
||||
// is supposed to be Object.prototype.
|
||||
browser.test.assertEq(
|
||||
script.global.Object.prototype,
|
||||
Object.getPrototypeOf(args[0]),
|
||||
"Calling getPrototypeOf on the XrayWrapped proxy object doesn't run the proxy trap");
|
||||
|
||||
browser.test.assertTrue(Array.isArray(args[0]),
|
||||
"Got an array object for the XrayWrapped proxy object param");
|
||||
browser.test.assertEq(undefined, args[0].length,
|
||||
"XrayWrappers deny access to the length property");
|
||||
browser.test.assertEq(undefined, args[0][0],
|
||||
"Got the expected item in the array object");
|
||||
return true;
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
const {
|
||||
assertTrue,
|
||||
notifyFinish,
|
||||
testAPIMethod,
|
||||
} = this;
|
||||
|
||||
let proxy = new Proxy(["expectedArrayValue"], {
|
||||
getPrototypeOf() {
|
||||
throw new Error("Proxy's getPrototypeOf trap");
|
||||
},
|
||||
get(target, prop, receiver) {
|
||||
throw new Error("Proxy's get trap");
|
||||
},
|
||||
});
|
||||
|
||||
let result = testAPIMethod(proxy);
|
||||
|
||||
assertTrue(result, `userScript got an unexpected returned value: ${result}`);
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_method_return_proxy_object() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
let proxyTrapsCount = 0;
|
||||
let scriptTrapsCount = 0;
|
||||
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIMethodError() {
|
||||
return new Proxy(["expectedArrayValue"], {
|
||||
getPrototypeOf(target) {
|
||||
proxyTrapsCount++;
|
||||
return Object.getPrototypeOf(target);
|
||||
},
|
||||
});
|
||||
},
|
||||
testAPIMethodOk() {
|
||||
return new script.global.Proxy(
|
||||
script.export(["expectedArrayValue"]),
|
||||
script.export({
|
||||
getPrototypeOf(target) {
|
||||
scriptTrapsCount++;
|
||||
return script.global.Object.getPrototypeOf(target);
|
||||
},
|
||||
}));
|
||||
},
|
||||
assertNoProxyTrapTriggered() {
|
||||
browser.test.assertEq(0, proxyTrapsCount, "Proxy traps should not be triggered");
|
||||
},
|
||||
assertScriptProxyTrapsCount(expected) {
|
||||
browser.test.assertEq(expected, scriptTrapsCount, "Script Proxy traps should have been triggered");
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
const {
|
||||
assertTrue,
|
||||
assertNoProxyTrapTriggered,
|
||||
assertScriptProxyTrapsCount,
|
||||
notifyFinish,
|
||||
testAPIMethodError,
|
||||
testAPIMethodOk,
|
||||
} = this;
|
||||
|
||||
let error;
|
||||
try {
|
||||
let result = testAPIMethodError();
|
||||
notifyFinish(`Unexpected returned value while expecting error: ${result}`);
|
||||
return;
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assertTrue(error && error.message.includes("Return value not accessible to the userScript"),
|
||||
`Got an unexpected error message: ${error}`);
|
||||
|
||||
error = undefined;
|
||||
try {
|
||||
let result = testAPIMethodOk();
|
||||
assertScriptProxyTrapsCount(0);
|
||||
if (!(result instanceof Array)) {
|
||||
notifyFinish(`Got an unexpected result: ${result}`);
|
||||
return;
|
||||
}
|
||||
assertScriptProxyTrapsCount(1);
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assertTrue(!error, `Got an unexpected error: ${error}`);
|
||||
|
||||
assertNoProxyTrapTriggered();
|
||||
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_returns_functions() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIReturnsFunction() {
|
||||
// Return a function with provides the same kind of behavior
|
||||
// of the API methods exported as globals.
|
||||
return script.export(() => window);
|
||||
},
|
||||
testAPIReturnsObjWithMethod() {
|
||||
return script.export({
|
||||
getWindow() {
|
||||
return window;
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
const {
|
||||
assertTrue,
|
||||
notifyFinish,
|
||||
testAPIReturnsFunction,
|
||||
testAPIReturnsObjWithMethod,
|
||||
} = this;
|
||||
|
||||
let resultFn = testAPIReturnsFunction();
|
||||
assertTrue(typeof resultFn === "function",
|
||||
`userScript got an unexpected returned value: ${typeof resultFn}`);
|
||||
|
||||
let fnRes = resultFn();
|
||||
assertTrue(fnRes === window,
|
||||
`Got an unexpected value from the returned function: ${fnRes}`);
|
||||
|
||||
let resultObj = testAPIReturnsObjWithMethod();
|
||||
let actualTypeof = resultObj && typeof resultObj.getWindow;
|
||||
assertTrue(actualTypeof === "function",
|
||||
`Returned object does not have the expected getWindow method: ${actualTypeof}`);
|
||||
|
||||
let methodRes = resultObj.getWindow();
|
||||
assertTrue(methodRes === window,
|
||||
`Got an unexpected value from the returned method: ${methodRes}`);
|
||||
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_method_clone_non_subsumed_returned_values() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIMethodReturnOk() {
|
||||
return script.export({
|
||||
objKey1: {
|
||||
nestedProp: "nestedvalue",
|
||||
},
|
||||
window,
|
||||
});
|
||||
},
|
||||
testAPIMethodExplicitlyClonedError() {
|
||||
let result = script.export({apiScopeObject: undefined});
|
||||
|
||||
browser.test.assertThrows(
|
||||
() => {
|
||||
result.apiScopeObject = {disallowedProp: "disallowedValue"};
|
||||
},
|
||||
/Not allowed to define cross-origin object as property on .* XrayWrapper/,
|
||||
"Assigning a property to a xRayWrapper is expected to throw");
|
||||
|
||||
// Let the exception to be raised, so that we check that the actual underlying
|
||||
// error message is not leaking in the userScript (replaced by the generic
|
||||
// "An unexpected apiScript error occurred" error message).
|
||||
result.apiScopeObject = {disallowedProp: "disallowedValue"};
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
const {
|
||||
assertTrue,
|
||||
notifyFinish,
|
||||
testAPIMethodReturnOk,
|
||||
testAPIMethodExplicitlyClonedError,
|
||||
} = this;
|
||||
|
||||
let result = testAPIMethodReturnOk();
|
||||
|
||||
assertTrue(result && ("objKey1" in result) && result.objKey1.nestedProp === "nestedvalue",
|
||||
`userScript got an unexpected returned value: ${result}`);
|
||||
|
||||
assertTrue(result.window === window,
|
||||
`userScript should have access to the window property: ${result.window}`);
|
||||
|
||||
let error;
|
||||
try {
|
||||
result = testAPIMethodExplicitlyClonedError();
|
||||
notifyFinish(`Unexpected returned value while expecting error: ${result}`);
|
||||
return;
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
// We expect the generic "unexpected apiScript error occurred" to be raised to the
|
||||
// userScript code.
|
||||
assertTrue(error && error.message.includes("An unexpected apiScript error occurred"),
|
||||
`Got an unexpected error message: ${error}`);
|
||||
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_method_export_primitive_types() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIMethod(typeToExport) {
|
||||
switch (typeToExport) {
|
||||
case "boolean": return script.export(true);
|
||||
case "number": return script.export(123);
|
||||
case "string": return script.export("a string");
|
||||
case "symbol": return script.export(Symbol("a symbol"));
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
const {assertTrue, notifyFinish, testAPIMethod} = this;
|
||||
|
||||
let v = testAPIMethod("boolean");
|
||||
assertTrue(v === true, `Should export a boolean`);
|
||||
|
||||
v = testAPIMethod("number");
|
||||
assertTrue(v === 123, `Should export a number`);
|
||||
|
||||
v = testAPIMethod("string");
|
||||
assertTrue(v === "a string", `Should export a string`);
|
||||
|
||||
v = testAPIMethod("symbol");
|
||||
assertTrue(typeof v === "symbol", `Should export a symbol`);
|
||||
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_method_avoid_unnecessary_params_cloning() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIMethodReturnsParam(param) {
|
||||
return param;
|
||||
},
|
||||
testAPIMethodReturnsUnwrappedParam(param) {
|
||||
return param.wrappedJSObject;
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
const {
|
||||
assertTrue,
|
||||
notifyFinish,
|
||||
testAPIMethodReturnsParam,
|
||||
testAPIMethodReturnsUnwrappedParam,
|
||||
} = this;
|
||||
|
||||
let obj = {};
|
||||
|
||||
let result = testAPIMethodReturnsParam(obj);
|
||||
|
||||
assertTrue(result === obj,
|
||||
`Expect returned value to be strictly equal to the API method parameter`);
|
||||
|
||||
result = testAPIMethodReturnsUnwrappedParam(obj);
|
||||
|
||||
assertTrue(result === obj,
|
||||
`Expect returned value to be strictly equal to the unwrapped API method parameter`);
|
||||
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_method_export_sparse_arrays() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIMethod() {
|
||||
const sparseArray = [];
|
||||
sparseArray[3] = "third-element";
|
||||
sparseArray[5] = "fifth-element";
|
||||
return script.export(sparseArray);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
const {assertTrue, notifyFinish, testAPIMethod} = this;
|
||||
|
||||
const result = testAPIMethod(window, document);
|
||||
|
||||
// We expect the returned value to be the uncloneable window object.
|
||||
assertTrue(result && result.length === 6,
|
||||
`the returned value should be an array of the expected length: ${result}`);
|
||||
assertTrue(result[3] === "third-element",
|
||||
`the third array element should have the expected value: ${result[3]}`);
|
||||
assertTrue(result[5] === "fifth-element",
|
||||
`the fifth array element should have the expected value: ${result[5]}`);
|
||||
assertTrue(result[0] === undefined,
|
||||
`the first array element should have the expected value: ${result[0]}`);
|
||||
assertTrue(!("0" in result), "Holey array should still be holey");
|
||||
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
});
|
||||
});
|
||||
|
||||
// This test verify that a cached script is still able to catch the document
|
||||
// while it is still loading (when we do not block the document parsing as
|
||||
// we do for a non cached script).
|
||||
|
|
|
@ -0,0 +1,907 @@
|
|||
"use strict";
|
||||
|
||||
const {
|
||||
createAppInfo,
|
||||
} = AddonTestUtils;
|
||||
|
||||
AddonTestUtils.init(this);
|
||||
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "49");
|
||||
|
||||
const server = createHttpServer();
|
||||
server.registerDirectory("/data/", do_get_file("data"));
|
||||
|
||||
const BASE_URL = `http://localhost:${server.identity.primaryPort}/data`;
|
||||
|
||||
// A small utility function used to test the expected behaviors of the userScripts API method
|
||||
// wrapper.
|
||||
async function test_userScript_APIMethod({
|
||||
apiScript, userScript, userScriptMetadata, testFn,
|
||||
runtimeMessageListener,
|
||||
}) {
|
||||
async function backgroundScript(userScriptFn, scriptMetadata, messageListener) {
|
||||
await browser.userScripts.register({
|
||||
js: [{
|
||||
code: `(${userScriptFn})();`,
|
||||
}],
|
||||
runAt: "document_end",
|
||||
matches: ["http://localhost/*/file_sample.html"],
|
||||
scriptMetadata,
|
||||
});
|
||||
|
||||
if (messageListener) {
|
||||
browser.runtime.onMessage.addListener(messageListener);
|
||||
}
|
||||
|
||||
browser.test.sendMessage("background-ready");
|
||||
}
|
||||
|
||||
function notifyFinish(failureReason) {
|
||||
browser.test.assertEq(undefined, failureReason, "should be completed without errors");
|
||||
browser.test.sendMessage("test_userScript_APIMethod:done");
|
||||
}
|
||||
|
||||
function assertTrue(val, message) {
|
||||
browser.test.assertTrue(val, message);
|
||||
if (!val) {
|
||||
browser.test.sendMessage("test_userScript_APIMethod:done");
|
||||
throw message;
|
||||
}
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: [
|
||||
"http://localhost/*/file_sample.html",
|
||||
],
|
||||
user_scripts: {
|
||||
api_script: "api-script.js",
|
||||
},
|
||||
},
|
||||
// Defines a background script that receives all the needed test parameters.
|
||||
background: `
|
||||
const metadata = ${JSON.stringify(userScriptMetadata)};
|
||||
(${backgroundScript})(${userScript}, metadata, ${runtimeMessageListener})
|
||||
`,
|
||||
files: {
|
||||
"api-script.js": `(${apiScript})({
|
||||
assertTrue: ${assertTrue},
|
||||
notifyFinish: ${notifyFinish}
|
||||
})`,
|
||||
},
|
||||
});
|
||||
|
||||
// Load a page in a content process, register the user script and then load a
|
||||
// new page in the existing content process.
|
||||
let url = `${BASE_URL}/file_sample.html`;
|
||||
let contentPage = await ExtensionTestUtils.loadContentPage(`about:blank`);
|
||||
|
||||
await extension.startup();
|
||||
await extension.awaitMessage("background-ready");
|
||||
await contentPage.loadURL(url);
|
||||
|
||||
// Run any additional test-specific assertions.
|
||||
if (testFn) {
|
||||
await testFn({extension, contentPage, url});
|
||||
}
|
||||
|
||||
await extension.awaitMessage("test_userScript_APIMethod:done");
|
||||
|
||||
await extension.unload();
|
||||
await contentPage.close();
|
||||
}
|
||||
|
||||
add_task(async function test_apiScript_exports_simple_sync_method() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
const scriptMetadata = script.metadata;
|
||||
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIMethod(stringParam, numberParam, boolParam, nullParam, undefinedParam, arrayParam) {
|
||||
browser.test.assertEq("test-user-script-exported-apis", scriptMetadata.name,
|
||||
"Got the expected value for a string scriptMetadata property");
|
||||
browser.test.assertEq(null, scriptMetadata.nullProperty,
|
||||
"Got the expected value for a null scriptMetadata property");
|
||||
browser.test.assertTrue(scriptMetadata.arrayProperty &&
|
||||
scriptMetadata.arrayProperty.length === 1 &&
|
||||
scriptMetadata.arrayProperty[0] === "el1",
|
||||
"Got the expected value for an array scriptMetadata property");
|
||||
browser.test.assertTrue(scriptMetadata.objectProperty &&
|
||||
scriptMetadata.objectProperty.nestedProp === "nestedValue",
|
||||
"Got the expected value for an object scriptMetadata property");
|
||||
|
||||
browser.test.assertEq("param1", stringParam, "Got the expected string parameter value");
|
||||
browser.test.assertEq(123, numberParam, "Got the expected number parameter value");
|
||||
browser.test.assertEq(true, boolParam, "Got the expected boolean parameter value");
|
||||
browser.test.assertEq(null, nullParam, "Got the expected null parameter value");
|
||||
browser.test.assertEq(undefined, undefinedParam, "Got the expected undefined parameter value");
|
||||
|
||||
browser.test.assertEq(3, arrayParam.length, "Got the expected length on the array param");
|
||||
browser.test.assertTrue(arrayParam.includes(1),
|
||||
"Got the expected result when calling arrayParam.includes");
|
||||
|
||||
return "returned_value";
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function userScript() {
|
||||
const {assertTrue, notifyFinish, testAPIMethod} = this;
|
||||
|
||||
// Redefine the includes method on the Array prototype, to explicitly verify that the method
|
||||
// redefined in the userScript is not used when accessing arrayParam.includes from the API script.
|
||||
Array.prototype.includes = () => { // eslint-disable-line no-extend-native
|
||||
throw new Error("Unexpected prototype leakage");
|
||||
};
|
||||
const arrayParam = new Array(1, 2, 3); // eslint-disable-line no-array-constructor
|
||||
const result = testAPIMethod("param1", 123, true, null, undefined, arrayParam);
|
||||
|
||||
assertTrue(result === "returned_value", `userScript got an unexpected result value: ${result}`);
|
||||
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
const userScriptMetadata = {
|
||||
name: "test-user-script-exported-apis",
|
||||
arrayProperty: ["el1"],
|
||||
objectProperty: {nestedProp: "nestedValue"},
|
||||
nullProperty: null,
|
||||
};
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
userScriptMetadata,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_async_method() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIMethod(param, cb, cb2, objWithCb) {
|
||||
browser.test.assertEq("function", typeof cb, "Got a callback function parameter");
|
||||
browser.test.assertTrue(cb === cb2, "Got the same cloned function for the same function parameter");
|
||||
|
||||
browser.runtime.sendMessage(param).then(bgPageRes => {
|
||||
const cbResult = cb(script.export(bgPageRes));
|
||||
browser.test.sendMessage("user-script-callback-return", cbResult);
|
||||
});
|
||||
|
||||
return "resolved_value";
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
// Redefine Promise to verify that it doesn't break the WebExtensions internals
|
||||
// that are going to use them.
|
||||
const {Promise} = this;
|
||||
Promise.resolve = function() {
|
||||
throw new Error("Promise.resolve poisoning");
|
||||
};
|
||||
this.Promise = function() {
|
||||
throw new Error("Promise constructor poisoning");
|
||||
};
|
||||
|
||||
const {assertTrue, notifyFinish, testAPIMethod} = this;
|
||||
|
||||
const cb = (cbParam) => {
|
||||
return `callback param: ${JSON.stringify(cbParam)}`;
|
||||
};
|
||||
const cb2 = cb;
|
||||
const asyncAPIResult = await testAPIMethod("param3", cb, cb2);
|
||||
|
||||
assertTrue(asyncAPIResult === "resolved_value",
|
||||
`userScript got an unexpected resolved value: ${asyncAPIResult}`);
|
||||
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
async function runtimeMessageListener(param) {
|
||||
if (param !== "param3") {
|
||||
browser.test.fail(`Got an unexpected message: ${param}`);
|
||||
}
|
||||
|
||||
return {bgPageReply: true};
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
runtimeMessageListener,
|
||||
async testFn({extension}) {
|
||||
const res = await extension.awaitMessage("user-script-callback-return");
|
||||
equal(res, `callback param: ${JSON.stringify({bgPageReply: true})}`,
|
||||
"Got the expected userScript callback return value");
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_method_with_webpage_objects_params() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIMethod(windowParam, documentParam) {
|
||||
browser.test.assertEq(window, windowParam, "Got a reference to the native window as first param");
|
||||
browser.test.assertEq(window.document, documentParam,
|
||||
"Got a reference to the native document as second param");
|
||||
|
||||
// Return an uncloneable webpage object, which checks that if the returned object is from a principal
|
||||
// that is subsumed by the userScript sandbox principal, it is returned without being cloned.
|
||||
return windowParam;
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
const {assertTrue, notifyFinish, testAPIMethod} = this;
|
||||
|
||||
const result = testAPIMethod(window, document);
|
||||
|
||||
// We expect the returned value to be the uncloneable window object.
|
||||
assertTrue(result === window,
|
||||
`userScript got an unexpected returned value: ${result}`);
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_method_got_param_with_methods() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
const scriptGlobal = script.global;
|
||||
const ScriptFunction = scriptGlobal.Function;
|
||||
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIMethod(objWithMethods) {
|
||||
browser.test.assertEq("objPropertyValue", objWithMethods && objWithMethods.objProperty,
|
||||
"Got the expected property on the object passed as a parameter");
|
||||
browser.test.assertEq(undefined, typeof objWithMethods && objWithMethods.objMethod,
|
||||
"XrayWrapper should deny access to a callable property");
|
||||
|
||||
browser.test.assertTrue(
|
||||
objWithMethods && objWithMethods.wrappedJSObject &&
|
||||
objWithMethods.wrappedJSObject.objMethod instanceof ScriptFunction.wrappedJSObject,
|
||||
"The callable property is accessible on the wrappedJSObject");
|
||||
|
||||
browser.test.assertEq("objMethodResult: p1", objWithMethods && objWithMethods.wrappedJSObject &&
|
||||
objWithMethods.wrappedJSObject.objMethod("p1"),
|
||||
"Got the expected result when calling the method on the wrappedJSObject");
|
||||
return true;
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
const {assertTrue, notifyFinish, testAPIMethod} = this;
|
||||
|
||||
let result = testAPIMethod({
|
||||
objProperty: "objPropertyValue",
|
||||
objMethod(param) {
|
||||
return `objMethodResult: ${param}`;
|
||||
},
|
||||
});
|
||||
|
||||
assertTrue(result === true, `userScript got an unexpected returned value: ${result}`);
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_method_throws_errors() {
|
||||
function apiScript({notifyFinish}) {
|
||||
let proxyTrapsCount = 0;
|
||||
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
const scriptGlobals = {
|
||||
Error: script.global.Error,
|
||||
TypeError: script.global.TypeError,
|
||||
Proxy: script.global.Proxy,
|
||||
};
|
||||
|
||||
script.defineGlobals({
|
||||
notifyFinish,
|
||||
testAPIMethod(errorTestName, returnRejectedPromise) {
|
||||
let err;
|
||||
|
||||
switch (errorTestName) {
|
||||
case "apiScriptError":
|
||||
err = new Error(`${errorTestName} message`);
|
||||
break;
|
||||
case "apiScriptThrowsPlainString":
|
||||
err = `${errorTestName} message`;
|
||||
break;
|
||||
case "apiScriptThrowsNull":
|
||||
err = null;
|
||||
break;
|
||||
case "userScriptError":
|
||||
err = new scriptGlobals.Error(`${errorTestName} message`);
|
||||
break;
|
||||
case "userScriptTypeError":
|
||||
err = new scriptGlobals.TypeError(`${errorTestName} message`);
|
||||
break;
|
||||
case "userScriptProxyObject":
|
||||
let proxyTarget = script.export({
|
||||
name: "ProxyObject", message: "ProxyObject message",
|
||||
});
|
||||
let proxyHandlers = script.export({
|
||||
get(target, prop) {
|
||||
proxyTrapsCount++;
|
||||
switch (prop) {
|
||||
case "name":
|
||||
return "ProxyObjectGetName";
|
||||
case "message":
|
||||
return "ProxyObjectGetMessage";
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
getPrototypeOf() {
|
||||
proxyTrapsCount++;
|
||||
return scriptGlobals.TypeError;
|
||||
},
|
||||
});
|
||||
err = new scriptGlobals.Proxy(proxyTarget, proxyHandlers);
|
||||
break;
|
||||
default:
|
||||
browser.test.fail(`Unknown ${errorTestName} error testname`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (returnRejectedPromise) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
|
||||
throw err;
|
||||
},
|
||||
assertNoProxyTrapTriggered() {
|
||||
browser.test.assertEq(0, proxyTrapsCount, "Proxy traps should not be triggered");
|
||||
},
|
||||
resetProxyTrapCounter() {
|
||||
proxyTrapsCount = 0;
|
||||
},
|
||||
sendResults(results) {
|
||||
browser.test.sendMessage("test-results", results);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
const {
|
||||
assertNoProxyTrapTriggered,
|
||||
notifyFinish,
|
||||
resetProxyTrapCounter,
|
||||
sendResults,
|
||||
testAPIMethod,
|
||||
} = this;
|
||||
|
||||
let apiThrowResults = {};
|
||||
let apiThrowTestCases = [
|
||||
"apiScriptError",
|
||||
"apiScriptThrowsPlainString",
|
||||
"apiScriptThrowsNull",
|
||||
"userScriptError",
|
||||
"userScriptTypeError",
|
||||
"userScriptProxyObject",
|
||||
];
|
||||
for (let errorTestName of apiThrowTestCases) {
|
||||
try {
|
||||
testAPIMethod(errorTestName);
|
||||
} catch (err) {
|
||||
// We expect that no proxy traps have been triggered by the WebExtensions internals.
|
||||
if (errorTestName === "userScriptProxyObject") {
|
||||
assertNoProxyTrapTriggered();
|
||||
}
|
||||
|
||||
if (err instanceof Error) {
|
||||
apiThrowResults[errorTestName] = {name: err.name, message: err.message};
|
||||
} else {
|
||||
apiThrowResults[errorTestName] = {
|
||||
name: err && err.name,
|
||||
message: err && err.message,
|
||||
typeOf: typeof err,
|
||||
value: err,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sendResults(apiThrowResults);
|
||||
|
||||
resetProxyTrapCounter();
|
||||
|
||||
let apiRejectsResults = {};
|
||||
for (let errorTestName of apiThrowTestCases) {
|
||||
try {
|
||||
await testAPIMethod(errorTestName, true);
|
||||
} catch (err) {
|
||||
// We expect that no proxy traps have been triggered by the WebExtensions internals.
|
||||
if (errorTestName === "userScriptProxyObject") {
|
||||
assertNoProxyTrapTriggered();
|
||||
}
|
||||
|
||||
if (err instanceof Error) {
|
||||
apiRejectsResults[errorTestName] = {name: err.name, message: err.message};
|
||||
} else {
|
||||
apiRejectsResults[errorTestName] = {
|
||||
name: err && err.name,
|
||||
message: err && err.message,
|
||||
typeOf: typeof err,
|
||||
value: err,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sendResults(apiRejectsResults);
|
||||
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
async testFn({extension}) {
|
||||
const expectedResults = {
|
||||
// Any error not explicitly raised as a userScript objects or error instance is
|
||||
// expected to be turned into a generic error message.
|
||||
"apiScriptError": {name: "Error", message: "An unexpected apiScript error occurred"},
|
||||
|
||||
// When the api script throws a primitive value, we expect to receive it unmodified on
|
||||
// the userScript side.
|
||||
"apiScriptThrowsPlainString": {
|
||||
typeOf: "string", value: "apiScriptThrowsPlainString message",
|
||||
name: undefined, message: undefined,
|
||||
},
|
||||
"apiScriptThrowsNull": {
|
||||
typeOf: "object", value: null,
|
||||
name: undefined, message: undefined,
|
||||
},
|
||||
|
||||
// Error messages that the apiScript has explicitly created as userScript's Error
|
||||
// global instances are expected to be passing through unmodified.
|
||||
"userScriptError": {name: "Error", message: "userScriptError message"},
|
||||
"userScriptTypeError": {name: "TypeError", message: "userScriptTypeError message"},
|
||||
|
||||
// Error raised from the apiScript as userScript proxy objects are expected to
|
||||
// be passing through unmodified.
|
||||
"userScriptProxyObject": {
|
||||
typeOf: "object", name: "ProxyObjectGetName", message: "ProxyObjectGetMessage",
|
||||
},
|
||||
};
|
||||
|
||||
info("Checking results from errors raised from an apiScript exported function");
|
||||
|
||||
const apiThrowResults = await extension.awaitMessage("test-results");
|
||||
|
||||
for (let [key, expected] of Object.entries(expectedResults)) {
|
||||
Assert.deepEqual(apiThrowResults[key], expected,
|
||||
`Got the expected error object for test case "${key}"`);
|
||||
}
|
||||
|
||||
Assert.deepEqual(Object.keys(expectedResults).sort(),
|
||||
Object.keys(apiThrowResults).sort(),
|
||||
"the expected and actual test case names matches");
|
||||
|
||||
info("Checking expected results from errors raised from an apiScript exported function");
|
||||
|
||||
// Verify expected results from rejected promises returned from an apiScript exported function.
|
||||
const apiThrowRejections = await extension.awaitMessage("test-results");
|
||||
|
||||
for (let [key, expected] of Object.entries(expectedResults)) {
|
||||
Assert.deepEqual(apiThrowRejections[key], expected,
|
||||
`Got the expected rejected object for test case "${key}"`);
|
||||
}
|
||||
|
||||
Assert.deepEqual(Object.keys(expectedResults).sort(),
|
||||
Object.keys(apiThrowRejections).sort(),
|
||||
"the expected and actual test case names matches");
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_method_ensure_xraywrapped_proxy_in_params() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIMethod(...args) {
|
||||
// Proxies are opaque when wrapped in Xrays, and the proto of an opaque object
|
||||
// is supposed to be Object.prototype.
|
||||
browser.test.assertEq(
|
||||
script.global.Object.prototype,
|
||||
Object.getPrototypeOf(args[0]),
|
||||
"Calling getPrototypeOf on the XrayWrapped proxy object doesn't run the proxy trap");
|
||||
|
||||
browser.test.assertTrue(Array.isArray(args[0]),
|
||||
"Got an array object for the XrayWrapped proxy object param");
|
||||
browser.test.assertEq(undefined, args[0].length,
|
||||
"XrayWrappers deny access to the length property");
|
||||
browser.test.assertEq(undefined, args[0][0],
|
||||
"Got the expected item in the array object");
|
||||
return true;
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
const {
|
||||
assertTrue,
|
||||
notifyFinish,
|
||||
testAPIMethod,
|
||||
} = this;
|
||||
|
||||
let proxy = new Proxy(["expectedArrayValue"], {
|
||||
getPrototypeOf() {
|
||||
throw new Error("Proxy's getPrototypeOf trap");
|
||||
},
|
||||
get(target, prop, receiver) {
|
||||
throw new Error("Proxy's get trap");
|
||||
},
|
||||
});
|
||||
|
||||
let result = testAPIMethod(proxy);
|
||||
|
||||
assertTrue(result, `userScript got an unexpected returned value: ${result}`);
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_method_return_proxy_object() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
let proxyTrapsCount = 0;
|
||||
let scriptTrapsCount = 0;
|
||||
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIMethodError() {
|
||||
return new Proxy(["expectedArrayValue"], {
|
||||
getPrototypeOf(target) {
|
||||
proxyTrapsCount++;
|
||||
return Object.getPrototypeOf(target);
|
||||
},
|
||||
});
|
||||
},
|
||||
testAPIMethodOk() {
|
||||
return new script.global.Proxy(
|
||||
script.export(["expectedArrayValue"]),
|
||||
script.export({
|
||||
getPrototypeOf(target) {
|
||||
scriptTrapsCount++;
|
||||
return script.global.Object.getPrototypeOf(target);
|
||||
},
|
||||
}));
|
||||
},
|
||||
assertNoProxyTrapTriggered() {
|
||||
browser.test.assertEq(0, proxyTrapsCount, "Proxy traps should not be triggered");
|
||||
},
|
||||
assertScriptProxyTrapsCount(expected) {
|
||||
browser.test.assertEq(expected, scriptTrapsCount, "Script Proxy traps should have been triggered");
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
const {
|
||||
assertTrue,
|
||||
assertNoProxyTrapTriggered,
|
||||
assertScriptProxyTrapsCount,
|
||||
notifyFinish,
|
||||
testAPIMethodError,
|
||||
testAPIMethodOk,
|
||||
} = this;
|
||||
|
||||
let error;
|
||||
try {
|
||||
let result = testAPIMethodError();
|
||||
notifyFinish(`Unexpected returned value while expecting error: ${result}`);
|
||||
return;
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assertTrue(error && error.message.includes("Return value not accessible to the userScript"),
|
||||
`Got an unexpected error message: ${error}`);
|
||||
|
||||
error = undefined;
|
||||
try {
|
||||
let result = testAPIMethodOk();
|
||||
assertScriptProxyTrapsCount(0);
|
||||
if (!(result instanceof Array)) {
|
||||
notifyFinish(`Got an unexpected result: ${result}`);
|
||||
return;
|
||||
}
|
||||
assertScriptProxyTrapsCount(1);
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assertTrue(!error, `Got an unexpected error: ${error}`);
|
||||
|
||||
assertNoProxyTrapTriggered();
|
||||
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_returns_functions() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIReturnsFunction() {
|
||||
// Return a function with provides the same kind of behavior
|
||||
// of the API methods exported as globals.
|
||||
return script.export(() => window);
|
||||
},
|
||||
testAPIReturnsObjWithMethod() {
|
||||
return script.export({
|
||||
getWindow() {
|
||||
return window;
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
const {
|
||||
assertTrue,
|
||||
notifyFinish,
|
||||
testAPIReturnsFunction,
|
||||
testAPIReturnsObjWithMethod,
|
||||
} = this;
|
||||
|
||||
let resultFn = testAPIReturnsFunction();
|
||||
assertTrue(typeof resultFn === "function",
|
||||
`userScript got an unexpected returned value: ${typeof resultFn}`);
|
||||
|
||||
let fnRes = resultFn();
|
||||
assertTrue(fnRes === window,
|
||||
`Got an unexpected value from the returned function: ${fnRes}`);
|
||||
|
||||
let resultObj = testAPIReturnsObjWithMethod();
|
||||
let actualTypeof = resultObj && typeof resultObj.getWindow;
|
||||
assertTrue(actualTypeof === "function",
|
||||
`Returned object does not have the expected getWindow method: ${actualTypeof}`);
|
||||
|
||||
let methodRes = resultObj.getWindow();
|
||||
assertTrue(methodRes === window,
|
||||
`Got an unexpected value from the returned method: ${methodRes}`);
|
||||
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_method_clone_non_subsumed_returned_values() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIMethodReturnOk() {
|
||||
return script.export({
|
||||
objKey1: {
|
||||
nestedProp: "nestedvalue",
|
||||
},
|
||||
window,
|
||||
});
|
||||
},
|
||||
testAPIMethodExplicitlyClonedError() {
|
||||
let result = script.export({apiScopeObject: undefined});
|
||||
|
||||
browser.test.assertThrows(
|
||||
() => {
|
||||
result.apiScopeObject = {disallowedProp: "disallowedValue"};
|
||||
},
|
||||
/Not allowed to define cross-origin object as property on .* XrayWrapper/,
|
||||
"Assigning a property to a xRayWrapper is expected to throw");
|
||||
|
||||
// Let the exception to be raised, so that we check that the actual underlying
|
||||
// error message is not leaking in the userScript (replaced by the generic
|
||||
// "An unexpected apiScript error occurred" error message).
|
||||
result.apiScopeObject = {disallowedProp: "disallowedValue"};
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
const {
|
||||
assertTrue,
|
||||
notifyFinish,
|
||||
testAPIMethodReturnOk,
|
||||
testAPIMethodExplicitlyClonedError,
|
||||
} = this;
|
||||
|
||||
let result = testAPIMethodReturnOk();
|
||||
|
||||
assertTrue(result && ("objKey1" in result) && result.objKey1.nestedProp === "nestedvalue",
|
||||
`userScript got an unexpected returned value: ${result}`);
|
||||
|
||||
assertTrue(result.window === window,
|
||||
`userScript should have access to the window property: ${result.window}`);
|
||||
|
||||
let error;
|
||||
try {
|
||||
result = testAPIMethodExplicitlyClonedError();
|
||||
notifyFinish(`Unexpected returned value while expecting error: ${result}`);
|
||||
return;
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
// We expect the generic "unexpected apiScript error occurred" to be raised to the
|
||||
// userScript code.
|
||||
assertTrue(error && error.message.includes("An unexpected apiScript error occurred"),
|
||||
`Got an unexpected error message: ${error}`);
|
||||
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_method_export_primitive_types() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIMethod(typeToExport) {
|
||||
switch (typeToExport) {
|
||||
case "boolean": return script.export(true);
|
||||
case "number": return script.export(123);
|
||||
case "string": return script.export("a string");
|
||||
case "symbol": return script.export(Symbol("a symbol"));
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
const {assertTrue, notifyFinish, testAPIMethod} = this;
|
||||
|
||||
let v = testAPIMethod("boolean");
|
||||
assertTrue(v === true, `Should export a boolean`);
|
||||
|
||||
v = testAPIMethod("number");
|
||||
assertTrue(v === 123, `Should export a number`);
|
||||
|
||||
v = testAPIMethod("string");
|
||||
assertTrue(v === "a string", `Should export a string`);
|
||||
|
||||
v = testAPIMethod("symbol");
|
||||
assertTrue(typeof v === "symbol", `Should export a symbol`);
|
||||
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_method_avoid_unnecessary_params_cloning() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIMethodReturnsParam(param) {
|
||||
return param;
|
||||
},
|
||||
testAPIMethodReturnsUnwrappedParam(param) {
|
||||
return param.wrappedJSObject;
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
const {
|
||||
assertTrue,
|
||||
notifyFinish,
|
||||
testAPIMethodReturnsParam,
|
||||
testAPIMethodReturnsUnwrappedParam,
|
||||
} = this;
|
||||
|
||||
let obj = {};
|
||||
|
||||
let result = testAPIMethodReturnsParam(obj);
|
||||
|
||||
assertTrue(result === obj,
|
||||
`Expect returned value to be strictly equal to the API method parameter`);
|
||||
|
||||
result = testAPIMethodReturnsUnwrappedParam(obj);
|
||||
|
||||
assertTrue(result === obj,
|
||||
`Expect returned value to be strictly equal to the unwrapped API method parameter`);
|
||||
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_apiScript_method_export_sparse_arrays() {
|
||||
function apiScript(sharedTestAPIMethods) {
|
||||
browser.userScripts.onBeforeScript.addListener(script => {
|
||||
script.defineGlobals({
|
||||
...sharedTestAPIMethods,
|
||||
testAPIMethod() {
|
||||
const sparseArray = [];
|
||||
sparseArray[3] = "third-element";
|
||||
sparseArray[5] = "fifth-element";
|
||||
return script.export(sparseArray);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function userScript() {
|
||||
const {assertTrue, notifyFinish, testAPIMethod} = this;
|
||||
|
||||
const result = testAPIMethod(window, document);
|
||||
|
||||
// We expect the returned value to be the uncloneable window object.
|
||||
assertTrue(result && result.length === 6,
|
||||
`the returned value should be an array of the expected length: ${result}`);
|
||||
assertTrue(result[3] === "third-element",
|
||||
`the third array element should have the expected value: ${result[3]}`);
|
||||
assertTrue(result[5] === "fifth-element",
|
||||
`the fifth array element should have the expected value: ${result[5]}`);
|
||||
assertTrue(result[0] === undefined,
|
||||
`the first array element should have the expected value: ${result[0]}`);
|
||||
assertTrue(!("0" in result), "Holey array should still be holey");
|
||||
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
await test_userScript_APIMethod({
|
||||
userScript,
|
||||
apiScript,
|
||||
});
|
||||
});
|
|
@ -131,7 +131,7 @@ skip-if = os == "android"
|
|||
[test_ext_unload_frame.js]
|
||||
skip-if = true # Too frequent intermittent failures
|
||||
[test_ext_userScripts.js]
|
||||
skip-if = os == "android" && debug # Bug 1512741
|
||||
[test_ext_userScripts_exports.js]
|
||||
[test_ext_userScripts_telemetry.js]
|
||||
[test_ext_webRequest_auth.js]
|
||||
skip-if = os == "android" && debug
|
||||
|
|
|
@ -31,6 +31,7 @@ support-files =
|
|||
|
||||
[test_nocache.js]
|
||||
[test_big_icon.js]
|
||||
skip-if = (os == "win" && processor == "x86_64" && !debug) # Bug 1496191
|
||||
[test_bug930456.js]
|
||||
[test_bug930456_child.js]
|
||||
[test_engine_set_alias.js]
|
||||
|
|
|
@ -313,7 +313,7 @@ const BaseControlMixin = Base => {
|
|||
};
|
||||
MozElements.BaseControl = BaseControlMixin(MozXULElement);
|
||||
|
||||
const BaseTextMixin = Base => class extends Base {
|
||||
const BaseTextMixin = Base => class extends BaseControlMixin(Base) {
|
||||
set label(val) {
|
||||
this.setAttribute("label", val);
|
||||
return val;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
testMixin();
|
||||
testBaseControl();
|
||||
testBaseControlMixin();
|
||||
testBaseText();
|
||||
testParseXULToFragment();
|
||||
testInherits();
|
||||
await testCustomInterface();
|
||||
|
@ -63,6 +64,14 @@
|
|||
ok("disabled" in HTMLSpanBaseControl.prototype, "Mixed in class prototype contains base control attributes");
|
||||
}
|
||||
|
||||
function testBaseText() {
|
||||
ok(MozElements.BaseText, "BaseText exists");
|
||||
ok("label" in MozElements.BaseText.prototype,
|
||||
"BaseText prototype inherits BaseText attributes");
|
||||
ok("disabled" in MozElements.BaseText.prototype,
|
||||
"BaseText prototype inherits BaseControl attributes");
|
||||
}
|
||||
|
||||
function testParseXULToFragment() {
|
||||
ok(MozXULElement.parseXULToFragment, "parseXULToFragment helper exists");
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@
|
|||
<content>
|
||||
<xul:hbox class="menu-iconic-left" align="center" pack="center"
|
||||
xbl:inherits="selected,_moz-menuactive,disabled,checked">
|
||||
<xul:image class="menu-iconic-icon" xbl:inherits="src=image,triggeringprincipal=iconloadingprincipal,validate,src"/>
|
||||
<xul:image class="menu-iconic-icon" xbl:inherits="src=image,triggeringprincipal=iconloadingprincipal,validate"/>
|
||||
</xul:hbox>
|
||||
<xul:label class="menu-iconic-text" flex="1" xbl:inherits="value=label,accesskey,crop,highlightable" crop="right"/>
|
||||
<xul:label class="menu-iconic-highlightable-text" xbl:inherits="xbl:text=label,crop,accesskey,highlightable" crop="right"/>
|
||||
|
@ -188,7 +188,7 @@
|
|||
<content>
|
||||
<xul:hbox class="menu-iconic-left" align="center" pack="center"
|
||||
xbl:inherits="selected,disabled,checked">
|
||||
<xul:image class="menu-iconic-icon" xbl:inherits="src=image,validate,src"/>
|
||||
<xul:image class="menu-iconic-icon" xbl:inherits="src=image,validate"/>
|
||||
</xul:hbox>
|
||||
<xul:label class="menu-iconic-text" flex="1" xbl:inherits="value=label,accesskey,crop,highlightable" crop="right"/>
|
||||
<xul:label class="menu-iconic-highlightable-text" xbl:inherits="xbl:text=label,crop,accesskey,highlightable" crop="right"/>
|
||||
|
|
|
@ -24,6 +24,7 @@ encoding_glue = { path = "../../../../intl/encoding_glue" }
|
|||
audioipc-client = { path = "../../../../media/audioipc/client", optional = true }
|
||||
audioipc-server = { path = "../../../../media/audioipc/server", optional = true }
|
||||
u2fhid = { path = "../../../../dom/webauthn/u2f-hid-rs" }
|
||||
gkrust_utils = { path = "../../../../xpcom/rust/gkrust_utils" }
|
||||
rsdparsa_capi = { path = "../../../../media/webrtc/signaling/src/sdp/rsdparsa_capi" }
|
||||
# We have these to enforce common feature sets for said crates.
|
||||
log = {version = "0.4", features = ["release_max_level_info"]}
|
||||
|
|
|
@ -29,6 +29,7 @@ extern crate audioipc_client;
|
|||
extern crate audioipc_server;
|
||||
extern crate env_logger;
|
||||
extern crate u2fhid;
|
||||
extern crate gkrust_utils;
|
||||
extern crate log;
|
||||
extern crate cosec;
|
||||
extern crate rsdparsa_capi;
|
||||
|
|
|
@ -1901,7 +1901,7 @@ var AddonManagerInternal = {
|
|||
this.installNotifyObservers("addon-install-disabled", topBrowser,
|
||||
aInstallingPrincipal.URI, aInstall);
|
||||
return;
|
||||
} else if (!aBrowser.contentPrincipal || !aInstallingPrincipal.subsumes(aBrowser.contentPrincipal)) {
|
||||
} else if (aInstallingPrincipal.isNullPrincipal || !aBrowser.contentPrincipal || !aInstallingPrincipal.subsumes(aBrowser.contentPrincipal)) {
|
||||
aInstall.cancel();
|
||||
|
||||
this.installNotifyObservers("addon-install-origin-blocked", topBrowser,
|
||||
|
|
|
@ -168,6 +168,7 @@ row[unsupported="true"] {
|
|||
}
|
||||
#detail-name, #detail-desc, #detail-fulldesc {
|
||||
-moz-user-select: text;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
#detail-name-container {
|
||||
|
|
|
@ -11,14 +11,16 @@ ChromeUtils.defineModuleGetter(this, "UpdateListener",
|
|||
"resource://gre/modules/UpdateListener.jsm");
|
||||
|
||||
const BIN_SUFFIX = (AppConstants.platform == "win" ? ".exe" : "");
|
||||
const FILE_UPDATER_BIN = "updater" + (AppConstants.platform == "macosx" ? ".app" : BIN_SUFFIX);
|
||||
const FILE_UPDATER_BIN =
|
||||
"updater" + (AppConstants.platform == "macosx" ? ".app" : BIN_SUFFIX);
|
||||
const FILE_UPDATER_BIN_BAK = FILE_UPDATER_BIN + ".bak";
|
||||
|
||||
const LOG_FUNCTION = info;
|
||||
|
||||
const MAX_UPDATE_COPY_ATTEMPTS = 10;
|
||||
|
||||
const DATA_URI_SPEC = "chrome://mochitests/content/browser/toolkit/mozapps/update/tests/browser/";
|
||||
const DATA_URI_SPEC =
|
||||
"chrome://mochitests/content/browser/toolkit/mozapps/update/tests/browser/";
|
||||
/* import-globals-from testConstants.js */
|
||||
Services.scriptloader.loadSubScript(DATA_URI_SPEC + "testConstants.js", this);
|
||||
|
||||
|
@ -35,14 +37,49 @@ let gOriginalUpdateAutoValue = null;
|
|||
// the test's onload function.
|
||||
gDebugTest = true;
|
||||
|
||||
/**
|
||||
* Common tasks to perform for all tests before each one has started.
|
||||
*/
|
||||
add_task(async function setupTestCommon() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
[PREF_APP_UPDATE_LOG, gDebugTest],
|
||||
],
|
||||
});
|
||||
|
||||
setUpdateTimerPrefs();
|
||||
removeUpdateFiles(true);
|
||||
// Most app update mochitest-browser-chrome tests expect auto update to be
|
||||
// enabled. Those that don't will explicitly change this.
|
||||
await setAppUpdateAutoEnabledHelper(true);
|
||||
});
|
||||
|
||||
/**
|
||||
* Common tasks to perform for all tests after each one has finished.
|
||||
*/
|
||||
registerCleanupFunction(async () => {
|
||||
gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "");
|
||||
gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "");
|
||||
UpdateListener.reset();
|
||||
reloadUpdateManagerData(true);
|
||||
// Pass false when the log files are needed for troubleshooting the tests.
|
||||
removeUpdateFiles(true);
|
||||
// Always try to restore the original updater files. If none of the updater
|
||||
// backup files are present then this is just a no-op.
|
||||
await finishTestRestoreUpdaterBackup();
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates the continue file used to signal that update staging or the mock http
|
||||
* server should continue. The delay this creates allows the tests to verify the
|
||||
* user interfaces before they auto advance to phases of an update. The continue
|
||||
* file for staging will be deleted by the test updater and the continue file
|
||||
* for update check and update download requests will be deleted by the test
|
||||
* http server handler implemented in app_update.sjs. The test returns a promise
|
||||
* so the test can wait on the deletion of the continue file when necessary.
|
||||
* user interfaces before they auto advance to other phases of an update. The
|
||||
* continue file for staging will be deleted by the test updater and the
|
||||
* continue file for the update check and update download requests will be
|
||||
* deleted by the test http server handler implemented in app_update.sjs. The
|
||||
* test returns a promise so the test can wait on the deletion of the continue
|
||||
* file when necessary. If the continue file still exists at the end of a test
|
||||
* it will be removed to prevent it from affecting tests that run after the test
|
||||
* that created it.
|
||||
*
|
||||
* @param leafName
|
||||
* The leafName of the file to create. This should be one of the
|
||||
|
@ -84,6 +121,16 @@ async function continueFileHandler(leafName) {
|
|||
continueFile.path);
|
||||
}
|
||||
continueFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE);
|
||||
// If for whatever reason the continue file hasn't been removed when a test
|
||||
// has finished remove it during cleanup so it doesn't affect tests that run
|
||||
// after the test that created it.
|
||||
registerCleanupFunction(() => {
|
||||
if (continueFile.exists()) {
|
||||
logTestInfo("Removing continue file during test cleanup, path: " +
|
||||
continueFile.path);
|
||||
continueFile.remove(false);
|
||||
}
|
||||
});
|
||||
return BrowserTestUtils.waitForCondition(() =>
|
||||
(!continueFile.exists()),
|
||||
"Waiting for file to be deleted, path: " + continueFile.path,
|
||||
|
@ -120,6 +167,13 @@ function lockWriteTestFile() {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the update mutex handle in nsUpdateService.js if it exists and then
|
||||
* creates a new update mutex handle so the update code thinks there is another
|
||||
* instance of the application handling updates.
|
||||
*
|
||||
* @throws If the function is called on a platform other than Windows.
|
||||
*/
|
||||
function setOtherInstanceHandlingUpdates() {
|
||||
if (AppConstants.platform != "win") {
|
||||
throw new Error("Windows only test function called");
|
||||
|
@ -146,14 +200,6 @@ function getVersionParams(aAppVersion) {
|
|||
return "&appVersion=" + (aAppVersion ? aAppVersion : appInfo.version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up updates list and the updates directory.
|
||||
*/
|
||||
function cleanUpUpdates() {
|
||||
reloadUpdateManagerData(true);
|
||||
removeUpdateFiles(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent nsIUpdateTimerManager from notifying nsIApplicationUpdateService
|
||||
* to check for updates by setting the app update last update time to the
|
||||
|
@ -167,8 +213,11 @@ function setUpdateTimerPrefs() {
|
|||
}
|
||||
|
||||
/*
|
||||
* In addition to changing the value of the Auto Update setting, this function
|
||||
* also takes care of cleaning up after itself.
|
||||
* Sets the value of the App Auto Update setting and sets it back to the
|
||||
* original value at the start of the test when the test finishes.
|
||||
*
|
||||
* @param enabled
|
||||
* The value to set App Auto Update to.
|
||||
*/
|
||||
async function setAppUpdateAutoEnabledHelper(enabled) {
|
||||
if (gOriginalUpdateAutoValue == null) {
|
||||
|
@ -180,19 +229,6 @@ async function setAppUpdateAutoEnabledHelper(enabled) {
|
|||
await UpdateUtils.setAppUpdateAutoEnabled(enabled);
|
||||
}
|
||||
|
||||
add_task(async function setDefaults() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
[PREF_APP_UPDATE_LOG, gDebugTest],
|
||||
// See bug 1505790 - uses a very large value to prevent the sync code
|
||||
// from running since it has nothing to do with these tests.
|
||||
["services.sync.autoconnectDelay", 600000],
|
||||
]});
|
||||
// Most tests in this directory expect auto update to be enabled. Those that
|
||||
// don't will explicitly change this.
|
||||
await setAppUpdateAutoEnabledHelper(true);
|
||||
});
|
||||
|
||||
/**
|
||||
* Runs a typical update test. Will set various common prefs for using the
|
||||
* updater doorhanger, runs the provided list of steps, and makes sure
|
||||
|
@ -211,22 +247,15 @@ add_task(async function setDefaults() {
|
|||
*/
|
||||
function runUpdateTest(updateParams, checkAttempts, steps) {
|
||||
return (async function() {
|
||||
registerCleanupFunction(() => {
|
||||
gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "");
|
||||
UpdateListener.reset();
|
||||
cleanUpUpdates();
|
||||
});
|
||||
|
||||
gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
|
||||
setUpdateTimerPrefs();
|
||||
removeUpdateFiles(true);
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
[PREF_APP_UPDATE_DOWNLOADPROMPTATTEMPTS, 0],
|
||||
[PREF_APP_UPDATE_DISABLEDFORTESTING, false],
|
||||
[PREF_APP_UPDATE_IDLETIME, 0],
|
||||
[PREF_APP_UPDATE_URL_MANUAL, URL_MANUAL_UPDATE],
|
||||
]});
|
||||
],
|
||||
});
|
||||
|
||||
await setupTestUpdater();
|
||||
|
||||
|
@ -249,8 +278,6 @@ function runUpdateTest(updateParams, checkAttempts, steps) {
|
|||
for (let step of steps) {
|
||||
await processStep(step);
|
||||
}
|
||||
|
||||
await finishTestRestoreUpdaterBackup();
|
||||
})();
|
||||
}
|
||||
|
||||
|
@ -267,22 +294,15 @@ function runUpdateTest(updateParams, checkAttempts, steps) {
|
|||
*/
|
||||
function runUpdateProcessingTest(updates, steps) {
|
||||
return (async function() {
|
||||
registerCleanupFunction(() => {
|
||||
gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "");
|
||||
UpdateListener.reset();
|
||||
cleanUpUpdates();
|
||||
});
|
||||
|
||||
gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
|
||||
setUpdateTimerPrefs();
|
||||
removeUpdateFiles(true);
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
[PREF_APP_UPDATE_DOWNLOADPROMPTATTEMPTS, 0],
|
||||
[PREF_APP_UPDATE_DISABLEDFORTESTING, false],
|
||||
[PREF_APP_UPDATE_IDLETIME, 0],
|
||||
[PREF_APP_UPDATE_URL_MANUAL, URL_MANUAL_UPDATE],
|
||||
]});
|
||||
],
|
||||
});
|
||||
|
||||
await setupTestUpdater();
|
||||
|
||||
|
@ -297,8 +317,6 @@ function runUpdateProcessingTest(updates, steps) {
|
|||
for (let step of steps) {
|
||||
await processStep(step);
|
||||
}
|
||||
|
||||
await finishTestRestoreUpdaterBackup();
|
||||
})();
|
||||
}
|
||||
|
||||
|
@ -366,7 +384,8 @@ function waitForEvent(topic, status = null) {
|
|||
* @return The button element.
|
||||
*/
|
||||
function getNotificationButton(win, notificationId, button) {
|
||||
let notification = win.document.getElementById(`appMenu-${notificationId}-notification`);
|
||||
let notification =
|
||||
win.document.getElementById(`appMenu-${notificationId}-notification`);
|
||||
is(notification.hidden, false, `${notificationId} notification is showing`);
|
||||
return notification[button];
|
||||
}
|
||||
|
@ -492,9 +511,11 @@ function copyTestUpdater(attempt = 0) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Restores the updater that was backed up. This is called in setupTestUpdater
|
||||
* before the backup of the real updater is done in case the previous test
|
||||
* failed to restore the updater when the test has finished.
|
||||
* Restores the updater and updater related file that if there a backup exists.
|
||||
* This is called in setupTestUpdater before the backup of the real updater is
|
||||
* done in case the previous test failed to restore the file when a test has
|
||||
* finished. This is also called in finishTestRestoreUpdaterBackup to restore
|
||||
* the files when a test finishes.
|
||||
*/
|
||||
function restoreUpdaterBackup() {
|
||||
let greBinDir = getGREBinDir();
|
||||
|
@ -538,23 +559,21 @@ function restoreUpdaterBackup() {
|
|||
}
|
||||
|
||||
/**
|
||||
* When a staging test finishes this will repeatedly attempt to restore the real
|
||||
* updater.
|
||||
* When a test finishes this will repeatedly attempt to restore the real updater
|
||||
* and the other files for the updater if a backup of the file exists.
|
||||
*/
|
||||
function finishTestRestoreUpdaterBackup() {
|
||||
return (async function() {
|
||||
if (Services.prefs.getBoolPref(PREF_APP_UPDATE_STAGING_ENABLED)) {
|
||||
try {
|
||||
// Windows debug builds keep the updater file in use for a short period of
|
||||
// time after the updater process exits.
|
||||
restoreUpdaterBackup();
|
||||
} catch (e) {
|
||||
logTestInfo("Attempt to restore the backed up updater failed... " +
|
||||
"will try again, Exception: " + e);
|
||||
try {
|
||||
// Windows debug builds keep the updater file in use for a short period of
|
||||
// time after the updater process exits.
|
||||
restoreUpdaterBackup();
|
||||
} catch (e) {
|
||||
logTestInfo("Attempt to restore the backed up updater failed... " +
|
||||
"will try again, Exception: " + e);
|
||||
|
||||
await TestUtils.waitForTick();
|
||||
await finishTestRestoreUpdaterBackup();
|
||||
}
|
||||
await TestUtils.waitForTick();
|
||||
await finishTestRestoreUpdaterBackup();
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
@ -575,7 +594,8 @@ function waitForAboutDialog() {
|
|||
async function aboutDialogOnLoad() {
|
||||
domwindow.removeEventListener("load", aboutDialogOnLoad, true);
|
||||
let chromeURI = "chrome://browser/content/aboutDialog.xul";
|
||||
is(domwindow.document.location.href, chromeURI, "About dialog appeared");
|
||||
is(domwindow.document.location.href, chromeURI,
|
||||
"About dialog appeared");
|
||||
resolve(domwindow);
|
||||
}
|
||||
|
||||
|
@ -664,6 +684,7 @@ function runAboutDialogUpdateTest(updateParams, backgroundUpdate, steps) {
|
|||
}
|
||||
|
||||
return (async function() {
|
||||
gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "1");
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
[PREF_APP_UPDATE_SERVICE_ENABLED, false],
|
||||
|
@ -671,20 +692,8 @@ function runAboutDialogUpdateTest(updateParams, backgroundUpdate, steps) {
|
|||
[PREF_APP_UPDATE_URL_MANUAL, detailsURL],
|
||||
],
|
||||
});
|
||||
registerCleanupFunction(() => {
|
||||
gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "");
|
||||
UpdateListener.reset();
|
||||
cleanUpUpdates();
|
||||
});
|
||||
|
||||
gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "1");
|
||||
setUpdateTimerPrefs();
|
||||
removeUpdateFiles(true);
|
||||
|
||||
await setupTestUpdater();
|
||||
registerCleanupFunction(async () => {
|
||||
await finishTestRestoreUpdaterBackup();
|
||||
});
|
||||
|
||||
let updateURL = URL_HTTP_UPDATE_SJS + "?detailsURL=" + detailsURL +
|
||||
updateParams + getVersionParams();
|
||||
|
@ -694,9 +703,6 @@ function runAboutDialogUpdateTest(updateParams, backgroundUpdate, steps) {
|
|||
// MOZ_TEST_SLOW_SKIP_UPDATE_STAGE in updater.cpp this removes the need
|
||||
// for the continue file to continue staging the update.
|
||||
gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
|
||||
registerCleanupFunction(() => {
|
||||
gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "");
|
||||
});
|
||||
}
|
||||
setUpdateURL(updateURL);
|
||||
gAUS.checkForBackgroundUpdates();
|
||||
|
@ -743,7 +749,8 @@ function runAboutPrefsUpdateTest(updateParams, backgroundUpdate, steps) {
|
|||
|
||||
const {panelId, checkActiveUpdate, continueFile} = step;
|
||||
return (async function() {
|
||||
await ContentTask.spawn(tab.linkedBrowser, {panelId}, async ({panelId}) => {
|
||||
await ContentTask.spawn(tab.linkedBrowser, {panelId},
|
||||
async ({panelId}) => {
|
||||
let updateDeck = content.document.getElementById("updateDeck");
|
||||
await ContentTaskUtils.waitForCondition(() =>
|
||||
(updateDeck.selectedPanel && updateDeck.selectedPanel.id == panelId),
|
||||
|
@ -766,7 +773,8 @@ function runAboutPrefsUpdateTest(updateParams, backgroundUpdate, steps) {
|
|||
await continueFileHandler(continueFile);
|
||||
}
|
||||
|
||||
await ContentTask.spawn(tab.linkedBrowser, {panelId, detailsURL}, async ({panelId, detailsURL}) => {
|
||||
await ContentTask.spawn(tab.linkedBrowser, {panelId, detailsURL},
|
||||
async ({panelId, detailsURL}) => {
|
||||
let linkPanels = ["downloadFailed", "manualUpdate", "unsupportedSystem"];
|
||||
if (linkPanels.includes(panelId)) {
|
||||
let selectedPanel =
|
||||
|
@ -787,13 +795,14 @@ function runAboutPrefsUpdateTest(updateParams, backgroundUpdate, steps) {
|
|||
|
||||
let buttonPanels = ["downloadAndInstall", "apply"];
|
||||
if (buttonPanels.includes(panelId)) {
|
||||
let selectedPanel = content.document.getElementById("updateDeck").selectedPanel;
|
||||
let selectedPanel =
|
||||
content.document.getElementById("updateDeck").selectedPanel;
|
||||
let buttonEl = selectedPanel.querySelector("button");
|
||||
// Note: The about:preferences doesn't focus the button like the
|
||||
// About Dialog does.
|
||||
ok(!buttonEl.disabled, "The button should be enabled");
|
||||
// Don't click the button on the apply panel since this will restart the
|
||||
// application.
|
||||
// Don't click the button on the apply panel since this will restart
|
||||
// the application.
|
||||
if (selectedPanel.id != "apply") {
|
||||
buttonEl.click();
|
||||
}
|
||||
|
@ -803,6 +812,7 @@ function runAboutPrefsUpdateTest(updateParams, backgroundUpdate, steps) {
|
|||
}
|
||||
|
||||
return (async function() {
|
||||
gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "1");
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
[PREF_APP_UPDATE_SERVICE_ENABLED, false],
|
||||
|
@ -810,20 +820,8 @@ function runAboutPrefsUpdateTest(updateParams, backgroundUpdate, steps) {
|
|||
[PREF_APP_UPDATE_URL_MANUAL, detailsURL],
|
||||
],
|
||||
});
|
||||
registerCleanupFunction(() => {
|
||||
gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "");
|
||||
UpdateListener.reset();
|
||||
cleanUpUpdates();
|
||||
});
|
||||
|
||||
gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "1");
|
||||
setUpdateTimerPrefs();
|
||||
removeUpdateFiles(true);
|
||||
|
||||
await setupTestUpdater();
|
||||
registerCleanupFunction(async () => {
|
||||
await finishTestRestoreUpdaterBackup();
|
||||
});
|
||||
|
||||
let updateURL = URL_HTTP_UPDATE_SJS + "?detailsURL=" + detailsURL +
|
||||
updateParams + getVersionParams();
|
||||
|
@ -833,9 +831,6 @@ function runAboutPrefsUpdateTest(updateParams, backgroundUpdate, steps) {
|
|||
// MOZ_TEST_SLOW_SKIP_UPDATE_STAGE in updater.cpp this removes the need
|
||||
// for the continue file to continue staging the update.
|
||||
gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
|
||||
registerCleanupFunction(() => {
|
||||
gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "");
|
||||
});
|
||||
}
|
||||
setUpdateURL(updateURL);
|
||||
gAUS.checkForBackgroundUpdates();
|
||||
|
@ -845,7 +840,8 @@ function runAboutPrefsUpdateTest(updateParams, backgroundUpdate, steps) {
|
|||
setUpdateURL(updateURL);
|
||||
}
|
||||
|
||||
tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:preferences");
|
||||
tab = await BrowserTestUtils.openNewForegroundTab(gBrowser,
|
||||
"about:preferences");
|
||||
registerCleanupFunction(async () => {
|
||||
await BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
|
Двоичные данные
toolkit/mozapps/update/tests/data/complete.mar
Двоичные данные
toolkit/mozapps/update/tests/data/complete.mar
Двоичный файл не отображается.
Двоичные данные
toolkit/mozapps/update/tests/data/complete_mac.mar
Двоичные данные
toolkit/mozapps/update/tests/data/complete_mac.mar
Двоичный файл не отображается.
Двоичные данные
toolkit/mozapps/update/tests/data/partial.mar
Двоичные данные
toolkit/mozapps/update/tests/data/partial.mar
Двоичный файл не отображается.
Двоичные данные
toolkit/mozapps/update/tests/data/partial_mac.mar
Двоичные данные
toolkit/mozapps/update/tests/data/partial_mac.mar
Двоичный файл не отображается.
|
@ -16,7 +16,7 @@
|
|||
/* global Services, UpdateUtils, gURLData */
|
||||
|
||||
const FILE_SIMPLE_MAR = "simple.mar";
|
||||
const SIZE_SIMPLE_MAR = "1404";
|
||||
const SIZE_SIMPLE_MAR = "1419";
|
||||
|
||||
const STATE_NONE = "null";
|
||||
const STATE_DOWNLOADING = "downloading";
|
||||
|
|
Двоичные данные
toolkit/mozapps/update/tests/data/simple.mar
Двоичные данные
toolkit/mozapps/update/tests/data/simple.mar
Двоичный файл не отображается.
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче