mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 15:25:52 +00:00
Merge mozilla-central to fx-team
This commit is contained in:
commit
4bfd2c3573
21
b2g/common.configure
Normal file
21
b2g/common.configure
Normal file
@ -0,0 +1,21 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# Truetype fonts for B2G
|
||||
# ==============================================================
|
||||
option(env='MOZTTDIR', nargs=1, help='Path to truetype fonts for B2G')
|
||||
|
||||
@depends('MOZTTDIR')
|
||||
def mozttdir(value):
|
||||
if value:
|
||||
path = value[0]
|
||||
if not os.path.isdir(path):
|
||||
error('MOZTTDIR "%s" is not a valid directory' % path)
|
||||
set_config('MOZTTDIR', path)
|
||||
set_define('PACKAGE_MOZTT', '1')
|
||||
|
||||
|
||||
include('../toolkit/moz.configure')
|
@ -4,4 +4,4 @@
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
include('../../toolkit/moz.configure')
|
||||
include('../common/moz.configure')
|
||||
|
@ -4,4 +4,4 @@
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
include('../../toolkit/moz.configure')
|
||||
include('../common.configure')
|
||||
|
@ -11,4 +11,4 @@ def gonkdir(value):
|
||||
return value[0] if value else ''
|
||||
|
||||
|
||||
include('../toolkit/moz.configure')
|
||||
include('common.configure')
|
||||
|
@ -193,6 +193,11 @@ extensions.registerSchemaAPI("windows", null, (extension, context) => {
|
||||
WindowManager.setState(window, updateInfo.state);
|
||||
}
|
||||
|
||||
if (updateInfo.drawAttention) {
|
||||
// Bug 1257497 - Firefox can't cancel attention actions.
|
||||
window.getAttention();
|
||||
}
|
||||
|
||||
// TODO: All the other properties, focused=false...
|
||||
|
||||
return Promise.resolve(WindowManager.convert(extension, window));
|
||||
|
@ -409,7 +409,6 @@
|
||||
"description": "If true, brings the window to the front. If false, brings the next window in the z-order to the front."
|
||||
},
|
||||
"drawAttention": {
|
||||
"unsupported": true,
|
||||
"type": "boolean",
|
||||
"optional": true,
|
||||
"description": "If true, causes the window to be displayed in a manner that draws the user's attention to the window, without changing the focused window. The effect lasts until the user changes focus to the window. This option has no effect if the window already has focus. Set to false to cancel a previous draw attention request."
|
||||
|
@ -125,3 +125,26 @@ add_task(function* testWindowUpdate() {
|
||||
yield extension.awaitFinish("window-update");
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
let window2 = yield BrowserTestUtils.openNewBrowserWindow();
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background: function() {
|
||||
browser.windows.getAll(undefined, function(wins) {
|
||||
browser.test.assertEq(wins.length, 2, "should have two windows");
|
||||
|
||||
let unfocused = wins.find(win => !win.focused);
|
||||
browser.windows.update(unfocused.id, {drawAttention: true}, function() {
|
||||
browser.test.sendMessage("check");
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
yield Promise.all([extension.startup(), extension.awaitMessage("check")]);
|
||||
|
||||
yield extension.unload();
|
||||
|
||||
yield BrowserTestUtils.closeWindow(window2);
|
||||
});
|
||||
|
@ -255,11 +255,20 @@ def wanted_mozconfig_variables(help):
|
||||
'DSYMUTIL',
|
||||
'EXTERNAL_SOURCE_DIR',
|
||||
'GENISOIMAGE',
|
||||
'L10NBASEDIR',
|
||||
'MOZILLABUILD',
|
||||
'MOZ_ARTIFACT_BUILDS',
|
||||
'MOZ_BUILD_APP',
|
||||
'MOZ_CALLGRIND',
|
||||
'MOZ_DMD',
|
||||
'MOZ_FMP4',
|
||||
'MOZ_INSTRUMENT_EVENT_LOOP',
|
||||
'MOZ_INSTRUMENTS',
|
||||
'MOZ_JPROF',
|
||||
'MOZ_PROFILING',
|
||||
'MOZ_USE_SYSTRACE',
|
||||
'MOZ_VTUNE',
|
||||
'MOZTTDIR',
|
||||
'PERL',
|
||||
'RPMBUILD',
|
||||
'TAR',
|
||||
@ -417,6 +426,15 @@ def split_triplet(triplet):
|
||||
)
|
||||
|
||||
|
||||
@template
|
||||
@advanced
|
||||
def config_sub(shell, triplet):
|
||||
import subprocess
|
||||
config_sub = os.path.join(os.path.dirname(__file__), '..',
|
||||
'autoconf', 'config.sub')
|
||||
return subprocess.check_output([shell, config_sub, triplet]).strip()
|
||||
|
||||
|
||||
@depends('--host', shell)
|
||||
@advanced
|
||||
def host(value, shell):
|
||||
@ -428,14 +446,14 @@ def host(value, shell):
|
||||
else:
|
||||
host = value[0]
|
||||
|
||||
return split_triplet(host)
|
||||
return split_triplet(config_sub(shell, host))
|
||||
|
||||
|
||||
@depends('--target', host)
|
||||
def target(value, host):
|
||||
@depends('--target', host, shell)
|
||||
def target(value, host, shell):
|
||||
if not value:
|
||||
return host
|
||||
return split_triplet(value[0])
|
||||
return split_triplet(config_sub(shell, value[0]))
|
||||
|
||||
|
||||
@depends(host, target)
|
||||
|
@ -178,7 +178,6 @@ def old_configure_options(*options):
|
||||
'--enable-b2g-camera',
|
||||
'--enable-b2g-ril',
|
||||
'--enable-bundled-fonts',
|
||||
'--enable-callgrind',
|
||||
'--enable-chrome-format',
|
||||
'--enable-clang-plugin',
|
||||
'--enable-content-sandbox',
|
||||
@ -192,7 +191,6 @@ def old_configure_options(*options):
|
||||
'--enable-debug-js-modules',
|
||||
'--enable-debug-symbols',
|
||||
'--enable-directshow',
|
||||
'--enable-dmd',
|
||||
'--enable-dtrace',
|
||||
'--enable-dump-painting',
|
||||
'--enable-elf-hack',
|
||||
@ -210,13 +208,11 @@ def old_configure_options(*options):
|
||||
'--enable-hardware-aec-ns',
|
||||
'--enable-icf',
|
||||
'--enable-install-strip',
|
||||
'--enable-instruments',
|
||||
'--enable-ion',
|
||||
'--enable-ios-target',
|
||||
'--enable-ipdl-tests',
|
||||
'--enable-jemalloc',
|
||||
'--enable-jitspew',
|
||||
'--enable-jprof',
|
||||
'--enable-libjpeg-turbo',
|
||||
'--enable-libproxy',
|
||||
'--enable-llvm-hacks',
|
||||
@ -246,7 +242,6 @@ def old_configure_options(*options):
|
||||
'--enable-pref-extensions',
|
||||
'--enable-printing',
|
||||
'--enable-profilelocking',
|
||||
'--enable-profiling',
|
||||
'--enable-pulseaudio',
|
||||
'--enable-raw',
|
||||
'--enable-readline',
|
||||
@ -274,7 +269,6 @@ def old_configure_options(*options):
|
||||
'--enable-system-hunspell',
|
||||
'--enable-system-pixman',
|
||||
'--enable-system-sqlite',
|
||||
'--enable-systrace',
|
||||
'--enable-tasktracer',
|
||||
'--enable-tests',
|
||||
'--enable-thread-sanitizer',
|
||||
@ -288,7 +282,6 @@ def old_configure_options(*options):
|
||||
'--enable-url-classifier',
|
||||
'--enable-valgrind',
|
||||
'--enable-verify-mar',
|
||||
'--enable-vtune',
|
||||
'--enable-warnings-as-errors',
|
||||
'--enable-webapp-runtime',
|
||||
'--enable-webrtc',
|
||||
@ -335,7 +328,6 @@ def old_configure_options(*options):
|
||||
'--with-ios-sdk',
|
||||
'--with-java-bin-path',
|
||||
'--with-jitreport-granularity',
|
||||
'--with-l10n-base',
|
||||
'--with-linux-headers',
|
||||
'--with-macbundlename-prefix',
|
||||
'--with-macos-private-frameworks',
|
||||
|
@ -41,13 +41,13 @@ skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'and
|
||||
[test_child.html]
|
||||
[test_grandchild.html]
|
||||
[test_not-opener.html]
|
||||
skip-if = buildapp == 'b2g' || (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
skip-if = buildapp == 'b2g'
|
||||
[test_opener.html]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
[test_popup-navigates-children.html]
|
||||
skip-if = buildapp == 'b2g' # b2g(Needs multiple window.open support, also uses docshelltreenode) b2g-debug(Needs multiple window.open support, also uses docshelltreenode) b2g-desktop(Needs multiple window.open support, also uses docshelltreenode)
|
||||
[test_reserved.html]
|
||||
skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || android_version == '10' || android_version == '18' || (e10s && debug && os == 'win') #too slow on Android 2.3 and 4.3 aws only; bug 1030403
|
||||
skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || (toolkit == 'android') || (e10s && debug && os == 'win') #too slow on Android 4.3 aws only; bug 1030403
|
||||
[test_sessionhistory.html]
|
||||
skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'android' #RANDOM # b2g-debug(Perma-orange on debug emulator builds) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
|
||||
[test_sibling-matching-parent.html]
|
||||
|
@ -573,15 +573,15 @@ KeyframeEffectReadOnly::ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
|
||||
// FIXME: Maybe cache the current segment?
|
||||
const AnimationPropertySegment *segment = prop.mSegments.Elements(),
|
||||
*segmentEnd = segment + prop.mSegments.Length();
|
||||
while (segment->mToKey < computedTiming.mProgress.Value()) {
|
||||
MOZ_ASSERT(segment->mFromKey < segment->mToKey, "incorrect keys");
|
||||
while (segment->mToKey <= computedTiming.mProgress.Value()) {
|
||||
MOZ_ASSERT(segment->mFromKey <= segment->mToKey, "incorrect keys");
|
||||
if ((segment+1) == segmentEnd) {
|
||||
break;
|
||||
}
|
||||
++segment;
|
||||
MOZ_ASSERT(segment->mFromKey == (segment-1)->mToKey, "incorrect keys");
|
||||
}
|
||||
MOZ_ASSERT(segment->mFromKey < segment->mToKey, "incorrect keys");
|
||||
MOZ_ASSERT(segment->mFromKey <= segment->mToKey, "incorrect keys");
|
||||
MOZ_ASSERT(segment >= prop.mSegments.Elements() &&
|
||||
size_t(segment - prop.mSegments.Elements()) <
|
||||
prop.mSegments.Length(),
|
||||
@ -592,6 +592,18 @@ KeyframeEffectReadOnly::ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
|
||||
aStyleRule = new AnimValuesStyleRule();
|
||||
}
|
||||
|
||||
StyleAnimationValue* val = aStyleRule->AddEmptyValue(prop.mProperty);
|
||||
|
||||
// Special handling for zero-length segments
|
||||
if (segment->mToKey == segment->mFromKey) {
|
||||
if (computedTiming.mProgress.Value() < 0) {
|
||||
*val = segment->mFromValue;
|
||||
} else {
|
||||
*val = segment->mToValue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
double positionInSegment =
|
||||
(computedTiming.mProgress.Value() - segment->mFromKey) /
|
||||
(segment->mToKey - segment->mFromKey);
|
||||
@ -599,8 +611,6 @@ KeyframeEffectReadOnly::ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
|
||||
ComputedTimingFunction::GetPortion(segment->mTimingFunction,
|
||||
positionInSegment);
|
||||
|
||||
StyleAnimationValue *val = aStyleRule->AddEmptyValue(prop.mProperty);
|
||||
|
||||
#ifdef DEBUG
|
||||
bool result =
|
||||
#endif
|
||||
@ -1789,6 +1799,93 @@ KeyframeEffectReadOnly::GetTarget(
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
CreatePropertyValue(nsCSSProperty aProperty,
|
||||
float aOffset,
|
||||
const Maybe<ComputedTimingFunction>& aTimingFunction,
|
||||
const StyleAnimationValue& aValue,
|
||||
AnimationPropertyValueDetails& aResult)
|
||||
{
|
||||
aResult.mOffset = aOffset;
|
||||
|
||||
nsString stringValue;
|
||||
StyleAnimationValue::UncomputeValue(aProperty, aValue, stringValue);
|
||||
aResult.mValue = stringValue;
|
||||
|
||||
if (aTimingFunction) {
|
||||
aResult.mEasing.Construct();
|
||||
aTimingFunction->AppendToString(aResult.mEasing.Value());
|
||||
} else {
|
||||
aResult.mEasing.Construct(NS_LITERAL_STRING("linear"));
|
||||
}
|
||||
|
||||
aResult.mComposite = CompositeOperation::Replace;
|
||||
}
|
||||
|
||||
void
|
||||
KeyframeEffectReadOnly::GetProperties(
|
||||
nsTArray<AnimationPropertyDetails>& aProperties,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
for (const AnimationProperty& property : mProperties) {
|
||||
AnimationPropertyDetails propertyDetails;
|
||||
propertyDetails.mProperty =
|
||||
NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(property.mProperty));
|
||||
propertyDetails.mRunningOnCompositor = property.mIsRunningOnCompositor;
|
||||
|
||||
nsXPIDLString localizedString;
|
||||
if (property.mPerformanceWarning &&
|
||||
property.mPerformanceWarning->ToLocalizedString(localizedString)) {
|
||||
propertyDetails.mWarning.Construct(localizedString);
|
||||
}
|
||||
|
||||
if (!propertyDetails.mValues.SetCapacity(property.mSegments.Length(),
|
||||
mozilla::fallible)) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t segmentIdx = 0, segmentLen = property.mSegments.Length();
|
||||
segmentIdx < segmentLen;
|
||||
segmentIdx++)
|
||||
{
|
||||
const AnimationPropertySegment& segment = property.mSegments[segmentIdx];
|
||||
|
||||
binding_detail::FastAnimationPropertyValueDetails fromValue;
|
||||
CreatePropertyValue(property.mProperty, segment.mFromKey,
|
||||
segment.mTimingFunction, segment.mFromValue,
|
||||
fromValue);
|
||||
// We don't apply timing functions for zero-length segments, so
|
||||
// don't return one here.
|
||||
if (segment.mFromKey == segment.mToKey) {
|
||||
fromValue.mEasing.Reset();
|
||||
}
|
||||
// The following won't fail since we have already allocated the capacity
|
||||
// above.
|
||||
propertyDetails.mValues.AppendElement(fromValue, mozilla::fallible);
|
||||
|
||||
// Normally we can ignore the to-value for this segment since it is
|
||||
// identical to the from-value from the next segment. However, we need
|
||||
// to add it if either:
|
||||
// a) this is the last segment, or
|
||||
// b) the next segment's from-value differs.
|
||||
if (segmentIdx == segmentLen - 1 ||
|
||||
property.mSegments[segmentIdx + 1].mFromValue != segment.mToValue) {
|
||||
binding_detail::FastAnimationPropertyValueDetails toValue;
|
||||
CreatePropertyValue(property.mProperty, segment.mToKey,
|
||||
Nothing(), segment.mToValue, toValue);
|
||||
// It doesn't really make sense to have a timing function on the
|
||||
// last property value or before a sudden jump so we just drop the
|
||||
// easing property altogether.
|
||||
toValue.mEasing.Reset();
|
||||
propertyDetails.mValues.AppendElement(toValue, mozilla::fallible);
|
||||
}
|
||||
}
|
||||
|
||||
aProperties.AppendElement(propertyDetails);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
KeyframeEffectReadOnly::GetFrames(JSContext*& aCx,
|
||||
nsTArray<JSObject*>& aResult,
|
||||
@ -1887,32 +1984,6 @@ KeyframeEffectReadOnly::GetFrames(JSContext*& aCx,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
KeyframeEffectReadOnly::GetPropertyState(
|
||||
nsTArray<AnimationPropertyState>& aStates) const
|
||||
{
|
||||
for (const AnimationProperty& property : mProperties) {
|
||||
// Bug 1252730: We should also expose this winsInCascade as well.
|
||||
if (!property.mWinsInCascade) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AnimationPropertyState state;
|
||||
state.mProperty.Construct(
|
||||
NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(property.mProperty)));
|
||||
state.mRunningOnCompositor.Construct(property.mIsRunningOnCompositor);
|
||||
|
||||
nsXPIDLString localizedString;
|
||||
if (property.mPerformanceWarning &&
|
||||
property.mPerformanceWarning->ToLocalizedString(localizedString)) {
|
||||
state.mWarning.Construct(localizedString);
|
||||
}
|
||||
|
||||
aStates.AppendElement(state);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ const TimeDuration
|
||||
KeyframeEffectReadOnly::OverflowRegionRefreshInterval()
|
||||
{
|
||||
|
@ -46,7 +46,7 @@ class UnrestrictedDoubleOrKeyframeAnimationOptions;
|
||||
class UnrestrictedDoubleOrKeyframeEffectOptions;
|
||||
enum class IterationCompositeOperation : uint32_t;
|
||||
enum class CompositeOperation : uint32_t;
|
||||
struct AnimationPropertyState;
|
||||
struct AnimationPropertyDetails;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -209,6 +209,8 @@ public:
|
||||
void GetFrames(JSContext*& aCx,
|
||||
nsTArray<JSObject*>& aResult,
|
||||
ErrorResult& aRv);
|
||||
void GetProperties(nsTArray<AnimationPropertyDetails>& aProperties,
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
// Temporary workaround to return both the target element and pseudo-type
|
||||
// until we implement PseudoElement (bug 1174575).
|
||||
@ -304,8 +306,6 @@ public:
|
||||
bool IsRunningOnCompositor() const;
|
||||
void SetIsRunningOnCompositor(nsCSSProperty aProperty, bool aIsRunning);
|
||||
|
||||
void GetPropertyState(nsTArray<AnimationPropertyState>& aStates) const;
|
||||
|
||||
// Returns true if this effect, applied to |aFrame|, contains properties
|
||||
// that mean we shouldn't run transform compositor animations on this element.
|
||||
//
|
||||
|
@ -7,6 +7,7 @@ support-files =
|
||||
# file_animate_xrays.html needs to go in mochitest.ini since it is served
|
||||
# over HTTP
|
||||
[chrome/test_animation_observers.html]
|
||||
[chrome/test_animation_properties.html]
|
||||
[chrome/test_animation_property_state.html]
|
||||
[chrome/test_generated_content_getAnimations.html]
|
||||
[chrome/test_restyles.html]
|
||||
|
503
dom/animation/test/chrome/test_animation_properties.html
Normal file
503
dom/animation/test/chrome/test_animation_properties.html
Normal file
@ -0,0 +1,503 @@
|
||||
<!doctype html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<title>Bug 1254419 - Test the values returned by
|
||||
KeyframeEffectReadOnly.getProperties()</title>
|
||||
<script type="application/javascript" src="../testharness.js"></script>
|
||||
<script type="application/javascript" src="../testharnessreport.js"></script>
|
||||
<script type="application/javascript" src="../testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1254419"
|
||||
target="_blank">Mozilla Bug 1254419</a>
|
||||
<div id="log"></div>
|
||||
<style>
|
||||
div {
|
||||
font-size: 10px; /* For calculating em-based units */
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
function assert_properties_equal(actual, expected) {
|
||||
assert_equals(actual.length, expected.length);
|
||||
|
||||
var compareProperties = (a, b) =>
|
||||
a.property == b.property ? 0 : (a.property < b.property ? -1 : 1);
|
||||
|
||||
var sortedActual = actual.sort(compareProperties);
|
||||
var sortedExpected = expected.sort(compareProperties);
|
||||
|
||||
// We want to serialize the values in the following form:
|
||||
//
|
||||
// { offset: 0, easing: linear, composite: replace, value: 5px }, ...
|
||||
//
|
||||
// So that we can just compare strings and, in the failure case,
|
||||
// easily see where the differences lie.
|
||||
var serializeMember = value => {
|
||||
return typeof value === 'undefined' ? '<not set>' : value;
|
||||
}
|
||||
var serializeValues = values =>
|
||||
values.map(value =>
|
||||
'{ ' +
|
||||
[ 'offset', 'value', 'easing', 'composite' ].map(
|
||||
member => `${member}: ${serializeMember(value[member])}`
|
||||
).join(', ') +
|
||||
' }')
|
||||
.join(', ');
|
||||
|
||||
for (var i = 0; i < sortedActual.length; i++) {
|
||||
assert_equals(sortedActual[i].property,
|
||||
sortedExpected[i].property,
|
||||
'CSS property name should match');
|
||||
assert_equals(serializeValues(sortedActual[i].values),
|
||||
serializeValues(sortedExpected[i].values),
|
||||
`Values arrays do not match for `
|
||||
+ `${sortedActual[i].property} property`);
|
||||
}
|
||||
}
|
||||
|
||||
// Shorthand for constructing a value object
|
||||
function value(offset, value, composite, easing) {
|
||||
return { offset: offset, value: value, easing: easing, composite: composite };
|
||||
}
|
||||
|
||||
var gTests = [
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
//
|
||||
// Tests for property-indexed specifications
|
||||
//
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
{ desc: 'a one-property two-value property-indexed specification',
|
||||
frames: { left: ['10px', '20px'] },
|
||||
expected: [ { property: 'left',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '20px', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a one-shorthand-property two-value property-indexed'
|
||||
+ ' specification',
|
||||
frames: { margin: ['10px', '10px 20px 30px 40px'] },
|
||||
expected: [ { property: 'margin-top',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '10px', 'replace') ] },
|
||||
{ property: 'margin-right',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '20px', 'replace') ] },
|
||||
{ property: 'margin-bottom',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '30px', 'replace') ] },
|
||||
{ property: 'margin-left',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '40px', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a two-property (one shorthand and one of its longhand'
|
||||
+ ' components) two-value property-indexed specification',
|
||||
frames: { marginTop: ['50px', '60px'],
|
||||
margin: ['10px', '10px 20px 30px 40px'] },
|
||||
expected: [ { property: 'margin-top',
|
||||
values: [ value(0, '50px', 'replace', 'linear'),
|
||||
value(1, '60px', 'replace') ] },
|
||||
{ property: 'margin-right',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '20px', 'replace') ] },
|
||||
{ property: 'margin-bottom',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '30px', 'replace') ] },
|
||||
{ property: 'margin-left',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '40px', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a two-property property-indexed specification with different'
|
||||
+ ' numbers of values',
|
||||
frames: { left: ['10px', '20px', '30px'],
|
||||
top: ['40px', '50px'] },
|
||||
expected: [ { property: 'left',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(0.5, '20px', 'replace', 'linear'),
|
||||
value(1, '30px', 'replace') ] },
|
||||
{ property: 'top',
|
||||
values: [ value(0, '40px', 'replace', 'linear'),
|
||||
value(1, '50px', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a property-indexed specification with an invalid value',
|
||||
frames: { left: ['10px', '20px', '30px', '40px', '50px'],
|
||||
top: ['15px', '25px', 'invalid', '45px', '55px'] },
|
||||
expected: [ { property: 'left',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(0.25, '20px', 'replace', 'linear'),
|
||||
value(0.5, '30px', 'replace', 'linear'),
|
||||
value(0.75, '40px', 'replace', 'linear'),
|
||||
value(1, '50px', 'replace') ] },
|
||||
{ property: 'top',
|
||||
values: [ value(0, '15px', 'replace', 'linear'),
|
||||
value(0.25, '25px', 'replace', 'linear'),
|
||||
value(0.75, '45px', 'replace', 'linear'),
|
||||
value(1, '55px', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a one-property two-value property-indexed specification that'
|
||||
+ ' needs to stringify its values',
|
||||
frames: { opacity: [0, 1] },
|
||||
expected: [ { property: 'opacity',
|
||||
values: [ value(0, '0', 'replace', 'linear'),
|
||||
value(1, '1', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a property-indexed keyframe where a lesser shorthand precedes'
|
||||
+ ' a greater shorthand',
|
||||
frames: { borderLeft: [ '1px solid rgb(1, 2, 3)',
|
||||
'2px solid rgb(4, 5, 6)' ],
|
||||
border: [ '3px dotted rgb(7, 8, 9)',
|
||||
'4px dashed rgb(10, 11, 12)' ] },
|
||||
expected: [ { property: 'border-bottom-color',
|
||||
values: [ value(0, 'rgb(7, 8, 9)', 'replace', 'linear'),
|
||||
value(1, 'rgb(10, 11, 12)', 'replace') ] },
|
||||
{ property: 'border-left-color',
|
||||
values: [ value(0, 'rgb(1, 2, 3)', 'replace', 'linear'),
|
||||
value(1, 'rgb(4, 5, 6)', 'replace') ] },
|
||||
{ property: 'border-right-color',
|
||||
values: [ value(0, 'rgb(7, 8, 9)', 'replace', 'linear'),
|
||||
value(1, 'rgb(10, 11, 12)', 'replace') ] },
|
||||
{ property: 'border-top-color',
|
||||
values: [ value(0, 'rgb(7, 8, 9)', 'replace', 'linear'),
|
||||
value(1, 'rgb(10, 11, 12)', 'replace') ] },
|
||||
{ property: 'border-bottom-width',
|
||||
values: [ value(0, '3px', 'replace', 'linear'),
|
||||
value(1, '4px', 'replace') ] },
|
||||
{ property: 'border-left-width',
|
||||
values: [ value(0, '1px', 'replace', 'linear'),
|
||||
value(1, '2px', 'replace') ] },
|
||||
{ property: 'border-right-width',
|
||||
values: [ value(0, '3px', 'replace', 'linear'),
|
||||
value(1, '4px', 'replace') ] },
|
||||
{ property: 'border-top-width',
|
||||
values: [ value(0, '3px', 'replace', 'linear'),
|
||||
value(1, '4px', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a property-indexed keyframe where a greater shorthand precedes'
|
||||
+ ' a lesser shorthand',
|
||||
frames: { border: [ '3px dotted rgb(7, 8, 9)',
|
||||
'4px dashed rgb(10, 11, 12)' ],
|
||||
borderLeft: [ '1px solid rgb(1, 2, 3)',
|
||||
'2px solid rgb(4, 5, 6)' ] },
|
||||
expected: [ { property: 'border-bottom-color',
|
||||
values: [ value(0, 'rgb(7, 8, 9)', 'replace', 'linear'),
|
||||
value(1, 'rgb(10, 11, 12)', 'replace') ] },
|
||||
{ property: 'border-left-color',
|
||||
values: [ value(0, 'rgb(1, 2, 3)', 'replace', 'linear'),
|
||||
value(1, 'rgb(4, 5, 6)', 'replace') ] },
|
||||
{ property: 'border-right-color',
|
||||
values: [ value(0, 'rgb(7, 8, 9)', 'replace', 'linear'),
|
||||
value(1, 'rgb(10, 11, 12)', 'replace') ] },
|
||||
{ property: 'border-top-color',
|
||||
values: [ value(0, 'rgb(7, 8, 9)', 'replace', 'linear'),
|
||||
value(1, 'rgb(10, 11, 12)', 'replace') ] },
|
||||
{ property: 'border-bottom-width',
|
||||
values: [ value(0, '3px', 'replace', 'linear'),
|
||||
value(1, '4px', 'replace') ] },
|
||||
{ property: 'border-left-width',
|
||||
values: [ value(0, '1px', 'replace', 'linear'),
|
||||
value(1, '2px', 'replace') ] },
|
||||
{ property: 'border-right-width',
|
||||
values: [ value(0, '3px', 'replace', 'linear'),
|
||||
value(1, '4px', 'replace') ] },
|
||||
{ property: 'border-top-width',
|
||||
values: [ value(0, '3px', 'replace', 'linear'),
|
||||
value(1, '4px', 'replace') ] } ]
|
||||
},
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
//
|
||||
// Tests for keyframe sequences
|
||||
//
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
{ desc: 'a keyframe sequence specification with repeated values at'
|
||||
+ ' offset 0/1 with different easings',
|
||||
frames: [ { offset: 0.0, left: '100px', easing: 'ease' },
|
||||
{ offset: 0.0, left: '200px', easing: 'ease' },
|
||||
{ offset: 0.5, left: '300px', easing: 'linear' },
|
||||
{ offset: 1.0, left: '400px', easing: 'ease-out' },
|
||||
{ offset: 1.0, left: '500px', easing: 'step-end' } ],
|
||||
expected: [ { property: 'left',
|
||||
values: [ value(0, '100px', 'replace'),
|
||||
value(0, '200px', 'replace', 'ease'),
|
||||
value(0.5, '300px', 'replace', 'linear'),
|
||||
value(1, '400px', 'replace'),
|
||||
value(1, '500px', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a one-property two-keyframe sequence',
|
||||
frames: [ { offset: 0, left: '10px' },
|
||||
{ offset: 1, left: '20px' } ],
|
||||
expected: [ { property: 'left',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '20px', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a two-property two-keyframe sequence',
|
||||
frames: [ { offset: 0, left: '10px', top: '30px' },
|
||||
{ offset: 1, left: '20px', top: '40px' } ],
|
||||
expected: [ { property: 'left',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '20px', 'replace') ] },
|
||||
{ property: 'top',
|
||||
values: [ value(0, '30px', 'replace', 'linear'),
|
||||
value(1, '40px', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a one shorthand property two-keyframe sequence',
|
||||
frames: [ { offset: 0, margin: '10px' },
|
||||
{ offset: 1, margin: '20px 30px 40px 50px' } ],
|
||||
expected: [ { property: 'margin-top',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '20px', 'replace') ] },
|
||||
{ property: 'margin-right',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '30px', 'replace') ] },
|
||||
{ property: 'margin-bottom',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '40px', 'replace') ] },
|
||||
{ property: 'margin-left',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '50px', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a two-property (a shorthand and one of its component longhands)'
|
||||
+ ' two-keyframe sequence',
|
||||
frames: [ { offset: 0, margin: '10px', marginTop: '20px' },
|
||||
{ offset: 1, marginTop: '70px',
|
||||
margin: '30px 40px 50px 60px' } ],
|
||||
expected: [ { property: 'margin-top',
|
||||
values: [ value(0, '20px', 'replace', 'linear'),
|
||||
value(1, '70px', 'replace') ] },
|
||||
{ property: 'margin-right',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '40px', 'replace') ] },
|
||||
{ property: 'margin-bottom',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '50px', 'replace') ] },
|
||||
{ property: 'margin-left',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '60px', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a keyframe sequence with duplicate values for a given interior'
|
||||
+ ' offset',
|
||||
frames: [ { offset: 0.0, left: '10px' },
|
||||
{ offset: 0.5, left: '20px' },
|
||||
{ offset: 0.5, left: '30px' },
|
||||
{ offset: 0.5, left: '40px' },
|
||||
{ offset: 1.0, left: '50px' } ],
|
||||
expected: [ { property: 'left',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(0.5, '20px', 'replace'),
|
||||
value(0.5, '40px', 'replace', 'linear'),
|
||||
value(1, '50px', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a keyframe sequence with duplicate values for offsets 0 and 1',
|
||||
frames: [ { offset: 0, left: '10px' },
|
||||
{ offset: 0, left: '20px' },
|
||||
{ offset: 0, left: '30px' },
|
||||
{ offset: 1, left: '40px' },
|
||||
{ offset: 1, left: '50px' },
|
||||
{ offset: 1, left: '60px' } ],
|
||||
expected: [ { property: 'left',
|
||||
values: [ value(0, '10px', 'replace'),
|
||||
value(0, '30px', 'replace', 'linear'),
|
||||
value(1, '40px', 'replace'),
|
||||
value(1, '60px', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a two-property four-keyframe sequence',
|
||||
frames: [ { offset: 0, left: '10px' },
|
||||
{ offset: 0, top: '20px' },
|
||||
{ offset: 1, top: '30px' },
|
||||
{ offset: 1, left: '40px' } ],
|
||||
expected: [ { property: 'left',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '40px', 'replace') ] },
|
||||
{ property: 'top',
|
||||
values: [ value(0, '20px', 'replace', 'linear'),
|
||||
value(1, '30px', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a one-property keyframe sequence with some omitted offsets',
|
||||
frames: [ { offset: 0.00, left: '10px' },
|
||||
{ offset: 0.25, left: '20px' },
|
||||
{ left: '30px' },
|
||||
{ left: '40px' },
|
||||
{ offset: 1.00, left: '50px' } ],
|
||||
expected: [ { property: 'left',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(0.25, '20px', 'replace', 'linear'),
|
||||
value(0.5, '30px', 'replace', 'linear'),
|
||||
value(0.75, '40px', 'replace', 'linear'),
|
||||
value(1, '50px', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a two-property keyframe sequence with some omitted offsets',
|
||||
frames: [ { offset: 0.00, left: '10px', top: '20px' },
|
||||
{ offset: 0.25, left: '30px' },
|
||||
{ left: '40px' },
|
||||
{ left: '50px', top: '60px' },
|
||||
{ offset: 1.00, left: '70px', top: '80px' } ],
|
||||
expected: [ { property: 'left',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(0.25, '30px', 'replace', 'linear'),
|
||||
value(0.5, '40px', 'replace', 'linear'),
|
||||
value(0.75, '50px', 'replace', 'linear'),
|
||||
value(1, '70px', 'replace') ] },
|
||||
{ property: 'top',
|
||||
values: [ value(0, '20px', 'replace', 'linear'),
|
||||
value(0.75, '60px', 'replace', 'linear'),
|
||||
value(1, '80px', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a one-property keyframe sequence with all omitted offsets',
|
||||
frames: [ { left: '10px' },
|
||||
{ left: '20px' },
|
||||
{ left: '30px' },
|
||||
{ left: '40px' },
|
||||
{ left: '50px' } ],
|
||||
expected: [ { property: 'left',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(0.25, '20px', 'replace', 'linear'),
|
||||
value(0.5, '30px', 'replace', 'linear'),
|
||||
value(0.75, '40px', 'replace', 'linear'),
|
||||
value(1, '50px', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a keyframe sequence with different easing values, but the'
|
||||
+ ' same easing value for a given offset',
|
||||
frames: [ { offset: 0.0, easing: 'ease', left: '10px'},
|
||||
{ offset: 0.0, easing: 'ease', top: '20px'},
|
||||
{ offset: 0.5, easing: 'linear', left: '30px' },
|
||||
{ offset: 0.5, easing: 'linear', top: '40px' },
|
||||
{ offset: 1.0, easing: 'step-end', left: '50px' },
|
||||
{ offset: 1.0, easing: 'step-end', top: '60px' } ],
|
||||
expected: [ { property: 'left',
|
||||
values: [ value(0, '10px', 'replace', 'ease'),
|
||||
value(0.5, '30px', 'replace', 'linear'),
|
||||
value(1, '50px', 'replace') ] },
|
||||
{ property: 'top',
|
||||
values: [ value(0, '20px', 'replace', 'ease'),
|
||||
value(0.5, '40px', 'replace', 'linear'),
|
||||
value(1, '60px', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a one-property two-keyframe sequence that needs to'
|
||||
+ ' stringify its values',
|
||||
frames: [ { offset: 0, opacity: 0 },
|
||||
{ offset: 1, opacity: 1 } ],
|
||||
expected: [ { property: 'opacity',
|
||||
values: [ value(0, '0', 'replace', 'linear'),
|
||||
value(1, '1', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a keyframe sequence where shorthand precedes longhand',
|
||||
frames: [ { offset: 0, margin: '10px', marginRight: '20px' },
|
||||
{ offset: 1, margin: '30px' } ],
|
||||
expected: [ { property: 'margin-top',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '30px', 'replace') ] },
|
||||
{ property: 'margin-right',
|
||||
values: [ value(0, '20px', 'replace', 'linear'),
|
||||
value(1, '30px', 'replace') ] },
|
||||
{ property: 'margin-bottom',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '30px', 'replace') ] },
|
||||
{ property: 'margin-left',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '30px', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a keyframe sequence where longhand precedes shorthand',
|
||||
frames: [ { offset: 0, marginRight: '20px', margin: '10px' },
|
||||
{ offset: 1, margin: '30px' } ],
|
||||
expected: [ { property: 'margin-top',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '30px', 'replace') ] },
|
||||
{ property: 'margin-right',
|
||||
values: [ value(0, '20px', 'replace', 'linear'),
|
||||
value(1, '30px', 'replace') ] },
|
||||
{ property: 'margin-bottom',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '30px', 'replace') ] },
|
||||
{ property: 'margin-left',
|
||||
values: [ value(0, '10px', 'replace', 'linear'),
|
||||
value(1, '30px', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a keyframe sequence where lesser shorthand precedes greater'
|
||||
+ ' shorthand',
|
||||
frames: [ { offset: 0, borderLeft: '1px solid rgb(1, 2, 3)',
|
||||
border: '2px dotted rgb(4, 5, 6)' },
|
||||
{ offset: 1, border: '3px dashed rgb(7, 8, 9)' } ],
|
||||
expected: [ { property: 'border-bottom-color',
|
||||
values: [ value(0, 'rgb(4, 5, 6)', 'replace', 'linear'),
|
||||
value(1, 'rgb(7, 8, 9)', 'replace') ] },
|
||||
{ property: 'border-left-color',
|
||||
values: [ value(0, 'rgb(1, 2, 3)', 'replace', 'linear'),
|
||||
value(1, 'rgb(7, 8, 9)', 'replace') ] },
|
||||
{ property: 'border-right-color',
|
||||
values: [ value(0, 'rgb(4, 5, 6)', 'replace', 'linear'),
|
||||
value(1, 'rgb(7, 8, 9)', 'replace') ] },
|
||||
{ property: 'border-top-color',
|
||||
values: [ value(0, 'rgb(4, 5, 6)', 'replace', 'linear'),
|
||||
value(1, 'rgb(7, 8, 9)', 'replace') ] },
|
||||
{ property: 'border-bottom-width',
|
||||
values: [ value(0, '2px', 'replace', 'linear'),
|
||||
value(1, '3px', 'replace') ] },
|
||||
{ property: 'border-left-width',
|
||||
values: [ value(0, '1px', 'replace', 'linear'),
|
||||
value(1, '3px', 'replace') ] },
|
||||
{ property: 'border-right-width',
|
||||
values: [ value(0, '2px', 'replace', 'linear'),
|
||||
value(1, '3px', 'replace') ] },
|
||||
{ property: 'border-top-width',
|
||||
values: [ value(0, '2px', 'replace', 'linear'),
|
||||
value(1, '3px', 'replace') ] } ]
|
||||
},
|
||||
{ desc: 'a keyframe sequence where greater shorthand precedes' +
|
||||
+ ' lesser shorthand',
|
||||
frames: [ { offset: 0, border: '2px dotted rgb(4, 5, 6)',
|
||||
borderLeft: '1px solid rgb(1, 2, 3)' },
|
||||
{ offset: 1, border: '3px dashed rgb(7, 8, 9)' } ],
|
||||
expected: [ { property: 'border-bottom-color',
|
||||
values: [ value(0, 'rgb(4, 5, 6)', 'replace', 'linear'),
|
||||
value(1, 'rgb(7, 8, 9)', 'replace') ] },
|
||||
{ property: 'border-left-color',
|
||||
values: [ value(0, 'rgb(1, 2, 3)', 'replace', 'linear'),
|
||||
value(1, 'rgb(7, 8, 9)', 'replace') ] },
|
||||
{ property: 'border-right-color',
|
||||
values: [ value(0, 'rgb(4, 5, 6)', 'replace', 'linear'),
|
||||
value(1, 'rgb(7, 8, 9)', 'replace') ] },
|
||||
{ property: 'border-top-color',
|
||||
values: [ value(0, 'rgb(4, 5, 6)', 'replace', 'linear'),
|
||||
value(1, 'rgb(7, 8, 9)', 'replace') ] },
|
||||
{ property: 'border-bottom-width',
|
||||
values: [ value(0, '2px', 'replace', 'linear'),
|
||||
value(1, '3px', 'replace') ] },
|
||||
{ property: 'border-left-width',
|
||||
values: [ value(0, '1px', 'replace', 'linear'),
|
||||
value(1, '3px', 'replace') ] },
|
||||
{ property: 'border-right-width',
|
||||
values: [ value(0, '2px', 'replace', 'linear'),
|
||||
value(1, '3px', 'replace') ] },
|
||||
{ property: 'border-top-width',
|
||||
values: [ value(0, '2px', 'replace', 'linear'),
|
||||
value(1, '3px', 'replace') ] } ]
|
||||
},
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
//
|
||||
// Tests for unit conversion
|
||||
//
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
{ desc: 'em units are resolved to px values',
|
||||
frames: { left: ['10em', '20em'] },
|
||||
expected: [ { property: 'left',
|
||||
values: [ value(0, '100px', 'replace', 'linear'),
|
||||
value(1, '200px', 'replace') ] } ]
|
||||
}
|
||||
];
|
||||
|
||||
gTests.forEach(function(subtest) {
|
||||
test(function(t) {
|
||||
var div = addDiv(t);
|
||||
var animation = div.animate(subtest.frames, 1000);
|
||||
assert_properties_equal(animation.effect.getProperties(),
|
||||
subtest.expected);
|
||||
}, subtest.desc);
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
@ -1,8 +1,8 @@
|
||||
<!doctype html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<title>Bug 1196114 - Animation property which indicates
|
||||
running on the compositor or not</title>
|
||||
<title>Bug 1196114 - Test metadata related to which animation properties
|
||||
are running on the compositor</title>
|
||||
<script type="application/javascript" src="../testharness.js"></script>
|
||||
<script type="application/javascript" src="../testharnessreport.js"></script>
|
||||
<script type="application/javascript" src="../testcommon.js"></script>
|
||||
@ -13,6 +13,10 @@
|
||||
height: 100px;
|
||||
background-color: white;
|
||||
}
|
||||
@keyframes fade {
|
||||
from { opacity: 1 }
|
||||
to { opacity: 0 }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@ -41,7 +45,7 @@ function compare_property_state(a, b) {
|
||||
}
|
||||
|
||||
function assert_animation_property_state_equals(actual, expected) {
|
||||
assert_equals(actual.length, expected.length);
|
||||
assert_equals(actual.length, expected.length, 'Number of properties');
|
||||
|
||||
var sortedActual = actual.sort(compare_property_state);
|
||||
var sortedExpected = expected.sort(compare_property_state);
|
||||
@ -215,7 +219,7 @@ gAnimationsTests.forEach(function(subtest) {
|
||||
var animation = div.animate(subtest.frames, 100000);
|
||||
return animation.ready.then(t.step_func(function() {
|
||||
assert_animation_property_state_equals(
|
||||
animation.effect.getPropertyState(),
|
||||
animation.effect.getProperties(),
|
||||
subtest.expected);
|
||||
}));
|
||||
}, subtest.desc);
|
||||
@ -501,7 +505,7 @@ function start() {
|
||||
var animation = div.animate(subtest.frames, 100000);
|
||||
return animation.ready.then(t.step_func(function() {
|
||||
assert_animation_property_state_equals(
|
||||
animation.effect.getPropertyState(),
|
||||
animation.effect.getProperties(),
|
||||
subtest.expected);
|
||||
}));
|
||||
}, subtest.desc);
|
||||
@ -518,19 +522,19 @@ function start() {
|
||||
var animation = div.animate(subtest.frames, 100000);
|
||||
return animation.ready.then(t.step_func(function() {
|
||||
assert_property_state_on_compositor(
|
||||
animation.effect.getPropertyState(),
|
||||
animation.effect.getProperties(),
|
||||
subtest.expected);
|
||||
div.style = subtest.style;
|
||||
return waitForFrame();
|
||||
})).then(t.step_func(function() {
|
||||
assert_animation_property_state_equals(
|
||||
animation.effect.getPropertyState(),
|
||||
animation.effect.getProperties(),
|
||||
subtest.expected);
|
||||
div.style = '';
|
||||
return waitForFrame();
|
||||
})).then(t.step_func(function() {
|
||||
assert_property_state_on_compositor(
|
||||
animation.effect.getPropertyState(),
|
||||
animation.effect.getProperties(),
|
||||
subtest.expected);
|
||||
}));
|
||||
}, subtest.desc);
|
||||
@ -554,7 +558,7 @@ function start() {
|
||||
return waitForAllAnimations(animations).then(t.step_func(function() {
|
||||
animations.forEach(t.step_func(function(anim) {
|
||||
assert_property_state_on_compositor(
|
||||
anim.effect.getPropertyState(),
|
||||
anim.effect.getProperties(),
|
||||
anim.expected);
|
||||
}));
|
||||
div.style = subtest.style;
|
||||
@ -562,7 +566,7 @@ function start() {
|
||||
})).then(t.step_func(function() {
|
||||
animations.forEach(t.step_func(function(anim) {
|
||||
assert_animation_property_state_equals(
|
||||
anim.effect.getPropertyState(),
|
||||
anim.effect.getProperties(),
|
||||
anim.expected);
|
||||
}));
|
||||
div.style = '';
|
||||
@ -570,7 +574,7 @@ function start() {
|
||||
})).then(t.step_func(function() {
|
||||
animations.forEach(t.step_func(function(anim) {
|
||||
assert_property_state_on_compositor(
|
||||
anim.effect.getPropertyState(),
|
||||
anim.effect.getProperties(),
|
||||
anim.expected);
|
||||
}));
|
||||
}));
|
||||
@ -590,7 +594,7 @@ function start() {
|
||||
return waitForAllAnimations(animations).then(t.step_func(function() {
|
||||
animations.forEach(t.step_func(function(anim) {
|
||||
assert_animation_property_state_equals(
|
||||
anim.effect.getPropertyState(),
|
||||
anim.effect.getProperties(),
|
||||
anim.expected);
|
||||
}));
|
||||
}));
|
||||
@ -613,7 +617,7 @@ function start() {
|
||||
return waitForAllAnimations(animations).then(t.step_func(function() {
|
||||
animations.forEach(t.step_func(function(anim) {
|
||||
assert_property_state_on_compositor(
|
||||
anim.effect.getPropertyState(),
|
||||
anim.effect.getProperties(),
|
||||
anim.expected);
|
||||
}));
|
||||
})).then(t.step_func(function() {
|
||||
@ -625,7 +629,7 @@ function start() {
|
||||
// the 'width' animation.
|
||||
animations.forEach(t.step_func(function(anim) {
|
||||
assert_animation_property_state_equals(
|
||||
anim.effect.getPropertyState(),
|
||||
anim.effect.getProperties(),
|
||||
anim.expected);
|
||||
}));
|
||||
// Remove the 'width' animation.
|
||||
@ -635,7 +639,7 @@ function start() {
|
||||
// Now all animations are running on compositor.
|
||||
animations.forEach(t.step_func(function(anim) {
|
||||
assert_property_state_on_compositor(
|
||||
anim.effect.getPropertyState(),
|
||||
anim.effect.getProperties(),
|
||||
anim.expected);
|
||||
}));
|
||||
}));
|
||||
@ -648,7 +652,7 @@ function start() {
|
||||
{ transform: ['translate(0px)', 'translate(100px)'] }, 100000);
|
||||
return animation.ready.then(t.step_func(function() {
|
||||
assert_animation_property_state_equals(
|
||||
animation.effect.getPropertyState(),
|
||||
animation.effect.getProperties(),
|
||||
[ { property: 'transform', runningOnCompositor: true } ]);
|
||||
div.style = 'width: 10000px; height: 10000px';
|
||||
return waitForFrame();
|
||||
@ -659,7 +663,7 @@ function start() {
|
||||
"bigger than the viewport \\(\\d+, \\d+\\) or the visual rectangle " +
|
||||
"\\(10000, 10000\\) is larger than the max allowed value \\(\\d+\\)");
|
||||
assert_animation_property_state_equals(
|
||||
animation.effect.getPropertyState(),
|
||||
animation.effect.getProperties(),
|
||||
[ {
|
||||
property: 'transform',
|
||||
runningOnCompositor: false,
|
||||
@ -670,7 +674,7 @@ function start() {
|
||||
})).then(t.step_func(function() {
|
||||
// FIXME: Bug 1253164: the animation should get back on compositor.
|
||||
assert_animation_property_state_equals(
|
||||
animation.effect.getPropertyState(),
|
||||
animation.effect.getProperties(),
|
||||
[ { property: 'transform', runningOnCompositor: false } ]);
|
||||
}));
|
||||
}, 'transform on too big element');
|
||||
@ -693,13 +697,13 @@ function start() {
|
||||
{ transform: ['translate(0px)', 'translate(100px)'] }, 100000);
|
||||
return animation.ready.then(t.step_func(function() {
|
||||
assert_animation_property_state_equals(
|
||||
animation.effect.getPropertyState(),
|
||||
animation.effect.getProperties(),
|
||||
[ { property: 'transform', runningOnCompositor: true } ]);
|
||||
svg.setAttribute('transform', 'translate(10, 20)');
|
||||
return waitForFrame();
|
||||
})).then(t.step_func(function() {
|
||||
assert_animation_property_state_equals(
|
||||
animation.effect.getPropertyState(),
|
||||
animation.effect.getProperties(),
|
||||
[ {
|
||||
property: 'transform',
|
||||
runningOnCompositor: false,
|
||||
@ -709,10 +713,25 @@ function start() {
|
||||
return waitForFrame();
|
||||
})).then(t.step_func(function() {
|
||||
assert_animation_property_state_equals(
|
||||
animation.effect.getPropertyState(),
|
||||
animation.effect.getProperties(),
|
||||
[ { property: 'transform', runningOnCompositor: true } ]);
|
||||
}));
|
||||
}, 'transform of nsIFrame with SVG transform');
|
||||
|
||||
promise_test(function(t) {
|
||||
var div = addDiv(t, { class: 'compositable',
|
||||
style: 'animation: fade 100s' });
|
||||
var cssAnimation = div.getAnimations()[0];
|
||||
var scriptAnimation = div.animate({ opacity: [ 1, 0 ] }, 1000);
|
||||
return scriptAnimation.ready.then(function() {
|
||||
assert_animation_property_state_equals(
|
||||
cssAnimation.effect.getProperties(),
|
||||
[ { property: 'opacity', runningOnCompositor: false } ]);
|
||||
assert_animation_property_state_equals(
|
||||
scriptAnimation.effect.getProperties(),
|
||||
[ { property: 'opacity', runningOnCompositor: true } ]);
|
||||
});
|
||||
}, 'overridden animation');
|
||||
}
|
||||
|
||||
</script>
|
||||
|
@ -61,9 +61,7 @@ skip-if = os == "android" || toolkit == "gonk" || e10s # embed-apps doesn't work
|
||||
[test_marketplace_pkg_install.html]
|
||||
skip-if = buildapp == "b2g" || toolkit == "android" # see bug 989806
|
||||
[test_packaged_app_install.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_packaged_app_update.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_receipt_operations.html]
|
||||
[test_signed_pkg_install.html]
|
||||
[test_uninstall_errors.html]
|
||||
|
@ -43,6 +43,66 @@ ParseInteger(const nsAString& aString, int32_t& aInt)
|
||||
nsContentUtils::eParseHTMLInteger_NonStandard ));
|
||||
}
|
||||
|
||||
static bool
|
||||
ParseFloat(const nsAString& aString, double& aDouble)
|
||||
{
|
||||
// Check if it is a valid floating-point number first since the result of
|
||||
// nsString.ToDouble() is more lenient than the spec,
|
||||
// https://html.spec.whatwg.org/#valid-floating-point-number
|
||||
nsAString::const_iterator iter, end;
|
||||
aString.BeginReading(iter);
|
||||
aString.EndReading(end);
|
||||
|
||||
if (iter == end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*iter == char16_t('-') && ++iter == end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nsCRT::IsAsciiDigit(*iter)) {
|
||||
for (; iter != end && nsCRT::IsAsciiDigit(*iter) ; ++iter);
|
||||
} else if (*iter == char16_t('.')) {
|
||||
// Do nothing, jumps to fraction part
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fraction
|
||||
if (*iter == char16_t('.')) {
|
||||
++iter;
|
||||
if (iter == end || !nsCRT::IsAsciiDigit(*iter)) {
|
||||
// U+002E FULL STOP character (.) must be followed by one or more ASCII digits
|
||||
return false;
|
||||
}
|
||||
|
||||
for (; iter != end && nsCRT::IsAsciiDigit(*iter) ; ++iter);
|
||||
}
|
||||
|
||||
if (iter != end && (*iter == char16_t('e') || *iter == char16_t('E'))) {
|
||||
++iter;
|
||||
if (*iter == char16_t('-') || *iter == char16_t('+')) {
|
||||
++iter;
|
||||
}
|
||||
|
||||
if (iter == end || !nsCRT::IsAsciiDigit(*iter)) {
|
||||
// Should have one or more ASCII digits
|
||||
return false;
|
||||
}
|
||||
|
||||
for (; iter != end && nsCRT::IsAsciiDigit(*iter) ; ++iter);
|
||||
}
|
||||
|
||||
if (iter != end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
aDouble = PromiseFlatString(aString).ToDouble(&rv);
|
||||
return NS_SUCCEEDED(rv);
|
||||
}
|
||||
|
||||
ResponsiveImageSelector::ResponsiveImageSelector(nsIContent *aContent)
|
||||
: mOwnerNode(aContent),
|
||||
mSelectedCandidateIndex(-1)
|
||||
@ -533,9 +593,8 @@ ResponsiveImageDescriptors::AddDescriptor(const nsAString& aDescriptor)
|
||||
} else if (*descType == char16_t('x')) {
|
||||
// If the value is not a valid floating point number, it doesn't match this
|
||||
// descriptor, fall through.
|
||||
nsresult rv;
|
||||
double possibleDensity = PromiseFlatString(valueStr).ToDouble(&rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
double possibleDensity = 0.0;
|
||||
if (ParseFloat(valueStr, possibleDensity)) {
|
||||
if (possibleDensity >= 0.0 &&
|
||||
mWidth.isNothing() &&
|
||||
mDensity.isNothing() &&
|
||||
|
@ -831,18 +831,6 @@ danger::AutoCxPusher::IsStackTop() const
|
||||
|
||||
AutoJSContext::AutoJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
|
||||
: mCx(nullptr)
|
||||
{
|
||||
Init(false MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT);
|
||||
}
|
||||
|
||||
AutoJSContext::AutoJSContext(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
|
||||
: mCx(nullptr)
|
||||
{
|
||||
Init(aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT);
|
||||
}
|
||||
|
||||
void
|
||||
AutoJSContext::Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
|
||||
{
|
||||
JS::AutoSuppressGCAnalysis nogc;
|
||||
MOZ_ASSERT(!mCx, "mCx should not be initialized!");
|
||||
@ -850,9 +838,7 @@ AutoJSContext::Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
|
||||
nsXPConnect *xpc = nsXPConnect::XPConnect();
|
||||
if (!aSafe) {
|
||||
mCx = xpc->GetCurrentJSContext();
|
||||
}
|
||||
mCx = xpc->GetCurrentJSContext();
|
||||
|
||||
if (!mCx) {
|
||||
mJSAPI.Init();
|
||||
@ -888,9 +874,17 @@ ThreadsafeAutoJSContext::operator JSContext*() const
|
||||
}
|
||||
|
||||
AutoSafeJSContext::AutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
|
||||
: AutoJSContext(true MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
|
||||
, mAc(mCx, xpc::UnprivilegedJunkScope())
|
||||
: AutoJSAPI()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
|
||||
DebugOnly<bool> ok = Init(xpc::UnprivilegedJunkScope());
|
||||
MOZ_ASSERT(ok,
|
||||
"This is quite odd. We should have crashed in the "
|
||||
"xpc::NativeGlobal() call if xpc::UnprivilegedJunkScope() "
|
||||
"returned null, and inited correctly otherwise!");
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -427,13 +427,6 @@ public:
|
||||
operator JSContext*() const;
|
||||
|
||||
protected:
|
||||
explicit AutoJSContext(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
|
||||
|
||||
// We need this Init() method because we can't use delegating constructor for
|
||||
// the moment. It is a C++11 feature and we do not require C++11 to be
|
||||
// supported to be able to compile Gecko.
|
||||
void Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
|
||||
|
||||
JSContext* mCx;
|
||||
dom::AutoJSAPI mJSAPI;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
@ -461,11 +454,16 @@ private:
|
||||
*
|
||||
* Note - This is deprecated. Please use AutoJSAPI instead.
|
||||
*/
|
||||
class MOZ_RAII AutoSafeJSContext : public AutoJSContext {
|
||||
class MOZ_RAII AutoSafeJSContext : public dom::AutoJSAPI {
|
||||
public:
|
||||
explicit AutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
|
||||
operator JSContext*() const
|
||||
{
|
||||
return cx();
|
||||
}
|
||||
|
||||
private:
|
||||
JSAutoCompartment mAc;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -2724,6 +2724,10 @@ public:
|
||||
}
|
||||
|
||||
void ReportHasScrollLinkedEffect();
|
||||
bool HasScrollLinkedEffect() const
|
||||
{
|
||||
return mHasScrollLinkedEffect;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool GetUseCounter(mozilla::UseCounter aUseCounter)
|
||||
|
@ -1413,20 +1413,29 @@ nsScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
|
||||
NS_ASSERTION(request, "null request in stream complete handler");
|
||||
NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIRequest> channelRequest;
|
||||
aLoader->GetRequest(getter_AddRefs(channelRequest));
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
channel = do_QueryInterface(channelRequest);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (!request->mIntegrity.IsEmpty() &&
|
||||
NS_SUCCEEDED((rv = aSRIStatus))) {
|
||||
MOZ_ASSERT(aSRIDataVerifier);
|
||||
|
||||
nsCOMPtr<nsIRequest> channelRequest;
|
||||
aLoader->GetRequest(getter_AddRefs(channelRequest));
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
channel = do_QueryInterface(channelRequest);
|
||||
|
||||
if (NS_FAILED(aSRIDataVerifier->Verify(request->mIntegrity, channel,
|
||||
request->mCORSMode, mDocument))) {
|
||||
rv = NS_ERROR_SRI_CORRUPT;
|
||||
}
|
||||
} else {
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
|
||||
|
||||
bool enforceSRI = false;
|
||||
loadInfo->GetEnforceSRI(&enforceSRI);
|
||||
if (enforceSRI) {
|
||||
MOZ_LOG(GetSriLog(), mozilla::LogLevel::Debug,
|
||||
("nsScriptLoader::OnStreamComplete, required SRI not found"));
|
||||
rv = NS_ERROR_SRI_CORRUPT;
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
@ -1489,7 +1489,9 @@ nsXMLHttpRequest::Open(const nsACString& inMethod, const nsACString& url,
|
||||
bool async, const Optional<nsAString>& user,
|
||||
const Optional<nsAString>& password)
|
||||
{
|
||||
NS_ENSURE_ARG(!inMethod.IsEmpty());
|
||||
if (inMethod.IsEmpty()) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
|
||||
if (!async && !DontWarnAboutSyncXHR() && GetOwner() &&
|
||||
GetOwner()->GetExtantDoc()) {
|
||||
|
@ -767,7 +767,6 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 775227
|
||||
[test_htmlcopyencoder.html]
|
||||
[test_htmlcopyencoder.xhtml]
|
||||
[test_ipc_messagemanager_blob.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 936226
|
||||
[test_meta_viewport0.html]
|
||||
skip-if = (os != 'b2g' && os != 'android') # meta-viewport tag support is mobile-only
|
||||
[test_meta_viewport1.html]
|
||||
|
@ -32,6 +32,14 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
// See CallbackObject for an explanation of the arguments.
|
||||
explicit CallbackFunction(JS::Handle<JSObject*> aCallable,
|
||||
JS::Handle<JSObject*> aAsyncStack,
|
||||
nsIGlobalObject* aIncumbentGlobal)
|
||||
: CallbackObject(aCallable, aAsyncStack, aIncumbentGlobal)
|
||||
{
|
||||
}
|
||||
|
||||
JS::Handle<JSObject*> Callable() const
|
||||
{
|
||||
return Callback();
|
||||
|
@ -31,6 +31,14 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
// See CallbackObject for an explanation of the arguments.
|
||||
explicit CallbackInterface(JS::Handle<JSObject*> aCallback,
|
||||
JS::Handle<JSObject*> aAsyncStack,
|
||||
nsIGlobalObject* aIncumbentGlobal)
|
||||
: CallbackObject(aCallback, aAsyncStack, aIncumbentGlobal)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
bool GetCallableProperty(JSContext* cx, JS::Handle<jsid> aPropId,
|
||||
JS::MutableHandle<JS::Value> aCallable);
|
||||
|
@ -67,6 +67,16 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Instead of capturing the current stack to use as an async parent when the
|
||||
// callback is invoked, the caller can use this overload to pass in a stack
|
||||
// for that purpose.
|
||||
explicit CallbackObject(JS::Handle<JSObject*> aCallback,
|
||||
JS::Handle<JSObject*> aAsyncStack,
|
||||
nsIGlobalObject *aIncumbentGlobal)
|
||||
{
|
||||
Init(aCallback, aAsyncStack, aIncumbentGlobal);
|
||||
}
|
||||
|
||||
JS::Handle<JSObject*> Callback() const
|
||||
{
|
||||
JS::ExposeObjectToActiveJS(mCallback);
|
||||
|
@ -14687,17 +14687,29 @@ class CGCallback(CGClass):
|
||||
# Not much we can assert about it, other than not being null, and
|
||||
# CallbackObject does that already.
|
||||
body = ""
|
||||
return [ClassConstructor(
|
||||
[Argument("JSContext*", "aCx"),
|
||||
Argument("JS::Handle<JSObject*>", "aCallback"),
|
||||
Argument("nsIGlobalObject*", "aIncumbentGlobal")],
|
||||
bodyInHeader=True,
|
||||
visibility="public",
|
||||
explicit=True,
|
||||
baseConstructors=[
|
||||
"%s(aCx, aCallback, aIncumbentGlobal)" % self.baseName,
|
||||
],
|
||||
body=body)]
|
||||
return [
|
||||
ClassConstructor(
|
||||
[Argument("JSContext*", "aCx"),
|
||||
Argument("JS::Handle<JSObject*>", "aCallback"),
|
||||
Argument("nsIGlobalObject*", "aIncumbentGlobal")],
|
||||
bodyInHeader=True,
|
||||
visibility="public",
|
||||
explicit=True,
|
||||
baseConstructors=[
|
||||
"%s(aCx, aCallback, aIncumbentGlobal)" % self.baseName,
|
||||
],
|
||||
body=body),
|
||||
ClassConstructor(
|
||||
[Argument("JS::Handle<JSObject*>", "aCallback"),
|
||||
Argument("JS::Handle<JSObject*>", "aAsyncStack"),
|
||||
Argument("nsIGlobalObject*", "aIncumbentGlobal")],
|
||||
bodyInHeader=True,
|
||||
visibility="public",
|
||||
explicit=True,
|
||||
baseConstructors=[
|
||||
"%s(aCallback, aAsyncStack, aIncumbentGlobal)" % self.baseName,
|
||||
],
|
||||
body=body)]
|
||||
|
||||
def getMethodImpls(self, method):
|
||||
assert method.needThisHandling
|
||||
|
@ -204,7 +204,6 @@ disabled = bug 1022281
|
||||
[test_browserElement_inproc_FrameWrongURI.html]
|
||||
skip-if = (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_inproc_GetScreenshot.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_browserElement_inproc_GetScreenshotDppx.html]
|
||||
[test_browserElement_inproc_Iconchange.html]
|
||||
[test_browserElement_inproc_LoadEvents.html]
|
||||
@ -258,7 +257,6 @@ skip-if = (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_inproc_XFrameOptionsDeny.html]
|
||||
[test_browserElement_inproc_XFrameOptionsSameOrigin.html]
|
||||
[test_browserElement_oop_NextPaint.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 936226
|
||||
# Disabled due to https://bugzilla.mozilla.org/show_bug.cgi?id=774100
|
||||
[test_browserElement_inproc_Reload.html]
|
||||
disabled = bug 774100
|
||||
@ -272,4 +270,4 @@ tags = audiochannel
|
||||
[test_browserElement_inproc_OpenWindowEmpty.html]
|
||||
skip-if = (toolkit == 'gonk') # Test doesn't work on B2G emulator
|
||||
[test_browserElement_inproc_ActiveStateChangeOnChangingMutedOrVolume.html]
|
||||
tags = audiochannel
|
||||
tags = audiochannel
|
||||
|
4
dom/cache/moz.build
vendored
4
dom/cache/moz.build
vendored
@ -93,10 +93,6 @@ MOCHITEST_MANIFESTS += [
|
||||
'test/mochitest/mochitest.ini',
|
||||
]
|
||||
|
||||
MOCHITEST_CHROME_MANIFESTS += [
|
||||
'test/mochitest/chrome.ini',
|
||||
]
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += [
|
||||
'test/mochitest/browser.ini',
|
||||
]
|
||||
|
1
dom/cache/test/mochitest/chrome.ini
vendored
1
dom/cache/test/mochitest/chrome.ini
vendored
@ -1 +0,0 @@
|
||||
[test_chrome_constructor.html]
|
1
dom/cache/test/mochitest/mochitest.ini
vendored
1
dom/cache/test/mochitest/mochitest.ini
vendored
@ -47,3 +47,4 @@ skip-if = e10s && debug && os == 'win'
|
||||
[test_cache_orphaned_cache.html]
|
||||
[test_cache_orphaned_body.html]
|
||||
[test_cache_untrusted.html]
|
||||
[test_chrome_constructor.html]
|
||||
|
@ -4,13 +4,11 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Validate Interfaces Exposed to Workers</title>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<script class="testbody" type="text/javascript">
|
||||
var Cu = Components.utils;
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv({
|
||||
@ -19,9 +17,7 @@
|
||||
}, function() {
|
||||
// attach to a different origin's CacheStorage
|
||||
var url = 'http://example.com/';
|
||||
var uri = Services.io.newURI(url, null, null);
|
||||
var principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
|
||||
var storage = new CacheStorage('content', principal);
|
||||
var storage = SpecialPowers.createChromeCache('content', url);
|
||||
|
||||
// verify we can use the other origin's CacheStorage as normal
|
||||
var req = new Request('http://example.com/index.html');
|
||||
|
@ -51,6 +51,9 @@ public:
|
||||
void Arc(double x, double y, double radius,
|
||||
double startAngle, double endAngle, bool anticlockwise,
|
||||
ErrorResult& error);
|
||||
void Ellipse(double x, double y, double radiusX, double radiusY,
|
||||
double rotation, double startAngle, double endAngle,
|
||||
bool anticlockwise, ErrorResult& error);
|
||||
|
||||
void LineTo(const gfx::Point& aPoint);
|
||||
void BezierTo(const gfx::Point& aCP1,
|
||||
|
@ -3045,6 +3045,22 @@ CanvasRenderingContext2D::Rect(double aX, double aY, double aW, double aH)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CanvasRenderingContext2D::Ellipse(double aX, double aY, double aRadiusX, double aRadiusY,
|
||||
double aRotation, double aStartAngle, double aEndAngle,
|
||||
bool aAnticlockwise, ErrorResult& aError)
|
||||
{
|
||||
if (aRadiusX < 0.0 || aRadiusY < 0.0) {
|
||||
aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureWritablePath();
|
||||
|
||||
ArcToBezier(this, Point(aX, aY), Size(aRadiusX, aRadiusY), aStartAngle, aEndAngle,
|
||||
aAnticlockwise, aRotation);
|
||||
}
|
||||
|
||||
void
|
||||
CanvasRenderingContext2D::EnsureWritablePath()
|
||||
{
|
||||
@ -5941,6 +5957,22 @@ CanvasPath::Arc(double aX, double aY, double aRadius,
|
||||
ArcToBezier(this, Point(aX, aY), Size(aRadius, aRadius), aStartAngle, aEndAngle, aAnticlockwise);
|
||||
}
|
||||
|
||||
void
|
||||
CanvasPath::Ellipse(double x, double y, double radiusX, double radiusY,
|
||||
double rotation, double startAngle, double endAngle,
|
||||
bool anticlockwise, ErrorResult& error)
|
||||
{
|
||||
if (radiusX < 0.0 || radiusY < 0.0) {
|
||||
error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
EnsurePathBuilder();
|
||||
|
||||
ArcToBezier(this, Point(x, y), Size(radiusX, radiusY), startAngle, endAngle,
|
||||
anticlockwise, rotation);
|
||||
}
|
||||
|
||||
void
|
||||
CanvasPath::LineTo(const gfx::Point& aPoint)
|
||||
{
|
||||
|
@ -346,6 +346,9 @@ public:
|
||||
void Rect(double aX, double aY, double aW, double aH);
|
||||
void Arc(double aX, double aY, double aRadius, double aStartAngle,
|
||||
double aEndAngle, bool aAnticlockwise, mozilla::ErrorResult& aError);
|
||||
void Ellipse(double aX, double aY, double aRadiusX, double aRadiusY,
|
||||
double aRotation, double aStartAngle, double aEndAngle,
|
||||
bool aAnticlockwise, ErrorResult& aError);
|
||||
|
||||
void GetMozCurrentTransform(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aResult,
|
||||
|
@ -47,6 +47,8 @@ ScopedResolveTexturesForDraw::ScopedResolveTexturesForDraw(WebGLContext* webgl,
|
||||
bool* const out_error)
|
||||
: mWebGL(webgl)
|
||||
{
|
||||
MOZ_ASSERT(webgl->gl->IsCurrent());
|
||||
|
||||
typedef decltype(WebGLContext::mBound2DTextures) TexturesT;
|
||||
|
||||
const auto fnResolveAll = [this, funcName](const TexturesT& textures)
|
||||
@ -220,7 +222,7 @@ WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcount,
|
||||
return false;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
MOZ_ASSERT(gl->IsCurrent());
|
||||
|
||||
if (mBoundDrawFramebuffer) {
|
||||
if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(info))
|
||||
@ -246,6 +248,8 @@ WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei count)
|
||||
if (!ValidateDrawModeEnum(mode, funcName))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
bool error;
|
||||
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
|
||||
if (error)
|
||||
@ -274,6 +278,8 @@ WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsiz
|
||||
if (!ValidateDrawModeEnum(mode, funcName))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
bool error;
|
||||
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
|
||||
if (error)
|
||||
@ -409,7 +415,7 @@ WebGLContext::DrawElements_check(GLsizei count, GLenum type,
|
||||
WebGLContext::EnumName(type));
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
MOZ_ASSERT(gl->IsCurrent());
|
||||
|
||||
if (mBoundDrawFramebuffer) {
|
||||
if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(info))
|
||||
@ -436,6 +442,8 @@ WebGLContext::DrawElements(GLenum mode, GLsizei count, GLenum type,
|
||||
if (!ValidateDrawModeEnum(mode, funcName))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
bool error;
|
||||
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
|
||||
if (error)
|
||||
@ -473,6 +481,8 @@ WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
|
||||
if (!ValidateDrawModeEnum(mode, funcName))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
bool error;
|
||||
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
|
||||
if (error)
|
||||
|
@ -39,51 +39,28 @@ support-files =
|
||||
[test_2d.clearRect.image.offscreen.html]
|
||||
[test_2d.clip.winding.html]
|
||||
[test_2d.composite.canvas.color-burn.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.color-dodge.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.color.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.darken.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.destination-atop.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.destination-in.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.difference.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.exclusion.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.hard-light.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.hue.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.lighten.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.luminosity.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.multiply.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.overlay.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.saturation.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.screen.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.soft-light.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.source-in.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.source-out.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.image.destination-atop.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.image.destination-in.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.image.source-in.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.image.source-out.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
# xor and lighter aren't well handled by cairo; they mostly work, but we don't want
|
||||
# to test that
|
||||
[test_2d.composite.solid.xor.html]
|
||||
@ -123,7 +100,7 @@ disabled =
|
||||
[test_2d.composite.solid.soft-light.html]
|
||||
[test_2d.composite.uncovered.image.destination-atop.html]
|
||||
# This test fails in Suite on Linux for some reason, disable it there
|
||||
skip-if = (os == 'linux' && buildapp == 'suite') || (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
skip-if = (os == 'linux' && buildapp == 'suite')
|
||||
[test_2d.composite.uncovered.fill.color-burn.html]
|
||||
[test_2d.composite.uncovered.fill.color-dodge.html]
|
||||
[test_2d.composite.uncovered.fill.color.html]
|
||||
@ -149,11 +126,8 @@ skip-if = toolkit != 'cocoa'
|
||||
[test_2d.composite.uncovered.fill.destination-atop.html]
|
||||
skip-if = toolkit != 'cocoa'
|
||||
[test_2d.composite.uncovered.image.destination-in.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.uncovered.image.source-in.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.uncovered.image.source-out.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
# Tests that fail on non-Mac (bug 407107)
|
||||
[test_2d.composite.uncovered.pattern.source-in.html]
|
||||
skip-if = toolkit != 'cocoa'
|
||||
@ -233,7 +207,7 @@ skip-if = (toolkit == 'gonk' && debug) #bug 1045153
|
||||
[test_bug902651.html]
|
||||
[test_bug1215072.html]
|
||||
[test_canvas.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) || (toolkit == 'android' && processor == 'x86') || (android_version == '18' && debug) #debug-only crash; bug 933541 #x86 only bug 913662 #android 4.3 debug bug 1143317
|
||||
skip-if = (toolkit == 'gonk' && debug) || (android_version == '18' && debug) #debug-only crash; bug 933541 #android 4.3 debug bug 1143317
|
||||
[test_canvas_focusring.html]
|
||||
skip-if = (toolkit == 'gonk' && !debug) || os == 'win' #specialpowers.wrap
|
||||
[test_canvas_font_setter.html]
|
||||
|
@ -153,8 +153,8 @@ skip-if(!winWidget) pref(webgl.disable-angle,true) == webgl-color-test.html?nat
|
||||
== stroketext-shadow.html stroketext-shadow-ref.html
|
||||
|
||||
# focus rings
|
||||
pref(canvas.focusring.enabled,true) skip-if(B2G) skip-if(Android&&AndroidVersion<15,8,500) skip-if(winWidget) needs-focus == drawFocusIfNeeded.html drawFocusIfNeeded-ref.html
|
||||
pref(canvas.customfocusring.enabled,true) skip-if(B2G) skip-if(Android&&AndroidVersion<15,8,500) skip-if(winWidget) needs-focus == drawCustomFocusRing.html drawCustomFocusRing-ref.html
|
||||
pref(canvas.focusring.enabled,true) skip-if(B2G) skip-if(cocoaWidget) skip-if(winWidget) needs-focus == drawFocusIfNeeded.html drawFocusIfNeeded-ref.html
|
||||
pref(canvas.customfocusring.enabled,true) skip-if(B2G) skip-if(cocoaWidget) skip-if(Android) skip-if(winWidget) needs-focus == drawCustomFocusRing.html drawCustomFocusRing-ref.html
|
||||
|
||||
# Check that captureStream() displays in a local video element
|
||||
skip-if(winWidget&&layersGPUAccelerated&&d2d) == capturestream.html wrapper.html?green.png
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -23,7 +23,7 @@ skip-if = (toolkit == 'gonk' && debug) || (os == 'win' && os_version == '5.1') #
|
||||
skip-if = (toolkit == 'gonk' && debug) #debug-only failure
|
||||
[test_contacts_events.html]
|
||||
[test_contacts_getall.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) || (toolkit == 'android' && processor == 'x86') #debug-only failure #x86 only
|
||||
skip-if = (toolkit == 'gonk' && debug) #debug-only failure
|
||||
[test_contacts_getall2.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #debug-only failure
|
||||
[test_contacts_international.html]
|
||||
|
@ -410,9 +410,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
AutoSafeJSContext cx;
|
||||
mRequest = store->OpenCursor(cx, JS::UndefinedHandleValue,
|
||||
IDBCursorDirection::Prev, error);
|
||||
mRequest = store->OpenCursor(IDBCursorDirection::Prev, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return;
|
||||
}
|
||||
@ -492,11 +490,9 @@ public:
|
||||
MOZ_ASSERT(type.EqualsASCII("success"));
|
||||
#endif
|
||||
|
||||
AutoSafeJSContext cx;
|
||||
|
||||
ErrorResult error;
|
||||
JS::Rooted<JS::Value> result(cx);
|
||||
request->GetResult(cx, &result, error);
|
||||
JS::Rooted<JS::Value> result(nsContentUtils::RootingCx());
|
||||
request->GetResult(&result, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
@ -38,15 +38,12 @@ support-files =
|
||||
[test_app_install.html]
|
||||
skip-if = toolkit == 'gonk' # embed-apps doesn't work in the mochitest app
|
||||
[test_readonly.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 936226
|
||||
[test_basic.html]
|
||||
[test_basic_worker.html]
|
||||
[test_changes.html]
|
||||
[test_arrays.html]
|
||||
[test_oop.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 936226
|
||||
[test_sync.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 936226
|
||||
[test_sync_worker.html]
|
||||
[test_bug924104.html]
|
||||
[test_certifiedApp.html]
|
||||
|
@ -1,5 +1,4 @@
|
||||
[DEFAULT]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') # Android: bug 781789 & bug 782275
|
||||
support-files = devicestorage_common.js
|
||||
remove_testing_directory.js
|
||||
|
||||
|
@ -15,10 +15,14 @@ FetchUtil::GetValidRequestMethod(const nsACString& aMethod, nsCString& outMethod
|
||||
{
|
||||
nsAutoCString upperCaseMethod(aMethod);
|
||||
ToUpperCase(upperCaseMethod);
|
||||
if (!NS_IsValidHTTPToken(aMethod)) {
|
||||
outMethod.SetIsVoid(true);
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
|
||||
if (upperCaseMethod.EqualsLiteral("CONNECT") ||
|
||||
upperCaseMethod.EqualsLiteral("TRACE") ||
|
||||
upperCaseMethod.EqualsLiteral("TRACK") ||
|
||||
!NS_IsValidHTTPToken(aMethod)) {
|
||||
upperCaseMethod.EqualsLiteral("TRACK")) {
|
||||
outMethod.SetIsVoid(true);
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
@ -775,7 +775,7 @@ NS_IMPL_ISUPPORTS(nsGeolocationRequest::TimerCallbackHolder, nsISupports, nsITim
|
||||
NS_IMETHODIMP
|
||||
nsGeolocationRequest::TimerCallbackHolder::Notify(nsITimer*)
|
||||
{
|
||||
if (mRequest) {
|
||||
if (mRequest.get()) {
|
||||
mRequest->Notify();
|
||||
}
|
||||
return NS_OK;
|
||||
|
@ -59,7 +59,6 @@ skip-if = (toolkit == 'gonk' && debug) #debug-only failure; bug 926546
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
[test_input_sanitization.html]
|
||||
[test_input_textarea_set_value_no_scroll.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_input_typing_sanitization.html]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[test_input_untrusted_key_events.html]
|
||||
|
@ -404,7 +404,7 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop spec
|
||||
[test_bug658746.html]
|
||||
[test_bug659596.html]
|
||||
[test_bug659743.xml]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || android_version == '10' #Bug 931116, b2g desktop specific, initial triage #Android 2.3 aws only; bug 1031103
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
[test_bug660663.html]
|
||||
[test_bug660959-1.html]
|
||||
[test_bug660959-2.html]
|
||||
|
@ -18005,18 +18005,12 @@ DatabaseMaintenance::CheckIntegrity(mozIStorageConnection* aConnection,
|
||||
}
|
||||
}
|
||||
|
||||
bool changedForeignKeys;
|
||||
if (foreignKeysWereEnabled) {
|
||||
changedForeignKeys = false;
|
||||
} else {
|
||||
if (!foreignKeysWereEnabled) {
|
||||
rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"PRAGMA foreign_keys = ON;"
|
||||
));
|
||||
"PRAGMA foreign_keys = ON;"));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
changedForeignKeys = true;
|
||||
}
|
||||
|
||||
bool foreignKeyError;
|
||||
@ -18035,14 +18029,10 @@ DatabaseMaintenance::CheckIntegrity(mozIStorageConnection* aConnection,
|
||||
}
|
||||
}
|
||||
|
||||
if (changedForeignKeys) {
|
||||
if (!foreignKeysWereEnabled) {
|
||||
nsAutoCString stmtSQL;
|
||||
stmtSQL.AssignLiteral("PRAGMA foreign_keys = ");
|
||||
if (foreignKeysWereEnabled) {
|
||||
stmtSQL.AppendLiteral("ON");
|
||||
} else {
|
||||
stmtSQL.AppendLiteral("OFF");
|
||||
}
|
||||
stmtSQL.AppendLiteral("OFF");
|
||||
stmtSQL.Append(';');
|
||||
|
||||
rv = aConnection->ExecuteSimpleSQL(stmtSQL);
|
||||
|
@ -99,6 +99,8 @@ IDBKeyRange::FromJSVal(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aVal,
|
||||
IDBKeyRange** aKeyRange)
|
||||
{
|
||||
MOZ_ASSERT_IF(!aCx, aVal.isUndefined());
|
||||
|
||||
RefPtr<IDBKeyRange> keyRange;
|
||||
|
||||
if (aVal.isNullOrUndefined()) {
|
||||
|
@ -57,6 +57,7 @@ public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IDBKeyRange)
|
||||
|
||||
// aCx is allowed to be null, but only if aVal.isUndefined().
|
||||
static nsresult
|
||||
FromJSVal(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aVal,
|
||||
|
@ -2089,6 +2089,7 @@ IDBObjectStore::OpenCursorInternal(bool aKeysOnly,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT_IF(!aCx, aRange.isUndefined());
|
||||
|
||||
if (mDeletedSpec) {
|
||||
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
|
||||
|
@ -261,6 +261,16 @@ public:
|
||||
aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<IDBRequest>
|
||||
OpenCursor(IDBCursorDirection aDirection,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return OpenCursorInternal(/* aKeysOnly */ false, nullptr,
|
||||
JS::UndefinedHandleValue, aDirection, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<IDBRequest>
|
||||
OpenKeyCursor(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aRange,
|
||||
@ -337,6 +347,8 @@ private:
|
||||
const IDBIndexParameters& aOptionalParameters,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// aCx is allowed to be null but only if aRange.isUndefined(). In that case,
|
||||
// we don't actually use aCx for anything, so it's OK.
|
||||
already_AddRefed<IDBRequest>
|
||||
OpenCursorInternal(bool aKeysOnly,
|
||||
JSContext* aCx,
|
||||
|
@ -20,13 +20,19 @@ FlushableTaskQueue::Flush()
|
||||
nsresult
|
||||
FlushableTaskQueue::FlushAndDispatch(already_AddRefed<nsIRunnable> aRunnable)
|
||||
{
|
||||
MonitorAutoLock mon(mQueueMonitor);
|
||||
AutoSetFlushing autoFlush(this);
|
||||
FlushLocked();
|
||||
nsCOMPtr<nsIRunnable> r = dont_AddRef(aRunnable.take());
|
||||
nsresult rv = DispatchLocked(r.forget(), IgnoreFlushing, AssertDispatchSuccess);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
AwaitIdleLocked();
|
||||
nsCOMPtr<nsIRunnable> r = aRunnable;
|
||||
{
|
||||
MonitorAutoLock mon(mQueueMonitor);
|
||||
AutoSetFlushing autoFlush(this);
|
||||
FlushLocked();
|
||||
nsresult rv = DispatchLocked(/* passed by ref */r, IgnoreFlushing, AssertDispatchSuccess);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
AwaitIdleLocked();
|
||||
}
|
||||
// If the ownership of |r| is not transferred in DispatchLocked() due to
|
||||
// dispatch failure, it will be deleted here outside the lock. We do so
|
||||
// since the destructor of the runnable might access TaskQueue and result
|
||||
// in deadlocks.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -662,6 +662,7 @@ void
|
||||
AudioCallbackDriver::Destroy()
|
||||
{
|
||||
STREAM_LOG(LogLevel::Debug, ("AudioCallbackDriver destroyed."));
|
||||
mAudioInput = nullptr;
|
||||
mAudioStream.reset();
|
||||
}
|
||||
|
||||
|
@ -270,10 +270,10 @@ MP4Decoder::IsVideoAccelerated(layers::LayersBackend aBackend, nsIGlobalObject*
|
||||
result.AssignLiteral("Yes");
|
||||
} else {
|
||||
result.AssignLiteral("No");
|
||||
if (failureReason.Length()) {
|
||||
result.AppendLiteral("; ");
|
||||
AppendUTF8toUTF16(failureReason, result);
|
||||
}
|
||||
}
|
||||
if (failureReason.Length()) {
|
||||
result.AppendLiteral("; ");
|
||||
AppendUTF8toUTF16(failureReason, result);
|
||||
}
|
||||
decoder->Shutdown();
|
||||
taskQueue->BeginShutdown();
|
||||
|
@ -220,4 +220,38 @@ TEST(MozPromise, PromiseAllReject)
|
||||
});
|
||||
}
|
||||
|
||||
// Test we don't hit the assertions in MozPromise when exercising promise
|
||||
// chaining upon task queue shutdown.
|
||||
TEST(MozPromise, Chaining)
|
||||
{
|
||||
AutoTaskQueue atq;
|
||||
RefPtr<TaskQueue> queue = atq.Queue();
|
||||
MozPromiseRequestHolder<TestPromise> holder;
|
||||
|
||||
RunOnTaskQueue(queue, [queue, &holder] () {
|
||||
auto p = TestPromise::CreateAndResolve(42, __func__);
|
||||
const size_t kIterations = 100;
|
||||
for (size_t i = 0; i < kIterations; ++i) {
|
||||
p = p->Then(queue, __func__,
|
||||
[] (int aVal) {
|
||||
EXPECT_EQ(aVal, 42);
|
||||
},
|
||||
[] () {}
|
||||
)->CompletionPromise();
|
||||
|
||||
if (i == kIterations / 2) {
|
||||
p->Then(queue, __func__,
|
||||
[queue, &holder] () {
|
||||
holder.Disconnect();
|
||||
queue->BeginShutdown();
|
||||
},
|
||||
DO_FAIL);
|
||||
}
|
||||
}
|
||||
// We will hit the assertion if we don't disconnect the leaf Request
|
||||
// in the promise chain.
|
||||
holder.Begin(p->Then(queue, __func__, [] () {}, [] () {}));
|
||||
});
|
||||
}
|
||||
|
||||
#undef DO_FAIL
|
||||
|
@ -68,7 +68,6 @@ TEST_DIRS += [
|
||||
MOCHITEST_MANIFESTS += [
|
||||
'test/mochitest.ini',
|
||||
'tests/mochitest/identity/mochitest.ini',
|
||||
'tests/mochitest/ipc/mochitest.ini',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBRTC']:
|
||||
|
@ -156,13 +156,23 @@ public:
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
|
||||
nsACString* failureReason = &mFailureReason;
|
||||
nsCString secondFailureReason;
|
||||
if (mBackend == LayersBackend::LAYERS_D3D11 &&
|
||||
Preferences::GetBool("media.windows-media-foundation.allow-d3d11-dxva", true) &&
|
||||
IsWin8OrLater()) {
|
||||
mDXVA2Manager = DXVA2Manager::CreateD3D11DXVA(mFailureReason);
|
||||
} else {
|
||||
mDXVA2Manager = DXVA2Manager::CreateD3D9DXVA(mFailureReason);
|
||||
mDXVA2Manager = DXVA2Manager::CreateD3D11DXVA(*failureReason);
|
||||
if (mDXVA2Manager) {
|
||||
return NS_OK;
|
||||
}
|
||||
// Try again with d3d9, but record the failure reason
|
||||
// into a new var to avoid overwriting the d3d11 failure.
|
||||
failureReason = &secondFailureReason;
|
||||
mFailureReason.Append(NS_LITERAL_CSTRING("; "));
|
||||
}
|
||||
mDXVA2Manager = DXVA2Manager::CreateD3D9DXVA(*failureReason);
|
||||
// Make sure we include the messages from both attempts (if applicable).
|
||||
mFailureReason.Append(secondFailureReason);
|
||||
return NS_OK;
|
||||
}
|
||||
nsAutoPtr<DXVA2Manager> mDXVA2Manager;
|
||||
@ -206,14 +216,14 @@ WMFVideoMFTManager::Init()
|
||||
{
|
||||
bool success = InitInternal(/* aForceD3D9 = */ false);
|
||||
|
||||
// If initialization failed with d3d11 DXVA then try falling back
|
||||
// to d3d9.
|
||||
if (!success && mDXVA2Manager && mDXVA2Manager->IsD3D11()) {
|
||||
mDXVA2Manager = nullptr;
|
||||
nsCString d3d11Failure = mDXVAFailureReason;
|
||||
success = InitInternal(true);
|
||||
mDXVAFailureReason.Append(NS_LITERAL_CSTRING("; "));
|
||||
mDXVAFailureReason.Append(d3d11Failure);
|
||||
if (success && mDXVA2Manager) {
|
||||
// If we had some failures but eventually made it work,
|
||||
// make sure we preserve the messages.
|
||||
if (mDXVA2Manager->IsD3D11()) {
|
||||
mDXVAFailureReason.Append(NS_LITERAL_CSTRING("Using D3D11 API"));
|
||||
} else {
|
||||
mDXVAFailureReason.Append(NS_LITERAL_CSTRING("Using D3D9 API"));
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
|
@ -577,25 +577,20 @@ skip-if = buildapp == 'b2g' && toolkit != 'gonk' # bug 1082984
|
||||
[test_aspectratio_mp4.html]
|
||||
[test_audio1.html]
|
||||
[test_audio2.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_audioDocumentTitle.html]
|
||||
skip-if = true # bug 475110 - disabled since we don't play Wave files standalone
|
||||
[test_autoplay.html]
|
||||
[test_autoplay_contentEditable.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_buffered.html]
|
||||
[test_bug448534.html]
|
||||
skip-if = buildapp == 'mulet' || os == 'win' || (toolkit == 'android' && processor == 'x86') # bug 894922 #x86 only bug 914439
|
||||
skip-if = buildapp == 'mulet' || os == 'win' # bug 894922
|
||||
[test_bug463162.xhtml]
|
||||
[test_bug465498.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86')
|
||||
[test_bug495145.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') || (os == 'mac' && os_version == '10.6') #x86 only bug 914439, bug 1021174
|
||||
skip-if = (os == 'mac' && os_version == '10.6') # bug 1021174
|
||||
[test_bug495300.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_bug654550.html]
|
||||
[test_bug686942.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_bug726904.html]
|
||||
[test_bug874897.html]
|
||||
[test_bug879717.html]
|
||||
@ -614,12 +609,11 @@ tags=capturestream
|
||||
tags=capturestream
|
||||
[test_can_play_type.html]
|
||||
[test_can_play_type_mpeg.html]
|
||||
skip-if = buildapp == 'b2g' || (toolkit == 'android' && processor == 'x86') # bug 1021675 #x86 only bug 914439
|
||||
skip-if = buildapp == 'b2g' # bug 1021675
|
||||
[test_can_play_type_no_ogg.html]
|
||||
[test_can_play_type_ogg.html]
|
||||
[test_chaining.html]
|
||||
[test_clone_media_element.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_closing_connections.html]
|
||||
[test_constants.html]
|
||||
[test_controls.html]
|
||||
@ -668,7 +662,6 @@ skip-if = os == 'win' && debug #win debug : Bug 1202683
|
||||
skip-if = toolkit == 'android' || (os == 'win' && !debug) || (os == 'mac' && !debug) # bug 608634
|
||||
[test_error_on_404.html]
|
||||
[test_fastSeek.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_fastSeek-forwards.html]
|
||||
[test_gmp_playback.html]
|
||||
skip-if = (os != 'win' || os_version == '5.1') # Only gmp-clearkey on Windows Vista and later decodes
|
||||
@ -678,18 +671,12 @@ skip-if = (os != 'win' || os_version == '5.1') # Only gmp-clearkey on Windows Vi
|
||||
[test_invalid_reject_play.html]
|
||||
[test_invalid_seek.html]
|
||||
[test_load.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_load_candidates.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_load_same_resource.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_load_source.html]
|
||||
[test_loop.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_media_selection.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_media_sniffer.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_mediarecorder_avoid_recursion.html]
|
||||
skip-if = os == 'win' && !debug # bug 1228605
|
||||
tags=msg
|
||||
@ -758,41 +745,30 @@ skip-if = true # bug 567954 and intermittent leaks
|
||||
[test_multiple_mediastreamtracks.html]
|
||||
[test_networkState.html]
|
||||
[test_new_audio.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_no_load_event.html]
|
||||
[test_paused.html]
|
||||
[test_paused_after_ended.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_play_events.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_play_events_2.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_play_twice.html]
|
||||
# Seamonkey: Bug 598252
|
||||
skip-if = appname == "seamonkey"
|
||||
[test_playback.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_playback_errors.html]
|
||||
skip-if = toolkit == 'gonk' # bug 1128845
|
||||
[test_playback_rate.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #bug 845162
|
||||
[test_playback_rate_playpause.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_playback_reactivate.html]
|
||||
#skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_played.html]
|
||||
[test_preload_actions.html]
|
||||
[test_preload_attribute.html]
|
||||
[test_preload_suspend.html]
|
||||
[test_progress.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_reactivate.html]
|
||||
skip-if = toolkit == 'gonk' || (toolkit == 'android' && processor == 'x86') #x86 only bug 914439 and bug 1128845 on gonk
|
||||
skip-if = toolkit == 'gonk' # bug 1128845 on gonk
|
||||
[test_readyState.html]
|
||||
[test_referer.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_replay_metadata.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_reset_events_async.html]
|
||||
[test_reset_src.html]
|
||||
[test_video_dimensions.html]
|
||||
@ -802,9 +778,7 @@ skip-if = true # bug 1021673
|
||||
[test_seek_negative.html]
|
||||
[test_seek_nosrc.html]
|
||||
[test_seek_out_of_range.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_seek-1.html]
|
||||
skip-if = android_version == '10' # bug 1059116
|
||||
[test_seek-2.html]
|
||||
[test_seek-3.html]
|
||||
[test_seek-4.html]
|
||||
@ -818,24 +792,21 @@ skip-if = android_version == '10' # bug 1059116
|
||||
[test_seek-12.html]
|
||||
[test_seek-13.html]
|
||||
[test_seekable1.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #timeout x86 only bug 914439
|
||||
[test_seekLies.html]
|
||||
[test_source.html]
|
||||
[test_source_media.html]
|
||||
[test_source_null.html]
|
||||
[test_source_write.html]
|
||||
[test_standalone.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_streams_autoplay.html]
|
||||
tags=msg capturestream
|
||||
[test_streams_capture_origin.html]
|
||||
tags=msg capturestream
|
||||
[test_streams_element_capture.html]
|
||||
#x86 only bug 914439, b2g desktop bug 752796
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') || (buildapp == 'b2g' && toolkit != 'gonk')
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk')
|
||||
tags=msg capturestream
|
||||
[test_streams_element_capture_createObjectURL.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
tags=msg capturestream
|
||||
[test_streams_element_capture_playback.html]
|
||||
tags=msg capturestream
|
||||
@ -859,13 +830,11 @@ tags=msg capturestream
|
||||
[test_texttrackregion.html]
|
||||
[test_texttrack_moz.html]
|
||||
[test_timeupdate_small_files.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_trackelementevent.html]
|
||||
[test_trackevent.html]
|
||||
[test_unseekable.html]
|
||||
skip-if = toolkit == 'gonk' || (toolkit == 'android' && processor == 'x86') #x86 only and bug 1128845 on gonk
|
||||
skip-if = toolkit == 'gonk' # bug 1128845 on gonk
|
||||
[test_video_to_canvas.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_video_in_audio_element.html]
|
||||
[test_videoDocumentTitle.html]
|
||||
[test_VideoPlaybackQuality.html]
|
||||
|
@ -268,10 +268,7 @@ function setupEnvironment() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Running as a Mochitest.
|
||||
SimpleTest.requestFlakyTimeout("WebRTC inherently depends on timeouts");
|
||||
window.finish = () => SimpleTest.finish();
|
||||
SpecialPowers.pushPrefEnv({
|
||||
var defaultMochitestPrefs = {
|
||||
'set': [
|
||||
['media.peerconnection.enabled', true],
|
||||
['media.peerconnection.identity.enabled', true],
|
||||
@ -285,7 +282,22 @@ function setupEnvironment() {
|
||||
['media.getusermedia.audiocapture.enabled', true],
|
||||
['media.recorder.audio_node.enabled', true]
|
||||
]
|
||||
}, setTestOptions);
|
||||
};
|
||||
|
||||
const isAndroid = !!navigator.userAgent.includes("Android");
|
||||
|
||||
if (isAndroid) {
|
||||
defaultMochitestPrefs.set.push(
|
||||
["media.navigator.video.default_width", 320],
|
||||
["media.navigator.video.default_height", 240],
|
||||
["media.navigator.video.max_fr", 10]
|
||||
);
|
||||
}
|
||||
|
||||
// Running as a Mochitest.
|
||||
SimpleTest.requestFlakyTimeout("WebRTC inherently depends on timeouts");
|
||||
window.finish = () => SimpleTest.finish();
|
||||
SpecialPowers.pushPrefEnv(defaultMochitestPrefs, setTestOptions);
|
||||
|
||||
// We don't care about waiting for this to complete, we just want to ensure
|
||||
// that we don't build up a huge backlog of GC work.
|
||||
|
@ -1,9 +1,10 @@
|
||||
[DEFAULT]
|
||||
# Android 2.3 - bug 981881
|
||||
# won't run on b2g desktop tests - bug 1119993
|
||||
# broken HTTPS on b2g emulator - bug 1135339
|
||||
# Android 4.3 - bug 981881
|
||||
# Exit code -11 for linux/opt/non-e10s - bug 1256284
|
||||
subsuite = media
|
||||
skip-if = android_version == '10' || android_version == '18' || (buildapp == 'b2g' && toolkit != 'gonk') || (buildapp == 'b2g' && toolkit == 'gonk') || buildapp == 'mulet'
|
||||
skip-if = android_version == '18' || (buildapp == 'b2g' && toolkit != 'gonk') || (buildapp == 'b2g' && toolkit == 'gonk') || buildapp == 'mulet' || (os == 'linux' && !debug && !e10s)
|
||||
support-files =
|
||||
/.well-known/idp-proxy/idp.js
|
||||
identityPcTest.js
|
||||
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"runtests":{
|
||||
"dom/media/tests/mochitest/test_getUserMedia_basicVideoAudio.html":"included",
|
||||
"dom/media/tests/mochitest/test_peerConnection_basicAudioVideo.html":"included",
|
||||
"dom/media/tests/mochitest/test_dataChannel_basicAudioVideo.html":"included"
|
||||
},
|
||||
"excludetests":{
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
[DEFAULT]
|
||||
tags=msg
|
||||
subsuite=media
|
||||
support-files =
|
||||
ipc.json
|
||||
|
||||
skip-if = e10s
|
||||
|
||||
[test_ipc.html]
|
||||
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' #bug 910661 # b2g(nested ipc not working) b2g-debug(debug-only failure) b2g-desktop(nested ipc not working)
|
@ -1,176 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for OOP PeerConncection</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="application/javascript;version=1.7">
|
||||
"use strict";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// This isn't a single test. It runs the entirety of the PeerConnection
|
||||
// tests. Each of those has a normal timeout handler, so there's no point in
|
||||
// having a timeout here. I'm setting this really high just to avoid getting
|
||||
// killed.
|
||||
SimpleTest.requestLongerTimeout(100);
|
||||
|
||||
// The crash observer registration functions are stubbed out here to
|
||||
// prevent the iframe test runner from breaking later crash-related tests.
|
||||
function iframeScriptFirst() {
|
||||
SpecialPowers.prototype.registerProcessCrashObservers = () => {};
|
||||
SpecialPowers.prototype.unregisterProcessCrashObservers = () => {};
|
||||
|
||||
content.wrappedJSObject.RunSet.reloadAndRunAll({
|
||||
preventDefault: function() { },
|
||||
__exposedProps__: { preventDefault: 'r' }
|
||||
});
|
||||
}
|
||||
|
||||
function iframeScriptSecond() {
|
||||
let TestRunner = content.wrappedJSObject.TestRunner;
|
||||
let oldComplete = TestRunner.onComplete;
|
||||
|
||||
TestRunner.onComplete = function() {
|
||||
TestRunner.onComplete = oldComplete;
|
||||
|
||||
sendAsyncMessage("test:PeerConnection:ipcTestComplete", {
|
||||
result: JSON.stringify(TestRunner._failedTests)
|
||||
});
|
||||
|
||||
if (oldComplete) {
|
||||
oldComplete();
|
||||
}
|
||||
};
|
||||
|
||||
TestRunner.structuredLogger._dumpMessage = function(msg) {
|
||||
sendAsyncMessage("test:PeerConnection:ipcTestMessage", { msg: msg });
|
||||
}
|
||||
}
|
||||
|
||||
let VALID_ACTIONS = ['suite_start', 'suite_end', 'test_start', 'test_end', 'test_status', 'process_output', 'log'];
|
||||
function validStructuredMessage(message) {
|
||||
return message.action !== undefined && VALID_ACTIONS.indexOf(message.action) >= 0;
|
||||
}
|
||||
function onTestMessage(data) {
|
||||
let message = SpecialPowers.wrap(data).data.msg;
|
||||
|
||||
if (validStructuredMessage(message)) {
|
||||
switch (message.action) {
|
||||
case "test_status":
|
||||
case "test_end":
|
||||
let test_tokens = message.test.split("/");
|
||||
let test_name = test_tokens[test_tokens.length - 1];
|
||||
if (message.subtest) {
|
||||
test_name += " | " + message.subtest;
|
||||
}
|
||||
ok(message.expected === undefined, test_name, message.message);
|
||||
break;
|
||||
case "log":
|
||||
info(message.message);
|
||||
break;
|
||||
default:
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onTestComplete() {
|
||||
let comp = SpecialPowers.wrap(SpecialPowers.Components);
|
||||
let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
|
||||
let spObserver = comp.classes["@mozilla.org/special-powers-observer;1"]
|
||||
.getService(comp.interfaces.nsIMessageListener);
|
||||
|
||||
mm.removeMessageListener("SPPrefService", spObserver);
|
||||
mm.removeMessageListener("SPProcessCrashService", spObserver);
|
||||
mm.removeMessageListener("SPPingService", spObserver);
|
||||
mm.removeMessageListener("SpecialPowers.Quit", spObserver);
|
||||
mm.removeMessageListener("SPPermissionManager", spObserver);
|
||||
|
||||
mm.removeMessageListener("test:PeerConnection:ipcTestMessage", onTestMessage);
|
||||
mm.removeMessageListener("test:PeerConnection:ipcTestComplete", onTestComplete);
|
||||
|
||||
SimpleTest.executeSoon(function () { SimpleTest.finish(); });
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
let iframe = document.createElement("iframe");
|
||||
SpecialPowers.wrap(iframe).mozbrowser = true;
|
||||
iframe.id = "iframe";
|
||||
iframe.style.width = "100%";
|
||||
iframe.style.height = "1000px";
|
||||
|
||||
function iframeLoadSecond() {
|
||||
ok(true, "Got second iframe load event.");
|
||||
iframe.removeEventListener("mozbrowserloadend", iframeLoadSecond);
|
||||
let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
|
||||
mm.loadFrameScript("data:,(" + iframeScriptSecond.toString() + ")();",
|
||||
false);
|
||||
}
|
||||
|
||||
function iframeLoadFirst() {
|
||||
ok(true, "Got first iframe load event.");
|
||||
iframe.removeEventListener("mozbrowserloadend", iframeLoadFirst);
|
||||
iframe.addEventListener("mozbrowserloadend", iframeLoadSecond);
|
||||
|
||||
let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
|
||||
|
||||
let comp = SpecialPowers.wrap(SpecialPowers.Components);
|
||||
|
||||
let spObserver =
|
||||
comp.classes["@mozilla.org/special-powers-observer;1"]
|
||||
.getService(comp.interfaces.nsIMessageListener);
|
||||
|
||||
mm.addMessageListener("SPPrefService", spObserver);
|
||||
mm.addMessageListener("SPProcessCrashService", spObserver);
|
||||
mm.addMessageListener("SPPingService", spObserver);
|
||||
mm.addMessageListener("SpecialPowers.Quit", spObserver);
|
||||
mm.addMessageListener("SPPermissionManager", spObserver);
|
||||
|
||||
mm.addMessageListener("test:PeerConnection:ipcTestMessage", onTestMessage);
|
||||
mm.addMessageListener("test:PeerConnection:ipcTestComplete", onTestComplete);
|
||||
|
||||
let specialPowersBase = "chrome://specialpowers/content/";
|
||||
mm.loadFrameScript(specialPowersBase + "MozillaLogger.js", false);
|
||||
mm.loadFrameScript(specialPowersBase + "specialpowersAPI.js", false);
|
||||
mm.loadFrameScript(specialPowersBase + "specialpowers.js", false);
|
||||
|
||||
mm.loadFrameScript("data:,(" + iframeScriptFirst.toString() + ")();", false);
|
||||
}
|
||||
|
||||
iframe.addEventListener("mozbrowserloadend", iframeLoadFirst);
|
||||
|
||||
// Strip the filename and a directory level.
|
||||
let href = window.location.href;
|
||||
href = href.substring(0, href.lastIndexOf('/'));
|
||||
href = href.substring(0, href.lastIndexOf('/'));
|
||||
|
||||
href += "?consoleLevel=INFO" +
|
||||
"&testManifest=tests/dom/media/tests/mochitest/ipc/ipc.json";
|
||||
iframe.src = href;
|
||||
document.body.appendChild(iframe);
|
||||
}
|
||||
|
||||
addEventListener("load", function() {
|
||||
|
||||
SpecialPowers.addPermission("browser", true, document);
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["media.peerconnection.ipc.enabled", true],
|
||||
|
||||
// TODO: remove this as part of bug 820712
|
||||
["network.disable.ipc.security", true],
|
||||
|
||||
["dom.ipc.browser_frames.oop_by_default", true],
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["browser.pagethumbnails.capturing_disabled", true]
|
||||
]
|
||||
}, runTests);
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,8 +1,7 @@
|
||||
[DEFAULT]
|
||||
# Android 2.3 - bug 981881
|
||||
tags = msg webrtc
|
||||
subsuite = media
|
||||
skip-if = android_version == '10' || (buildapp == 'mulet') || (toolkit == 'gonk' && debug) # b2g(Either bug 1171118 or bug 1169838, take your pick)
|
||||
skip-if = (buildapp == 'mulet') || (toolkit == 'gonk' && debug) # b2g(Either bug 1171118 or bug 1169838, take your pick)
|
||||
support-files =
|
||||
head.js
|
||||
dataChannel.js
|
||||
|
@ -41,7 +41,7 @@ support-files =
|
||||
[test_audioBufferSourceNodeLoopStartEnd.html]
|
||||
[test_audioBufferSourceNodeLoopStartEndSame.html]
|
||||
[test_audioBufferSourceNodeDetached.html]
|
||||
skip-if = (toolkit == 'android' && (processor == 'x86' || debug)) || os == 'win' # bug 1127845, bug 1138468
|
||||
skip-if = (toolkit == 'android' && debug) || os == 'win' # bug 1127845, bug 1138468
|
||||
[test_audioBufferSourceNodeNoStart.html]
|
||||
[test_audioBufferSourceNodeNullBuffer.html]
|
||||
[test_audioBufferSourceNodeOffset.html]
|
||||
@ -146,10 +146,10 @@ tags=capturestream
|
||||
[test_mediaStreamAudioSourceNodeResampling.html]
|
||||
tags=capturestream
|
||||
[test_mixingRules.html]
|
||||
skip-if = android_version == '10' || android_version == '18' # bug 1091965
|
||||
skip-if = toolkit == 'android' # bug 1091965
|
||||
[test_mozaudiochannel.html]
|
||||
# Android: bug 1061675; OSX 10.6: bug 1097721
|
||||
skip-if = (toolkit == 'gonk' && !debug) || android_version == '10' || android_version == '18' || (os == 'mac' && os_version == '10.6')
|
||||
skip-if = (toolkit == 'gonk' && !debug) || (toolkit == 'android') || (os == 'mac' && os_version == '10.6')
|
||||
[test_nodeToParamConnection.html]
|
||||
[test_OfflineAudioContext.html]
|
||||
[test_offlineDestinationChannelCountLess.html]
|
||||
|
@ -42,6 +42,7 @@ MediaEngineTabVideoSource::MediaEngineTabVideoSource()
|
||||
, mViewportHeight(0)
|
||||
, mTimePerFrame(0)
|
||||
, mDataSize(0)
|
||||
, mBlackedoutWindow(false)
|
||||
, mMonitor("MediaEngineTabVideoSource") {}
|
||||
|
||||
nsresult
|
||||
@ -80,19 +81,26 @@ MediaEngineTabVideoSource::Notify(nsITimer*) {
|
||||
Draw();
|
||||
return NS_OK;
|
||||
}
|
||||
#define LOGTAG "TabVideo"
|
||||
|
||||
nsresult
|
||||
MediaEngineTabVideoSource::InitRunnable::Run()
|
||||
{
|
||||
if (mVideoSource->mWindowId != -1) {
|
||||
nsCOMPtr<nsPIDOMWindowOuter> window =
|
||||
nsGlobalWindow::GetOuterWindowWithId(mVideoSource->mWindowId)->AsOuter();
|
||||
if (window) {
|
||||
mVideoSource->mWindow = window;
|
||||
nsGlobalWindow* globalWindow =
|
||||
nsGlobalWindow::GetOuterWindowWithId(mVideoSource->mWindowId);
|
||||
if (!globalWindow) {
|
||||
// We can't access the window, just send a blacked out screen.
|
||||
mVideoSource->mWindow = nullptr;
|
||||
mVideoSource->mBlackedoutWindow = true;
|
||||
} else {
|
||||
nsCOMPtr<nsPIDOMWindowOuter> window = globalWindow->AsOuter();
|
||||
if (window) {
|
||||
mVideoSource->mWindow = window;
|
||||
mVideoSource->mBlackedoutWindow = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!mVideoSource->mWindow) {
|
||||
if (!mVideoSource->mWindow && !mVideoSource->mBlackedoutWindow) {
|
||||
nsresult rv;
|
||||
mVideoSource->mTabSource = do_GetService(NS_TABSOURCESERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -104,6 +112,7 @@ MediaEngineTabVideoSource::InitRunnable::Run()
|
||||
return NS_OK;
|
||||
|
||||
mVideoSource->mWindow = nsPIDOMWindowOuter::From(win);
|
||||
MOZ_ASSERT(mVideoSource->mWindow);
|
||||
}
|
||||
nsCOMPtr<nsIRunnable> start(new StartRunnable(mVideoSource));
|
||||
start->Run();
|
||||
@ -211,24 +220,33 @@ MediaEngineTabVideoSource::NotifyPull(MediaStreamGraph*,
|
||||
|
||||
void
|
||||
MediaEngineTabVideoSource::Draw() {
|
||||
if (!mWindow) {
|
||||
if (!mWindow && !mBlackedoutWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mScrollWithPage || mViewportWidth == INT32_MAX) {
|
||||
mWindow->GetInnerWidth(&mViewportWidth);
|
||||
}
|
||||
if (mScrollWithPage || mViewportHeight == INT32_MAX) {
|
||||
mWindow->GetInnerHeight(&mViewportHeight);
|
||||
}
|
||||
if (!mViewportWidth || !mViewportHeight) {
|
||||
return;
|
||||
if (mWindow) {
|
||||
if (mScrollWithPage || mViewportWidth == INT32_MAX) {
|
||||
mWindow->GetInnerWidth(&mViewportWidth);
|
||||
}
|
||||
if (mScrollWithPage || mViewportHeight == INT32_MAX) {
|
||||
mWindow->GetInnerHeight(&mViewportHeight);
|
||||
}
|
||||
if (!mViewportWidth || !mViewportHeight) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
mViewportWidth = 640;
|
||||
mViewportHeight = 480;
|
||||
}
|
||||
|
||||
IntSize size;
|
||||
{
|
||||
float pixelRatio;
|
||||
mWindow->GetDevicePixelRatio(&pixelRatio);
|
||||
if (mWindow) {
|
||||
mWindow->GetDevicePixelRatio(&pixelRatio);
|
||||
} else {
|
||||
pixelRatio = 1.0f;
|
||||
}
|
||||
const int32_t deviceWidth = (int32_t)(pixelRatio * mViewportWidth);
|
||||
const int32_t deviceHeight = (int32_t)(pixelRatio * mViewportHeight);
|
||||
|
||||
@ -255,7 +273,7 @@ MediaEngineTabVideoSource::Draw() {
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
{
|
||||
if (mWindow) {
|
||||
RefPtr<nsPresContext> presContext;
|
||||
nsIDocShell* docshell = mWindow->GetDocShell();
|
||||
if (docshell) {
|
||||
@ -267,15 +285,6 @@ MediaEngineTabVideoSource::Draw() {
|
||||
presShell = presContext->PresShell();
|
||||
}
|
||||
|
||||
nscolor bgColor = NS_RGB(255, 255, 255);
|
||||
uint32_t renderDocFlags = mScrollWithPage? 0 :
|
||||
(nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING |
|
||||
nsIPresShell::RENDER_DOCUMENT_RELATIVE);
|
||||
nsRect r(nsPresContext::CSSPixelsToAppUnits((float)mViewportOffsetX),
|
||||
nsPresContext::CSSPixelsToAppUnits((float)mViewportOffsetY),
|
||||
nsPresContext::CSSPixelsToAppUnits((float)mViewportWidth),
|
||||
nsPresContext::CSSPixelsToAppUnits((float)mViewportHeight));
|
||||
|
||||
RefPtr<layers::ImageContainer> container = layers::LayerManager::CreateImageContainer();
|
||||
RefPtr<DrawTarget> dt =
|
||||
Factory::CreateDrawTargetForData(BackendType::CAIRO,
|
||||
@ -290,7 +299,17 @@ MediaEngineTabVideoSource::Draw() {
|
||||
context->SetMatrix(context->CurrentMatrix().Scale((((float) size.width)/mViewportWidth),
|
||||
(((float) size.height)/mViewportHeight)));
|
||||
|
||||
NS_ENSURE_SUCCESS_VOID(presShell->RenderDocument(r, renderDocFlags, bgColor, context));
|
||||
if (mWindow) {
|
||||
nscolor bgColor = NS_RGB(255, 255, 255);
|
||||
uint32_t renderDocFlags = mScrollWithPage? 0 :
|
||||
(nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING |
|
||||
nsIPresShell::RENDER_DOCUMENT_RELATIVE);
|
||||
nsRect r(nsPresContext::CSSPixelsToAppUnits((float)mViewportOffsetX),
|
||||
nsPresContext::CSSPixelsToAppUnits((float)mViewportOffsetY),
|
||||
nsPresContext::CSSPixelsToAppUnits((float)mViewportWidth),
|
||||
nsPresContext::CSSPixelsToAppUnits((float)mViewportHeight));
|
||||
NS_ENSURE_SUCCESS_VOID(presShell->RenderDocument(r, renderDocFlags, bgColor, context));
|
||||
}
|
||||
|
||||
RefPtr<SourceSurface> surface = dt->Snapshot();
|
||||
if (!surface) {
|
||||
@ -306,8 +325,11 @@ MediaEngineTabVideoSource::Draw() {
|
||||
nsresult
|
||||
MediaEngineTabVideoSource::Stop(mozilla::SourceMediaStream*, mozilla::TrackID)
|
||||
{
|
||||
if (!mWindow)
|
||||
// If mBlackedoutWindow is true, we may be running
|
||||
// despite mWindow == nullptr.
|
||||
if (!mWindow && !mBlackedoutWindow) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_DispatchToMainThread(new StopRunnable(this));
|
||||
return NS_OK;
|
||||
|
@ -89,6 +89,8 @@ private:
|
||||
UniquePtr<unsigned char[]> mData;
|
||||
size_t mDataSize;
|
||||
nsCOMPtr<nsPIDOMWindowOuter> mWindow;
|
||||
// If this is set, we will run despite mWindow == nullptr.
|
||||
bool mBlackedoutWindow;
|
||||
RefPtr<layers::SourceSurfaceImage> mImage;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
Monitor mMonitor;
|
||||
|
@ -220,9 +220,6 @@ MediaEngineWebRTC::EnumerateVideoDevices(dom::MediaSourceEnum aMediaSource,
|
||||
num = mozilla::camera::GetChildAndCall(
|
||||
&mozilla::camera::CamerasChild::NumberOfCaptureDevices,
|
||||
capEngine);
|
||||
if (num <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < num; i++) {
|
||||
char deviceName[MediaEngineSource::kMaxDeviceNameLength];
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include "SpeechSynthesisUtterance.h"
|
||||
#include "SpeechSynthesisVoice.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
@ -120,7 +122,7 @@ SpeechSynthesisUtterance::Volume() const
|
||||
void
|
||||
SpeechSynthesisUtterance::SetVolume(float aVolume)
|
||||
{
|
||||
mVolume = aVolume;
|
||||
mVolume = std::max<float>(std::min<float>(aVolume, 1), 0);
|
||||
}
|
||||
|
||||
float
|
||||
@ -132,7 +134,7 @@ SpeechSynthesisUtterance::Rate() const
|
||||
void
|
||||
SpeechSynthesisUtterance::SetRate(float aRate)
|
||||
{
|
||||
mRate = aRate;
|
||||
mRate = std::max<float>(std::min<float>(aRate, 10), 0.1f);
|
||||
}
|
||||
|
||||
float
|
||||
@ -144,7 +146,7 @@ SpeechSynthesisUtterance::Pitch() const
|
||||
void
|
||||
SpeechSynthesisUtterance::SetPitch(float aPitch)
|
||||
{
|
||||
mPitch = aPitch;
|
||||
mPitch = std::max<float>(std::min<float>(aPitch, 2), 0);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -48,6 +48,24 @@ is(ssu.volume, 0.5, "SpeechSynthesisUtterance.volume is correct");
|
||||
is(ssu.rate, 2.0, "SpeechSynthesisUtterance.rate is correct");
|
||||
is(ssu.pitch, 1.5, "SpeechSynthesisUtterance.pitch is correct");
|
||||
|
||||
// Assign a rate that is out of bounds
|
||||
ssu.rate = 20;
|
||||
is(ssu.rate, 10, "SpeechSynthesisUtterance.rate enforces max of 10");
|
||||
ssu.rate = 0;
|
||||
is(ssu.rate.toPrecision(1), "0.1", "SpeechSynthesisUtterance.rate enforces min of 0.1");
|
||||
|
||||
// Assign a volume which is out of bounds
|
||||
ssu.volume = 2;
|
||||
is(ssu.volume, 1, "SpeechSynthesisUtterance.volume enforces max of 1");
|
||||
ssu.volume = -1;
|
||||
is(ssu.volume, 0, "SpeechSynthesisUtterance.volume enforces min of 0");
|
||||
|
||||
// Assign a pitch which is out of bounds
|
||||
ssu.pitch = 2.1;
|
||||
is(ssu.pitch, 2, "SpeechSynthesisUtterance.pitch enforces max of 2");
|
||||
ssu.pitch = -1;
|
||||
is(ssu.pitch, 0, "SpeechSynthesisUtterance.pitch enforces min of 0");
|
||||
|
||||
// Test for singleton instance hanging off of window.
|
||||
ok(speechSynthesis, "speechSynthesis exists in global scope");
|
||||
is(typeof speechSynthesis, "object", "speechSynthesis instance is an object");
|
||||
|
@ -255,6 +255,17 @@ Object.assign(PushServiceParent.prototype, {
|
||||
let name = requestName.slice("Push:".length);
|
||||
return "PushService:" + name + ":" + suffix;
|
||||
},
|
||||
|
||||
// Methods used for mocking in tests.
|
||||
|
||||
replaceServiceBackend(options) {
|
||||
this._service.changeTestServer(options.serverURI, options);
|
||||
},
|
||||
|
||||
restoreServiceBackend() {
|
||||
var defaultServerURL = Services.prefs.getCharPref("dom.push.serverURL");
|
||||
this._service.changeTestServer(defaultServerURL);
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -235,6 +235,20 @@ this.PushService = {
|
||||
}
|
||||
},
|
||||
|
||||
// Used for testing.
|
||||
changeTestServer(url, options = {}) {
|
||||
console.debug("changeTestServer()");
|
||||
|
||||
this._stateChangeProcessEnqueue(_ => {
|
||||
if (this._state < PUSH_SERVICE_ACTIVATING) {
|
||||
console.debug("changeTestServer: PushService not activated?");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return this._changeServerURL(url, CHANGING_SERVICE_EVENT, options);
|
||||
});
|
||||
},
|
||||
|
||||
observe: function observe(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
/*
|
||||
@ -367,7 +381,7 @@ this.PushService = {
|
||||
return [service, uri];
|
||||
},
|
||||
|
||||
_changeServerURL: function(serverURI, event) {
|
||||
_changeServerURL: function(serverURI, event, options = {}) {
|
||||
console.debug("changeServerURL()");
|
||||
|
||||
switch(event) {
|
||||
@ -392,7 +406,7 @@ this.PushService = {
|
||||
if (this._state == PUSH_SERVICE_INIT) {
|
||||
this._setState(PUSH_SERVICE_ACTIVATING);
|
||||
// The service has not been running - start it.
|
||||
return this._startService(service, uri)
|
||||
return this._startService(service, uri, options)
|
||||
.then(_ => this._stateChangeProcessEnqueue(_ =>
|
||||
this._changeStateConnectionEnabledEvent(prefs.get("connection.enabled")))
|
||||
);
|
||||
@ -404,7 +418,7 @@ this.PushService = {
|
||||
// check is called in changeStateConnectionEnabledEvent function)
|
||||
return this._stopService(CHANGING_SERVICE_EVENT)
|
||||
.then(_ =>
|
||||
this._startService(service, uri)
|
||||
this._startService(service, uri, options)
|
||||
)
|
||||
.then(_ => this._stateChangeProcessEnqueue(_ =>
|
||||
this._changeStateConnectionEnabledEvent(prefs.get("connection.enabled")))
|
||||
@ -610,9 +624,10 @@ this.PushService = {
|
||||
|
||||
this._stateChangeProcessEnqueue(_ =>
|
||||
{
|
||||
this._changeServerURL("", UNINIT_EVENT);
|
||||
var p = this._changeServerURL("", UNINIT_EVENT);
|
||||
this._setState(PUSH_SERVICE_UNINIT);
|
||||
console.debug("uninit: shutdown complete!");
|
||||
return p;
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -2,11 +2,11 @@
|
||||
subsuite = push
|
||||
support-files =
|
||||
worker.js
|
||||
push-server.sjs
|
||||
frame.html
|
||||
webpush.js
|
||||
lifetime_worker.js
|
||||
test_utils.js
|
||||
mockpushserviceparent.js
|
||||
skip-if = os == "android" || toolkit == "gonk"
|
||||
|
||||
[test_has_permissions.html]
|
||||
|
111
dom/push/test/mockpushserviceparent.js
Normal file
111
dom/push/test/mockpushserviceparent.js
Normal file
@ -0,0 +1,111 @@
|
||||
"use strict";
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
/**
|
||||
* Defers one or more callbacks until the next turn of the event loop. Multiple
|
||||
* callbacks are executed in order.
|
||||
*
|
||||
* @param {Function[]} callbacks The callbacks to execute. One callback will be
|
||||
* executed per tick.
|
||||
*/
|
||||
function waterfall(...callbacks) {
|
||||
callbacks.reduce((promise, callback) => promise.then(() => {
|
||||
callback();
|
||||
}), Promise.resolve()).catch(Cu.reportError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimal implementation of a mock WebSocket connect to be used with
|
||||
* PushService. Forwards and receive messages from the implementation
|
||||
* that lives in the content process.
|
||||
*/
|
||||
function MockWebSocketParent(originalURI) {
|
||||
this._originalURI = originalURI;
|
||||
}
|
||||
|
||||
MockWebSocketParent.prototype = {
|
||||
_originalURI: null,
|
||||
|
||||
_listener: null,
|
||||
_context: null,
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsISupports,
|
||||
Ci.nsIWebSocketChannel
|
||||
]),
|
||||
|
||||
get originalURI() {
|
||||
return this._originalURI;
|
||||
},
|
||||
|
||||
asyncOpen(uri, origin, windowId, listener, context) {
|
||||
this._listener = listener;
|
||||
this._context = context;
|
||||
waterfall(() => this._listener.onStart(this._context));
|
||||
},
|
||||
|
||||
sendMsg(msg) {
|
||||
sendAsyncMessage("client-msg", msg);
|
||||
},
|
||||
|
||||
close() {
|
||||
waterfall(() => this._listener.onStop(this._context, Cr.NS_OK));
|
||||
},
|
||||
|
||||
serverSendMsg(msg) {
|
||||
waterfall(() => this._listener.onMessageAvailable(this._context, msg),
|
||||
() => this._listener.onAcknowledge(this._context, 0));
|
||||
},
|
||||
};
|
||||
|
||||
function MockNetworkInfo() {}
|
||||
|
||||
MockNetworkInfo.prototype = {
|
||||
getNetworkInformation() {
|
||||
return {mcc: '', mnc: '', ip: ''};
|
||||
},
|
||||
|
||||
getNetworkState(callback) {
|
||||
callback({mcc: '', mnc: '', ip: '', netid: ''});
|
||||
},
|
||||
|
||||
getNetworkStateChangeEventName() {
|
||||
return 'network:offline-status-changed';
|
||||
}
|
||||
};
|
||||
|
||||
var pushService = Cc["@mozilla.org/push/Service;1"].
|
||||
getService(Ci.nsIPushService).
|
||||
wrappedJSObject;
|
||||
|
||||
var mockWebSocket;
|
||||
|
||||
addMessageListener("setup", function () {
|
||||
mockWebSocket = new Promise((resolve, reject) => {
|
||||
pushService.replaceServiceBackend({
|
||||
serverURI: "wss://push.example.org/",
|
||||
networkInfo: new MockNetworkInfo(),
|
||||
makeWebSocket(uri) {
|
||||
var socket = new MockWebSocketParent(uri);
|
||||
resolve(socket);
|
||||
return socket;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
addMessageListener("teardown", function () {
|
||||
mockWebSocket.then(socket => {
|
||||
socket.close();
|
||||
pushService.restoreServiceBackend();
|
||||
});
|
||||
});
|
||||
|
||||
addMessageListener("server-msg", function (msg) {
|
||||
mockWebSocket.then(socket => {
|
||||
socket.serverSendMsg(msg);
|
||||
});
|
||||
});
|
@ -1,59 +0,0 @@
|
||||
function debug(str) {
|
||||
// dump("@@@ push-server " + str + "\n");
|
||||
}
|
||||
|
||||
function concatUint8Arrays(arrays, size) {
|
||||
let index = 0;
|
||||
return arrays.reduce((result, a) => {
|
||||
result.set(new Uint8Array(a), index);
|
||||
index += a.byteLength;
|
||||
return result;
|
||||
}, new Uint8Array(size));
|
||||
}
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
debug("handling request!");
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
let params = request.getHeader("X-Push-Server");
|
||||
debug("params = " + params);
|
||||
|
||||
let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
|
||||
xhr.open(request.getHeader("X-Push-Method"), params);
|
||||
|
||||
for (let headers = request.headers; headers.hasMoreElements();) {
|
||||
let header = headers.getNext().QueryInterface(Ci.nsISupportsString).data;
|
||||
if (header.toLowerCase() != "x-push-server") {
|
||||
xhr.setRequestHeader(header, request.getHeader(header));
|
||||
}
|
||||
}
|
||||
|
||||
let bodyStream = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
|
||||
bodyStream.setInputStream(request.bodyInputStream);
|
||||
let size = 0;
|
||||
let data = [];
|
||||
for (let available; available = bodyStream.available();) {
|
||||
data.push(bodyStream.readByteArray(available));
|
||||
size += available;
|
||||
}
|
||||
|
||||
function reply(statusCode, statusText) {
|
||||
response.setStatusLine(request.httpVersion, statusCode, statusText);
|
||||
response.finish();
|
||||
}
|
||||
|
||||
xhr.onload = function(e) {
|
||||
debug("xhr : " + this.status);
|
||||
reply(this.status, this.statusText);
|
||||
};
|
||||
xhr.onerror = function(e) {
|
||||
debug("xhr error: " + e);
|
||||
reply(500, "Internal Server Error");
|
||||
};
|
||||
|
||||
response.processAsync();
|
||||
xhr.send(concatUint8Arrays(data, size));
|
||||
}
|
@ -25,10 +25,24 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
</pre>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
var userAgentID = "ac44402c-85fc-41e4-a0d0-483316d15351";
|
||||
var channelID = null;
|
||||
|
||||
var mockSocket = new MockWebSocket();
|
||||
mockSocket.onRegister = function(request) {
|
||||
channelID = request.channelID;
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: "register",
|
||||
uaid: userAgentID,
|
||||
channelID,
|
||||
status: 200,
|
||||
pushEndpoint: "https://example.com/endpoint/1"
|
||||
}));
|
||||
};
|
||||
|
||||
var registration;
|
||||
add_task(function* start() {
|
||||
yield setupPrefs();
|
||||
yield setupPrefsAndMock(mockSocket);
|
||||
yield setPushPermission(true);
|
||||
|
||||
var url = "worker.js" + "?" + (Math.random());
|
||||
@ -104,10 +118,28 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
);
|
||||
});
|
||||
|
||||
var version = 0;
|
||||
function sendEncryptedMsg(pushSubscription, message) {
|
||||
return webPushEncrypt(pushSubscription, message)
|
||||
.then((encryptedData) => {
|
||||
mockSocket.serverSendMsg(JSON.stringify({
|
||||
messageType: 'notification',
|
||||
version: version++,
|
||||
channelID: channelID,
|
||||
data: encryptedData.data,
|
||||
headers: {
|
||||
encryption: encryptedData.encryption,
|
||||
encryption_key: encryptedData.encryption_key,
|
||||
encoding: encryptedData.encoding
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
function waitForMessage(pushSubscription, message) {
|
||||
return Promise.all([
|
||||
controlledFrame.waitOnWorkerMessage("finished"),
|
||||
webpush(pushSubscription, message, 120),
|
||||
sendEncryptedMsg(pushSubscription, message),
|
||||
]).then(([message]) => message);
|
||||
}
|
||||
|
||||
@ -159,18 +191,15 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
});
|
||||
is(text, "Hi! \ud83d\udc40", "Wrong blob data for message with emoji");
|
||||
|
||||
var finishedPromise = controlledFrame.waitOnWorkerMessage("finished");
|
||||
// Send a blank message.
|
||||
var [message] = yield Promise.all([
|
||||
controlledFrame.waitOnWorkerMessage("finished"),
|
||||
fetch("http://mochi.test:8888/tests/dom/push/test/push-server.sjs", {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"X-Push-Method": "POST",
|
||||
"X-Push-Server": pushSubscription.endpoint,
|
||||
"TTL": "120",
|
||||
},
|
||||
}),
|
||||
]);
|
||||
mockSocket.serverSendMsg(JSON.stringify({
|
||||
messageType: "notification",
|
||||
version: "vDummy",
|
||||
channelID: channelID
|
||||
}));
|
||||
|
||||
var message = yield finishedPromise;
|
||||
ok(!message.data, "Should exclude data for blank messages");
|
||||
});
|
||||
|
||||
|
@ -10,6 +10,7 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
<head>
|
||||
<title>Test for Bug 1038811</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/dom/push/test/test_utils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
</head>
|
||||
@ -118,13 +119,7 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
}).then(SimpleTest.finish);
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.push.enabled", true],
|
||||
["dom.push.connection.enabled", true],
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true]
|
||||
]}, runTest);
|
||||
setupPrefsAndMock(new MockWebSocket()).then(_ => runTest());
|
||||
SpecialPowers.addPermission("desktop-notification", true, document);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
|
@ -10,6 +10,7 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
<head>
|
||||
<title>Test for Bug 1150812</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/dom/push/test/test_utils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
</head>
|
||||
@ -113,13 +114,7 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
}).then(SimpleTest.finish);
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.push.enabled", true],
|
||||
["dom.push.connection.enabled", true],
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true]
|
||||
]}, runTest);
|
||||
setupPrefsAndMock(new MockWebSocket()).then(_ => runTest());
|
||||
SpecialPowers.addPermission("desktop-notification", true, document);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
|
@ -12,6 +12,7 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
<head>
|
||||
<title>Test for Bug 1150812</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/dom/push/test/test_utils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
</head>
|
||||
@ -54,13 +55,11 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
});
|
||||
}
|
||||
|
||||
var defaultServerURL = SpecialPowers.getCharPref("dom.push.serverURL");
|
||||
|
||||
function setupMultipleSubscriptions(swr) {
|
||||
|
||||
// We need to do this to restart service so that a queue will be formed.
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.push.serverURL", defaultServerURL]]},
|
||||
null);
|
||||
teardownMockPushService();
|
||||
setupMockPushService(new MockWebSocket());
|
||||
|
||||
return Promise.all([
|
||||
subscribe(swr),
|
||||
subscribe(swr)
|
||||
@ -100,14 +99,7 @@ var defaultServerURL = SpecialPowers.getCharPref("dom.push.serverURL");
|
||||
}).then(SimpleTest.finish);
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.push.enabled", true],
|
||||
["dom.push.connection.enabled", true],
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
["dom.push.serverURL", "wss://something.org"]
|
||||
]}, runTest);
|
||||
setupPrefsAndMock(new MockWebSocket()).then(_ => runTest());
|
||||
SpecialPowers.addPermission("desktop-notification", true, document);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
|
@ -31,7 +31,7 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
var registration;
|
||||
add_task(function* start() {
|
||||
yield setupPrefs();
|
||||
yield setupPrefsAndMock(new MockWebSocket());
|
||||
yield setPushPermission(false);
|
||||
|
||||
var url = "worker.js" + "?" + Math.random();
|
||||
|
@ -29,9 +29,24 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
// console.log(str + "\n");
|
||||
}
|
||||
|
||||
var mockSocket = new MockWebSocket();
|
||||
|
||||
var channelID = null;
|
||||
|
||||
mockSocket.onRegister = function(request) {
|
||||
channelID = request.channelID;
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: "register",
|
||||
uaid: "c69e2014-9e15-438d-b253-d79cc2df60a8",
|
||||
channelID,
|
||||
status: 200,
|
||||
pushEndpoint: "https://example.com/endpoint/1"
|
||||
}));
|
||||
};
|
||||
|
||||
var registration;
|
||||
add_task(function* start() {
|
||||
yield setupPrefs();
|
||||
yield setupPrefsAndMock(mockSocket);
|
||||
yield setPushPermission(true);
|
||||
|
||||
var url = "worker.js" + "?" + (Math.random());
|
||||
@ -64,17 +79,16 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
});
|
||||
|
||||
add_task(function* waitForPushNotification() {
|
||||
yield Promise.all([
|
||||
controlledFrame.waitOnWorkerMessage("finished"),
|
||||
fetch("http://mochi.test:8888/tests/dom/push/test/push-server.sjs", {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"X-Push-Method": "POST",
|
||||
"X-Push-Server": pushSubscription.endpoint,
|
||||
"TTL": "120",
|
||||
},
|
||||
}),
|
||||
]);
|
||||
var finishedPromise = controlledFrame.waitOnWorkerMessage("finished");
|
||||
|
||||
// Send a blank message.
|
||||
mockSocket.serverSendMsg(JSON.stringify({
|
||||
messageType: "notification",
|
||||
version: "vDummy",
|
||||
channelID: channelID
|
||||
}));
|
||||
|
||||
yield finishedPromise;
|
||||
});
|
||||
|
||||
add_task(function* unsubscribe() {
|
||||
|
@ -23,6 +23,7 @@
|
||||
<head>
|
||||
<title>Test for Bug 1188545</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/dom/push/test/test_utils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
</head>
|
||||
@ -71,14 +72,27 @@
|
||||
return p;
|
||||
}
|
||||
|
||||
var mockSocket = new MockWebSocket();
|
||||
var endpoint = "https://example.com/endpoint/1";
|
||||
var channelID = null;
|
||||
mockSocket.onRegister = function(request) {
|
||||
channelID = request.channelID;
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: "register",
|
||||
uaid: "fa8f2e4b-5ddc-4408-b1e3-5f25a02abff0",
|
||||
channelID,
|
||||
status: 200,
|
||||
pushEndpoint: endpoint
|
||||
}));
|
||||
};
|
||||
|
||||
function sendPushToPushServer(pushEndpoint) {
|
||||
// Work around CORS for now.
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', "http://mochi.test:8888/tests/dom/push/test/push-server.sjs", true);
|
||||
xhr.setRequestHeader("X-Push-Method", "POST");
|
||||
xhr.setRequestHeader("X-Push-Server", pushEndpoint);
|
||||
xhr.setRequestHeader("TTL", "120");
|
||||
xhr.send(null);
|
||||
is(pushEndpoint, endpoint, "Got unexpected endpoint");
|
||||
mockSocket.serverSendMsg(JSON.stringify({
|
||||
messageType: "notification",
|
||||
version: "vDummy",
|
||||
channelID
|
||||
}));
|
||||
}
|
||||
|
||||
function unregisterPushNotification(ctx) {
|
||||
@ -321,13 +335,7 @@
|
||||
}).then(SimpleTest.finish);
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.push.enabled", true],
|
||||
["dom.push.connection.enabled", true],
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
]}, runTest);
|
||||
setupPrefsAndMock(mockSocket).then(_ => runTest());
|
||||
SpecialPowers.addPermission('desktop-notification', true, document);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
|
@ -27,7 +27,7 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
var registration;
|
||||
add_task(function* start() {
|
||||
yield setupPrefs();
|
||||
yield setupPrefsAndMock(new MockWebSocket());
|
||||
yield setPushPermission(true);
|
||||
|
||||
var url = "worker.js" + "?" + (Math.random());
|
||||
|
@ -10,6 +10,7 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
<head>
|
||||
<title>Test for Bug 1170817</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/dom/push/test/test_utils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
</head>
|
||||
@ -79,13 +80,7 @@ http://creativecommons.org/licenses/publicdomain/
|
||||
}).then(SimpleTest.finish);
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.push.enabled", true],
|
||||
["dom.push.connection.enabled", true],
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true]
|
||||
]}, runTest);
|
||||
setupPrefsAndMock(new MockWebSocket()).then(_ => runTest());
|
||||
SpecialPowers.addPermission("desktop-notification", true, document);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
|
@ -1,11 +1,115 @@
|
||||
(function (g) {
|
||||
"use strict";
|
||||
|
||||
let url = SimpleTest.getTestFileURL("mockpushserviceparent.js");
|
||||
let chromeScript = SpecialPowers.loadChromeScript(url);
|
||||
|
||||
let userAgentID = "8e1c93a9-139b-419c-b200-e715bb1e8ce8";
|
||||
|
||||
let currentMockSocket = null;
|
||||
|
||||
function setupMockPushService(mockWebSocket) {
|
||||
currentMockSocket = mockWebSocket;
|
||||
currentMockSocket._isActive = true;
|
||||
chromeScript.sendSyncMessage("setup");
|
||||
chromeScript.addMessageListener("client-msg", function(msg) {
|
||||
mockWebSocket.handleMessage(msg);
|
||||
});
|
||||
}
|
||||
|
||||
function teardownMockPushService() {
|
||||
if (currentMockSocket) {
|
||||
currentMockSocket._isActive = false;
|
||||
chromeScript.sendSyncMessage("teardown");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimal implementation of web sockets for use in testing. Forwards
|
||||
* messages to a mock web socket in the parent process that is used
|
||||
* by the push service.
|
||||
*/
|
||||
function MockWebSocket() {}
|
||||
|
||||
let registerCount = 0;
|
||||
|
||||
// Default implementation to make the push server work minimally.
|
||||
// Override methods to implement custom functionality.
|
||||
MockWebSocket.prototype = {
|
||||
// We only allow one active mock web socket to talk to the parent.
|
||||
// This flag is used to keep track of which mock web socket is active.
|
||||
_isActive: false,
|
||||
|
||||
onHello(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: "hello",
|
||||
uaid: userAgentID,
|
||||
status: 200,
|
||||
use_webpush: true,
|
||||
}));
|
||||
},
|
||||
|
||||
onRegister(request) {
|
||||
this.serverSendMsg(JSON.stringify({
|
||||
messageType: "register",
|
||||
uaid: userAgentID,
|
||||
channelID: request.channelID,
|
||||
status: 200,
|
||||
pushEndpoint: "https://example.com/endpoint/" + registerCount++
|
||||
}));
|
||||
},
|
||||
|
||||
onUnregister(request) {
|
||||
// Do nothing.
|
||||
},
|
||||
|
||||
onAck(request) {
|
||||
// Do nothing.
|
||||
},
|
||||
|
||||
handleMessage(msg) {
|
||||
let request = JSON.parse(msg);
|
||||
let messageType = request.messageType;
|
||||
switch (messageType) {
|
||||
case "hello":
|
||||
this.onHello(request);
|
||||
break;
|
||||
case "register":
|
||||
this.onRegister(request);
|
||||
break;
|
||||
case "unregister":
|
||||
this.onUnregister(request);
|
||||
break;
|
||||
case "ack":
|
||||
this.onAck(request);
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unexpected message: " + messageType);
|
||||
}
|
||||
},
|
||||
|
||||
serverSendMsg(msg) {
|
||||
if (this._isActive) {
|
||||
chromeScript.sendAsyncMessage("server-msg", msg);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
g.MockWebSocket = MockWebSocket;
|
||||
g.setupMockPushService = setupMockPushService;
|
||||
g.teardownMockPushService = teardownMockPushService;
|
||||
}(this));
|
||||
|
||||
// Remove permissions and prefs when the test finishes.
|
||||
SimpleTest.registerCleanupFunction(() =>
|
||||
SimpleTest.registerCleanupFunction(() => {
|
||||
new Promise(resolve => {
|
||||
SpecialPowers.flushPermissions(_ => {
|
||||
SpecialPowers.flushPrefEnv(resolve);
|
||||
});
|
||||
})
|
||||
);
|
||||
}).then(_ => {
|
||||
teardownMockPushService();
|
||||
});
|
||||
});
|
||||
|
||||
function setPushPermission(allow) {
|
||||
return new Promise(resolve => {
|
||||
@ -15,8 +119,9 @@ function setPushPermission(allow) {
|
||||
});
|
||||
}
|
||||
|
||||
function setupPrefs() {
|
||||
function setupPrefsAndMock(mockSocket) {
|
||||
return new Promise(resolve => {
|
||||
setupMockPushService(mockSocket);
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.push.enabled", true],
|
||||
["dom.push.connection.enabled", true],
|
||||
|
@ -161,15 +161,7 @@
|
||||
}).then(bsConcat);
|
||||
}
|
||||
|
||||
/*
|
||||
* Request push for a message. This returns a promise that resolves when the
|
||||
* push has been delivered to the push service.
|
||||
*
|
||||
* @param subscription A PushSubscription that contains endpoint and p256dh
|
||||
* parameters.
|
||||
* @param data The message to send.
|
||||
*/
|
||||
function webpush(subscription, data, ttl) {
|
||||
function webPushEncrypt(subscription, data) {
|
||||
data = ensureView(data);
|
||||
|
||||
var salt = g.crypto.getRandomValues(new Uint8Array(16));
|
||||
@ -181,27 +173,14 @@
|
||||
webCrypto.exportKey('raw', localKey.publicKey),
|
||||
]);
|
||||
}).then(([payload, pubkey]) => {
|
||||
var options = {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'X-Push-Server': subscription.endpoint,
|
||||
// Web Push requires POST requests.
|
||||
'X-Push-Method': 'POST',
|
||||
'Encryption-Key': 'keyid=p256dh;dh=' + base64url.encode(pubkey),
|
||||
Encryption: 'keyid=p256dh;salt=' + base64url.encode(salt),
|
||||
'Content-Encoding': 'aesgcm128',
|
||||
'TTL': ttl,
|
||||
},
|
||||
body: payload,
|
||||
return {
|
||||
data: base64url.encode(payload),
|
||||
encryption: 'keyid=p256dh;salt=' + base64url.encode(salt),
|
||||
encryption_key: 'keyid=p256dh;dh=' + base64url.encode(pubkey),
|
||||
encoding: 'aesgcm128'
|
||||
};
|
||||
return fetch('http://mochi.test:8888/tests/dom/push/test/push-server.sjs', options);
|
||||
}).then(response => {
|
||||
if (Math.floor(response.status / 100) !== 2) {
|
||||
throw new Error('Unable to deliver message');
|
||||
}
|
||||
return response;
|
||||
});
|
||||
}
|
||||
|
||||
g.webpush = webpush;
|
||||
g.webPushEncrypt = webPushEncrypt;
|
||||
}(this));
|
||||
|
@ -6,5 +6,9 @@ support-files =
|
||||
file_about_newtab_good_signature
|
||||
file_about_newtab_bad_signature
|
||||
file_about_newtab_broken_signature
|
||||
file_about_newtab_sri.html
|
||||
file_about_newtab_sri_signature
|
||||
script.js
|
||||
style.css
|
||||
|
||||
[browser_verify_content_about_newtab.js]
|
||||
|
@ -43,22 +43,40 @@ const GOOD_ABOUT_STRING = "Just a fully good testpage for Bug 1226928";
|
||||
const BAD_ABOUT_STRING = "Just a bad testpage for Bug 1226928";
|
||||
const ABOUT_BLANK = "<head></head><body></body>";
|
||||
|
||||
const URI_CLEANUP = BASE + "cleanup=true";
|
||||
const CLEANUP_DONE = "Done";
|
||||
|
||||
const URI_SRI = BASE + "sig=sri&key=good&file=sri&header=good";
|
||||
const STYLESHEET_WITHOUT_SRI_BLOCKED = "Stylesheet without SRI blocked";
|
||||
const STYLESHEET_WITH_SRI_BLOCKED = "Stylesheet with SRI blocked";
|
||||
const STYLESHEET_WITH_SRI_LOADED = "Stylesheet with SRI loaded";
|
||||
const SCRIPT_WITHOUT_SRI_BLOCKED = "Script without SRI blocked";
|
||||
const SCRIPT_WITH_SRI_BLOCKED = "Script with SRI blocked";
|
||||
const SCRIPT_WITH_SRI_LOADED = "Script with SRI loaded";
|
||||
|
||||
const TESTS = [
|
||||
// { newtab (aboutURI) or regular load (url) : url,
|
||||
// testString : expected string in the loaded page }
|
||||
{ "aboutURI" : URI_GOOD, "testString" : GOOD_ABOUT_STRING },
|
||||
{ "aboutURI" : URI_ERROR_HEADER, "testString" : ABOUT_BLANK },
|
||||
{ "aboutURI" : URI_KEYERROR_HEADER, "testString" : ABOUT_BLANK },
|
||||
{ "aboutURI" : URI_SIGERROR_HEADER, "testString" : ABOUT_BLANK },
|
||||
{ "aboutURI" : URI_NO_HEADER, "testString" : ABOUT_BLANK },
|
||||
{ "aboutURI" : URI_BAD_SIG, "testString" : ABOUT_BLANK },
|
||||
{ "aboutURI" : URI_BROKEN_SIG, "testString" : ABOUT_BLANK },
|
||||
{ "aboutURI" : URI_BAD_KEY, "testString" : ABOUT_BLANK },
|
||||
{ "aboutURI" : URI_BAD_FILE, "testString" : ABOUT_BLANK },
|
||||
{ "aboutURI" : URI_BAD_ALL, "testString" : ABOUT_BLANK },
|
||||
{ "url" : URI_BAD_FILE_CACHED, "testString" : BAD_ABOUT_STRING },
|
||||
{ "aboutURI" : URI_BAD_FILE_CACHED, "testString" : ABOUT_BLANK },
|
||||
{ "aboutURI" : URI_GOOD, "testString" : GOOD_ABOUT_STRING }
|
||||
// testStrings : expected strings in the loaded page }
|
||||
{ "aboutURI" : URI_GOOD, "testStrings" : [GOOD_ABOUT_STRING] },
|
||||
{ "aboutURI" : URI_ERROR_HEADER, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "aboutURI" : URI_KEYERROR_HEADER, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "aboutURI" : URI_SIGERROR_HEADER, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "aboutURI" : URI_NO_HEADER, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "aboutURI" : URI_BAD_SIG, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "aboutURI" : URI_BROKEN_SIG, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "aboutURI" : URI_BAD_KEY, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "aboutURI" : URI_BAD_FILE, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "aboutURI" : URI_BAD_ALL, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "url" : URI_BAD_FILE_CACHED, "testStrings" : [BAD_ABOUT_STRING] },
|
||||
{ "aboutURI" : URI_BAD_FILE_CACHED, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "aboutURI" : URI_GOOD, "testStrings" : [GOOD_ABOUT_STRING] },
|
||||
{ "aboutURI" : URI_SRI, "testStrings" : [
|
||||
STYLESHEET_WITHOUT_SRI_BLOCKED,
|
||||
STYLESHEET_WITH_SRI_LOADED,
|
||||
SCRIPT_WITHOUT_SRI_BLOCKED,
|
||||
SCRIPT_WITH_SRI_LOADED,
|
||||
]},
|
||||
{ "url" : URI_CLEANUP, "testStrings" : [CLEANUP_DONE] },
|
||||
];
|
||||
|
||||
var browser = null;
|
||||
@ -74,7 +92,7 @@ function pushPrefs(...aPrefs) {
|
||||
/*
|
||||
* run tests with input from TESTS
|
||||
*/
|
||||
function doTest(aExpectedString, reload, aUrl, aNewTabPref) {
|
||||
function doTest(aExpectedStrings, reload, aUrl, aNewTabPref) {
|
||||
// set about:newtab location for this test if it's a newtab test
|
||||
if (aNewTabPref) {
|
||||
aboutNewTabService.newTabURL = aNewTabPref;
|
||||
@ -115,10 +133,12 @@ function doTest(aExpectedString, reload, aUrl, aNewTabPref) {
|
||||
"sanity check: default URL for about:newtab should return the new URL");
|
||||
}
|
||||
yield ContentTask.spawn(
|
||||
browser, aExpectedString, function * (aExpectedString) {
|
||||
ok(content.document.documentElement.innerHTML.includes(aExpectedString),
|
||||
"Expect the following value in the result\n" + aExpectedString +
|
||||
"\nand got " + content.document.documentElement.innerHTML);
|
||||
browser, aExpectedStrings, function * (aExpectedStrings) {
|
||||
for (let expectedString of aExpectedStrings) {
|
||||
ok(content.document.documentElement.innerHTML.includes(expectedString),
|
||||
"Expect the following value in the result\n" + expectedString +
|
||||
"\nand got " + content.document.documentElement.innerHTML);
|
||||
}
|
||||
});
|
||||
|
||||
// for good test cases we check if a reload fails if the remote page
|
||||
@ -140,12 +160,22 @@ function doTest(aExpectedString, reload, aUrl, aNewTabPref) {
|
||||
browser.reload();
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
aExpectedString = ABOUT_BLANK;
|
||||
yield ContentTask.spawn(browser, aExpectedString,
|
||||
function * (aExpectedString) {
|
||||
ok(content.document.documentElement.innerHTML.includes(aExpectedString),
|
||||
"Expect the following value in the result\n" + aExpectedString +
|
||||
"\nand got " + content.document.documentElement.innerHTML);
|
||||
let expectedStrings = [ABOUT_BLANK];
|
||||
if (aNewTabPref == URI_SRI) {
|
||||
expectedStrings = [
|
||||
STYLESHEET_WITHOUT_SRI_BLOCKED,
|
||||
STYLESHEET_WITH_SRI_BLOCKED,
|
||||
SCRIPT_WITHOUT_SRI_BLOCKED,
|
||||
SCRIPT_WITH_SRI_BLOCKED
|
||||
];
|
||||
}
|
||||
yield ContentTask.spawn(browser, expectedStrings,
|
||||
function * (expectedStrings) {
|
||||
for (let expectedString of expectedStrings) {
|
||||
ok(content.document.documentElement.innerHTML.includes(expectedString),
|
||||
"Expect the following value in the result\n" + expectedString +
|
||||
"\nand got " + content.document.documentElement.innerHTML);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@ -172,17 +202,17 @@ add_task(function * test() {
|
||||
let testCase = TESTS[i];
|
||||
let url = "", aNewTabPref = "";
|
||||
let reload = false;
|
||||
let aExpectedString = testCase.testString;
|
||||
var aExpectedStrings = testCase.testStrings;
|
||||
if (testCase.aboutURI) {
|
||||
url = ABOUT_NEWTAB_URI;
|
||||
aNewTabPref = testCase.aboutURI;
|
||||
if (aExpectedString == GOOD_ABOUT_STRING) {
|
||||
if (aNewTabPref == URI_GOOD || aNewTabPref == URI_SRI) {
|
||||
reload = true;
|
||||
}
|
||||
} else {
|
||||
url = testCase.url;
|
||||
}
|
||||
|
||||
yield doTest(aExpectedString, reload, url, aNewTabPref);
|
||||
yield doTest(aExpectedStrings, reload, url, aNewTabPref);
|
||||
}
|
||||
});
|
||||
|
36
dom/security/test/contentverifier/file_about_newtab_sri.html
Normal file
36
dom/security/test/contentverifier/file_about_newtab_sri.html
Normal file
@ -0,0 +1,36 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=1235572 -->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Testpage for bug 1235572</title>
|
||||
<script>
|
||||
function loaded(resource) {
|
||||
document.getElementById("result").innerHTML += resource + " loaded\n";
|
||||
}
|
||||
function blocked(resource) {
|
||||
document.getElementById("result").innerHTML += resource + " blocked\n";
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
Testing script loading without SRI for Bug 1235572<br/>
|
||||
<div id="result"></div>
|
||||
|
||||
<!-- use css1 and css2 to make urls different to avoid the resource being cached-->
|
||||
<link rel="stylesheet" href="https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?resource=css1"
|
||||
onload="loaded('Stylesheet without SRI')"
|
||||
onerror="blocked('Stylesheet without SRI')">
|
||||
<link rel="stylesheet" href="https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?resource=css2"
|
||||
integrity="sha384-/6Tvxh7SX39y62qePcvYoi5Vrf0lK8Ix3wJFLCYKI5KNJ5wIlCR8UsFC1OXwmwgd"
|
||||
onload="loaded('Stylesheet with SRI')"
|
||||
onerror="blocked('Stylesheet with SRI')">
|
||||
<script src="https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?resource=script"
|
||||
onload="loaded('Script without SRI')"
|
||||
onerror="blocked('Script without SRI')"></script>
|
||||
<script src="https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?resource=script"
|
||||
integrity="sha384-zDCkvKOHXk8mM6Nk07oOGXGME17PA4+ydFw+hq0r9kgF6ZDYFWK3fLGPEy7FoOAo"
|
||||
onload="loaded('Script with SRI')"
|
||||
onerror="blocked('Script with SRI')"></script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1 @@
|
||||
i5jOnrZWwyNwrTcIjfJ6fUR-8MhhvhtMvQbdrUD7j8aHTybNolv25v9NwJAT6rVU6kgkxmD_st9Kla086CQmzYQdLhKfzgLbTDXz0-1j23fQnyjsP1_4MNIu2xTea11p
|
@ -14,21 +14,30 @@ goodFile.append(goodFileName);
|
||||
const goodSignature = path + "file_about_newtab_good_signature";
|
||||
const goodKeyId = "RemoteNewTab";
|
||||
|
||||
const scriptFileName = "script.js";
|
||||
const cssFileName = "style.css";
|
||||
const badFile = path + "file_about_newtab_bad.html";
|
||||
const brokenSignature = path + "file_about_newtab_broken_signature";
|
||||
const badSignature = path + "file_about_newtab_bad_signature";
|
||||
const badKeyId = "OldRemoteNewTabKey";
|
||||
|
||||
const sriFile = path + "file_about_newtab_sri.html";
|
||||
const sriSignature = path + "file_about_newtab_sri_signature";
|
||||
|
||||
const tempFileNames = [goodFileName, scriptFileName, cssFileName];
|
||||
|
||||
// we copy the file to serve as newtab to a temp directory because
|
||||
// we modify it during tests.
|
||||
setupTestFile();
|
||||
setupTestFiles();
|
||||
|
||||
function setupTestFile() {
|
||||
let tempFile = FileUtils.getDir("TmpD", [], true);
|
||||
tempFile.append(goodFileName);
|
||||
if (!tempFile.exists()) {
|
||||
let fileIn = getFileName(goodFileBase, "CurWorkD");
|
||||
fileIn.copyTo(FileUtils.getDir("TmpD", [], true), "");
|
||||
function setupTestFiles() {
|
||||
for (let fileName of tempFileNames) {
|
||||
let tempFile = FileUtils.getDir("TmpD", [], true);
|
||||
tempFile.append(fileName);
|
||||
if (!tempFile.exists()) {
|
||||
let fileIn = getFileName(path + fileName, "CurWorkD");
|
||||
fileIn.copyTo(FileUtils.getDir("TmpD", [], true), "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,6 +94,14 @@ function truncateFile(aFile, length) {
|
||||
return "Done";
|
||||
}
|
||||
|
||||
function cleanupTestFiles() {
|
||||
for (let fileName of tempFileNames) {
|
||||
let tempFile = FileUtils.getDir("TmpD", [], true);
|
||||
tempFile.append(fileName);
|
||||
tempFile.remove(true);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* handle requests of the following form:
|
||||
* sig=good&key=good&file=good&header=good&cached=no to serve pages with
|
||||
@ -102,13 +119,37 @@ function handleRequest(request, response) {
|
||||
let cached = params.get("cached");
|
||||
let invalidateFile = params.get("invalidateFile");
|
||||
let validateFile = params.get("validateFile");
|
||||
let resource = params.get("resource");
|
||||
|
||||
if (params.get("cleanup")) {
|
||||
cleanupTestFiles();
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
response.write("Done");
|
||||
return;
|
||||
}
|
||||
|
||||
if (resource) {
|
||||
if (resource == "script") {
|
||||
response.setHeader("Content-Type", "application/javascript", false);
|
||||
response.write(loadFile(getFileName(scriptFileName, "TmpD")));
|
||||
} else { // resource == "css1" || resource == "css2"
|
||||
response.setHeader("Content-Type", "text/css", false);
|
||||
response.write(loadFile(getFileName(cssFileName, "TmpD")));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// if invalidateFile is set, this doesn't actually return a newtab page
|
||||
// but changes the served file to invalidate the signature
|
||||
// NOTE: make sure to make the file valid again afterwards!
|
||||
if (invalidateFile) {
|
||||
let r = "Done";
|
||||
for (let fileName of tempFileNames) {
|
||||
if (appendToFile(getFileName(fileName, "TmpD"), "!") != "Done") {
|
||||
r = "Error";
|
||||
}
|
||||
}
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
let r = appendToFile(goodFile, "!");
|
||||
response.write(r);
|
||||
return;
|
||||
}
|
||||
@ -116,8 +157,13 @@ function handleRequest(request, response) {
|
||||
// if validateFile is set, this doesn't actually return a newtab page
|
||||
// but changes the served file to make the signature valid again
|
||||
if (validateFile) {
|
||||
let r = "Done";
|
||||
for (let fileName of tempFileNames) {
|
||||
if (truncateFile(getFileName(fileName, "TmpD"), 1) != "Done") {
|
||||
r = "Error";
|
||||
}
|
||||
}
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
let r = truncateFile(goodFile, 1);
|
||||
response.write(r);
|
||||
return;
|
||||
}
|
||||
@ -147,9 +193,13 @@ function handleRequest(request, response) {
|
||||
signature = badSignature;
|
||||
} else if (signatureType == "broken") {
|
||||
signature = brokenSignature;
|
||||
} else if (signatureType == "sri") {
|
||||
signature = sriSignature;
|
||||
}
|
||||
if (fileType == "bad") {
|
||||
file = getFileName(badFile, "CurWorkD");
|
||||
} else if (fileType == "sri") {
|
||||
file = getFileName(sriFile, "CurWorkD");
|
||||
}
|
||||
|
||||
if (headerType == "good") {
|
||||
|
1
dom/security/test/contentverifier/script.js
Normal file
1
dom/security/test/contentverifier/script.js
Normal file
@ -0,0 +1 @@
|
||||
var load=true;
|
3
dom/security/test/contentverifier/style.css
Normal file
3
dom/security/test/contentverifier/style.css
Normal file
@ -0,0 +1,3 @@
|
||||
#red-text {
|
||||
color: red;
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
* In particular, the tests check that default-src and manifest-src directives are
|
||||
* are respected by the ManifestObtainer.
|
||||
*/
|
||||
/*globals Components*/
|
||||
/*globals Cu, is, ok*/
|
||||
'use strict';
|
||||
requestLongerTimeout(10); // e10s tests take time.
|
||||
const {
|
||||
@ -15,11 +15,9 @@ const path = '/tests/dom/security/test/csp/';
|
||||
const testFile = `file=${path}file_web_manifest.html`;
|
||||
const remoteFile = `file=${path}file_web_manifest_remote.html`;
|
||||
const httpsManifest = `file=${path}file_web_manifest_https.html`;
|
||||
const mixedContent = `file=${path}file_web_manifest_mixed_content.html`;
|
||||
const server = 'file_testserver.sjs';
|
||||
const defaultURL = `http://example.org${path}${server}`;
|
||||
const remoteURL = `http://mochi.test:8888`;
|
||||
const secureURL = `https://example.com${path}${server}`;
|
||||
const secureURL = `https://example.com:443${path}${server}`;
|
||||
const tests = [
|
||||
// CSP block everything, so trying to load a manifest
|
||||
// will result in a policy violation.
|
||||
@ -103,7 +101,7 @@ const tests = [
|
||||
expected: `CSP manifest-src allows self`,
|
||||
get tabURL() {
|
||||
let queryParts = [
|
||||
`manifest-src 'self'`,
|
||||
`csp=manifest-src 'self'`,
|
||||
testFile
|
||||
];
|
||||
return `${defaultURL}?${queryParts.join('&')}`;
|
||||
@ -117,7 +115,7 @@ const tests = [
|
||||
expected: `CSP manifest-src allows http://example.org`,
|
||||
get tabURL() {
|
||||
let queryParts = [
|
||||
`manifest-src http://example.org`,
|
||||
`csp=manifest-src http://example.org`,
|
||||
testFile
|
||||
];
|
||||
return `${defaultURL}?${queryParts.join('&')}`;
|
||||
@ -126,42 +124,11 @@ const tests = [
|
||||
is(manifest.name, 'loaded', this.expected);
|
||||
}
|
||||
},
|
||||
// Check interaction with default-src and another origin,
|
||||
// CSP allows fetching from example.org, so manifest should load.
|
||||
{
|
||||
expected: `CSP manifest-src overrides default-src of elsewhere.com`,
|
||||
get tabURL() {
|
||||
let queryParts = [
|
||||
`default-src: http://elsewhere.com; manifest-src http://example.org`,
|
||||
testFile
|
||||
];
|
||||
return `${defaultURL}?${queryParts.join('&')}`;
|
||||
},
|
||||
run(manifest) {
|
||||
is(manifest.name, 'loaded', this.expected);
|
||||
}
|
||||
},
|
||||
// Check interaction with default-src none,
|
||||
// CSP allows fetching manifest from example.org, so manifest should load.
|
||||
{
|
||||
expected: `CSP manifest-src overrides default-src`,
|
||||
get tabURL() {
|
||||
let queryParts = [
|
||||
`default-src: 'none'; manifest-src 'self'`,
|
||||
testFile
|
||||
];
|
||||
return `${defaultURL}?${queryParts.join('&')}`;
|
||||
},
|
||||
run(manifest) {
|
||||
is(manifest.name, 'loaded', this.expected);
|
||||
}
|
||||
},
|
||||
// CSP allows fetching from mochi.test:8888, which has a
|
||||
// CORS header set to '*'. So the manifest should load.
|
||||
{
|
||||
expected: `CSP manifest-src allows mochi.test:8888`,
|
||||
get tabURL() {
|
||||
let queryParts = [
|
||||
`cors=*`,
|
||||
`csp=default-src *; manifest-src http://mochi.test:8888`,
|
||||
remoteFile
|
||||
];
|
||||
@ -202,63 +169,81 @@ const tests = [
|
||||
run(topic) {
|
||||
is(topic, 'csp-on-violate-policy', this.expected);
|
||||
}
|
||||
}
|
||||
},
|
||||
// CSP allows fetching over TLS from example.org, so manifest should load.
|
||||
{
|
||||
expected: `CSP manifest-src allows example.com over TLS`,
|
||||
get tabURL() {
|
||||
let queryParts = [
|
||||
'cors=*',
|
||||
'csp=manifest-src https://example.com:443',
|
||||
httpsManifest
|
||||
];
|
||||
// secureURL loads https://example.com:443
|
||||
// and gets manifest from https://example.org:443
|
||||
return `${secureURL}?${queryParts.join('&')}`;
|
||||
},
|
||||
run(manifest) {
|
||||
is(manifest.name, 'loaded', this.expected);
|
||||
}
|
||||
},
|
||||
];
|
||||
//jscs:disable
|
||||
add_task(function* () {
|
||||
//jscs:enable
|
||||
for (let test of tests) {
|
||||
let tabOptions = {
|
||||
gBrowser: gBrowser,
|
||||
url: test.tabURL,
|
||||
};
|
||||
yield BrowserTestUtils.withNewTab(
|
||||
tabOptions,
|
||||
browser => testObtainingManifest(browser, test)
|
||||
var testPromises = tests.map(
|
||||
(test) => ([test, {gBrowser, url: test.tabURL, skipAnimation: true}])
|
||||
).map(
|
||||
([test, tabOptions]) => BrowserTestUtils.withNewTab(tabOptions, (browser) => testObtainingManifest(browser, test))
|
||||
);
|
||||
}
|
||||
|
||||
function* testObtainingManifest(aBrowser, aTest) {
|
||||
const observer = (/blocks/.test(aTest.expected)) ? new NetworkObserver(aTest) : null;
|
||||
let manifest;
|
||||
// Expect an exception (from promise rejection) if there a content policy
|
||||
// that is violated.
|
||||
try {
|
||||
manifest = yield ManifestObtainer.browserObtainManifest(aBrowser);
|
||||
} catch (e) {
|
||||
const msg = `Expected promise rejection obtaining.`;
|
||||
ok(/blocked the loading of a resource/.test(e.message), msg);
|
||||
if (observer) {
|
||||
yield observer.finished;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// otherwise, we test manifest's content.
|
||||
if (manifest) {
|
||||
aTest.run(manifest);
|
||||
}
|
||||
}
|
||||
yield Promise.all(testPromises);
|
||||
});
|
||||
|
||||
// Helper object used to observe policy violations. It waits 10 seconds
|
||||
function* testObtainingManifest(aBrowser, aTest) {
|
||||
const expectsBlocked = aTest.expected.includes('block');
|
||||
const observer = (expectsBlocked) ? createNetObserver(aTest) : null;
|
||||
// Expect an exception (from promise rejection) if there a content policy
|
||||
// that is violated.
|
||||
try {
|
||||
const manifest = yield ManifestObtainer.browserObtainManifest(aBrowser);
|
||||
aTest.run(manifest);
|
||||
} catch (e) {
|
||||
const wasBlocked = e.message.includes('blocked the loading of a resource');
|
||||
ok(wasBlocked,`Expected promise rejection obtaining ${aTest.tabURL}: ${e.message}`);
|
||||
if (observer) {
|
||||
yield observer.untilFinished;
|
||||
return;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper object used to observe policy violations. It waits 1 seconds
|
||||
// for a response, and then times out causing its associated test to fail.
|
||||
function NetworkObserver(test) {
|
||||
function createNetObserver(test) {
|
||||
let finishedTest;
|
||||
let success = false;
|
||||
this.finished = new Promise((resolver) => {
|
||||
const finished = new Promise((resolver) => {
|
||||
finishedTest = resolver;
|
||||
})
|
||||
this.observe = function observer(subject, topic) {
|
||||
SpecialPowers.removeObserver(this, 'csp-on-violate-policy');
|
||||
test.run(topic);
|
||||
finishedTest();
|
||||
success = true;
|
||||
};
|
||||
SpecialPowers.addObserver(this, 'csp-on-violate-policy', false);
|
||||
setTimeout(() => {
|
||||
});
|
||||
const timeoutId = setTimeout(() => {
|
||||
if (!success) {
|
||||
test.run('This test timed out.');
|
||||
finishedTest();
|
||||
}
|
||||
}, 1000);
|
||||
var observer = {
|
||||
get untilFinished(){
|
||||
return finished;
|
||||
},
|
||||
observe(subject, topic) {
|
||||
SpecialPowers.removeObserver(observer, 'csp-on-violate-policy');
|
||||
test.run(topic);
|
||||
finishedTest();
|
||||
clearTimeout(timeoutId);
|
||||
success = true;
|
||||
},
|
||||
};
|
||||
SpecialPowers.addObserver(observer, 'csp-on-violate-policy', false);
|
||||
return observer;
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ TelephonyDialCallback::NotifyDialMMISuccess(const nsAString& aStatusMessage)
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
MozMMIResult result;
|
||||
RootedDictionary<MozMMIResult> result(cx);
|
||||
result.mSuccess = true;
|
||||
result.mServiceCode.Assign(mServiceCode);
|
||||
result.mStatusMessage.Assign(aStatusMessage);
|
||||
@ -94,7 +94,7 @@ TelephonyDialCallback::NotifyDialMMISuccessWithInteger(const nsAString& aStatusM
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
MozMMIResult result;
|
||||
RootedDictionary<MozMMIResult> result(cx);
|
||||
result.mSuccess = true;
|
||||
result.mServiceCode.Assign(mServiceCode);
|
||||
result.mStatusMessage.Assign(aStatusMessage);
|
||||
@ -217,7 +217,7 @@ TelephonyDialCallback::NotifyDialMMIError(const nsAString& aError)
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
MozMMIResult result;
|
||||
RootedDictionary<MozMMIResult> result(cx);
|
||||
result.mSuccess = false;
|
||||
result.mServiceCode.Assign(mServiceCode);
|
||||
result.mStatusMessage.Assign(aError);
|
||||
@ -236,7 +236,7 @@ TelephonyDialCallback::NotifyDialMMIErrorWithInfo(const nsAString& aError,
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
MozMMIResult result;
|
||||
RootedDictionary<MozMMIResult> result(cx);
|
||||
result.mSuccess = false;
|
||||
result.mServiceCode.Assign(mServiceCode);
|
||||
result.mStatusMessage.Assign(aError);
|
||||
|
@ -298,7 +298,9 @@ interface CanvasPathMethods {
|
||||
|
||||
[Throws, LenientFloat]
|
||||
void arc(double x, double y, double radius, double startAngle, double endAngle, optional boolean anticlockwise = false);
|
||||
// NOT IMPLEMENTED [LenientFloat] void ellipse(double x, double y, double radiusX, double radiusY, double rotation, double startAngle, double endAngle, boolean anticlockwise);
|
||||
|
||||
[Throws, LenientFloat]
|
||||
void ellipse(double x, double y, double radiusX, double radiusY, double rotation, double startAngle, double endAngle, optional boolean anticlockwise = false);
|
||||
};
|
||||
|
||||
interface CanvasGradient {
|
||||
|
@ -46,14 +46,22 @@ interface KeyframeEffectReadOnly : AnimationEffectReadOnly {
|
||||
};
|
||||
|
||||
// Non-standard extensions
|
||||
dictionary AnimationPropertyState {
|
||||
DOMString property;
|
||||
boolean runningOnCompositor;
|
||||
DOMString? warning;
|
||||
dictionary AnimationPropertyValueDetails {
|
||||
required double offset;
|
||||
required DOMString value;
|
||||
DOMString easing;
|
||||
required CompositeOperation composite;
|
||||
};
|
||||
|
||||
dictionary AnimationPropertyDetails {
|
||||
required DOMString property;
|
||||
required boolean runningOnCompositor;
|
||||
DOMString warning;
|
||||
required sequence<AnimationPropertyValueDetails> values;
|
||||
};
|
||||
|
||||
partial interface KeyframeEffectReadOnly {
|
||||
[ChromeOnly] sequence<AnimationPropertyState> getPropertyState();
|
||||
[ChromeOnly, Throws] sequence<AnimationPropertyDetails> getProperties();
|
||||
};
|
||||
|
||||
[Func="nsDocument::IsWebAnimationsEnabled",
|
||||
|
@ -1934,11 +1934,8 @@ RuntimeService::Shutdown()
|
||||
{
|
||||
MutexAutoUnlock unlock(mMutex);
|
||||
|
||||
AutoSafeJSContext cx;
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
for (uint32_t index = 0; index < workers.Length(); index++) {
|
||||
if (!workers[index]->Kill(cx)) {
|
||||
if (!workers[index]->Kill()) {
|
||||
NS_WARNING("Failed to cancel worker!");
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsIInputStreamPump.h"
|
||||
@ -893,6 +894,28 @@ private:
|
||||
|
||||
nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
|
||||
|
||||
// Get the top-level worker.
|
||||
WorkerPrivate* topWorkerPrivate = mWorkerPrivate;
|
||||
WorkerPrivate* parent = topWorkerPrivate->GetParent();
|
||||
while (parent) {
|
||||
topWorkerPrivate = parent;
|
||||
parent = topWorkerPrivate->GetParent();
|
||||
}
|
||||
|
||||
// If the top-level worker is a dedicated worker and has a window, and the
|
||||
// window has a docshell, the caching behavior of this worker should match
|
||||
// that of that docshell.
|
||||
if (topWorkerPrivate->IsDedicatedWorker()) {
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = topWorkerPrivate->GetWindow();
|
||||
if (window) {
|
||||
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(window);
|
||||
if (docShell) {
|
||||
nsresult rv = docShell->GetDefaultLoadFlags(&loadFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we are loading a script for a ServiceWorker then we must not
|
||||
// try to intercept it. If the interception matches the current
|
||||
// ServiceWorker's scope then we could deadlock the load.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user