merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2015-04-15 14:28:05 +02:00
Родитель 07bcc385b7 35f5826c5e
Коммит 40ae721556
184 изменённых файлов: 5129 добавлений и 3230 удалений

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

@ -142,15 +142,13 @@ skip-if = os != "win" || e10s # The Fitts Law back button is only supported on W
skip-if = e10s # bug 967873 means permitUnload doesn't work in e10s mode
[browser_blob-channelname.js]
[browser_bookmark_titles.js]
skip-if = buildapp == 'mulet' || toolkit == "windows" || e10s # Disabled on Windows due to frequent failures (bugs 825739, 841341) / e10s - Bug 1094205 - places doesn't return the right thing in e10s mode, for some reason
skip-if = buildapp == 'mulet' || toolkit == "windows" # Disabled on Windows due to frequent failures (bugs 825739, 841341)
[browser_bug304198.js]
skip-if = e10s
[browser_bug321000.js]
skip-if = true # browser_bug321000.js is disabled because newline handling is shaky (bug 592528)
[browser_bug329212.js]
skip-if = e10s
[browser_bug331772_xul_tooltiptext_in_html.js]
skip-if = e10s
[browser_bug356571.js]
[browser_bug380960.js]
[browser_bug386835.js]
@ -159,7 +157,6 @@ skip-if = e10s # Bug 1056146 - zoom tests use FullZoomHelper and break in e10s
[browser_bug406216.js]
[browser_bug409481.js]
[browser_bug409624.js]
skip-if = e10s
[browser_bug413915.js]
[browser_bug416661.js]
skip-if = e10s # Bug 1056146 - zoom tests use FullZoomHelper and break in e10s
@ -181,7 +178,6 @@ skip-if = buildapp == 'mulet' || e10s # Bug 1099156 - test directly manipulates
[browser_bug441778.js]
skip-if = buildapp == 'mulet' || e10s # Bug 1056146 - zoom tests use FullZoomHelper and break in e10s
[browser_bug455852.js]
skip-if = e10s
[browser_bug460146.js]
skip-if = e10s # Bug 866413 - PageInfo doesn't work in e10s
[browser_bug462289.js]
@ -192,7 +188,6 @@ skip-if = toolkit == "cocoa" || e10s # Bug 1102017 - middle-button mousedown on
skip-if = buildapp == 'mulet'
[browser_bug481560.js]
[browser_bug484315.js]
skip-if = e10s
[browser_bug491431.js]
skip-if = buildapp == 'mulet'
[browser_bug495058.js]
@ -216,7 +211,6 @@ skip-if = e10s # Bug 1093373 - relies on browser.sessionHistory
[browser_bug556061.js]
[browser_bug559991.js]
[browser_bug561623.js]
skip-if = e10s
[browser_bug561636.js]
[browser_bug562649.js]
[browser_bug563588.js]
@ -237,7 +231,6 @@ skip-if = e10s # Bug 1056146 - zoom tests use FullZoomHelper and break in e10s
[browser_bug581253.js]
skip-if = e10s # Bug 1093756 - can't bookmark the data: url in e10s somehow
[browser_bug581947.js]
skip-if = e10s
[browser_bug585558.js]
[browser_bug585785.js]
[browser_bug585830.js]
@ -272,7 +265,6 @@ skip-if = e10s # Bug 1093155 - tries to use context menu from browser-chrome and
[browser_bug735471.js]
[browser_bug749738.js]
[browser_bug763468_perwindowpb.js]
skip-if = e10s
[browser_bug767836_perwindowpb.js]
[browser_bug771331.js]
[browser_bug783614.js]
@ -296,7 +288,6 @@ skip-if = os == 'win' || e10s # Bug 1056146 - zoom tests use FullZoomHelper and
[browser_canonizeURL.js]
skip-if = e10s # Bug 1094510 - test hits the network in e10s mode only
[browser_contentAreaClick.js]
skip-if = e10s
[browser_contextSearchTabPosition.js]
skip-if = os == "mac" || e10s # bug 967013; e10s: bug 1094761 - test hits the network in e10s, causing next test to crash
[browser_ctrlTab.js]
@ -316,7 +307,6 @@ skip-if = e10s
[browser_drag.js]
skip-if = true # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638.
[browser_favicon_change.js]
skip-if = e10s
[browser_favicon_change_not_in_document.js]
skip-if = e10s
[browser_findbarClose.js]
@ -368,7 +358,7 @@ skip-if = asan # Disabled because it takes a long time (see test for more inform
[browser_plainTextLinks.js]
skip-if = e10s # Bug 1093155 - tries to use context menu from browser-chrome and gets in a mess when in e10s mode
[browser_popupUI.js]
skip-if = buildapp == 'mulet' || e10s # Bug 1100707 - test fails in e10s because it can't get accel-w to close the popup (?)
skip-if = buildapp == 'mulet'
[browser_popup_blocker.js]
skip-if = e10s && debug # Frequent bug 1125520 failures
[browser_printpreview.js]
@ -383,7 +373,6 @@ support-files =
test_remoteTroubleshoot.html
[browser_removeTabsToTheEnd.js]
[browser_removeUnsafeProtocolsFromURLBarPaste.js]
skip-if = e10s
[browser_restore_isAppTab.js]
[browser_sanitize-passwordDisabledHosts.js]
[browser_sanitize-sitepermissions.js]
@ -457,7 +446,6 @@ skip-if = e10s # Bug 1093941 - used to cause obscure non-windows child process c
[browser_urlbarEnterAfterMouseOver.js]
skip-if = os == "linux" || e10s # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s
[browser_urlbarRevert.js]
skip-if = e10s # Bug 1093941 - ESC reverted the location bar value - Got foobar, expected example.com
[browser_urlbarSearchSingleWordNotification.js]
[browser_urlbarStop.js]
[browser_urlbarTrimURLs.js]
@ -483,9 +471,7 @@ skip-if = e10s # Bug 1094240 - has findbar-related failures
skip-if = e10s # Bug 940206 - nsIWebContentHandlerRegistrar::registerProtocolHandler doesn't work in e10s
[browser_no_mcb_on_http_site.js]
[browser_bug1003461-switchtab-override.js]
skip-if = e10s
[browser_bug1024133-switchtab-override-keynav.js]
skip-if = e10s
[browser_bug1025195_switchToTabHavingURI_aOpenParams.js]
[browser_addCertException.js]
skip-if = e10s # Bug 1100687 - test directly manipulates content (content.document.getElementById)

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

@ -0,0 +1,19 @@
. $topsrcdir/build/macosx/mozconfig.common
ac_add_options --enable-signmar
ac_add_options --with-google-oauth-api-keyfile=/builds/google-oauth-api.key
# Needed to enable breakpad in application.ini
export MOZILLA_OFFICIAL=1
if test "${MOZ_UPDATE_CHANNEL}" = "nightly"; then
ac_add_options --with-macbundlename-prefix=Firefox
fi
# Treat warnings as errors in directories with FAIL_ON_WARNINGS.
ac_add_options --enable-warnings-as-errors
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1
. "$topsrcdir/build/mozconfig.common.override"

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

@ -79,6 +79,11 @@ private:
virtual void run(const MatchFinder::MatchResult &Result);
};
class RefCountedInsideLambdaChecker : public MatchFinder::MatchCallback {
public:
virtual void run(const MatchFinder::MatchResult &Result);
};
ScopeChecker stackClassChecker;
ScopeChecker globalClassChecker;
NonHeapClassChecker nonheapClassChecker;
@ -86,6 +91,7 @@ private:
TrivialCtorDtorChecker trivialCtorDtorChecker;
NaNExprChecker nanExprChecker;
NoAddRefReleaseOnReturnChecker noAddRefReleaseOnReturnChecker;
RefCountedInsideLambdaChecker refCountedInsideLambdaChecker;
MatchFinder astMatcher;
};
@ -354,6 +360,62 @@ ClassAllocationNature getClassAttrs(QualType T) {
return clazz ? getClassAttrs(clazz) : RegularClass;
}
/// A cached data of whether classes are refcounted or not.
typedef DenseMap<const CXXRecordDecl *,
std::pair<const Decl *, bool> > RefCountedMap;
RefCountedMap refCountedClasses;
bool classHasAddRefRelease(const CXXRecordDecl *D) {
const RefCountedMap::iterator& it = refCountedClasses.find(D);
if (it != refCountedClasses.end()) {
return it->second.second;
}
bool seenAddRef = false;
bool seenRelease = false;
for (CXXRecordDecl::method_iterator method = D->method_begin();
method != D->method_end(); ++method) {
std::string name = method->getNameAsString();
if (name == "AddRef") {
seenAddRef = true;
} else if (name == "Release") {
seenRelease = true;
}
}
refCountedClasses[D] = std::make_pair(D, seenAddRef && seenRelease);
return seenAddRef && seenRelease;
}
bool isClassRefCounted(QualType T);
bool isClassRefCounted(const CXXRecordDecl *D) {
// Normalize so that D points to the definition if it exists.
if (!D->hasDefinition())
return false;
D = D->getDefinition();
// Base class: anyone with AddRef/Release is obviously a refcounted class.
if (classHasAddRefRelease(D))
return true;
// Look through all base cases to figure out if the parent is a refcounted class.
for (CXXRecordDecl::base_class_const_iterator base = D->bases_begin();
base != D->bases_end(); ++base) {
bool super = isClassRefCounted(base->getType());
if (super) {
return true;
}
}
return false;
}
bool isClassRefCounted(QualType T) {
while (const ArrayType *arrTy = T->getAsArrayTypeUnsafe())
T = arrTy->getElementType();
CXXRecordDecl *clazz = T->getAsCXXRecordDecl();
return clazz ? isClassRefCounted(clazz) : RegularClass;
}
}
namespace clang {
@ -481,6 +543,11 @@ AST_MATCHER(MemberExpr, isAddRefOrRelease) {
return false;
}
/// This matcher will select classes which are refcounted.
AST_MATCHER(QualType, isRefCounted) {
return isClassRefCounted(Node);
}
}
}
@ -577,6 +644,11 @@ DiagnosticsMatcher::DiagnosticsMatcher()
hasParent(callExpr())).bind("member")
)).bind("node"),
&noAddRefReleaseOnReturnChecker);
astMatcher.addMatcher(lambdaExpr(
hasDescendant(declRefExpr(hasType(pointerType(pointee(isRefCounted())))).bind("node"))
),
&refCountedInsideLambdaChecker);
}
void DiagnosticsMatcher::ScopeChecker::run(
@ -775,6 +847,20 @@ void DiagnosticsMatcher::NoAddRefReleaseOnReturnChecker::run(
Diag.Report(node->getLocStart(), errorID) << func << method;
}
void DiagnosticsMatcher::RefCountedInsideLambdaChecker::run(
const MatchFinder::MatchResult &Result) {
DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
DiagnosticIDs::Error, "Refcounted variable %0 of type %1 cannot be used inside a lambda");
unsigned noteID = Diag.getDiagnosticIDs()->getCustomDiagID(
DiagnosticIDs::Note, "Please consider using a smart pointer");
const DeclRefExpr *node = Result.Nodes.getNodeAs<DeclRefExpr>("node");
Diag.Report(node->getLocStart(), errorID) << node->getFoundDecl() <<
node->getType()->getPointeeType();
Diag.Report(node->getLocStart(), noteID);
}
class MozCheckAction : public PluginASTAction {
public:
ASTConsumerPtr CreateASTConsumer(CompilerInstance &CI, StringRef fileName) override {

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

@ -0,0 +1,58 @@
#define MOZ_STRONG_REF __attribute__((annotate("moz_strong_ref")))
struct RefCountedBase {
void AddRef();
void Release();
};
template <class T>
struct SmartPtr {
T* MOZ_STRONG_REF t;
T* operator->() const;
};
struct R : RefCountedBase {
void method();
};
void take(...);
void foo() {
R* ptr;
SmartPtr<R> sp;
take([&]() {
ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}}
});
take([&]() {
sp->method();
});
take([&]() {
take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}}
});
take([&]() {
take(sp);
});
take([=]() {
ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}}
});
take([=]() {
sp->method();
});
take([=]() {
take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}}
});
take([=]() {
take(sp);
});
take([ptr]() {
ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}}
});
take([sp]() {
sp->method();
});
take([ptr]() {
take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be used inside a lambda}} expected-note{{Please consider using a smart pointer}}
});
take([sp]() {
take(sp);
});
}

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

@ -14,6 +14,7 @@ SOURCES += [
'TestNoAddRefReleaseOnReturn.cpp',
'TestNoArithmeticExprInArgument.cpp',
'TestNonHeapClass.cpp',
'TestNoRefcountedInsideLambdas.cpp',
'TestStackClass.cpp',
'TestTrivialCtorDtor.cpp',
]

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

@ -23,7 +23,14 @@ make $make_flags || exit 1
make install $make_flags DESTDIR=$root_dir || exit 1
cd ..
case "$gcc_version" in
*-*)
wget -c -P $TMPDIR ftp://gcc.gnu.org/pub/gcc/snapshots/$gcc_version/gcc-$gcc_version.tar.bz2 || exit 1
;;
*)
wget -c -P $TMPDIR ftp://ftp.gnu.org/gnu/gcc/gcc-$gcc_version/gcc-$gcc_version.tar.bz2 || exit 1
;;
esac
tar xjf $TMPDIR/gcc-$gcc_version.tar.bz2
cd gcc-$gcc_version

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

@ -163,5 +163,8 @@ endif
ifdef MOZ_CRT
mozglue/crt/target: mozglue/build/target
endif
# js/src/target can end up invoking js/src/host rules (through object files
# depending on jsautokw.h, which depends on host_jskwgen, and that can't
# happen at the same time (bug #1146738)
js/src/target: js/src/host
endif

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

@ -73,7 +73,7 @@ GNOMEUI_VERSION=2.2.0
GCONF_VERSION=1.2.1
STARTUP_NOTIFICATION_VERSION=0.8
DBUS_VERSION=0.60
SQLITE_VERSION=3.8.8.2
SQLITE_VERSION=3.8.9
MSMANIFEST_TOOL=
@ -6948,12 +6948,15 @@ elif test "$GNU_CC"; then
# -Wdeprecated-declarations - we don't want our builds held hostage when a
# platform-specific API becomes deprecated.
# -Wfree-nonheap-object - false positives during PGO
# -Warray-bounds - false positives depending on optimization
MOZ_C_SUPPORTS_WARNING(-W, no-error=uninitialized, ac_c_has_noerror_uninitialized)
MOZ_CXX_SUPPORTS_WARNING(-W, no-error=uninitialized, ac_cxx_has_noerror_uninitialized)
MOZ_C_SUPPORTS_WARNING(-W, no-error=maybe-uninitialized, ac_c_has_noerror_maybe_uninitialized)
MOZ_CXX_SUPPORTS_WARNING(-W, no-error=maybe-uninitialized, ac_cxx_has_noerror_maybe_uninitialized)
MOZ_C_SUPPORTS_WARNING(-W, no-error=deprecated-declarations, ac_c_has_noerror_deprecated_declarations)
MOZ_CXX_SUPPORTS_WARNING(-W, no-error=deprecated-declarations, ac_cxx_has_noerror_deprecated_declarations)
MOZ_C_SUPPORTS_WARNING(-W, no-error=array-bounds, ac_c_has_noerror_array_bounds)
MOZ_CXX_SUPPORTS_WARNING(-W, no-error=array-bounds, ac_cxx_has_noerror_array_bounds)
if test -n "$MOZ_PGO"; then
MOZ_C_SUPPORTS_WARNING(-W, no-error=coverage-mismatch, ac_c_has_noerror_coverage_mismatch)

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

@ -10,5 +10,4 @@ To move to a new version:
Copy the sqlite3.h and sqlite3.c files from the amalgamation of sqlite.
Be sure to update SQLITE_VERSION accordingly in $(topsrcdir)/configure.in as
well as the version number at the top of this file.
Be sure to update SQLITE_VERSION accordingly in $(topsrcdir)/configure.in.

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

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

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

@ -1,24 +0,0 @@
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
/* 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/. */
#include "mozilla/dom/AnimationEffect.h"
#include "mozilla/dom/AnimationEffectBinding.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AnimationEffect, mAnimation)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AnimationEffect, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AnimationEffect, Release)
JSObject*
AnimationEffect::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return AnimationEffectBinding::Wrap(aCx, this, aGivenProto);
}
} // namespace dom
} // namespace mozilla

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

@ -1,46 +0,0 @@
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
/* 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/. */
#ifndef mozilla_dom_AnimationEffect_h
#define mozilla_dom_AnimationEffect_h
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"
#include "mozilla/dom/Animation.h"
struct JSContext;
namespace mozilla {
namespace dom {
class AnimationEffect final : public nsWrapperCache
{
public:
explicit AnimationEffect(Animation* aAnimation)
: mAnimation(aAnimation)
{
}
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AnimationEffect)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(AnimationEffect)
Animation* GetParentObject() const { return mAnimation; }
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
// AnimationEffect interface
void GetName(nsString& aRetVal) const {
aRetVal = mAnimation->Name();
}
private:
~AnimationEffect() { }
nsRefPtr<Animation> mAnimation;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_AnimationEffect_h

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

@ -0,0 +1,23 @@
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
/* 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/. */
#include "mozilla/dom/AnimationEffectReadonly.h"
#include "mozilla/dom/AnimationEffectReadonlyBinding.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AnimationEffectReadonly, mParent)
NS_IMPL_CYCLE_COLLECTING_ADDREF(AnimationEffectReadonly)
NS_IMPL_CYCLE_COLLECTING_RELEASE(AnimationEffectReadonly)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AnimationEffectReadonly)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
} // namespace dom
} // namespace mozilla

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

@ -0,0 +1,42 @@
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
/* 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/. */
#ifndef mozilla_dom_AnimationEffect_h
#define mozilla_dom_AnimationEffect_h
#include "nsISupports.h"
#include "nsWrapperCache.h"
#include "nsCycleCollectionParticipant.h"
#include "nsCOMPtr.h"
namespace mozilla {
namespace dom {
class AnimationEffectReadonly
: public nsISupports
, public nsWrapperCache
{
protected:
virtual ~AnimationEffectReadonly() { }
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AnimationEffectReadonly)
explicit AnimationEffectReadonly(nsISupports* aParent)
: mParent(aParent)
{
}
nsISupports* GetParentObject() const { return mParent; }
protected:
nsCOMPtr<nsISupports> mParent;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_AnimationEffect_h

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

@ -18,7 +18,7 @@ namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AnimationPlayer, mTimeline,
mSource, mReady, mFinished)
mEffect, mReady, mFinished)
NS_IMPL_CYCLE_COLLECTING_ADDREF(AnimationPlayer)
NS_IMPL_CYCLE_COLLECTING_RELEASE(AnimationPlayer)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AnimationPlayer)
@ -127,7 +127,7 @@ AnimationPlayer::SetCurrentTime(const TimeDuration& aSeekTime)
}
UpdateFinishedState(true);
UpdateSourceContent();
UpdateEffect();
PostUpdate();
}
@ -171,7 +171,7 @@ AnimationPlayer::PlayState() const
return AnimationPlayState::Paused;
}
if ((mPlaybackRate > 0.0 && currentTime.Value() >= SourceContentEnd()) ||
if ((mPlaybackRate > 0.0 && currentTime.Value() >= EffectEnd()) ||
(mPlaybackRate < 0.0 && currentTime.Value().ToMilliseconds() <= 0.0)) {
return AnimationPlayState::Finished;
}
@ -266,14 +266,14 @@ AnimationPlayer::SetCurrentTimeAsDouble(const Nullable<double>& aCurrentTime,
}
void
AnimationPlayer::SetSource(Animation* aSource)
AnimationPlayer::SetEffect(KeyframeEffectReadonly* aEffect)
{
if (mSource) {
mSource->SetParentTime(Nullable<TimeDuration>());
if (mEffect) {
mEffect->SetParentTime(Nullable<TimeDuration>());
}
mSource = aSource;
if (mSource) {
mSource->SetParentTime(GetCurrentTime());
mEffect = aEffect;
if (mEffect) {
mEffect->SetParentTime(GetCurrentTime());
}
UpdateRelevance();
}
@ -367,14 +367,14 @@ AnimationPlayer::Cancel()
mHoldTime.SetNull();
mStartTime.SetNull();
UpdateSourceContent();
UpdateEffect();
}
void
AnimationPlayer::UpdateRelevance()
{
bool wasRelevant = mIsRelevant;
mIsRelevant = HasCurrentSource() || HasInEffectSource();
mIsRelevant = HasCurrentEffect() || IsInEffect();
// Notify animation observers.
if (wasRelevant && !mIsRelevant) {
@ -387,9 +387,9 @@ AnimationPlayer::UpdateRelevance()
bool
AnimationPlayer::CanThrottle() const
{
if (!mSource ||
mSource->IsFinishedTransition() ||
mSource->Properties().IsEmpty()) {
if (!mEffect ||
mEffect->IsFinishedTransition() ||
mEffect->Properties().IsEmpty()) {
return true;
}
@ -414,7 +414,7 @@ AnimationPlayer::ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule,
nsCSSPropertySet& aSetProperties,
bool& aNeedsRefreshes)
{
if (!mSource || mSource->IsFinishedTransition()) {
if (!mEffect || mEffect->IsFinishedTransition()) {
return;
}
@ -476,13 +476,13 @@ AnimationPlayer::ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule,
if (!timeToUse.IsNull()) {
mHoldTime.SetValue((timeToUse.Value() - mStartTime.Value())
.MultDouble(mPlaybackRate));
// Push the change down to the source content
UpdateSourceContent();
// Push the change down to the effect
UpdateEffect();
updatedHoldTime = true;
}
}
mSource->ComposeStyle(aStyleRule, aSetProperties);
mEffect->ComposeStyle(aStyleRule, aSetProperties);
if (updatedHoldTime) {
UpdateTiming();
@ -508,14 +508,14 @@ AnimationPlayer::DoPlay(LimitBehavior aLimitBehavior)
(currentTime.IsNull() ||
(aLimitBehavior == LimitBehavior::AutoRewind &&
(currentTime.Value().ToMilliseconds() < 0.0 ||
currentTime.Value() >= SourceContentEnd())))) {
currentTime.Value() >= EffectEnd())))) {
mHoldTime.SetValue(TimeDuration(0));
} else if (mPlaybackRate < 0.0 &&
(currentTime.IsNull() ||
(aLimitBehavior == LimitBehavior::AutoRewind &&
(currentTime.Value().ToMilliseconds() <= 0.0 ||
currentTime.Value() > SourceContentEnd())))) {
mHoldTime.SetValue(TimeDuration(SourceContentEnd()));
currentTime.Value() > EffectEnd())))) {
mHoldTime.SetValue(TimeDuration(EffectEnd()));
} else if (mPlaybackRate == 0.0 && currentTime.IsNull()) {
mHoldTime.SetValue(TimeDuration(0));
}
@ -647,30 +647,29 @@ AnimationPlayer::PauseAt(const TimeDuration& aReadyTime)
void
AnimationPlayer::UpdateTiming()
{
// We call UpdateFinishedState before UpdateSourceContent because the former
// We call UpdateFinishedState before UpdateEffect because the former
// can change the current time, which is used by the latter.
UpdateFinishedState();
UpdateSourceContent();
UpdateEffect();
}
void
AnimationPlayer::UpdateFinishedState(bool aSeekFlag)
{
Nullable<TimeDuration> currentTime = GetCurrentTime();
TimeDuration targetEffectEnd = TimeDuration(SourceContentEnd());
TimeDuration effectEnd = TimeDuration(EffectEnd());
if (!mStartTime.IsNull() &&
mPendingState == PendingState::NotPending) {
if (mPlaybackRate > 0.0 &&
!currentTime.IsNull() &&
currentTime.Value() >= targetEffectEnd) {
currentTime.Value() >= effectEnd) {
if (aSeekFlag) {
mHoldTime = currentTime;
} else if (!mPreviousCurrentTime.IsNull()) {
mHoldTime.SetValue(std::max(mPreviousCurrentTime.Value(),
targetEffectEnd));
mHoldTime.SetValue(std::max(mPreviousCurrentTime.Value(), effectEnd));
} else {
mHoldTime.SetValue(targetEffectEnd);
mHoldTime.SetValue(effectEnd);
}
} else if (mPlaybackRate < 0.0 &&
!currentTime.IsNull() &&
@ -706,10 +705,10 @@ AnimationPlayer::UpdateFinishedState(bool aSeekFlag)
}
void
AnimationPlayer::UpdateSourceContent()
AnimationPlayer::UpdateEffect()
{
if (mSource) {
mSource->SetParentTime(GetCurrentTime());
if (mEffect) {
mEffect->SetParentTime(GetCurrentTime());
UpdateRelevance();
}
}
@ -764,7 +763,7 @@ AnimationPlayer::IsFinished() const
// and we need this much more messy check to see if we're finished.
Nullable<TimeDuration> currentTime = GetCurrentTime();
return !currentTime.IsNull() &&
((mPlaybackRate > 0.0 && currentTime.Value() >= SourceContentEnd()) ||
((mPlaybackRate > 0.0 && currentTime.Value() >= EffectEnd()) ||
(mPlaybackRate < 0.0 && currentTime.Value().ToMilliseconds() <= 0.0));
}
@ -776,15 +775,15 @@ AnimationPlayer::IsPossiblyOrphanedPendingPlayer() const
//
// This covers the following cases:
//
// * We started playing but our source content's target element was orphaned
// * We started playing but our effect's target element was orphaned
// or bound to a different document.
// (note that for the case of our source content changing we should handle
// that in SetSource)
// (note that for the case of our effect changing we should handle
// that in SetEffect)
// * We started playing but our timeline became inactive.
// In this case the pending player tracker will drop us from its hashmap
// when we have been painted.
// * When we started playing we couldn't find a PendingPlayerTracker to
// register with (perhaps the source content had no document) so we simply
// register with (perhaps the effect had no document) so we simply
// set mPendingState in DoPlay and relied on this method to catch us on the
// next tick.
@ -823,26 +822,26 @@ AnimationPlayer::IsPossiblyOrphanedPendingPlayer() const
}
StickyTimeDuration
AnimationPlayer::SourceContentEnd() const
AnimationPlayer::EffectEnd() const
{
if (!mSource) {
if (!mEffect) {
return StickyTimeDuration(0);
}
return mSource->Timing().mDelay
+ mSource->GetComputedTiming().mActiveDuration;
return mEffect->Timing().mDelay
+ mEffect->GetComputedTiming().mActiveDuration;
}
nsIDocument*
AnimationPlayer::GetRenderedDocument() const
{
if (!mSource) {
if (!mEffect) {
return nullptr;
}
Element* targetElement;
nsCSSPseudoElements::Type pseudoType;
mSource->GetTarget(targetElement, pseudoType);
mEffect->GetTarget(targetElement, pseudoType);
if (!targetElement) {
return nullptr;
}
@ -871,11 +870,11 @@ AnimationPlayer::GetCollection() const
if (!manager) {
return nullptr;
}
MOZ_ASSERT(mSource, "A player with an animation manager must have a source");
MOZ_ASSERT(mEffect, "A player with an animation manager must have an effect");
Element* targetElement;
nsCSSPseudoElements::Type targetPseudoType;
mSource->GetTarget(targetElement, targetPseudoType);
mEffect->GetTarget(targetElement, targetPseudoType);
MOZ_ASSERT(targetElement,
"A player with an animation manager must have a target");

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

@ -10,9 +10,9 @@
#include "nsCycleCollectionParticipant.h"
#include "mozilla/Attributes.h"
#include "mozilla/TimeStamp.h" // for TimeStamp, TimeDuration
#include "mozilla/dom/Animation.h" // for Animation
#include "mozilla/dom/AnimationPlayerBinding.h" // for AnimationPlayState
#include "mozilla/dom/DocumentTimeline.h" // for DocumentTimeline
#include "mozilla/dom/KeyframeEffect.h" // for KeyframeEffectReadonly
#include "mozilla/dom/Promise.h" // for Promise
#include "nsCSSProperty.h" // for nsCSSProperty
@ -80,7 +80,7 @@ public:
};
// AnimationPlayer methods
Animation* GetSource() const { return mSource; }
KeyframeEffectReadonly* GetEffect() const { return mEffect; }
DocumentTimeline* Timeline() const { return mTimeline; }
Nullable<TimeDuration> GetStartTime() const { return mStartTime; }
void SetStartTime(const Nullable<TimeDuration>& aNewStartTime);
@ -113,14 +113,14 @@ public:
// CSSAnimationPlayer::PauseFromJS so we leave it for now.
void PauseFromJS() { Pause(); }
void SetSource(Animation* aSource);
void SetEffect(KeyframeEffectReadonly* aEffect);
void Tick();
/**
* Set the time to use for starting or pausing a pending player.
*
* Typically, when a player is played, it does not start immediately but is
* added to a table of pending players on the document of its source content.
* added to a table of pending players on the document of its effect.
* In the meantime it sets its hold time to the time from which playback
* should begin.
*
@ -203,7 +203,7 @@ public:
const nsString& Name() const
{
return mSource ? mSource->Name() : EmptyString();
return mEffect ? mEffect->Name() : EmptyString();
}
bool IsPausedOrPausing() const
@ -212,17 +212,17 @@ public:
mPendingState == PendingState::PausePending;
}
bool HasInPlaySource() const
bool HasInPlayEffect() const
{
return GetSource() && GetSource()->IsInPlay(*this);
return GetEffect() && GetEffect()->IsInPlay(*this);
}
bool HasCurrentSource() const
bool HasCurrentEffect() const
{
return GetSource() && GetSource()->IsCurrent(*this);
return GetEffect() && GetEffect()->IsCurrent(*this);
}
bool HasInEffectSource() const
bool IsInEffect() const
{
return GetSource() && GetSource()->IsInEffect();
return GetEffect() && GetEffect()->IsInEffect();
}
/**
@ -235,9 +235,9 @@ public:
*/
bool IsPlaying() const
{
// We need to have a source animation in its active interval, and
// We need to have an effect in its active interval, and
// be either running or waiting to run.
return HasInPlaySource() &&
return HasInPlayEffect() &&
(PlayState() == AnimationPlayState::Running ||
mPendingState == PendingState::PlayPending);
}
@ -253,13 +253,13 @@ public:
// running on the compositor).
bool CanThrottle() const;
// Updates |aStyleRule| with the animation values of this player's source
// content, if any.
// Updates |aStyleRule| with the animation values of this player's effect,
// if any.
// Any properties already contained in |aSetProperties| are not changed. Any
// properties that are changed are added to |aSetProperties|.
// |aNeedsRefreshes| will be set to true if this player expects to update
// the style rule on the next refresh driver tick as well (because it
// is running and has source content to sample).
// is running and has an effect to sample).
void ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule,
nsCSSPropertySet& aSetProperties,
bool& aNeedsRefreshes);
@ -282,7 +282,7 @@ protected:
void UpdateTiming();
void UpdateFinishedState(bool aSeekFlag = false);
void UpdateSourceContent();
void UpdateEffect();
void FlushStyle() const;
void PostUpdate();
/**
@ -295,7 +295,7 @@ protected:
bool IsFinished() const;
bool IsPossiblyOrphanedPendingPlayer() const;
StickyTimeDuration SourceContentEnd() const;
StickyTimeDuration EffectEnd() const;
nsIDocument* GetRenderedDocument() const;
nsPresContext* GetPresContext() const;
@ -303,7 +303,7 @@ protected:
AnimationPlayerCollection* GetCollection() const;
nsRefPtr<DocumentTimeline> mTimeline;
nsRefPtr<Animation> mSource;
nsRefPtr<KeyframeEffectReadonly> mEffect;
// The beginning of the delay period.
Nullable<TimeDuration> mStartTime; // Timeline timescale
Nullable<TimeDuration> mHoldTime; // Player timescale
@ -317,7 +317,7 @@ protected:
// See http://w3c.github.io/web-animations/#current-ready-promise
nsRefPtr<Promise> mReady;
// A Promise that is resolved when we reach the end of the source content, or
// A Promise that is resolved when we reach the end of the effect, or
// 0 when playing backwards. The Promise is replaced if the animation is
// finished but then a state change makes it not finished.
// This object is lazily created by GetFinished.

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

@ -3,9 +3,8 @@
* 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 "mozilla/dom/Animation.h"
#include "mozilla/dom/AnimationBinding.h"
#include "mozilla/dom/AnimationEffect.h"
#include "mozilla/dom/KeyframeEffect.h"
#include "mozilla/dom/KeyframeEffectBinding.h"
#include "mozilla/FloatingPoint.h"
#include "AnimationCommon.h"
#include "nsCSSPropertySet.h"
@ -60,33 +59,37 @@ const double ComputedTiming::kNullTimeFraction = PositiveInfinity<double>();
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Animation, mDocument, mTarget)
NS_IMPL_CYCLE_COLLECTION_INHERITED(KeyframeEffectReadonly,
AnimationEffectReadonly,
mTarget)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(Animation, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(Animation, Release)
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(KeyframeEffectReadonly,
AnimationEffectReadonly)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(KeyframeEffectReadonly)
NS_INTERFACE_MAP_END_INHERITING(AnimationEffectReadonly)
NS_IMPL_ADDREF_INHERITED(KeyframeEffectReadonly, AnimationEffectReadonly)
NS_IMPL_RELEASE_INHERITED(KeyframeEffectReadonly, AnimationEffectReadonly)
JSObject*
Animation::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
KeyframeEffectReadonly::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto)
{
return AnimationBinding::Wrap(aCx, this, aGivenProto);
}
already_AddRefed<AnimationEffect>
Animation::GetEffect()
{
nsRefPtr<AnimationEffect> effect = new AnimationEffect(this);
return effect.forget();
return KeyframeEffectReadonlyBinding::Wrap(aCx, this, aGivenProto);
}
void
Animation::SetParentTime(Nullable<TimeDuration> aParentTime)
KeyframeEffectReadonly::SetParentTime(Nullable<TimeDuration> aParentTime)
{
mParentTime = aParentTime;
}
ComputedTiming
Animation::GetComputedTimingAt(const Nullable<TimeDuration>& aLocalTime,
const AnimationTiming& aTiming)
KeyframeEffectReadonly::GetComputedTimingAt(
const Nullable<TimeDuration>& aLocalTime,
const AnimationTiming& aTiming)
{
const TimeDuration zeroDuration;
@ -214,7 +217,7 @@ Animation::GetComputedTimingAt(const Nullable<TimeDuration>& aLocalTime,
}
StickyTimeDuration
Animation::ActiveDuration(const AnimationTiming& aTiming)
KeyframeEffectReadonly::ActiveDuration(const AnimationTiming& aTiming)
{
if (aTiming.mIterationCount == mozilla::PositiveInfinity<float>()) {
// An animation that repeats forever has an infinite active duration
@ -231,7 +234,7 @@ Animation::ActiveDuration(const AnimationTiming& aTiming)
// http://w3c.github.io/web-animations/#in-play
bool
Animation::IsInPlay(const AnimationPlayer& aPlayer) const
KeyframeEffectReadonly::IsInPlay(const AnimationPlayer& aPlayer) const
{
if (IsFinishedTransition() ||
aPlayer.PlayState() == AnimationPlayState::Finished) {
@ -243,7 +246,7 @@ Animation::IsInPlay(const AnimationPlayer& aPlayer) const
// http://w3c.github.io/web-animations/#current
bool
Animation::IsCurrent(const AnimationPlayer& aPlayer) const
KeyframeEffectReadonly::IsCurrent(const AnimationPlayer& aPlayer) const
{
if (IsFinishedTransition() ||
aPlayer.PlayState() == AnimationPlayState::Finished) {
@ -256,7 +259,7 @@ Animation::IsCurrent(const AnimationPlayer& aPlayer) const
}
bool
Animation::IsInEffect() const
KeyframeEffectReadonly::IsInEffect() const
{
if (IsFinishedTransition()) {
return false;
@ -267,7 +270,7 @@ Animation::IsInEffect() const
}
const AnimationProperty*
Animation::GetAnimationOfProperty(nsCSSProperty aProperty) const
KeyframeEffectReadonly::GetAnimationOfProperty(nsCSSProperty aProperty) const
{
for (size_t propIdx = 0, propEnd = mProperties.Length();
propIdx != propEnd; ++propIdx) {
@ -283,8 +286,9 @@ Animation::GetAnimationOfProperty(nsCSSProperty aProperty) const
}
bool
Animation::HasAnimationOfProperties(const nsCSSProperty* aProperties,
size_t aPropertyCount) const
KeyframeEffectReadonly::HasAnimationOfProperties(
const nsCSSProperty* aProperties,
size_t aPropertyCount) const
{
for (size_t i = 0; i < aPropertyCount; i++) {
if (HasAnimationOfProperty(aProperties[i])) {
@ -295,8 +299,9 @@ Animation::HasAnimationOfProperties(const nsCSSProperty* aProperties,
}
void
Animation::ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule,
nsCSSPropertySet& aSetProperties)
KeyframeEffectReadonly::ComposeStyle(
nsRefPtr<css::AnimValuesStyleRule>& aStyleRule,
nsCSSPropertySet& aSetProperties)
{
ComputedTiming computedTiming = GetComputedTiming();

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

@ -3,8 +3,8 @@
* 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/. */
#ifndef mozilla_dom_Animation_h
#define mozilla_dom_Animation_h
#ifndef mozilla_dom_KeyframeEffect_h
#define mozilla_dom_KeyframeEffect_h
#include "nsAutoPtr.h"
#include "nsCycleCollectionParticipant.h"
@ -15,6 +15,7 @@
#include "mozilla/StickyTimeDuration.h"
#include "mozilla/StyleAnimationValue.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/dom/AnimationEffectReadonly.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Nullable.h"
#include "nsSMILKeySpline.h"
@ -117,8 +118,8 @@ public:
bool operator==(const ComputedTimingFunction& aOther) const {
return mType == aOther.mType &&
(mType == nsTimingFunction::Function ?
mTimingFunction == aOther.mTimingFunction :
mSteps == aOther.mSteps);
mTimingFunction == aOther.mTimingFunction :
mSteps == aOther.mSteps);
}
bool operator!=(const ComputedTimingFunction& aOther) const {
return !(*this == aOther);
@ -184,17 +185,15 @@ struct ElementPropertyTransition;
namespace dom {
class AnimationEffect;
class Animation : public nsWrapperCache
class KeyframeEffectReadonly : public AnimationEffectReadonly
{
public:
Animation(nsIDocument* aDocument,
Element* aTarget,
nsCSSPseudoElements::Type aPseudoType,
const AnimationTiming &aTiming,
const nsSubstring& aName)
: mDocument(aDocument)
KeyframeEffectReadonly(nsIDocument* aDocument,
Element* aTarget,
nsCSSPseudoElements::Type aPseudoType,
const AnimationTiming &aTiming,
const nsSubstring& aName)
: AnimationEffectReadonly(aDocument)
, mTarget(aTarget)
, mTiming(aTiming)
, mName(aName)
@ -204,33 +203,32 @@ public:
MOZ_ASSERT(aTarget, "null animation target is not yet supported");
}
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(Animation)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(Animation)
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(KeyframeEffectReadonly,
AnimationEffectReadonly)
nsIDocument* GetParentObject() const { return mDocument; }
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
// FIXME: If we succeed in moving transition-specific code to a type of
// AnimationEffect (as per the Web Animations API) we should remove these
// virtual methods.
virtual ElementPropertyTransition* AsTransition() { return nullptr; }
virtual const ElementPropertyTransition* AsTransition() const {
return nullptr;
}
// Animation interface
// This currently returns a new object each time when used from C++ but is
// cached when used from JS.
already_AddRefed<AnimationEffect> GetEffect();
// KeyframeEffectReadonly interface
Element* GetTarget() const {
// Currently we only implement Element.getAnimations() which only
// returns animations targetting Elements so this should never
// be called for an animation that targets a pseudo-element.
MOZ_ASSERT(mPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement,
"Requesting the target of an Animation that targets a"
"Requesting the target of a KeyframeEffect that targets a"
" pseudo-element is not yet supported.");
return mTarget;
}
void GetName(nsString& aRetVal) const
{
aRetVal = Name();
}
// Temporary workaround to return both the target element and pseudo-type
// until we implement PseudoElement.
@ -239,6 +237,12 @@ public:
aTarget = mTarget;
aPseudoType = mPseudoType;
}
// Alternative to GetName that returns a reference to the member for
// more efficient internal usage.
virtual const nsString& Name() const
{
return mName;
}
void SetParentTime(Nullable<TimeDuration> aParentTime);
@ -249,10 +253,6 @@ public:
return mTiming;
}
virtual const nsString& Name() const {
return mName;
}
// Return the duration from the start the active interval to the point where
// the animation begins playback. This is zero unless the animation has
// a negative delay in which case it is the absolute value of the delay.
@ -332,11 +332,8 @@ public:
nsCSSPropertySet& aSetProperties);
protected:
virtual ~Animation() { }
virtual ~KeyframeEffectReadonly() { }
// We use a document for a parent object since the other likely candidate,
// the target element, can be empty.
nsCOMPtr<nsIDocument> mDocument;
nsCOMPtr<Element> mTarget;
Nullable<TimeDuration> mParentTime;
@ -353,4 +350,4 @@ protected:
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_Animation_h
#endif // mozilla_dom_KeyframeEffect_h

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

@ -8,11 +8,11 @@ MOCHITEST_MANIFESTS += ['test/mochitest.ini']
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
EXPORTS.mozilla.dom += [
'Animation.h',
'AnimationEffect.h',
'AnimationEffectReadonly.h',
'AnimationPlayer.h',
'AnimationTimeline.h',
'DocumentTimeline.h',
'KeyframeEffect.h',
]
EXPORTS.mozilla += [
@ -21,11 +21,11 @@ EXPORTS.mozilla += [
]
UNIFIED_SOURCES += [
'Animation.cpp',
'AnimationEffect.cpp',
'AnimationEffectReadonly.cpp',
'AnimationPlayer.cpp',
'AnimationTimeline.cpp',
'DocumentTimeline.cpp',
'KeyframeEffect.cpp',
'PendingPlayerTracker.cpp',
]

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

@ -208,11 +208,11 @@ function checkStateOnSettingCurrentTimeToZero(animation)
'Animation.playState should be "running" at the start of ' +
'the start delay');
assert_equals(animation.source.target.style.animationPlayState, 'running',
'Animation.source.target.style.animationPlayState should be ' +
assert_equals(animation.effect.target.style.animationPlayState, 'running',
'Animation.effect.target.style.animationPlayState should be ' +
'"running" at the start of the start delay');
var div = animation.source.target;
var div = animation.effect.target;
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
assert_equals(marginLeft, UNANIMATED_POSITION,
'the computed value of margin-left should be unaffected ' +
@ -233,11 +233,11 @@ function checkStateOnReadyPromiseResolved(animation)
'Animation.playState should be "running" on the first paint ' +
'tick after animation creation');
assert_equals(animation.source.target.style.animationPlayState, 'running',
'Animation.source.target.style.animationPlayState should be ' +
assert_equals(animation.effect.target.style.animationPlayState, 'running',
'Animation.effect.target.style.animationPlayState should be ' +
'"running" on the first paint tick after animation creation');
var div = animation.source.target;
var div = animation.effect.target;
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
assert_equals(marginLeft, UNANIMATED_POSITION,
'the computed value of margin-left should be unaffected ' +
@ -253,11 +253,11 @@ function checkStateAtActiveIntervalStartTime(animation)
'Animation.playState should be "running" at the start of ' +
'the active interval');
assert_equals(animation.source.target.style.animationPlayState, 'running',
'Animation.source.target.style.animationPlayState should be ' +
assert_equals(animation.effect.target.style.animationPlayState, 'running',
'Animation.effect.target.style.animationPlayState should be ' +
'"running" at the start of the active interval');
var div = animation.source.target;
var div = animation.effect.target;
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
assert_between_inclusive(marginLeft, INITIAL_POSITION, TEN_PCT_POSITION,
'the computed value of margin-left should be close to the value at the ' +
@ -268,7 +268,7 @@ function checkStateAtFiftyPctOfActiveInterval(animation)
{
// We don't test animation.currentTime since our caller just set it.
var div = animation.source.target;
var div = animation.effect.target;
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
assert_equals(marginLeft, FIFTY_PCT_POSITION,
'the computed value of margin-left should be half way through the ' +
@ -284,11 +284,11 @@ function checkStateAtActiveIntervalEndTime(animation)
'Animation.playState should be "finished" at the end of ' +
'the active interval');
assert_equals(animation.source.target.style.animationPlayState, "running",
'Animation.source.target.style.animationPlayState should be ' +
assert_equals(animation.effect.target.style.animationPlayState, "running",
'Animation.effect.target.style.animationPlayState should be ' +
'"finished" at the end of the active interval');
var div = animation.source.target;
var div = animation.effect.target;
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
assert_equals(marginLeft, UNANIMATED_POSITION,
'the computed value of margin-left should be unaffected ' +
@ -314,8 +314,8 @@ test(function(t)
'Animation.playState should be "pending" when an animation ' +
'is initially created');
assert_equals(animation.source.target.style.animationPlayState, 'running',
'Animation.source.target.style.animationPlayState should be ' +
assert_equals(animation.effect.target.style.animationPlayState, 'running',
'Animation.effect.target.style.animationPlayState should be ' +
'"running" when an animation is initially created');
// XXX Ideally we would have a test to check the ready Promise is initially

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

@ -210,11 +210,11 @@ function checkStateOnReadyPromiseResolved(animation)
'Animation.playState should be "running" on the first paint ' +
'tick after animation creation');
assert_equals(animation.source.target.style.animationPlayState, 'running',
'Animation.source.target.style.animationPlayState should be ' +
assert_equals(animation.effect.target.style.animationPlayState, 'running',
'Animation.effect.target.style.animationPlayState should be ' +
'"running" on the first paint tick after animation creation');
var div = animation.source.target;
var div = animation.effect.target;
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
assert_equals(marginLeft, UNANIMATED_POSITION,
'the computed value of margin-left should be unaffected ' +
@ -230,11 +230,11 @@ function checkStateAtActiveIntervalStartTime(animation)
'Animation.playState should be "running" at the start of ' +
'the active interval');
assert_equals(animation.source.target.style.animationPlayState, 'running',
'Animation.source.target.style.animationPlayState should be ' +
assert_equals(animation.effect.target.style.animationPlayState, 'running',
'Animation.effect.target.style.animationPlayState should be ' +
'"running" at the start of the active interval');
var div = animation.source.target;
var div = animation.effect.target;
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
assert_between_inclusive(marginLeft, INITIAL_POSITION, TEN_PCT_POSITION,
'the computed value of margin-left should be close to the value at the ' +
@ -245,7 +245,7 @@ function checkStateAtFiftyPctOfActiveInterval(animation)
{
// We don't test animation.startTime since our caller just set it.
var div = animation.source.target;
var div = animation.effect.target;
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
assert_equals(marginLeft, FIFTY_PCT_POSITION,
'the computed value of margin-left should be half way through the ' +
@ -261,11 +261,11 @@ function checkStateAtActiveIntervalEndTime(animation)
'Animation.playState should be "finished" at the end of ' +
'the active interval');
assert_equals(animation.source.target.style.animationPlayState, "running",
'Animation.source.target.style.animationPlayState should be ' +
assert_equals(animation.effect.target.style.animationPlayState, "running",
'Animation.effect.target.style.animationPlayState should be ' +
'"finished" at the end of the active interval');
var div = animation.source.target;
var div = animation.effect.target;
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
assert_equals(marginLeft, UNANIMATED_POSITION,
'the computed value of margin-left should be unaffected ' +

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

@ -15,22 +15,22 @@
test(function(t) {
var div = addDiv(t);
div.style.animation = 'xyz 100s';
assert_equals(div.getAnimations()[0].source.effect.name, 'xyz',
assert_equals(div.getAnimations()[0].effect.name, 'xyz',
'Animation effect name matches keyframes rule name');
}, 'Effect name makes keyframe rule');
test(function(t) {
var div = addDiv(t);
div.style.animation = 'x\\yz 100s';
assert_equals(div.getAnimations()[0].source.effect.name, 'xyz',
assert_equals(div.getAnimations()[0].effect.name, 'xyz',
'Escaped animation effect name matches keyframes rule name');
}, 'Escaped animation name');
test(function(t) {
var div = addDiv(t);
div.style.animation = 'x\\79 z 100s';
assert_equals(div.getAnimations()[0].source.effect.name, 'xyz',
'Hex-escaped animation effect name matches keyframes rule'
assert_equals(div.getAnimations()[0].effect.name, 'xyz',
'Hex-escaped animation name matches keyframes rule'
+ ' name');
}, 'Animation name with hex-escape');

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

@ -14,7 +14,7 @@ test(function(t) {
var div = addDiv(t);
div.style.animation = 'anim 100s';
var animation = div.getAnimations()[0];
assert_equals(animation.source.target, div,
assert_equals(animation.effect.target, div,
'Animation.target is the animatable div');
}, 'Returned CSS animations have the correct Animation.target');

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

@ -243,7 +243,7 @@ test(function(t) {
// Update duration (an Animation change)
div.style.animationDuration = '200s';
var extendedAnimation = div.getAnimations()[0];
// FIXME: Check extendedAnimation.source.timing.duration has changed once the
// FIXME: Check extendedAnimation.effect.timing.duration has changed once the
// API is available
assert_equals(originalAnimation, extendedAnimation,
'getAnimations returns the same objects even when their'

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

@ -194,11 +194,11 @@ function checkStateOnSettingCurrentTimeToZero(animation)
'Animation.playState should be "running" at the start of ' +
'the start delay');
assert_equals(animation.source.target.style.animationPlayState, 'running',
'Animation.source.target.style.animationPlayState should be ' +
assert_equals(animation.effect.target.style.animationPlayState, 'running',
'Animation.effect.target.style.animationPlayState should be ' +
'"running" at the start of the start delay');
var div = animation.source.target;
var div = animation.effect.target;
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
assert_equals(marginLeft, UNANIMATED_POSITION,
'the computed value of margin-left should be unaffected ' +
@ -219,7 +219,7 @@ function checkStateOnReadyPromiseResolved(animation)
'Animation.playState should be "running" on the first paint ' +
'tick after animation creation');
var div = animation.source.target;
var div = animation.effect.target;
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
assert_equals(marginLeft, INITIAL_POSITION,
'the computed value of margin-left should be unaffected ' +
@ -235,7 +235,7 @@ function checkStateAtActiveIntervalStartTime(animation)
'Animation.playState should be "running" at the start of ' +
'the active interval');
var div = animation.source.target;
var div = animation.effect.target;
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
assert_between_inclusive(marginLeft, INITIAL_POSITION, TEN_PCT_POSITION,
'the computed value of margin-left should be close to the value at the ' +
@ -246,7 +246,7 @@ function checkStateAtFiftyPctOfActiveInterval(animation)
{
// We don't test animation.currentTime since our caller just set it.
var div = animation.source.target;
var div = animation.effect.target;
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
assert_equals(marginLeft, FIFTY_PCT_POSITION,
'the computed value of margin-left should be half way through the ' +
@ -262,7 +262,7 @@ function checkStateAtActiveIntervalEndTime(animation)
'Animation.playState should be "finished" at the end of ' +
'the active interval');
var div = animation.source.target;
var div = animation.effect.target;
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
assert_equals(marginLeft, END_POSITION,
'the computed value of margin-left should be the final transitioned-to ' +

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

@ -200,7 +200,7 @@ function checkStateOnReadyPromiseResolved(animation)
'Animation.playState should be "running" on the first paint ' +
'tick after animation creation');
var div = animation.source.target;
var div = animation.effect.target;
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
assert_equals(marginLeft, INITIAL_POSITION,
'the computed value of margin-left should be unaffected ' +
@ -216,7 +216,7 @@ function checkStateAtActiveIntervalStartTime(animation)
'Animation.playState should be "running" at the start of ' +
'the active interval');
var div = animation.source.target;
var div = animation.effect.target;
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
assert_between_inclusive(marginLeft, INITIAL_POSITION, TEN_PCT_POSITION,
'the computed value of margin-left should be close to the value at the ' +
@ -227,7 +227,7 @@ function checkStateAtFiftyPctOfActiveInterval(animation)
{
// We don't test animation.startTime since our caller just set it.
var div = animation.source.target;
var div = animation.effect.target;
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
assert_equals(marginLeft, FIFTY_PCT_POSITION,
'the computed value of margin-left should be half way through the ' +
@ -243,7 +243,7 @@ function checkStateAtActiveIntervalEndTime(animation)
'Animation.playState should be "finished" at the end of ' +
'the active interval');
var div = animation.source.target;
var div = animation.effect.target;
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
assert_equals(marginLeft, END_POSITION,
'the computed value of margin-left should be the final transitioned-to ' +

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

@ -16,7 +16,7 @@ test(function(t) {
div.style.transition = 'all 100s';
div.style.left = '100px';
assert_equals(div.getAnimations()[0].source.effect.name, 'left',
assert_equals(div.getAnimations()[0].effect.name, 'left',
'The name for the transitions corresponds to the property ' +
'being transitioned');
}, 'Effect name for transitions');

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

@ -16,7 +16,7 @@ test(function(t) {
div.style.left = '100px';
var animation = div.getAnimations()[0];
assert_equals(animation.source.target, div,
assert_equals(animation.effect.target, div,
'Animation.target is the animatable div');
}, 'Returned CSS transitions have the correct Animation.target');

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

@ -3,22 +3,22 @@ support-files =
testcommon.js
[css-animations/test_animations-dynamic-changes.html]
[css-animations/test_animation-effect-name.html]
[css-animations/test_animation-pausing.html]
[css-animations/test_animation-player-currenttime.html]
[css-animations/test_animation-player-finished.html]
[css-animations/test_animation-player-playstate.html]
[css-animations/test_animation-player-ready.html]
[css-animations/test_animation-player-starttime.html]
[css-animations/test_animation-target.html]
[css-animations/test_effect-name.html]
[css-animations/test_effect-target.html]
[css-animations/test_element-get-animation-players.html]
skip-if = buildapp == 'mulet'
[css-transitions/test_animation-effect-name.html]
[css-transitions/test_animation-pausing.html]
[css-transitions/test_animation-player-currenttime.html]
[css-transitions/test_animation-player-ready.html]
[css-transitions/test_animation-target.html]
[css-transitions/test_animation-player-starttime.html]
[css-transitions/test_effect-name.html]
[css-transitions/test_effect-target.html]
[css-transitions/test_element-get-animation-players.html]
skip-if = buildapp == 'mulet'
[document-timeline/test_document-timeline.html]

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

@ -0,0 +1,72 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */
#include "SameProcessMessageQueue.h"
using namespace mozilla;
using namespace mozilla::dom;
SameProcessMessageQueue* SameProcessMessageQueue::sSingleton;
SameProcessMessageQueue::SameProcessMessageQueue()
{
}
SameProcessMessageQueue::~SameProcessMessageQueue()
{
// This code should run during shutdown, and we should already have pumped the
// event loop. So we should only see messages here if someone is sending
// messages pretty late in shutdown.
NS_WARN_IF_FALSE(mQueue.IsEmpty(), "Shouldn't send messages during shutdown");
sSingleton = nullptr;
}
void
SameProcessMessageQueue::Push(Runnable* aRunnable)
{
mQueue.AppendElement(aRunnable);
NS_DispatchToCurrentThread(aRunnable);
}
void
SameProcessMessageQueue::Flush()
{
nsTArray<nsRefPtr<Runnable>> queue;
mQueue.SwapElements(queue);
for (size_t i = 0; i < queue.Length(); i++) {
queue[i]->Run();
}
}
/* static */ SameProcessMessageQueue*
SameProcessMessageQueue::Get()
{
if (!sSingleton) {
sSingleton = new SameProcessMessageQueue();
}
return sSingleton;
}
SameProcessMessageQueue::Runnable::Runnable()
: mDispatched(false)
{
}
NS_IMPL_ISUPPORTS(SameProcessMessageQueue::Runnable, nsIRunnable)
nsresult
SameProcessMessageQueue::Runnable::Run()
{
if (mDispatched) {
return NS_OK;
}
SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
queue->mQueue.RemoveElement(this);
mDispatched = true;
return HandleMessage();
}

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

@ -0,0 +1,57 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_SameProcessMessageQueue_h
#define mozilla_dom_SameProcessMessageQueue_h
#include "nsIRunnable.h"
#include "nsRefPtr.h"
#include "nsTArray.h"
namespace mozilla {
namespace dom {
class CancelableRunnable;
class SameProcessMessageQueue
{
public:
SameProcessMessageQueue();
virtual ~SameProcessMessageQueue();
class Runnable : public nsIRunnable
{
public:
explicit Runnable();
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
virtual nsresult HandleMessage() = 0;
protected:
virtual ~Runnable() {}
private:
bool mDispatched;
};
void Push(Runnable* aRunnable);
void Flush();
static SameProcessMessageQueue* Get();
private:
friend class CancelableRunnable;
nsTArray<nsRefPtr<Runnable>> mQueue;
static SameProcessMessageQueue* sSingleton;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_SameProcessMessageQueue_h

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

@ -191,6 +191,7 @@ EXPORTS.mozilla.dom += [
'PerformanceResourceTiming.h',
'ProcessGlobal.h',
'ResponsiveImageSelector.h',
'SameProcessMessageQueue.h',
'ScreenOrientation.h',
'ScriptSettings.h',
'ShadowRoot.h',
@ -328,6 +329,7 @@ UNIFIED_SOURCES += [
'PerformanceResourceTiming.cpp',
'ProcessGlobal.cpp',
'ResponsiveImageSelector.cpp',
'SameProcessMessageQueue.cpp',
'ScriptSettings.cpp',
'ShadowRoot.cpp',
'StyleSheetList.cpp',

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

@ -14,6 +14,8 @@
#include "nsIDOMMutationEvent.h"
#include "nsTextFragment.h"
#include "nsServiceManagerUtils.h"
#include "mozilla/dom/AnimationPlayer.h"
#include "mozilla/dom/KeyframeEffect.h"
nsAutoTArray<nsRefPtr<nsDOMMutationObserver>, 4>*
nsDOMMutationObserver::sScheduledMutationObservers = nullptr;
@ -326,12 +328,12 @@ void
nsAnimationReceiver::RecordAnimationMutation(AnimationPlayer* aPlayer,
AnimationMutation aMutationType)
{
Animation* source = aPlayer->GetSource();
if (!source) {
KeyframeEffectReadonly* effect = aPlayer->GetEffect();
if (!effect) {
return;
}
Element* animationTarget = source->GetTarget();
Element* animationTarget = effect->GetTarget();
if (!animationTarget) {
return;
}

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

@ -973,6 +973,8 @@ nsFrameLoader::SwapWithOtherRemoteLoader(nsFrameLoader* aOther,
return rv;
}
mRemoteBrowser->SwapLayerTreeObservers(aOther->mRemoteBrowser);
nsCOMPtr<nsIBrowserDOMWindow> otherBrowserDOMWindow =
aOther->mRemoteBrowser->GetBrowserDOMWindow();
nsCOMPtr<nsIBrowserDOMWindow> browserDOMWindow =

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

@ -35,6 +35,7 @@
#include "mozilla/dom/nsIContentParent.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/dom/ProcessGlobal.h"
#include "mozilla/dom/SameProcessMessageQueue.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/StructuredCloneUtils.h"
#include "mozilla/dom/ipc/BlobChild.h"
@ -1749,7 +1750,6 @@ NS_IMPL_ISUPPORTS(nsScriptCacheCleaner, nsIObserver)
nsFrameMessageManager* nsFrameMessageManager::sChildProcessManager = nullptr;
nsFrameMessageManager* nsFrameMessageManager::sParentProcessManager = nullptr;
nsFrameMessageManager* nsFrameMessageManager::sSameProcessParentManager = nullptr;
nsTArray<nsCOMPtr<nsIRunnable> >* nsFrameMessageManager::sPendingSameProcessAsyncMessages = nullptr;
class nsAsyncMessageToSameProcessChild : public nsSameProcessAsyncMessageBase,
public nsRunnable
@ -1907,7 +1907,7 @@ public:
class nsAsyncMessageToSameProcessParent : public nsSameProcessAsyncMessageBase,
public nsRunnable
public SameProcessMessageQueue::Runnable
{
public:
nsAsyncMessageToSameProcessParent(JSContext* aCx,
@ -1916,25 +1916,15 @@ public:
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal)
: nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal)
, mDelivered(false)
{
}
NS_IMETHOD Run()
virtual nsresult HandleMessage() override
{
if (nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
nsFrameMessageManager::sPendingSameProcessAsyncMessages->RemoveElement(this);
}
if (!mDelivered) {
mDelivered = true;
nsFrameMessageManager* ppm = nsFrameMessageManager::sSameProcessParentManager;
ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm), ppm);
}
nsFrameMessageManager* ppm = nsFrameMessageManager::sSameProcessParentManager;
ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm), ppm);
return NS_OK;
}
private:
bool mDelivered;
};
/**
@ -1960,15 +1950,9 @@ public:
InfallibleTArray<nsString>* aJSONRetVal,
bool aIsSync) override
{
nsTArray<nsCOMPtr<nsIRunnable> > asyncMessages;
if (nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
asyncMessages.SwapElements(*nsFrameMessageManager::sPendingSameProcessAsyncMessages);
uint32_t len = asyncMessages.Length();
for (uint32_t i = 0; i < len; ++i) {
nsCOMPtr<nsIRunnable> async = asyncMessages[i];
async->Run();
}
}
SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
queue->Flush();
if (nsFrameMessageManager::sSameProcessParentManager) {
SameProcessCpowHolder cpows(js::GetRuntime(aCx), aCpows);
nsRefPtr<nsFrameMessageManager> ppm = nsFrameMessageManager::sSameProcessParentManager;
@ -1984,13 +1968,10 @@ public:
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal) override
{
if (!nsFrameMessageManager::sPendingSameProcessAsyncMessages) {
nsFrameMessageManager::sPendingSameProcessAsyncMessages = new nsTArray<nsCOMPtr<nsIRunnable> >;
}
nsCOMPtr<nsIRunnable> ev =
SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
nsRefPtr<nsAsyncMessageToSameProcessParent> ev =
new nsAsyncMessageToSameProcessParent(aCx, aMessage, aData, aCpows, aPrincipal);
nsFrameMessageManager::sPendingSameProcessAsyncMessages->AppendElement(ev);
NS_DispatchToCurrentThread(ev);
queue->Push(ev);
return true;
}

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

@ -27,6 +27,7 @@
#include "mozilla/Attributes.h"
#include "js/RootingAPI.h"
#include "nsTObserverArray.h"
#include "mozilla/dom/SameProcessMessageQueue.h"
#include "mozilla/dom/StructuredCloneUtils.h"
#include "mozilla/jsipc/CpowHolder.h"
@ -203,8 +204,7 @@ private:
}
if (this == sChildProcessManager) {
sChildProcessManager = nullptr;
delete sPendingSameProcessAsyncMessages;
sPendingSameProcessAsyncMessages = nullptr;
delete mozilla::dom::SameProcessMessageQueue::Get();
}
if (this == sSameProcessParentManager) {
sSameProcessParentManager = nullptr;

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

@ -19,6 +19,7 @@
#include "nsIMozBrowserFrame.h"
#include "nsDOMClassInfoID.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/dom/SameProcessMessageQueue.h"
#include "mozilla/dom/StructuredCloneUtils.h"
#include "js/StructuredClone.h"
@ -35,13 +36,9 @@ nsInProcessTabChildGlobal::DoSendBlockingMessage(JSContext* aCx,
InfallibleTArray<nsString>* aJSONRetVal,
bool aIsSync)
{
nsTArray<nsCOMPtr<nsIRunnable> > asyncMessages;
asyncMessages.SwapElements(mASyncMessages);
uint32_t len = asyncMessages.Length();
for (uint32_t i = 0; i < len; ++i) {
nsCOMPtr<nsIRunnable> async = asyncMessages[i];
async->Run();
}
SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
queue->Flush();
if (mChromeMessageManager) {
SameProcessCpowHolder cpows(js::GetRuntime(aCx), aCpows);
nsRefPtr<nsFrameMessageManager> mm = mChromeMessageManager;
@ -52,7 +49,7 @@ nsInProcessTabChildGlobal::DoSendBlockingMessage(JSContext* aCx,
}
class nsAsyncMessageToParent : public nsSameProcessAsyncMessageBase,
public nsRunnable
public SameProcessMessageQueue::Runnable
{
public:
nsAsyncMessageToParent(JSContext* aCx,
@ -62,25 +59,16 @@ public:
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal)
: nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal),
mTabChild(aTabChild), mRun(false)
mTabChild(aTabChild)
{
}
NS_IMETHOD Run()
virtual nsresult HandleMessage() override
{
if (mRun) {
return NS_OK;
}
mRun = true;
mTabChild->mASyncMessages.RemoveElement(this);
ReceiveMessage(mTabChild->mOwner, mTabChild->mChromeMessageManager);
return NS_OK;
}
nsRefPtr<nsInProcessTabChildGlobal> mTabChild;
// True if this runnable has already been called. This can happen if DoSendSyncMessage
// is called while waiting for an asynchronous message send.
bool mRun;
};
bool
@ -90,10 +78,10 @@ nsInProcessTabChildGlobal::DoSendAsyncMessage(JSContext* aCx,
JS::Handle<JSObject *> aCpows,
nsIPrincipal* aPrincipal)
{
nsCOMPtr<nsIRunnable> ev =
SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
nsRefPtr<nsAsyncMessageToParent> ev =
new nsAsyncMessageToParent(aCx, this, aMessage, aData, aCpows, aPrincipal);
mASyncMessages.AppendElement(ev);
NS_DispatchToCurrentThread(ev);
queue->Push(ev);
return true;
}

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

@ -168,7 +168,6 @@ protected:
public:
nsIContent* mOwner;
nsFrameMessageManager* mChromeMessageManager;
nsTArray<nsCOMPtr<nsIRunnable> > mASyncMessages;
};
#endif

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

@ -24,8 +24,10 @@
#include "nsBindingManager.h"
#include "nsGenericHTMLElement.h"
#include "mozilla/Assertions.h"
#include "mozilla/dom/AnimationPlayer.h"
#include "mozilla/dom/HTMLImageElement.h"
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/dom/KeyframeEffect.h"
#include "nsWrapperCacheInlines.h"
#include "nsObjectLoadingContent.h"
#include "nsDOMMutationObserver.h"
@ -216,14 +218,14 @@ nsNodeUtils::ContentRemoved(nsINode* aContainer,
static inline Element*
GetTarget(AnimationPlayer* aPlayer)
{
Animation* source = aPlayer->GetSource();
if (!source) {
KeyframeEffectReadonly* effect = aPlayer->GetEffect();
if (!effect) {
return nullptr;
}
Element* target;
nsCSSPseudoElements::Type pseudoType;
source->GetTarget(target, pseudoType);
effect->GetTarget(target, pseudoType);
// If the animation targets a pseudo-element, we don't dispatch
// notifications for it. (In the future we will have PseudoElement
@ -232,7 +234,7 @@ GetTarget(AnimationPlayer* aPlayer)
return nullptr;
}
return source->GetTarget();
return effect->GetTarget();
}
void

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

@ -545,6 +545,7 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop spec
[test_bug558726.html]
[test_bug559526.html]
[test_bug560780.html]
skip-if = android_version == '18' # Android 4.3 intermittent, Bug 1154497
[test_bug562137.html]
[test_bug562169-1.html]
[test_bug562169-2.html]

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

@ -88,6 +88,10 @@ DOMInterfaces = {
'concrete': False
},
'AnimationEffectReadonly': {
'concrete': False
},
'AnimationTimeline': {
'concrete': False
},

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

@ -977,7 +977,6 @@ nsTextInputListener::UpdateTextInputCommands(const nsAString& commandsToUpdate,
nsTextEditorState::nsTextEditorState(nsITextControlElement* aOwningElement)
: mTextCtrlElement(aOwningElement),
mRestoringSelection(nullptr),
mBoundFrame(nullptr),
mEverInited(false),
mEditorInitialized(false),
@ -1452,6 +1451,12 @@ nsTextEditorState::PrepareEditor(const nsAString *aValue)
return rv;
}
void
nsTextEditorState::FinishedRestoringSelection()
{
mRestoringSelection = nullptr;
}
bool
nsTextEditorState::IsSelectionCached() const
{

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

@ -239,7 +239,7 @@ private:
nsresult InitializeRootNode();
void FinishedRestoringSelection() { mRestoringSelection = nullptr; }
void FinishedRestoringSelection();
mozilla::dom::HTMLInputElement* GetParentNumberControl(nsFrame* aFrame) const;
@ -271,7 +271,7 @@ private:
nsITextControlElement* const mTextCtrlElement;
nsRefPtr<nsTextInputSelectionImpl> mSelCon;
RestoreSelectionState* mRestoringSelection;
nsRefPtr<RestoreSelectionState> mRestoringSelection;
nsCOMPtr<nsIEditor> mEditor;
nsCOMPtr<mozilla::dom::Element> mRootNode;
nsCOMPtr<mozilla::dom::Element> mPlaceholderDiv;

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

@ -483,7 +483,7 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e1
[test_iframe_sandbox_popups.html]
skip-if = buildapp == 'b2g' # b2g(multiple concurrent window.open()s fail on B2G) b2g-debug(multiple concurrent window.open()s fail on B2G) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
[test_iframe_sandbox_popups_inheritance.html]
skip-if = buildapp == 'b2g' || e10s # b2g(multiple concurrent window.open()s fail on B2G) b2g-debug(multiple concurrent window.open()s fail on B2G) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
skip-if = buildapp == 'b2g' || e10s || toolkit == 'android' # b2g(multiple concurrent window.open()s fail on B2G) b2g-debug(multiple concurrent window.open()s fail on B2G) b2g-desktop(Bug 931116, b2g desktop specific, initial triage) android(bug 939642)
[test_iframe_sandbox_redirect.html]
[test_iframe_sandbox_same_origin.html]
[test_iframe_sandbox_workers.html]

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

@ -6591,6 +6591,11 @@ class OpenDatabaseOp final
nsRefPtr<DatabaseOfflineStorage> mOfflineStorage;
// This is only set while a VersionChangeOp is live. It holds a strong
// reference to its OpenDatabaseOp object so this is a weak pointer to avoid
// cycles.
VersionChangeOp* mVersionChangeOp;
public:
OpenDatabaseOp(Factory* aFactory,
already_AddRefed<ContentParent> aContentParent,
@ -6607,7 +6612,9 @@ public:
private:
~OpenDatabaseOp()
{ }
{
MOZ_ASSERT(!mVersionChangeOp);
}
nsresult
LoadDatabaseInformation(mozIStorageConnection* aConnection);
@ -6635,6 +6642,9 @@ private:
void
ConnectionClosedCallback();
virtual void
ActorDestroy(ActorDestroyReason aWhy) override;
virtual nsresult
QuotaManagerOpen() override;
@ -6655,9 +6665,6 @@ private:
virtual void
SendResults() override;
virtual void
ActorDestroy(ActorDestroyReason aWhy) override;
};
class OpenDatabaseOp::VersionChangeOp final
@ -6684,7 +6691,9 @@ private:
}
~VersionChangeOp()
{ }
{
MOZ_ASSERT(!mOpenDatabaseOp);
}
virtual nsresult
DoDatabaseWork(DatabaseConnection* aConnection) override;
@ -7908,7 +7917,7 @@ class DatabaseOfflineStorage final
bool mInvalidatedOnMainThread;
bool mInvalidatedOnOwningThread;
DebugOnly<bool> mRegisteredWithQuotaManager;
bool mRegisteredWithQuotaManager;
public:
DatabaseOfflineStorage(QuotaClient* aQuotaClient,
@ -7964,7 +7973,7 @@ private:
~DatabaseOfflineStorage()
{
MOZ_ASSERT(!mDatabase);
MOZ_ASSERT(!mRegisteredWithQuotaManager);
MOZ_RELEASE_ASSERT(!mRegisteredWithQuotaManager);
}
void
@ -8454,10 +8463,11 @@ DatabaseConnection::FinishWriteTransaction()
{
AssertIsOnConnectionThread();
MOZ_ASSERT(mStorageConnection);
MOZ_ASSERT(mUpdateRefcountFunction);
MOZ_ASSERT(mDEBUGInWriteTransaction);
mUpdateRefcountFunction->Reset();
if (mUpdateRefcountFunction) {
mUpdateRefcountFunction->Reset();
}
#ifdef DEBUG
mDEBUGInWriteTransaction = false;
@ -17095,6 +17105,7 @@ OpenDatabaseOp::OpenDatabaseOp(Factory* aFactory,
: FactoryOp(aFactory, Move(aContentParent), aParams, /* aDeleting */ false)
, mMetadata(new FullDatabaseMetadata(aParams.metadata()))
, mRequestedVersion(aParams.metadata().version())
, mVersionChangeOp(nullptr)
{
auto& optionalContentParentId =
const_cast<OptionalContentId&>(mOptionalContentParentId);
@ -17108,6 +17119,22 @@ OpenDatabaseOp::OpenDatabaseOp(Factory* aFactory,
}
}
void
OpenDatabaseOp::ActorDestroy(ActorDestroyReason aWhy)
{
AssertIsOnOwningThread();
if (mDatabase && aWhy != Deletion) {
mDatabase->Invalidate();
}
if (mVersionChangeOp) {
mVersionChangeOp->NoteActorDestroyed();
}
FactoryOp::ActorDestroy(aWhy);
}
nsresult
OpenDatabaseOp::QuotaManagerOpen()
{
@ -17751,6 +17778,10 @@ OpenDatabaseOp::DispatchToWorkThread()
const nsID& backgroundChildLoggingId =
mVersionChangeTransaction->GetLoggingInfo()->Id();
if (NS_WARN_IF(!mDatabase->RegisterTransaction(mVersionChangeTransaction))) {
return NS_ERROR_OUT_OF_MEMORY;
}
nsRefPtr<VersionChangeOp> versionChangeOp = new VersionChangeOp(this);
uint64_t transactionId =
@ -17761,13 +17792,10 @@ OpenDatabaseOp::DispatchToWorkThread()
/* aIsWriteTransaction */ true,
versionChangeOp);
mVersionChangeTransaction->SetActive(transactionId);
mVersionChangeOp = versionChangeOp;
mVersionChangeTransaction->NoteActiveRequest();
if (NS_WARN_IF(!mDatabase->RegisterTransaction(mVersionChangeTransaction))) {
return NS_ERROR_OUT_OF_MEMORY;
}
mVersionChangeTransaction->SetActive(transactionId);
return NS_OK;
}
@ -17897,18 +17925,6 @@ OpenDatabaseOp::SendResults()
FinishSendResults();
}
void
OpenDatabaseOp::ActorDestroy(ActorDestroyReason aWhy)
{
AssertIsOnBackgroundThread();
NoteActorDestroyed();
if (mDatabase && aWhy != Deletion) {
mDatabase->Invalidate();
}
}
void
OpenDatabaseOp::ConnectionClosedCallback()
{
@ -18222,6 +18238,7 @@ VersionChangeOp::DoDatabaseWork(DatabaseConnection* aConnection)
{
MOZ_ASSERT(aConnection);
aConnection->AssertIsOnConnectionThread();
MOZ_ASSERT(mOpenDatabaseOp);
MOZ_ASSERT(mOpenDatabaseOp->mState == State_DatabaseWorkVersionChange);
if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) ||
@ -18276,6 +18293,7 @@ VersionChangeOp::SendSuccessResult()
AssertIsOnOwningThread();
MOZ_ASSERT(mOpenDatabaseOp);
MOZ_ASSERT(mOpenDatabaseOp->mState == State_DatabaseWorkVersionChange);
MOZ_ASSERT(mOpenDatabaseOp->mVersionChangeOp == this);
nsresult rv = mOpenDatabaseOp->SendUpgradeNeeded();
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -18292,6 +18310,7 @@ VersionChangeOp::SendFailureResult(nsresult aResultCode)
AssertIsOnOwningThread();
MOZ_ASSERT(mOpenDatabaseOp);
MOZ_ASSERT(mOpenDatabaseOp->mState == State_DatabaseWorkVersionChange);
MOZ_ASSERT(mOpenDatabaseOp->mVersionChangeOp == this);
mOpenDatabaseOp->SetFailureCode(aResultCode);
mOpenDatabaseOp->mState = State_SendingResults;
@ -18306,7 +18325,10 @@ OpenDatabaseOp::
VersionChangeOp::Cleanup()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mOpenDatabaseOp);
MOZ_ASSERT(mOpenDatabaseOp->mVersionChangeOp == this);
mOpenDatabaseOp->mVersionChangeOp = nullptr;
mOpenDatabaseOp = nullptr;
#ifdef DEBUG
@ -19343,13 +19365,15 @@ CommitOp::Run()
MOZ_ASSERT(database);
if (DatabaseConnection* connection = database->GetConnection()) {
// May be null if the VersionChangeOp was canceled.
DatabaseConnection::UpdateRefcountFunction* fileRefcountFunction =
connection->GetUpdateRefcountFunction();
MOZ_ASSERT(fileRefcountFunction);
if (NS_SUCCEEDED(mResultCode)) {
mResultCode = fileRefcountFunction->WillCommit();
NS_WARN_IF_FALSE(NS_SUCCEEDED(mResultCode), "WillCommit() failed!");
if (fileRefcountFunction) {
mResultCode = fileRefcountFunction->WillCommit();
NS_WARN_IF_FALSE(NS_SUCCEEDED(mResultCode), "WillCommit() failed!");
}
if (NS_SUCCEEDED(mResultCode)) {
mResultCode = WriteAutoIncrementCounts();
@ -19373,7 +19397,7 @@ CommitOp::Run()
mResultCode = connection->Checkpoint(/* aIdle */ false);
}
if (NS_SUCCEEDED(mResultCode)) {
if (NS_SUCCEEDED(mResultCode) && fileRefcountFunction) {
fileRefcountFunction->DidCommit();
}
}
@ -19382,7 +19406,9 @@ CommitOp::Run()
}
if (NS_FAILED(mResultCode)) {
fileRefcountFunction->DidAbort();
if (fileRefcountFunction) {
fileRefcountFunction->DidAbort();
}
DatabaseConnection::CachedStatement stmt;
if (NS_SUCCEEDED(connection->GetCachedStatement("ROLLBACK", &stmt))) {

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

@ -3,6 +3,14 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var disableWorkerTest =
"This test requires a precise 'executeSoon()' to complete reliably. On a " +
"worker 'executeSoon()' currently uses 'setTimeout()', and that switches " +
"to the timer thread and back before completing. That gives the IndexedDB " +
"transaction thread time to fully complete transactions and to place " +
"'complete' events in the worker thread's queue before the timer event, " +
"causing ordering problems in the spot marked 'Worker Fails Here' below.";
var testGenerator = testSteps();
function testSteps()
@ -41,6 +49,8 @@ function testSteps()
let wasAbleToGrabObjectStoreOutsideOfCallback = false;
let wasAbleToGrabIndexOutsideOfCallback = false;
executeSoon(function() {
// Worker Fails Here! Due to the thread switching of 'executeSoon()' the
// transaction can commit and fire a 'complete' event before we continue.
ok(!requestComplete, "Ordering is correct.");
wasAbleToGrabObjectStoreOutsideOfCallback = !!transaction.objectStore("foo");
wasAbleToGrabIndexOutsideOfCallback =

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

@ -895,7 +895,6 @@ ContentParent::SendAsyncUpdate(nsIWidget* aWidget)
if (!aWidget || aWidget->Destroyed()) {
return;
}
printf_stderr("TabParent::SendAsyncUpdate()\n");
// Fire off an async request to the plugin to paint its window
HWND hwnd = (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW);
NS_ASSERTION(hwnd, "Expected valid hwnd value.");
@ -1881,6 +1880,11 @@ struct DelayedDeleteContentParentTask : public nsRunnable
void
ContentParent::ActorDestroy(ActorDestroyReason why)
{
#ifdef MOZ_CRASHREPORTER
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ChildShutdownState"),
NS_LITERAL_CSTRING("ActorDestroy"));
#endif
if (mForceKillTimer) {
mForceKillTimer->Cancel();
mForceKillTimer = nullptr;
@ -2042,6 +2046,12 @@ ContentParent::NotifyTabDestroying(PBrowserParent* aTab)
StartForceKillTimer();
}
static int32_t
ForceKillTimeout()
{
return Preferences::GetInt("dom.ipc.tabs.shutdownTimeoutSecs", 5);
}
void
ContentParent::StartForceKillTimer()
{
@ -2049,8 +2059,7 @@ ContentParent::StartForceKillTimer()
return;
}
int32_t timeoutSecs =
Preferences::GetInt("dom.ipc.tabs.shutdownTimeoutSecs", 5);
int32_t timeoutSecs = ForceKillTimeout();
if (timeoutSecs > 0) {
mForceKillTimer = do_CreateInstance("@mozilla.org/timer;1");
MOZ_ASSERT(mForceKillTimer);
@ -2882,13 +2891,27 @@ ContentParent::Observe(nsISupports* aSubject,
{
if (mSubprocess && (!strcmp(aTopic, "profile-before-change") ||
!strcmp(aTopic, "xpcom-shutdown"))) {
#ifdef MOZ_CRASHREPORTER
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ChildShutdownState"),
NS_LITERAL_CSTRING("Begin"));
#endif
// Okay to call ShutDownProcess multiple times.
ShutDownProcess(SEND_SHUTDOWN_MESSAGE);
int32_t timeout = ForceKillTimeout();
// Make sure we have a KillHard timer before we start waiting.
MOZ_RELEASE_ASSERT(!timeout || !mIPCOpen || mCalledKillHard || mForceKillTimer);
// Wait for shutdown to complete, so that we receive any shutdown
// data (e.g. telemetry) from the child before we quit.
// This loop terminate prematurely based on mForceKillTimer.
while (mIPCOpen) {
// If we clear the KillHard timer, it should only be because we
// called KillHard. In that case, ActorDestroy should happen
// momentarily.
MOZ_RELEASE_ASSERT(!timeout || mCalledKillHard || mForceKillTimer);
NS_ProcessNextEvent(nullptr, true);
}
NS_ASSERTION(!mSubprocess, "Close should have nulled mSubprocess");
@ -3335,6 +3358,11 @@ ContentParent::ForceKillTimerCallback(nsITimer* aTimer, void* aClosure)
void
ContentParent::KillHard(const char* aReason)
{
#ifdef MOZ_CRASHREPORTER
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ChildShutdownState"),
NS_LITERAL_CSTRING("KillHard"));
#endif
// On Windows, calling KillHard multiple times causes problems - the
// process handle becomes invalid on the first call, causing a second call
// to crash our process - more details in bug 890840.

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

@ -2906,6 +2906,23 @@ TabParent::LayerTreeUpdate(bool aActive)
return true;
}
void
TabParent::SwapLayerTreeObservers(TabParent* aOther)
{
if (IsDestroyed() || aOther->IsDestroyed()) {
return;
}
RenderFrameParent* rfp = GetRenderFrame();
RenderFrameParent* otherRfp = aOther->GetRenderFrame();
if(!rfp || !otherRfp) {
return;
}
CompositorParent::SwapLayerTreeObservers(rfp->GetLayersId(),
otherRfp->GetLayersId());
}
bool
TabParent::RecvRemotePaintIsReady()
{

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

@ -399,6 +399,7 @@ public:
bool RequestNotifyLayerTreeReady();
bool RequestNotifyLayerTreeCleared();
bool LayerTreeUpdate(bool aActive);
void SwapLayerTreeObservers(TabParent* aOther);
virtual bool
RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,

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

@ -101,14 +101,18 @@ ManifestProcessor.prototype = {
// * manifestURL: the URL of the manifest, to resolve URLs.
// * docURL: the URL of the owner doc, for security checks.
process({
jsonText, manifestURL, docURL
jsonText: aJsonText,
manifestURL: aManifestURL,
docURL: aDocURL
}) {
const manifestURL = new URL(aManifestURL);
const docURL = new URL(aDocURL);
const console = new ConsoleAPI({
prefix: 'Web Manifest: '
});
let rawManifest = {};
try {
rawManifest = JSON.parse(jsonText);
rawManifest = JSON.parse(aJsonText);
} catch (e) {}
if (typeof rawManifest !== 'object' || rawManifest === null) {
let msg = 'Manifest needs to be an object.';
@ -124,7 +128,8 @@ ManifestProcessor.prototype = {
short_name: processShortNameMember(rawManifest),
};
processedManifest.scope = processScopeMember(rawManifest, manifestURL,
docURL, processedManifest.start_url);
docURL, new URL(processedManifest.start_url));
return processedManifest;
function processNameMember(aManifest) {
@ -188,8 +193,11 @@ ManifestProcessor.prototype = {
expectedType: 'string',
trim: false
};
const value = extractValue(spec, console);
let scopeURL;
const value = extractValue(spec, console);
if (value === undefined || value === '') {
return undefined;
}
try {
scopeURL = new URL(value, aManifestURL);
} catch (e) {
@ -210,7 +218,7 @@ ManifestProcessor.prototype = {
console.warn(msg);
return undefined;
}
return scopeURL;
return scopeURL.href;
}
function processStartURLMember(aManifest, aManifestURL, aDocURL) {
@ -221,7 +229,7 @@ ManifestProcessor.prototype = {
expectedType: 'string',
trim: false
};
let result = new URL(aDocURL);
let result = new URL(aDocURL).href;
const value = extractValue(spec, console);
if (value === undefined || value === '') {
return result;
@ -237,7 +245,7 @@ ManifestProcessor.prototype = {
let msg = 'start_url must be same origin as document.';
console.warn(msg);
} else {
result = potentialResult;
result = potentialResult.href;
}
return result;
}
@ -248,7 +256,7 @@ this.ManifestProcessor = ManifestProcessor;
function IconsProcessor() {}
// Static getters
Object.defineProperties(IconsProcessor,{
Object.defineProperties(IconsProcessor, {
'onlyDecimals': {
get: function() {
return /^\d+$/;
@ -324,7 +332,7 @@ IconsProcessor.process = function(aManifest, aBaseURL, console) {
let url;
if (value && value.length) {
try {
url = new URL(value, aBaseURL);
url = new URL(value, aBaseURL).href;
} catch (e) {}
}
return url;

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

@ -1,5 +1,4 @@
[DEFAULT]
skip-if = e10s
support-files =
common.js

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

@ -61,7 +61,7 @@ data.jsonText = JSON.stringify(noSrc);
var result = processor.process(data);
ise(result.icons.length, 0, expected);
var expected = `Expect icon's src to be an instance of URL.`;
var expected = `Expect icon's src to be a string.`;
var withSrc = {
icons: [{
src: 'pass'
@ -69,7 +69,7 @@ var withSrc = {
};
data.jsonText = JSON.stringify(withSrc);
var result = processor.process(data);
ise(SpecialPowers.unwrap(result.icons[0].src) instanceof URL, true, expected);
ise(typeof result.icons[0].src, "string", expected);
var expected = `Expect only icons with a src prop to be kept.`;
var withSrc = {

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

@ -20,7 +20,7 @@ invalidJson.forEach((testString) => {
var expected = `Expect to recover from invalid JSON: ${testString}`;
data.jsonText = testString;
var result = processor.process(data);
SimpleTest.ok(result.start_url.href === docURL.href, true, expected);
SimpleTest.ise(result.start_url, docURL.href, expected);
});
var validButUnhelpful = ["1", 1, "", "[{}]", "null"];
@ -28,7 +28,7 @@ validButUnhelpful.forEach((testString) => {
var expected = `Expect to recover from invalid JSON: ${testString}`;
data.jsonText = testString;
var result = processor.process(data);
SimpleTest.ok(result.start_url.href === docURL.href, true, expected);
SimpleTest.ise(result.start_url, docURL.href, expected);
});
</script>
</head>

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

@ -47,8 +47,7 @@ URLs.forEach((url) => {
});
var absURL = new URL(url, manifestURL).toString();
var result = processor.process(data);
console.log(result);
ise(String(result.scope), absURL, expected);
ise(result.scope, absURL, expected);
});
var expected = 'If start URL is not in scope, return undefined.';

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

@ -489,7 +489,7 @@ MediaRawData::MediaRawData()
, mData(nullptr)
, mSize(0)
, mCrypto(mCryptoInternal)
, mBuffer(new LargeDataBuffer(RAW_DATA_DEFAULT_SIZE))
, mBuffer(new MediaLargeByteBuffer(RAW_DATA_DEFAULT_SIZE))
, mPadding(0)
{
}
@ -499,7 +499,7 @@ MediaRawData::MediaRawData(const uint8_t* aData, size_t aSize)
, mData(nullptr)
, mSize(0)
, mCrypto(mCryptoInternal)
, mBuffer(new LargeDataBuffer(RAW_DATA_DEFAULT_SIZE))
, mBuffer(new MediaLargeByteBuffer(RAW_DATA_DEFAULT_SIZE))
, mPadding(0)
{
if (!EnsureCapacity(aSize)) {

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

@ -22,8 +22,8 @@ class Image;
class ImageContainer;
}
class LargeDataBuffer;
class DataBuffer;
class MediaLargeByteBuffer;
class MediaByteBuffer;
// Container that holds media samples.
class MediaData {
@ -369,7 +369,7 @@ private:
explicit MediaRawDataWriter(MediaRawData* aMediaRawData);
bool EnsureSize(size_t aSize);
MediaRawData* mTarget;
nsRefPtr<LargeDataBuffer> mBuffer;
nsRefPtr<MediaLargeByteBuffer> mBuffer;
};
class MediaRawData : public MediaData {
@ -383,7 +383,7 @@ public:
size_t mSize;
const CryptoSample& mCrypto;
nsRefPtr<DataBuffer> mExtraData;
nsRefPtr<MediaByteBuffer> mExtraData;
// Return a deep copy or nullptr if out of memory.
virtual already_AddRefed<MediaRawData> Clone() const;
@ -403,29 +403,29 @@ private:
// read as required by some data decoders.
// Returns false if memory couldn't be allocated.
bool EnsureCapacity(size_t aSize);
nsRefPtr<LargeDataBuffer> mBuffer;
nsRefPtr<MediaLargeByteBuffer> mBuffer;
CryptoSample mCryptoInternal;
uint32_t mPadding;
MediaRawData(const MediaRawData&); // Not implemented
};
// LargeDataBuffer is a ref counted fallible TArray.
// MediaLargeByteBuffer is a ref counted fallible TArray.
// It is designed to share potentially big byte arrays.
class LargeDataBuffer : public FallibleTArray<uint8_t> {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LargeDataBuffer);
LargeDataBuffer() = default;
explicit LargeDataBuffer(size_t aCapacity) : FallibleTArray<uint8_t>(aCapacity) {}
class MediaLargeByteBuffer : public FallibleTArray<uint8_t> {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaLargeByteBuffer);
MediaLargeByteBuffer() = default;
explicit MediaLargeByteBuffer(size_t aCapacity) : FallibleTArray<uint8_t>(aCapacity) {}
private:
~LargeDataBuffer() {}
~MediaLargeByteBuffer() {}
};
// DataBuffer is a ref counted infallible TArray.
class DataBuffer : public nsTArray<uint8_t> {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DataBuffer);
// MediaByteBuffer is a ref counted infallible TArray.
class MediaByteBuffer : public nsTArray<uint8_t> {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaByteBuffer);
private:
~DataBuffer() {}
~MediaByteBuffer() {}
};
} // namespace mozilla

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

@ -112,7 +112,7 @@ public:
, mDisplay(nsIntSize(aWidth, aHeight))
, mStereoMode(StereoMode::MONO)
, mImage(nsIntSize(aWidth, aHeight))
, mExtraData(new DataBuffer)
, mExtraData(new MediaByteBuffer)
{
}
@ -131,7 +131,7 @@ public:
// Size in pixels of decoded video's image.
nsIntSize mImage;
nsRefPtr<DataBuffer> mExtraData;
nsRefPtr<MediaByteBuffer> mExtraData;
};
class AudioInfo : public TrackInfo {
@ -144,8 +144,8 @@ public:
, mBitDepth(0)
, mProfile(0)
, mExtendedProfile(0)
, mCodecSpecificConfig(new DataBuffer)
, mExtraData(new DataBuffer)
, mCodecSpecificConfig(new MediaByteBuffer)
, mExtraData(new MediaByteBuffer)
{
}
@ -164,8 +164,8 @@ public:
// Extended codec profile.
int8_t mExtendedProfile;
nsRefPtr<DataBuffer> mCodecSpecificConfig;
nsRefPtr<DataBuffer> mExtraData;
nsRefPtr<MediaByteBuffer> mCodecSpecificConfig;
nsRefPtr<MediaByteBuffer> mExtraData;
virtual bool IsValid() const override
{

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

@ -46,6 +46,7 @@
#include "MediaTrackConstraints.h"
#include "VideoUtils.h"
#include "Latency.h"
#include "nsProxyRelease.h"
// For PR_snprintf
#include "prprf.h"
@ -332,6 +333,18 @@ public:
mOnFailure.swap(aOnFailure);
}
~DeviceSuccessCallbackRunnable()
{
if (!NS_IsMainThread()) {
// This can happen if the main thread processes the runnable before
// GetUserMediaDevicesTask::Run returns.
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
NS_ProxyRelease(mainThread, mOnSuccess);
NS_ProxyRelease(mainThread, mOnFailure);
}
}
nsresult
AnonymizeId(nsAString& aId, const nsACString& aOriginKey)
{
@ -1498,10 +1511,7 @@ public:
result->AppendElement(source);
}
}
// In the case of failure with this newly allocated runnable, we
// intentionally leak the runnable, because we've pawned mOnSuccess and
// mOnFailure onto it which are main thread objects unsafe to release here.
DeviceSuccessCallbackRunnable* runnable =
nsRefPtr<DeviceSuccessCallbackRunnable> runnable =
new DeviceSuccessCallbackRunnable(mWindowId, mOnSuccess, mOnFailure,
result.forget());
if (mPrivileged) {

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

@ -124,6 +124,7 @@ private:
nsresult
MediaTaskQueue::SyncDispatch(TemporaryRef<nsIRunnable> aRunnable) {
NS_WARNING("MediaTaskQueue::SyncDispatch is dangerous and deprecated. Stop using this!");
RefPtr<MediaTaskQueueSyncRunnable> task(new MediaTaskQueueSyncRunnable(aRunnable));
nsresult rv = Dispatch(task);
NS_ENSURE_SUCCESS(rv, rv);

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

@ -84,6 +84,8 @@ public:
// flushed. Normal operations should use Dispatch.
nsresult ForceDispatch(TemporaryRef<nsIRunnable> aRunnable);
// DEPRECATED! Do not us, if a flush happens at the same time, this function
// can hang and block forever!
nsresult SyncDispatch(TemporaryRef<nsIRunnable> aRunnable);
// Puts the queue in a shutdown state and returns immediately. The queue will

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

@ -440,7 +440,7 @@ CDMProxy::gmp_Shutdown()
// Abort any pending decrypt jobs, to awaken any clients waiting on a job.
for (size_t i = 0; i < mDecryptionJobs.Length(); i++) {
DecryptJob* job = mDecryptionJobs[i];
job->mClient->Decrypted(GMPAbortedErr, nullptr);
job->PostResult(GMPAbortedErr);
}
mDecryptionJobs.Clear();
@ -625,23 +625,22 @@ CDMProxy::Capabilites() {
void
CDMProxy::Decrypt(MediaRawData* aSample,
DecryptionClient* aClient)
DecryptionClient* aClient,
MediaTaskQueue* aTaskQueue)
{
nsAutoPtr<DecryptJob> job(new DecryptJob(aSample, aClient));
nsRefPtr<DecryptJob> job(new DecryptJob(aSample, aClient, aTaskQueue));
nsCOMPtr<nsIRunnable> task(
NS_NewRunnableMethodWithArg<nsAutoPtr<DecryptJob>>(this, &CDMProxy::gmp_Decrypt, job));
NS_NewRunnableMethodWithArg<nsRefPtr<DecryptJob>>(this, &CDMProxy::gmp_Decrypt, job));
mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
}
void
CDMProxy::gmp_Decrypt(nsAutoPtr<DecryptJob> aJob)
CDMProxy::gmp_Decrypt(nsRefPtr<DecryptJob> aJob)
{
MOZ_ASSERT(IsOnGMPThread());
MOZ_ASSERT(aJob->mClient);
MOZ_ASSERT(aJob->mSample);
if (!mCDM) {
aJob->mClient->Decrypted(GMPAbortedErr, nullptr);
aJob->PostResult(GMPAbortedErr);
return;
}
@ -658,34 +657,64 @@ CDMProxy::gmp_Decrypted(uint32_t aId,
const nsTArray<uint8_t>& aDecryptedData)
{
MOZ_ASSERT(IsOnGMPThread());
#ifdef DEBUG
bool jobIdFound = false;
#endif
for (size_t i = 0; i < mDecryptionJobs.Length(); i++) {
DecryptJob* job = mDecryptionJobs[i];
if (job->mId == aId) {
if (aDecryptedData.Length() != job->mSample->mSize) {
NS_WARNING("CDM returned incorrect number of decrypted bytes");
}
if (GMP_SUCCEEDED(aResult)) {
nsAutoPtr<MediaRawDataWriter> writer(job->mSample->CreateWriter());
PodCopy(writer->mData,
aDecryptedData.Elements(),
std::min<size_t>(aDecryptedData.Length(), job->mSample->mSize));
job->mClient->Decrypted(GMPNoErr, job->mSample);
} else if (aResult == GMPNoKeyErr) {
NS_WARNING("CDM returned GMPNoKeyErr");
// We still have the encrypted sample, so we can re-enqueue it to be
// decrypted again once the key is usable again.
job->mClient->Decrypted(GMPNoKeyErr, job->mSample);
} else {
nsAutoCString str("CDM returned decode failure GMPErr=");
str.AppendInt(aResult);
NS_WARNING(str.get());
job->mClient->Decrypted(aResult, nullptr);
}
#ifdef DEBUG
jobIdFound = true;
#endif
job->PostResult(aResult, aDecryptedData);
mDecryptionJobs.RemoveElementAt(i);
return;
}
}
NS_WARNING("GMPDecryptorChild returned incorrect job ID");
#ifdef DEBUG
if (!jobIdFound) {
NS_WARNING("GMPDecryptorChild returned incorrect job ID");
}
#endif
}
void
CDMProxy::DecryptJob::PostResult(GMPErr aResult)
{
nsTArray<uint8_t> empty;
PostResult(aResult, empty);
}
void
CDMProxy::DecryptJob::PostResult(GMPErr aResult, const nsTArray<uint8_t>& aDecryptedData)
{
if (aDecryptedData.Length() != mSample->mSize) {
NS_WARNING("CDM returned incorrect number of decrypted bytes");
}
mResult = aResult;
if (GMP_SUCCEEDED(aResult)) {
nsAutoPtr<MediaRawDataWriter> writer(mSample->CreateWriter());
PodCopy(writer->mData,
aDecryptedData.Elements(),
std::min<size_t>(aDecryptedData.Length(), mSample->mSize));
} else if (aResult == GMPNoKeyErr) {
NS_WARNING("CDM returned GMPNoKeyErr");
// We still have the encrypted sample, so we can re-enqueue it to be
// decrypted again once the key is usable again.
} else {
nsAutoCString str("CDM returned decode failure GMPErr=");
str.AppendInt(aResult);
NS_WARNING(str.get());
mSample = nullptr;
}
mTaskQueue->Dispatch(RefPtr<nsIRunnable>(this).forget());
}
nsresult
CDMProxy::DecryptJob::Run()
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
mClient->Decrypted(mResult, mSample);
return NS_OK;
}
void

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

@ -141,7 +141,9 @@ public:
const nsAString& aMsg);
// Threadsafe.
void Decrypt(MediaRawData* aSample, DecryptionClient* aSink);
void Decrypt(MediaRawData* aSample,
DecryptionClient* aSink,
MediaTaskQueue* aTaskQueue);
// Reject promise with DOMException corresponding to aExceptionCode.
// Can be called from any thread.
@ -234,18 +236,35 @@ private:
// GMP thread only.
void gmp_RemoveSession(nsAutoPtr<SessionOpData> aData);
struct DecryptJob {
DecryptJob(MediaRawData* aSample, DecryptionClient* aClient)
class DecryptJob : public nsRunnable {
public:
explicit DecryptJob(MediaRawData* aSample,
DecryptionClient* aClient,
MediaTaskQueue* aTaskQueue)
: mId(0)
, mSample(aSample)
, mClient(aClient)
{}
, mResult(GMPGenericErr)
, mTaskQueue(aTaskQueue)
{
MOZ_ASSERT(mClient);
MOZ_ASSERT(mSample);
}
NS_METHOD Run() override;
void PostResult(GMPErr aResult, const nsTArray<uint8_t>& aDecryptedData);
void PostResult(GMPErr aResult);
uint32_t mId;
nsRefPtr<MediaRawData> mSample;
private:
~DecryptJob() {}
nsAutoPtr<DecryptionClient> mClient;
GMPErr mResult;
nsRefPtr<MediaTaskQueue> mTaskQueue;
};
// GMP thread only.
void gmp_Decrypt(nsAutoPtr<DecryptJob> aJob);
void gmp_Decrypt(nsRefPtr<DecryptJob> aJob);
class RejectPromiseTask : public nsRunnable {
public:
@ -316,7 +335,7 @@ private:
// Decryption jobs sent to CDM, awaiting result.
// GMP thread only.
nsTArray<nsAutoPtr<DecryptJob>> mDecryptionJobs;
nsTArray<nsRefPtr<DecryptJob>> mDecryptionJobs;
// Number of buffers we've decrypted. Used to uniquely identify
// decryption jobs sent to CDM. Note we can't just use the length of

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

@ -71,7 +71,7 @@ TrackTypeToStr(TrackType aTrack)
#endif
bool
AccumulateSPSTelemetry(const DataBuffer* aExtradata)
AccumulateSPSTelemetry(const MediaByteBuffer* aExtradata)
{
SPSData spsdata;
if (H264::DecodeSPSFromExtraData(aExtradata, spsdata)) {
@ -781,7 +781,7 @@ MP4Reader::Update(TrackType aTrack)
// Collect telemetry from h264 Annex B SPS.
if (!mFoundSPSForTelemetry && sample && AnnexB::HasSPS(sample)) {
nsRefPtr<DataBuffer> extradata = AnnexB::ExtractExtraData(sample);
nsRefPtr<MediaByteBuffer> extradata = AnnexB::ExtractExtraData(sample);
mFoundSPSForTelemetry = AccumulateSPSTelemetry(extradata);
}

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

@ -20,7 +20,7 @@ class TrackInfo;
class AudioInfo;
class VideoInfo;
class MediaRawData;
class DataBuffer;
class MediaByteBuffer;
namespace layers {
class ImageContainer;

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

@ -89,7 +89,7 @@ public:
void ClearReorderedFrames();
CFDictionaryRef CreateOutputConfiguration();
nsRefPtr<DataBuffer> mExtraData;
nsRefPtr<MediaByteBuffer> mExtraData;
nsRefPtr<FlushableMediaTaskQueue> mTaskQueue;
MediaDataDecoderCallback* mCallback;
nsRefPtr<layers::ImageContainer> mImageContainer;

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

@ -22,71 +22,38 @@ public:
EMEDecryptor(MediaDataDecoder* aDecoder,
MediaDataDecoderCallback* aCallback,
CDMProxy* aProxy)
CDMProxy* aProxy,
MediaTaskQueue* aDecodeTaskQueue)
: mDecoder(aDecoder)
, mCallback(aCallback)
, mTaskQueue(CreateFlushableMediaDecodeTaskQueue())
, mTaskQueue(aDecodeTaskQueue)
, mProxy(aProxy)
, mSamplesWaitingForKey(new SamplesWaitingForKey(this, mTaskQueue, mProxy))
#ifdef DEBUG
, mIsShutdown(false)
#endif
{
}
virtual nsresult Init() override {
MOZ_ASSERT(!mIsShutdown);
nsresult rv = mTaskQueue->SyncDispatch(
NS_NewRunnableMethod(mDecoder, &MediaDataDecoder::Init));
unused << NS_WARN_IF(NS_FAILED(rv));
return rv;
return mDecoder->Init();
}
class DeliverDecrypted : public DecryptionClient {
public:
DeliverDecrypted(EMEDecryptor* aDecryptor, FlushableMediaTaskQueue* aTaskQueue)
explicit DeliverDecrypted(EMEDecryptor* aDecryptor)
: mDecryptor(aDecryptor)
, mTaskQueue(aTaskQueue)
{}
virtual void Decrypted(GMPErr aResult,
MediaRawData* aSample) override {
if (aResult == GMPNoKeyErr) {
RefPtr<nsIRunnable> task;
task = NS_NewRunnableMethodWithArg<nsRefPtr<MediaRawData>>(
mDecryptor,
&EMEDecryptor::Input,
nsRefPtr<MediaRawData>(aSample));
mTaskQueue->Dispatch(task.forget());
} else if (GMP_FAILED(aResult)) {
if (mDecryptor->mCallback) {
mDecryptor->mCallback->Error();
}
MOZ_ASSERT(!aSample);
} else {
RefPtr<nsIRunnable> task;
task = NS_NewRunnableMethodWithArg<nsRefPtr<MediaRawData>>(
mDecryptor,
&EMEDecryptor::Decrypted,
nsRefPtr<MediaRawData>(aSample));
mTaskQueue->Dispatch(task.forget());
}
mTaskQueue = nullptr;
{ }
virtual void Decrypted(GMPErr aResult, MediaRawData* aSample) override {
mDecryptor->Decrypted(aResult, aSample);
mDecryptor = nullptr;
}
private:
nsRefPtr<EMEDecryptor> mDecryptor;
nsRefPtr<FlushableMediaTaskQueue> mTaskQueue;
};
virtual nsresult Input(MediaRawData* aSample) override {
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
MOZ_ASSERT(!mIsShutdown);
// We run the PDM on its own task queue. We can't run it on the decode
// task queue, because that calls into Input() in a loop and waits until
// output is delivered. We need to defer some Input() calls while we wait
// for keys to become usable, and once they do we need to dispatch an event
// to run the PDM on the same task queue, but since the decode task queue
// is waiting in MP4Reader::Decode() for output our task would never run.
// So we dispatch tasks to make all calls into the wrapped decoder.
if (mSamplesWaitingForKey->WaitIfKeyNotUsable(aSample)) {
return NS_OK;
}
@ -95,57 +62,59 @@ public:
mProxy->GetSessionIdsForKeyId(aSample->mCrypto.mKeyId,
writer->mCrypto.mSessionIds);
mProxy->Decrypt(aSample, new DeliverDecrypted(this, mTaskQueue));
mProxy->Decrypt(aSample, new DeliverDecrypted(this), mTaskQueue);
return NS_OK;
}
void Decrypted(MediaRawData* aSample) {
MOZ_ASSERT(!mIsShutdown);
nsresult rv = mTaskQueue->Dispatch(
NS_NewRunnableMethodWithArg<nsRefPtr<MediaRawData>>(
mDecoder,
&MediaDataDecoder::Input,
nsRefPtr<MediaRawData>(aSample)));
unused << NS_WARN_IF(NS_FAILED(rv));
void Decrypted(GMPErr aResult, MediaRawData* aSample) {
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
if (mIsShutdown) {
NS_WARNING("EME decrypted sample arrived after shutdown");
return;
}
if (aResult == GMPNoKeyErr) {
// Key became unusable after we sent the sample to CDM to decrypt.
// Call Input() again, so that the sample is enqueued for decryption
// if the key becomes usable again.
Input(aSample);
} else if (GMP_FAILED(aResult)) {
if (mCallback) {
mCallback->Error();
}
MOZ_ASSERT(!aSample);
} else {
MOZ_ASSERT(!mIsShutdown);
nsresult rv = mDecoder->Input(aSample);
unused << NS_WARN_IF(NS_FAILED(rv));
}
}
virtual nsresult Flush() override {
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
MOZ_ASSERT(!mIsShutdown);
nsresult rv = mTaskQueue->SyncDispatch(
NS_NewRunnableMethod(
mDecoder,
&MediaDataDecoder::Flush));
nsresult rv = mDecoder->Flush();
unused << NS_WARN_IF(NS_FAILED(rv));
mSamplesWaitingForKey->Flush();
return rv;
}
virtual nsresult Drain() override {
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
MOZ_ASSERT(!mIsShutdown);
nsresult rv = mTaskQueue->Dispatch(
NS_NewRunnableMethod(
mDecoder,
&MediaDataDecoder::Drain));
nsresult rv = mDecoder->Drain();
unused << NS_WARN_IF(NS_FAILED(rv));
return rv;
}
virtual nsresult Shutdown() override {
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
MOZ_ASSERT(!mIsShutdown);
#ifdef DEBUG
mIsShutdown = true;
#endif
nsresult rv = mTaskQueue->SyncDispatch(
NS_NewRunnableMethod(
mDecoder,
&MediaDataDecoder::Shutdown));
nsresult rv = mDecoder->Shutdown();
unused << NS_WARN_IF(NS_FAILED(rv));
mSamplesWaitingForKey->BreakCycles();
mSamplesWaitingForKey = nullptr;
mDecoder = nullptr;
mTaskQueue->BeginShutdown();
mTaskQueue->AwaitShutdownAndIdle();
mTaskQueue = nullptr;
mProxy = nullptr;
mCallback = nullptr;
return rv;
@ -155,12 +124,10 @@ private:
nsRefPtr<MediaDataDecoder> mDecoder;
MediaDataDecoderCallback* mCallback;
nsRefPtr<FlushableMediaTaskQueue> mTaskQueue;
nsRefPtr<MediaTaskQueue> mTaskQueue;
nsRefPtr<CDMProxy> mProxy;
nsRefPtr<SamplesWaitingForKey> mSamplesWaitingForKey;
#ifdef DEBUG
bool mIsShutdown;
#endif
};
class EMEMediaDataDecoderProxy : public MediaDataDecoderProxy {
@ -273,7 +240,8 @@ EMEDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig,
nsRefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor(decoder,
aCallback,
mProxy));
mProxy,
MediaTaskQueue::GetCurrentQueue()));
return emeDecoder.forget();
}
@ -303,7 +271,8 @@ EMEDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig,
nsRefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor(decoder,
aCallback,
mProxy));
mProxy,
MediaTaskQueue::GetCurrentQueue()));
return emeDecoder.forget();
}

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

@ -21,8 +21,8 @@ FFmpegAudioDecoder<LIBAV_VER>::FFmpegAudioDecoder(
, mCallback(aCallback)
{
MOZ_COUNT_CTOR(FFmpegAudioDecoder);
// Use a new DataBuffer as the object will be modified during initialization.
mExtraData = new DataBuffer;
// Use a new MediaByteBuffer as the object will be modified during initialization.
mExtraData = new MediaByteBuffer;
mExtraData->AppendElements(*aConfig.mCodecSpecificConfig);
}

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

@ -41,7 +41,7 @@ protected:
FlushableMediaTaskQueue* mTaskQueue;
AVCodecContext* mCodecContext;
AVFrame* mFrame;
nsRefPtr<DataBuffer> mExtraData;
nsRefPtr<MediaByteBuffer> mExtraData;
private:
static bool sFFmpegInitDone;

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

@ -32,8 +32,8 @@ FFmpegH264Decoder<LIBAV_VER>::FFmpegH264Decoder(
, mDisplayHeight(aConfig.mDisplay.height)
{
MOZ_COUNT_CTOR(FFmpegH264Decoder);
// Use a new DataBuffer as the object will be modified during initialization.
mExtraData = new DataBuffer;
// Use a new MediaByteBuffer as the object will be modified during initialization.
mExtraData = new MediaByteBuffer;
mExtraData->AppendElements(*aConfig.mExtraData);
}

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

@ -150,7 +150,7 @@ H264Converter::CreateDecoder()
nsresult
H264Converter::CreateDecoderAndInit(MediaRawData* aSample)
{
nsRefPtr<DataBuffer> extra_data =
nsRefPtr<MediaByteBuffer> extra_data =
mp4_demuxer::AnnexB::ExtractExtraData(aSample);
if (!mp4_demuxer::AnnexB::HasSPS(extra_data)) {
return NS_ERROR_NOT_INITIALIZED;
@ -165,7 +165,7 @@ H264Converter::CreateDecoderAndInit(MediaRawData* aSample)
nsresult
H264Converter::CheckForSPSChange(MediaRawData* aSample)
{
nsRefPtr<DataBuffer> extra_data =
nsRefPtr<MediaByteBuffer> extra_data =
mp4_demuxer::AnnexB::ExtractExtraData(aSample);
if (!mp4_demuxer::AnnexB::HasSPS(extra_data) ||
mp4_demuxer::AnnexB::CompareExtraData(extra_data,
@ -185,7 +185,7 @@ H264Converter::CheckForSPSChange(MediaRawData* aSample)
}
void
H264Converter::UpdateConfigFromExtraData(DataBuffer* aExtraData)
H264Converter::UpdateConfigFromExtraData(MediaByteBuffer* aExtraData)
{
mp4_demuxer::SPSData spsdata;
if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtraData, spsdata) &&

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

@ -47,7 +47,7 @@ private:
nsresult CreateDecoder();
nsresult CreateDecoderAndInit(MediaRawData* aSample);
nsresult CheckForSPSChange(MediaRawData* aSample);
void UpdateConfigFromExtraData(DataBuffer* aExtraData);
void UpdateConfigFromExtraData(MediaByteBuffer* aExtraData);
nsRefPtr<PlatformDecoderModule> mPDM;
VideoInfo mCurrentConfig;

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

@ -40,7 +40,7 @@ ContainerParser::ContainerParser(const nsACString& aType)
}
bool
ContainerParser::IsInitSegmentPresent(LargeDataBuffer* aData)
ContainerParser::IsInitSegmentPresent(MediaLargeByteBuffer* aData)
{
MSE_DEBUG(ContainerParser, "aLength=%u [%x%x%x%x]",
aData->Length(),
@ -52,7 +52,7 @@ return false;
}
bool
ContainerParser::IsMediaSegmentPresent(LargeDataBuffer* aData)
ContainerParser::IsMediaSegmentPresent(MediaLargeByteBuffer* aData)
{
MSE_DEBUG(ContainerParser, "aLength=%u [%x%x%x%x]",
aData->Length(),
@ -64,7 +64,7 @@ ContainerParser::IsMediaSegmentPresent(LargeDataBuffer* aData)
}
bool
ContainerParser::ParseStartAndEndTimestamps(LargeDataBuffer* aData,
ContainerParser::ParseStartAndEndTimestamps(MediaLargeByteBuffer* aData,
int64_t& aStart, int64_t& aEnd)
{
return false;
@ -89,7 +89,7 @@ ContainerParser::HasCompleteInitData()
return mHasInitData && !!mInitData->Length();
}
LargeDataBuffer*
MediaLargeByteBuffer*
ContainerParser::InitData()
{
return mInitData;
@ -106,7 +106,7 @@ public:
static const unsigned NS_PER_USEC = 1000;
static const unsigned USEC_PER_SEC = 1000000;
bool IsInitSegmentPresent(LargeDataBuffer* aData)
bool IsInitSegmentPresent(MediaLargeByteBuffer* aData)
{
ContainerParser::IsInitSegmentPresent(aData);
// XXX: This is overly primitive, needs to collect data as it's appended
@ -129,7 +129,7 @@ public:
return false;
}
bool IsMediaSegmentPresent(LargeDataBuffer* aData)
bool IsMediaSegmentPresent(MediaLargeByteBuffer* aData)
{
ContainerParser::IsMediaSegmentPresent(aData);
// XXX: This is overly primitive, needs to collect data as it's appended
@ -150,7 +150,7 @@ public:
return false;
}
bool ParseStartAndEndTimestamps(LargeDataBuffer* aData,
bool ParseStartAndEndTimestamps(MediaLargeByteBuffer* aData,
int64_t& aStart, int64_t& aEnd)
{
bool initSegment = IsInitSegmentPresent(aData);
@ -158,7 +158,7 @@ public:
mOffset = 0;
mParser = WebMBufferedParser(0);
mOverlappedMapping.Clear();
mInitData = new LargeDataBuffer();
mInitData = new MediaLargeByteBuffer();
mResource = new SourceBufferResource(NS_LITERAL_CSTRING("video/webm"));
}
@ -242,7 +242,7 @@ public:
, mMonitor("MP4ContainerParser Index Monitor")
{}
bool IsInitSegmentPresent(LargeDataBuffer* aData)
bool IsInitSegmentPresent(MediaLargeByteBuffer* aData)
{
ContainerParser::IsInitSegmentPresent(aData);
// Each MP4 atom has a chunk size and chunk type. The root chunk in an MP4
@ -262,7 +262,7 @@ public:
(*aData)[7] == 'p';
}
bool IsMediaSegmentPresent(LargeDataBuffer* aData)
bool IsMediaSegmentPresent(MediaLargeByteBuffer* aData)
{
ContainerParser::IsMediaSegmentPresent(aData);
if (aData->Length() < 8) {
@ -280,7 +280,7 @@ public:
(*aData)[7] == 'p');
}
bool ParseStartAndEndTimestamps(LargeDataBuffer* aData,
bool ParseStartAndEndTimestamps(MediaLargeByteBuffer* aData,
int64_t& aStart, int64_t& aEnd)
{
MonitorAutoLock mon(mMonitor); // We're not actually racing against anything,
@ -294,7 +294,7 @@ public:
// manually. This allows the ContainerParser to be shared across different
// timestampOffsets.
mParser = new mp4_demuxer::MoofParser(mStream, 0, /* aIsAudio = */ false, &mMonitor);
mInitData = new LargeDataBuffer();
mInitData = new MediaLargeByteBuffer();
} else if (!mStream || !mParser) {
return false;
}

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

@ -12,7 +12,7 @@
namespace mozilla {
class LargeDataBuffer;
class MediaLargeByteBuffer;
class SourceBufferResource;
class ContainerParser {
@ -23,17 +23,17 @@ public:
// Return true if aData starts with an initialization segment.
// The base implementation exists only for debug logging and is expected
// to be called first from the overriding implementation.
virtual bool IsInitSegmentPresent(LargeDataBuffer* aData);
virtual bool IsInitSegmentPresent(MediaLargeByteBuffer* aData);
// Return true if aData starts with a media segment.
// The base implementation exists only for debug logging and is expected
// to be called first from the overriding implementation.
virtual bool IsMediaSegmentPresent(LargeDataBuffer* aData);
virtual bool IsMediaSegmentPresent(MediaLargeByteBuffer* aData);
// Parse aData to extract the start and end frame times from the media
// segment. aData may not start on a parser sync boundary. Return true
// if aStart and aEnd have been updated.
virtual bool ParseStartAndEndTimestamps(LargeDataBuffer* aData,
virtual bool ParseStartAndEndTimestamps(MediaLargeByteBuffer* aData,
int64_t& aStart, int64_t& aEnd);
// Compare aLhs and rHs, considering any error that may exist in the
@ -43,7 +43,7 @@ public:
virtual int64_t GetRoundingError();
LargeDataBuffer* InitData();
MediaLargeByteBuffer* InitData();
bool HasInitData()
{
@ -55,7 +55,7 @@ public:
static ContainerParser* CreateForMIMEType(const nsACString& aType);
protected:
nsRefPtr<LargeDataBuffer> mInitData;
nsRefPtr<MediaLargeByteBuffer> mInitData;
nsRefPtr<SourceBufferResource> mResource;
bool mHasInitData;
const nsCString mType;

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

@ -41,7 +41,7 @@ namespace mozilla {
// timepoint.
struct ResourceItem {
explicit ResourceItem(LargeDataBuffer* aData)
explicit ResourceItem(MediaLargeByteBuffer* aData)
: mData(aData)
{
}
@ -56,7 +56,7 @@ struct ResourceItem {
return size;
}
nsRefPtr<LargeDataBuffer> mData;
nsRefPtr<MediaLargeByteBuffer> mData;
};
class ResourceQueueDeallocator : public nsDequeFunctor {
@ -103,7 +103,7 @@ public:
}
}
void AppendItem(LargeDataBuffer* aData) {
void AppendItem(MediaLargeByteBuffer* aData) {
mLogicalLength += aData->Length();
Push(new ResourceItem(aData));
}
@ -129,7 +129,7 @@ public:
uint32_t offset = aOffset - mOffset;
mOffset += offset;
evicted += offset;
nsRefPtr<LargeDataBuffer> data = new LargeDataBuffer;
nsRefPtr<MediaLargeByteBuffer> data = new MediaLargeByteBuffer;
data->AppendElements(item->mData->Elements() + offset,
item->mData->Length() - offset);
item->mData = data;

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

@ -46,7 +46,7 @@ namespace dom {
class AppendDataRunnable : public nsRunnable {
public:
AppendDataRunnable(SourceBuffer* aSourceBuffer,
LargeDataBuffer* aData,
MediaLargeByteBuffer* aData,
double aTimestampOffset,
uint32_t aUpdateID)
: mSourceBuffer(aSourceBuffer)
@ -65,7 +65,7 @@ public:
private:
nsRefPtr<SourceBuffer> mSourceBuffer;
nsRefPtr<LargeDataBuffer> mData;
nsRefPtr<MediaLargeByteBuffer> mData;
double mTimestampOffset;
uint32_t mUpdateID;
};
@ -425,7 +425,7 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
{
MSE_DEBUG("AppendData(aLength=%u)", aLength);
nsRefPtr<LargeDataBuffer> data = PrepareAppend(aData, aLength, aRv);
nsRefPtr<MediaLargeByteBuffer> data = PrepareAppend(aData, aLength, aRv);
if (!data) {
return;
}
@ -439,7 +439,7 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
}
void
SourceBuffer::AppendData(LargeDataBuffer* aData, double aTimestampOffset,
SourceBuffer::AppendData(MediaLargeByteBuffer* aData, double aTimestampOffset,
uint32_t aUpdateID)
{
if (!mUpdating || aUpdateID != mUpdateID) {
@ -528,7 +528,7 @@ SourceBuffer::AppendError(bool aDecoderError)
}
}
already_AddRefed<LargeDataBuffer>
already_AddRefed<MediaLargeByteBuffer>
SourceBuffer::PrepareAppend(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv)
{
if (!IsAttached() || mUpdating) {
@ -574,7 +574,7 @@ SourceBuffer::PrepareAppend(const uint8_t* aData, uint32_t aLength, ErrorResult&
return nullptr;
}
nsRefPtr<LargeDataBuffer> data = new LargeDataBuffer();
nsRefPtr<MediaLargeByteBuffer> data = new MediaLargeByteBuffer();
if (!data->AppendElements(aData, aLength)) {
aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
return nullptr;

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

@ -30,7 +30,7 @@ struct JSContext;
namespace mozilla {
class ErrorResult;
class LargeDataBuffer;
class MediaLargeByteBuffer;
class TrackBuffer;
template <typename T> class AsyncEventRunner;
typedef MediaPromise<bool, nsresult, /* IsExclusive = */ true> TrackBufferAppendPromise;
@ -147,7 +147,7 @@ private:
// Shared implementation of AppendBuffer overloads.
void AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv);
void AppendData(LargeDataBuffer* aData, double aTimestampOffset,
void AppendData(MediaLargeByteBuffer* aData, double aTimestampOffset,
uint32_t aAppendID);
// Implement the "Append Error Algorithm".
@ -156,11 +156,11 @@ private:
// http://w3c.github.io/media-source/#sourcebuffer-append-error
void AppendError(bool aDecoderError);
// Implements the "Prepare Append Algorithm". Returns LargeDataBuffer object
// Implements the "Prepare Append Algorithm". Returns MediaLargeByteBuffer object
// on success or nullptr (with aRv set) on error.
already_AddRefed<LargeDataBuffer> PrepareAppend(const uint8_t* aData,
uint32_t aLength,
ErrorResult& aRv);
already_AddRefed<MediaLargeByteBuffer> PrepareAppend(const uint8_t* aData,
uint32_t aLength,
ErrorResult& aRv);
void AppendDataCompletedWithSuccess(bool aValue);
void AppendDataErrored(nsresult aError);

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

@ -216,7 +216,7 @@ SourceBufferResource::EvictAll()
}
void
SourceBufferResource::AppendData(LargeDataBuffer* aData)
SourceBufferResource::AppendData(MediaLargeByteBuffer* aData)
{
SBR_DEBUG("AppendData(aData=%p, aLength=%u)",
aData->Elements(), aData->Length());

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

@ -27,7 +27,7 @@ class nsIStreamListener;
namespace mozilla {
class MediaDecoder;
class LargeDataBuffer;
class MediaLargeByteBuffer;
namespace dom {
@ -103,7 +103,7 @@ public:
}
// Used by SourceBuffer.
void AppendData(LargeDataBuffer* aData);
void AppendData(MediaLargeByteBuffer* aData);
void Ended();
bool IsEnded()
{

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

@ -142,7 +142,7 @@ TrackBuffer::ContinueShutdown()
}
nsRefPtr<TrackBufferAppendPromise>
TrackBuffer::AppendData(LargeDataBuffer* aData, int64_t aTimestampOffset)
TrackBuffer::AppendData(MediaLargeByteBuffer* aData, int64_t aTimestampOffset)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mInitializationPromise.IsEmpty());
@ -151,7 +151,7 @@ TrackBuffer::AppendData(LargeDataBuffer* aData, int64_t aTimestampOffset)
nsRefPtr<TrackBufferAppendPromise> p = mInitializationPromise.Ensure(__func__);
bool hadInitData = mParser->HasInitData();
bool hadCompleteInitData = mParser->HasCompleteInitData();
nsRefPtr<LargeDataBuffer> oldInit = mParser->InitData();
nsRefPtr<MediaLargeByteBuffer> oldInit = mParser->InitData();
bool newInitData = mParser->IsInitSegmentPresent(aData);
// TODO: Run more of the buffer append algorithm asynchronously.
@ -249,7 +249,7 @@ TrackBuffer::AppendData(LargeDataBuffer* aData, int64_t aTimestampOffset)
}
bool
TrackBuffer::AppendDataToCurrentResource(LargeDataBuffer* aData, uint32_t aDuration)
TrackBuffer::AppendDataToCurrentResource(MediaLargeByteBuffer* aData, uint32_t aDuration)
{
MOZ_ASSERT(NS_IsMainThread());
if (!mCurrentDecoder) {
@ -631,7 +631,7 @@ TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder)
}
if (!wasEnded) {
// Adding an empty buffer will reopen the SourceBufferResource
nsRefPtr<LargeDataBuffer> emptyBuffer = new LargeDataBuffer;
nsRefPtr<MediaLargeByteBuffer> emptyBuffer = new MediaLargeByteBuffer;
aDecoder->GetResource()->AppendData(emptyBuffer);
}
// HACK END.

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

@ -22,7 +22,7 @@ namespace mozilla {
class ContainerParser;
class MediaSourceDecoder;
class LargeDataBuffer;
class MediaLargeByteBuffer;
namespace dom {
@ -41,7 +41,7 @@ public:
// Append data to the current decoder. Also responsible for calling
// NotifyDataArrived on the decoder to keep buffered range computation up
// to date. Returns false if the append failed.
nsRefPtr<TrackBufferAppendPromise> AppendData(LargeDataBuffer* aData,
nsRefPtr<TrackBufferAppendPromise> AppendData(MediaLargeByteBuffer* aData,
int64_t aTimestampOffset /* microseconds */);
// Evicts data held in the current decoders SourceBufferResource from the
@ -133,7 +133,7 @@ private:
// Helper for AppendData, ensures NotifyDataArrived is called whenever
// data is appended to the current decoder's SourceBufferResource.
bool AppendDataToCurrentResource(LargeDataBuffer* aData,
bool AppendDataToCurrentResource(MediaLargeByteBuffer* aData,
uint32_t aDuration /* microseconds */);
// Queue execution of InitializeDecoder on mTaskQueue.

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

@ -0,0 +1 @@
Cache-Control: no-store

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

@ -0,0 +1 @@
Cache-Control: no-store

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

@ -0,0 +1 @@
Cache-Control: no-store

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

@ -0,0 +1 @@
Cache-Control: no-store

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

@ -0,0 +1 @@
Cache-Control: no-store

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

@ -0,0 +1 @@
Cache-Control: no-store

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

@ -0,0 +1 @@
Cache-Control: no-store

Двоичные данные
dom/media/test/bipbop-cenc1-audio1.m4s Normal file

Двоичный файл не отображается.

Двоичные данные
dom/media/test/bipbop-cenc1-audio2.m4s Normal file

Двоичный файл не отображается.

Двоичные данные
dom/media/test/bipbop-cenc1-audio3.m4s Normal file

Двоичный файл не отображается.

Двоичные данные
dom/media/test/bipbop-cenc1-audioinit.mp4 Normal file

Двоичный файл не отображается.

Двоичные данные
dom/media/test/bipbop-cenc1-video1.m4s Normal file

Двоичный файл не отображается.

Двоичные данные
dom/media/test/bipbop-cenc1-video2.m4s Normal file

Двоичный файл не отображается.

Двоичные данные
dom/media/test/bipbop-cenc1-videoinit.mp4 Normal file

Двоичный файл не отображается.

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

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
This XML file describes the encryption applied to |bipbop-cenc*|. To
generate the bipbop-cenc1 files, run the following commands:
# Encrypt bipbop-no-edts.mp4 with the keys specified in this file,
# and output to |bipbop-cenc1-{video,audio}.mp4|
MP4Box -crypt bipbop-frag-cenc-video.xml -rem 2 -out bipbop-cenc1-video.mp4 bipbop-no-edts.mp4
MP4Box -crypt bipbop-frag-cenc-audio.xml -rem 1 -out bipbop-cenc1-audio.mp4 bipbop-no-edts.mp4
# Fragment |bipbop-cenc1-*.mp4| into 500ms segments:
MP4Box -dash 500 -rap -segment-name bipbop-cenc1-video -subsegs-per-sidx 5 bipbop-cenc1-video.mp4
MP4Box -dash 500 -rap -segment-name bipbop-cenc1-audio -subsegs-per-sidx 5 bipbop-cenc1-audio.mp4
# The above command will generate a set of fragments in |bipbop-cenc1-{video,audio}*.m4s
# and |bipbop-cenc1-{video,audio}init.mp4| containing just the init segment.
# To cut down the duration, we throw out all but the first 3 audio & 2 video segments:
rm bipbop-cenc1-audio{[^123],[123][^.]}.m4s
rm bipbop-cenc1-video{[^12],[12][^.]}.m4s
# MP4Box will also have generated some *.mpd files we don't need:
rm bipbop-cenc1-*.mpd
# Delete intermediate encrypted files:
rm bipbop-cenc1-{audio,video}.mp4
-->
<GPACDRM type="CENC AES-CTR">
<DRMInfo type="pssh" version="1">
<!--
SystemID specified in
https://dvcs.w3.org/hg/html-media/raw-file/tip/encrypted-media/cenc-format.html
-->
<BS ID128="1077efecc0b24d02ace33c1e52e2fb4b" />
<!-- Number of KeyIDs = 1 -->
<BS bits="32" value="1" />
<!-- KeyID -->
<BS ID128="0x7e571d047e571d047e571d047e571d04" />
</DRMInfo>
<CrypTrack trackID="2" isEncrypted="1" IV_size="16" saiSavedBox="senc"
first_IV="0x00000000000000000000000000000000">
<key KID="0x7e571d047e571d047e571d047e571d04"
value="0x7e5744447e5744447e5744447e574444" />
</CrypTrack>
</GPACDRM>

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

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
This XML file describes the encryption applied to |bipbop-cenc*|. To
generate the bipbop-cenc1 files, run the following commands:
# Encrypt bipbop-no-edts.mp4 with the keys specified in this file,
# and output to |bipbop-cenc1-{video,audio}.mp4|
MP4Box -crypt bipbop-frag-cenc-video.xml -rem 2 -out bipbop-cenc1-video.mp4 bipbop-no-edts.mp4
MP4Box -crypt bipbop-frag-cenc-audio.xml -rem 1 -out bipbop-cenc1-audio.mp4 bipbop-no-edts.mp4
# Fragment |bipbop-cenc1-*.mp4| into 500ms segments:
MP4Box -dash 500 -rap -segment-name bipbop-cenc1-video -subsegs-per-sidx 5 bipbop-cenc1-video.mp4
MP4Box -dash 500 -rap -segment-name bipbop-cenc1-audio -subsegs-per-sidx 5 bipbop-cenc1-audio.mp4
# The above command will generate a set of fragments in |bipbop-cenc1-{video,audio}*.m4s
# and |bipbop-cenc1-{video,audio}init.mp4| containing just the init segment.
# To cut down the duration, we throw out all but the first 3 audio & 2 video segments:
rm bipbop-cenc1-audio{[^123],[123][^.]}.m4s
rm bipbop-cenc1-video{[^12],[12][^.]}.m4s
# MP4Box will also have generated some *.mpd files we don't need:
rm bipbop-cenc1-*.mpd
# Delete intermediate encrypted files:
rm bipbop-cenc1-{audio,video}.mp4
-->
<GPACDRM type="CENC AES-CTR">
<DRMInfo type="pssh" version="1">
<!--
SystemID specified in
https://dvcs.w3.org/hg/html-media/raw-file/tip/encrypted-media/cenc-format.html
-->
<BS ID128="1077efecc0b24d02ace33c1e52e2fb4b" />
<!-- Number of KeyIDs = 1 -->
<BS bits="32" value="1" />
<!-- KeyID -->
<BS ID128="0x7e571d037e571d037e571d037e571d03" />
</DRMInfo>
<CrypTrack trackID="1" isEncrypted="1" IV_size="16" saiSavedBox="senc"
first_IV="0x00000000000000000000000000000000">
<key KID="0x7e571d037e571d037e571d037e571d03"
value="0x7e5733337e5733337e5733337e573333" />
</CrypTrack>
</GPACDRM>

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

@ -34,6 +34,14 @@ function StringToArrayBuffer(str)
return arr;
}
function StringToHex(str){
var res = "";
for (var i = 0; i < str.length; ++i) {
res += ("0" + str.charCodeAt(i).toString(16)).slice(-2);
}
return res;
}
function Base64ToHex(str)
{
var bin = window.atob(str.replace(/-/g, "+").replace(/_/g, "/"));
@ -136,23 +144,28 @@ function MaybeCrossOriginURI(test, uri)
}
}
function AppendTrack(test, ms, track, token)
function AppendTrack(test, ms, track, token, loadParams)
{
return new Promise(function(resolve, reject) {
var sb;
var curFragment = 0;
var resolved = false;
var fragments = track.fragments;
var fragmentFile;
if (loadParams && loadParams.onlyLoadFirstFragments) {
fragments = fragments.slice(0, loadParams.onlyLoadFirstFragments);
}
function addNextFragment() {
if (curFragment >= track.fragments.length) {
if (curFragment >= fragments.length) {
Log(token, track.name + ": end of track");
resolve();
resolved = true;
return;
}
fragmentFile = MaybeCrossOriginURI(test, track.fragments[curFragment++]);
fragmentFile = MaybeCrossOriginURI(test, fragments[curFragment++]);
var req = new XMLHttpRequest();
req.open("GET", fragmentFile);
@ -198,7 +211,7 @@ function AppendTrack(test, ms, track, token)
//Returns a promise that is resolved when the media element is ready to have
//its play() function called; when it's loaded MSE fragments.
function LoadTest(test, elem, token)
function LoadTest(test, elem, token, loadParams)
{
if (!test.tracks) {
ok(false, token + " test does not have a tracks list");
@ -219,16 +232,36 @@ function LoadTest(test, elem, token)
firstOpen = false;
Log(token, "sourceopen");
return Promise.all(test.tracks.map(function(track) {
return AppendTrack(test, ms, track, token);
return AppendTrack(test, ms, track, token, loadParams);
})).then(function(){
Log(token, "end of stream");
ms.endOfStream();
if (loadParams && loadParams.noEndOfStream) {
Log(token, "Tracks loaded");
} else {
Log(token, "Tracks loaded, calling MediaSource.endOfStream()");
ms.endOfStream();
}
resolve();
});
})
});
}
// Same as LoadTest, but manage a token+"_load" start&finished.
// Also finish main token if loading fails.
function LoadTestWithManagedLoadToken(test, elem, manager, token)
{
manager.started(token + "_load");
return LoadTest(test, elem, token)
.catch(function (reason) {
ok(false, TimeStamp(token) + " - Error during load: " + reason);
manager.finished(token + "_load");
manager.finished(token);
})
.then(function () {
manager.finished(token + "_load");
});
}
function SetupEME(test, token, params)
{
var v = document.createElement("video");
@ -251,76 +284,103 @@ function SetupEME(test, token, params)
? params.onSetKeysFail
: bail(token + " Failed to set MediaKeys on <video> element");
var firstEncrypted = true;
// null: No session management in progress, just go ahead and update the session.
// [...]: Session management in progress, add [initDataType, initData] to
// this queue to get it processed when possible.
var initDataQueue = [];
function processInitDataQueue()
{
if (initDataQueue === null) { return; }
if (initDataQueue.length === 0) { initDataQueue = null; return; }
var ev = initDataQueue.shift();
v.addEventListener("encrypted", function(ev) {
if (!firstEncrypted) {
// TODO: Better way to handle 'encrypted'?
// Maybe wait for metadataloaded and all expected 'encrypted's?
Log(token, "got encrypted event again, initDataType=" + ev.initDataType);
return;
}
firstEncrypted = false;
Log(token, "got encrypted event, initDataType=" + ev.initDataType);
var options = [
{
initDataType: ev.initDataType,
videoType: test.type,
audioType: test.type,
}
];
function chain(promise, onReject) {
return promise.then(function(value) {
return Promise.resolve(value);
}).catch(function(reason) {
onReject(reason);
return Promise.reject();
})
var sessionType = (params && params.sessionType) ? params.sessionType : "temporary";
Log(token, "createSession(" + sessionType + ") for (" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ")");
var session = v.mediaKeys.createSession(sessionType);
if (params && params.onsessioncreated) {
params.onsessioncreated(session);
}
var p = navigator.requestMediaKeySystemAccess(KEYSYSTEM_TYPE, options);
var r = bail(token + " Failed to request key system access.");
chain(p, r)
.then(function(keySystemAccess) {
var p = keySystemAccess.createMediaKeys();
var r = bail(token + " Failed to create MediaKeys object");
return chain(p, r);
})
.then(function(mediaKeys) {
Log(token, "created MediaKeys object ok");
mediaKeys.sessions = [];
var p = v.setMediaKeys(mediaKeys);
return chain(p, onSetKeysFail);
})
.then(function() {
Log(token, "set MediaKeys on <video> element ok");
var sessionType = (params && params.sessionType) ? params.sessionType : "temporary";
var session = v.mediaKeys.createSession(sessionType);
if (params && params.onsessioncreated) {
params.onsessioncreated(session);
}
return new Promise(function (resolve, reject) {
session.addEventListener("message", UpdateSessionFunc(test, token, sessionType, resolve, reject));
session.generateRequest(ev.initDataType, ev.initData).catch(function(reason) {
// Reject the promise if generateRequest() failed. Otherwise it will
// be resolve in UpdateSessionFunc().
bail(token + ": session.generateRequest failed")(reason);
reject();
});
return new Promise(function (resolve, reject) {
session.addEventListener("message", UpdateSessionFunc(test, token, sessionType, resolve, reject));
Log(token, "session[" + session.sessionId + "].generateRequest(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ")");
session.generateRequest(ev.initDataType, ev.initData).catch(function(reason) {
// Reject the promise if generateRequest() failed. Otherwise it will
// be resolve in UpdateSessionFunc().
bail(token + ": session[" + session.sessionId + "].generateRequest(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") failed")(reason);
reject();
});
})
.then(function(session) {
Log(token, ": session.generateRequest succeeded");
.then(function(aSession) {
Log(token, "session[" + session.sessionId + "].generateRequest(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") succeeded");
if (params && params.onsessionupdated) {
params.onsessionupdated(session);
params.onsessionupdated(aSession);
}
processInitDataQueue();
});
}
// All 'initDataType's should be the same.
// null indicates no 'encrypted' event received yet.
var initDataType = null;
v.addEventListener("encrypted", function(ev) {
if (initDataType === null) {
Log(token, "got first encrypted(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + "), setup session");
initDataType = ev.initDataType;
initDataQueue.push(ev);
function chain(promise, onReject) {
return promise.then(function(value) {
return Promise.resolve(value);
}).catch(function(reason) {
onReject(reason);
return Promise.reject();
})
}
var options = [
{
initDataType: ev.initDataType,
videoType: test.type,
audioType: test.type,
}
];
var p = navigator.requestMediaKeySystemAccess(KEYSYSTEM_TYPE, options);
var r = bail(token + " Failed to request key system access.");
chain(p, r)
.then(function(keySystemAccess) {
var p = keySystemAccess.createMediaKeys();
var r = bail(token + " Failed to create MediaKeys object");
return chain(p, r);
})
.then(function(mediaKeys) {
Log(token, "created MediaKeys object ok");
mediaKeys.sessions = [];
var p = v.setMediaKeys(mediaKeys);
return chain(p, onSetKeysFail);
})
.then(function() {
Log(token, "set MediaKeys on <video> element ok");
processInitDataQueue();
})
} else {
if (ev.initDataType !== initDataType) {
return bail(token + ": encrypted(" + ev.initDataType + ", " +
StringToHex(ArrayBufferToString(ev.initData)) + ")")
("expected " + initDataType);
}
if (initDataQueue !== null) {
Log(token, "got encrypted(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") event, queue it for later session update");
initDataQueue.push(ev);
} else {
Log(token, "got encrypted(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") event, update session now");
initDataQueue = [ev];
processInitDataQueue();
}
}
});
return v;
}

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

@ -8,9 +8,9 @@
# requests is not interferred with by Necko's cache. See bug 977398
# for details. Necko will fix this in bug 977314.
FILES=(`ls *.ogg *.ogv *.webm *.mp3 *.opus *.mp4 *.wav`)
FILES=(`ls *.ogg *.ogv *.webm *.mp3 *.opus *.mp4 *.m4s *.wav`)
rm *.ogg^headers^ *.ogv^headers^ *.webm^headers^ *.mp3^headers^ *.opus^headers^ *.mp4^headers^ *.wav^headers^
rm -f *.ogg^headers^ *.ogv^headers^ *.webm^headers^ *.mp3^headers^ *.opus^headers^ *.mp4^headers^ *.m4s^headers^ *.wav^headers^
# Restore special headers.
echo "X-Content-Duration: 1.96" > bug500311.ogv^headers^

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

@ -647,7 +647,7 @@ var gMetadataTests = [
// Test files for Encrypted Media Extensions
var gEMETests = [
{
name:"bipbop-cenc-videoinit.mp4",
name:"video-only with 2 keys",
tracks: [
{
name:"video",
@ -668,7 +668,7 @@ var gEMETests = [
duration:1.60,
},
{
name:"bipbop-cenc-videoinit.mp4",
name:"video-only with 2 keys, CORS",
tracks: [
{
name:"video",
@ -690,7 +690,7 @@ var gEMETests = [
duration:1.60,
},
{
name:"bipbop-cenc-videoinit.mp4",
name:"audio&video tracks, both with all keys",
tracks: [
{
name:"audio",
@ -720,7 +720,7 @@ var gEMETests = [
duration:1.60,
},
{
name:"bipbop-cenc-videoinit.mp4",
name:"audio&video tracks, both with all keys, CORS",
tracks: [
{
name:"audio",
@ -750,6 +750,37 @@ var gEMETests = [
crossOrigin:true,
duration:1.60,
},
{
name:"audio&video tracks, each with its key",
type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
tracks: [
{
name:"audio",
type:"audio/mp4; codecs=\"mp4a.40.2\"",
fragments:[ "bipbop-cenc1-audioinit.mp4",
"bipbop-cenc1-audio1.m4s",
"bipbop-cenc1-audio2.m4s",
"bipbop-cenc1-audio3.m4s",
],
},
{
name:"video",
type:"video/mp4; codecs=\"avc1.64000d\"",
fragments:[ "bipbop-cenc1-videoinit.mp4",
"bipbop-cenc1-video1.m4s",
"bipbop-cenc1-video2.m4s",
],
},
],
keys: {
// "keyid" : "key"
"7e571d037e571d037e571d037e571d03" : "7e5733337e5733337e5733337e573333",
"7e571d047e571d047e571d047e571d04" : "7e5744447e5744447e5744447e574444",
},
sessionType:"temporary",
sessionCount:2,
duration:1.60,
},
];
var gEMENonMSEFailTests = [
@ -903,29 +934,36 @@ function MediaTestManager() {
this.tokens = [];
this.isShutdown = false;
this.numTestsRunning = 0;
this.handlers = {};
// Always wait for explicit finish.
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({'set': gTestPrefs}, (function() {
this.nextTest();
}).bind(this));
SimpleTest.registerCleanupFunction(function() {
if (this.tokens.length > 0) {
info("Test timed out. Remaining tests=" + this.tokens);
}
for (var token of this.tokens) {
var handler = this.handlers[token];
if (handler && handler.ontimeout) {
handler.ontimeout();
}
}
}.bind(this));
}
// Registers that the test corresponding to 'token' has been started.
// Don't call more than once per token.
this.started = function(token) {
this.started = function(token, handler) {
this.tokens.push(token);
this.numTestsRunning++;
this.handlers[token] = handler;
is(this.numTestsRunning, this.tokens.length, "[started " + token + "] Length of array should match number of running tests");
}
this.watchdog = null;
this.watchdogFn = function() {
if (this.tokens.length > 0) {
info("Watchdog remaining tests= " + this.tokens);
}
}
// Registers that the test corresponding to 'token' has finished. Call when
// you've finished your test. If all tests are complete this will finish the
// run, otherwise it may start up the next run. It's ok to call multiple times
@ -937,17 +975,11 @@ function MediaTestManager() {
this.tokens.splice(i, 1);
}
if (this.watchdog) {
clearTimeout(this.watchdog);
this.watchdog = null;
}
info("[finished " + token + "] remaining= " + this.tokens);
this.numTestsRunning--;
is(this.numTestsRunning, this.tokens.length, "[finished " + token + "] Length of array should match number of running tests");
if (this.tokens.length < PARALLEL_TESTS) {
this.nextTest();
this.watchdog = setTimeout(this.watchdogFn.bind(this), 10000);
}
}

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