This commit is contained in:
Phil Ringnalda 2015-03-21 12:31:07 -07:00
Родитель 21922001d8 6fc6aa0fbc
Коммит 09f1e96e74
370 изменённых файлов: 7835 добавлений и 4909 удалений

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

@ -13,7 +13,6 @@ DEFFILE = SRCDIR + '/IA2Marshal.def'
OS_LIBS += [
'uuid',
'kernel32',
'rpcns4',
'rpcrt4',
'ole32',
'oleaut32',

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

@ -22,7 +22,6 @@ DEFFILE = SRCDIR + '/AccessibleMarshal.def'
OS_LIBS += [
'kernel32',
'rpcns4',
'rpcrt4',
'oleaut32',
]

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

@ -202,7 +202,7 @@ var Connection = Class({
},
poolFor: function(id) {
for (let pool of this.pools.values()) {
if pool.has(id)
if (pool.has(id))
return pool;
}
},
@ -797,7 +797,7 @@ var Tab = Client.from({
"storageActor": "storage",
"gcliActor": "gcli",
"memoryActor": "memory",
"eventLoopLag": "eventLoopLag"
"eventLoopLag": "eventLoopLag",
"trace": "trace", // missing
}

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

@ -322,7 +322,6 @@ pref("media.fragmented-mp4.gonk.enabled", true);
pref("media.video-queue.default-size", 3);
// optimize images' memory usage
pref("image.downscale-during-decode.enabled", true);
pref("image.mem.decodeondraw", true);
pref("image.mem.allow_locking_in_content_processes", false); /* don't allow image locking */
// Limit the surface cache to 1/8 of main memory or 128MB, whichever is smaller.

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

@ -1,6 +1,7 @@
MOZ_AUTOMATION_L10N_CHECK=0
MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
MOZ_AUTOMATION_UPDATE_PACKAGING=0
MOZ_AUTOMATION_SDK=0
. "$topsrcdir/b2g/config/mozconfigs/common"
. "$topsrcdir/build/unix/mozconfig.linux32"

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

@ -1,6 +1,7 @@
MOZ_AUTOMATION_L10N_CHECK=0
MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
MOZ_AUTOMATION_UPDATE_PACKAGING=0
MOZ_AUTOMATION_SDK=0
. "$topsrcdir/b2g/config/mozconfigs/common"
. "$topsrcdir/build/unix/mozconfig.linux"

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

@ -1,5 +1,6 @@
MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
MOZ_AUTOMATION_UPDATE_PACKAGING=0
MOZ_AUTOMATION_SDK=0
. "$topsrcdir/b2g/config/mozconfigs/common"
# Use sccache

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

@ -1,6 +1,7 @@
MOZ_AUTOMATION_L10N_CHECK=0
MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
MOZ_AUTOMATION_UPDATE_PACKAGING=0
MOZ_AUTOMATION_SDK=0
. "$topsrcdir/b2g/config/mozconfigs/common"
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}

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

@ -1,6 +1,7 @@
MOZ_AUTOMATION_L10N_CHECK=0
MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
MOZ_AUTOMATION_UPDATE_PACKAGING=0
MOZ_AUTOMATION_SDK=0
. "$topsrcdir/browser/config/mozconfigs/linux64/nightly"
ac_add_options --enable-application=b2g/dev

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

@ -2,6 +2,7 @@ MOZ_AUTOMATION_BUILD_SYMBOLS=0
MOZ_AUTOMATION_PACKAGE_TESTS=0
MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
MOZ_AUTOMATION_UPDATE_PACKAGING=0
MOZ_AUTOMATION_SDK=0
. $topsrcdir/build/macosx/mozconfig.common
ac_add_options --enable-application=b2g/dev

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

@ -4,6 +4,7 @@ MOZ_AUTOMATION_PACKAGE_TESTS=0
MOZ_AUTOMATION_INSTALLER=0
MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
MOZ_AUTOMATION_UPDATE_PACKAGING=0
MOZ_AUTOMATION_SDK=0
. "$topsrcdir/browser/config/mozconfigs/win32/nightly"
ac_add_options --enable-application=b2g/dev

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

@ -266,7 +266,7 @@ var gSanitizePromptDialog = {
this.showItemList();
else
this.hideItemList();
}
},
#ifdef CRH_DIALOG_TREE_VIEW
// A duration value; used in the same context as Sanitizer.TIMESPAN_HOUR,

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

@ -83,6 +83,9 @@
<field name="PlacesUtils" readonly="true">
(Components.utils.import("resource://gre/modules/PlacesUtils.jsm", {})).PlacesUtils;
</field>
<field name="AppConstants" readonly="true">
(Components.utils.import("resource://gre/modules/AppConstants.jsm", {})).AppConstants;
</field>
<field name="mTabBox" readonly="true">
document.getAnonymousElementByAttribute(this, "anonid", "tabbox");
</field>
@ -120,11 +123,7 @@
new Map();
</field>
<field name="arrowKeysShouldWrap" readonly="true">
#ifdef XP_MACOSX
true
#else
false
#endif
this.AppConstants.platform == "macosx";
</field>
<field name="_autoScrollPopup">
@ -2722,18 +2721,19 @@
</body>
</method>
#ifdef E10S_TESTING_ONLY
<!-- Opens a given tab to a non-remote window. -->
<method name="openNonRemoteWindow">
<parameter name="aTab"/>
<body>
<![CDATA[
if (!this.AppConstants.E10S_TESTING_ONLY) {
throw "This method is intended only for e10s testing!";
}
let url = aTab.linkedBrowser.currentURI.spec;
return window.openDialog("chrome://browser/content/", "_blank", "chrome,all,dialog=no,non-remote", url);
]]>
</body>
</method>
#endif
<method name="moveTabTo">
<parameter name="aTab"/>
@ -3094,14 +3094,14 @@
}
}
#ifndef XP_MACOSX
if (aEvent.ctrlKey && !aEvent.shiftKey && !aEvent.metaKey &&
aEvent.keyCode == KeyEvent.DOM_VK_F4 &&
!this.mCurrentTab.pinned) {
this.removeCurrentTab({animate: true});
aEvent.preventDefault();
if (this.AppConstants.platform != "macosx") {
if (aEvent.ctrlKey && !aEvent.shiftKey && !aEvent.metaKey &&
aEvent.keyCode == KeyEvent.DOM_VK_F4 &&
!this.mCurrentTab.pinned) {
this.removeCurrentTab({animate: true});
aEvent.preventDefault();
}
}
#endif
]]></body>
</method>
@ -3133,21 +3133,21 @@
}
}
#ifdef XP_MACOSX
if (!aEvent.metaKey)
return;
if (this.AppConstants.platform == "macosx") {
if (!aEvent.metaKey)
return;
var offset = 1;
switch (aEvent.charCode) {
case '}'.charCodeAt(0):
offset = -1;
case '{'.charCodeAt(0):
if (window.getComputedStyle(this, null).direction == "ltr")
offset *= -1;
this.tabContainer.advanceSelectedTab(offset, true);
aEvent.preventDefault();
var offset = 1;
switch (aEvent.charCode) {
case '}'.charCodeAt(0):
offset = -1;
case '{'.charCodeAt(0):
if (window.getComputedStyle(this, null).direction == "ltr")
offset *= -1;
this.tabContainer.advanceSelectedTab(offset, true);
aEvent.preventDefault();
}
}
#endif
]]></body>
</method>
@ -3755,15 +3755,16 @@
</xul:hbox>
<xul:arrowscrollbox anonid="arrowscrollbox" orient="horizontal" flex="1"
style="min-width: 1px;"
#ifndef XP_MACOSX
clicktoscroll="true"
#endif
class="tabbrowser-arrowscrollbox">
# This is a hack to circumvent bug 472020, otherwise the tabs show up on the
# right of the newtab button.
<!--
This is a hack to circumvent bug 472020, otherwise the tabs show up on the
right of the newtab button.
-->
<children includes="tab"/>
# This is to ensure anything extensions put here will go before the newtab
# button, necessary due to the previous hack.
<!--
This is to ensure anything extensions put here will go before the newtab
button, necessary due to the previous hack.
-->
<children/>
<xul:toolbarbutton class="tabs-newtab-button"
anonid="tabs-newtab-button"
@ -4397,11 +4398,8 @@
sourceNode.ownerDocument.defaultView.gMultiProcessBrowser)
return dt.effectAllowed = "none";
#ifdef XP_MACOSX
return dt.effectAllowed = event.altKey ? "copy" : "move";
#else
return dt.effectAllowed = event.ctrlKey ? "copy" : "move";
#endif
let copyModifier = this.AppConstants.platform == "macosx" ? event.altKey : event.ctrlKey;
return dt.effectAllowed = copyModifier ? "copy" : "move";
}
}
@ -4556,13 +4554,13 @@
]]></handler>
<handler event="dblclick"><![CDATA[
#ifndef XP_MACOSX
// When the tabbar has an unified appearance with the titlebar
// and menubar, a double-click in it should have the same behavior
// as double-clicking the titlebar
if (TabsInTitlebar.enabled || this.parentNode._dragBindingAlive)
return;
#endif
if (gBrowser.AppConstants.platform != "macosx") {
// When the tabbar has an unified appearance with the titlebar
// and menubar, a double-click in it should have the same behavior
// as double-clicking the titlebar
if (TabsInTitlebar.enabled || this.parentNode._dragBindingAlive)
return;
}
if (event.button != 0 ||
event.originalTarget.localName != "box")
@ -4646,12 +4644,17 @@
]]></handler>
<handler event="keydown" group="system"><![CDATA[
if (event.altKey || event.shiftKey ||
#ifdef XP_MACOSX
!event.metaKey)
#else
!event.ctrlKey || event.metaKey)
#endif
if (event.altKey || event.shiftKey)
return;
let wrongModifiers;
if (this.tabbrowser.AppConstants.platform == "macosx") {
wrongModifiers = !event.metaKey;
} else {
wrongModifiers = !event.ctrlKey || event.metaKey;
}
if (wrongModifiers)
return;
// Don't check if the event was already consumed because tab navigation
@ -4978,13 +4981,12 @@
window.moveTo(left, top);
window.focus();
} else {
this.tabbrowser.replaceTabWithWindow(draggedTab, { screenX: left,
screenY: top,
#ifndef XP_WIN
outerWidth: winWidth,
outerHeight: winHeight
#endif
});
let props = { screenX: left, screenY: top };
if (this.tabbrowser.AppConstants.platform != "win") {
props.outerWidth = winWidth;
props.outerHeight = winHeight;
}
this.tabbrowser.replaceTabWithWindow(draggedTab, props);
}
event.stopPropagation();
]]></handler>

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

@ -141,7 +141,7 @@ browser.jar:
content/browser/searchSuggestionUI.js (content/searchSuggestionUI.js)
content/browser/searchSuggestionUI.css (content/searchSuggestionUI.css)
content/browser/tabbrowser.css (content/tabbrowser.css)
* content/browser/tabbrowser.xml (content/tabbrowser.xml)
content/browser/tabbrowser.xml (content/tabbrowser.xml)
* content/browser/urlbarBindings.xml (content/urlbarBindings.xml)
* content/browser/utilityOverlay.js (content/utilityOverlay.js)
content/browser/web-panels.js (content/web-panels.js)

0
browser/components/downloads/DownloadsViewUI.jsm Executable file → Normal file
Просмотреть файл

0
browser/components/downloads/content/downloads.js Executable file → Normal file
Просмотреть файл

0
browser/components/loop/content/shared/libs/sdk.js Executable file → Normal file
Просмотреть файл

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

@ -55,6 +55,7 @@ def getUrlProperties(filename):
('completeMarUrl', lambda m: m.endswith('.complete.mar')),
('partialMarUrl', lambda m: m.endswith('.mar') and '.partial.' in m),
('codeCoverageURL', lambda m: m.endswith('code-coverage-gcno.zip')),
('sdkUrl', lambda m: m.endswith(('sdk.tar.bz2', 'sdk.zip'))),
# packageUrl must be last!
('packageUrl', lambda m: True),
]

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

@ -8,6 +8,7 @@ if [ "x$IS_NIGHTLY" = "xyes" ]; then
# Some nightlies (eg: Mulet) don't want these set.
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
fi
. "$topsrcdir/build/mozconfig.common"

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

@ -6,6 +6,7 @@ if [ "x$IS_NIGHTLY" = "xyes" ]; then
# Some nightlies (eg: Mulet) don't want these set.
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
fi
# Some builds (eg: Mulet) don't want the installer, so only set this if it

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

@ -2,6 +2,7 @@ if [ "x$IS_NIGHTLY" = "xyes" ]; then
# Some nightlies (eg: Mulet) don't want these set.
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1}
fi
. "$topsrcdir/build/mozconfig.common"

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

@ -3629,7 +3629,7 @@ MOZ_ARG_WITH_BOOL(system-nss,
_USE_SYSTEM_NSS=1 )
if test -n "$_USE_SYSTEM_NSS"; then
AM_PATH_NSS(3.17.4, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
AM_PATH_NSS(3.18, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
fi
if test -n "$MOZ_NATIVE_NSS"; then

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

@ -859,6 +859,7 @@ nsDocShell::nsDocShell()
, mAllowDNSPrefetch(true)
, mAllowWindowControl(true)
, mAllowContentRetargeting(true)
, mAllowContentRetargetingOnChildren(true)
, mCreatingDocument(false)
, mUseErrorPages(false)
, mObserveErrorPages(true)
@ -2587,10 +2588,25 @@ nsDocShell::GetAllowContentRetargeting(bool* aAllowContentRetargeting)
NS_IMETHODIMP
nsDocShell::SetAllowContentRetargeting(bool aAllowContentRetargeting)
{
mAllowContentRetargetingOnChildren = aAllowContentRetargeting;
mAllowContentRetargeting = aAllowContentRetargeting;
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::GetAllowContentRetargetingOnChildren(bool* aAllowContentRetargetingOnChildren)
{
*aAllowContentRetargetingOnChildren = mAllowContentRetargetingOnChildren;
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::SetAllowContentRetargetingOnChildren(bool aAllowContentRetargetingOnChildren)
{
mAllowContentRetargetingOnChildren = aAllowContentRetargetingOnChildren;
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::GetFullscreenAllowed(bool* aFullscreenAllowed)
{
@ -3461,7 +3477,7 @@ nsDocShell::SetDocLoaderParent(nsDocLoader* aParent)
if (NS_SUCCEEDED(parentAsDocShell->GetAllowWindowControl(&value))) {
SetAllowWindowControl(value);
}
SetAllowContentRetargeting(parentAsDocShell->GetAllowContentRetargeting());
SetAllowContentRetargeting(parentAsDocShell->GetAllowContentRetargetingOnChildren());
if (NS_SUCCEEDED(parentAsDocShell->GetIsActive(&value))) {
SetIsActive(value);
}
@ -8738,6 +8754,7 @@ nsDocShell::RestoreFromHistory()
childShell->GetAllowDNSPrefetch(&allowDNSPrefetch);
bool allowContentRetargeting = childShell->GetAllowContentRetargeting();
bool allowContentRetargetingOnChildren = childShell->GetAllowContentRetargetingOnChildren();
uint32_t defaultLoadFlags;
childShell->GetDefaultLoadFlags(&defaultLoadFlags);
@ -8756,6 +8773,7 @@ nsDocShell::RestoreFromHistory()
childShell->SetAllowMedia(allowMedia);
childShell->SetAllowDNSPrefetch(allowDNSPrefetch);
childShell->SetAllowContentRetargeting(allowContentRetargeting);
childShell->SetAllowContentRetargetingOnChildren(allowContentRetargetingOnChildren);
childShell->SetDefaultLoadFlags(defaultLoadFlags);
rv = childShell->BeginRestore(nullptr, false);

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

@ -883,6 +883,7 @@ protected:
bool mAllowDNSPrefetch;
bool mAllowWindowControl;
bool mAllowContentRetargeting;
bool mAllowContentRetargetingOnChildren;
bool mCreatingDocument; // (should be) debugging only
bool mUseErrorPages;
bool mObserveErrorPages;

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

@ -54,7 +54,7 @@ interface nsITabParent;
typedef unsigned long nsLoadFlags;
[scriptable, builtinclass, uuid(f84b1ae4-2f78-4bad-b36a-6a8516ee6e40)]
[scriptable, builtinclass, uuid(68ba7610-e33d-47ce-8fa2-af07af2422bc)]
interface nsIDocShell : nsIDocShellTreeItem
{
/**
@ -289,6 +289,12 @@ interface nsIDocShell : nsIDocShellTreeItem
*/
[infallible] attribute boolean allowContentRetargeting;
/**
* True if new child docshells should allow content retargeting.
* Setting allowContentRetargeting also overwrites this value.
*/
[infallible] attribute boolean allowContentRetargetingOnChildren;
/**
* Get an enumerator over this docShell and its children.
*

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

@ -252,16 +252,16 @@ Animation::IsInEffect() const
return computedTiming.mTimeFraction != ComputedTiming::kNullTimeFraction;
}
bool
Animation::HasAnimationOfProperty(nsCSSProperty aProperty) const
const AnimationProperty*
Animation::GetAnimationOfProperty(nsCSSProperty aProperty) const
{
for (size_t propIdx = 0, propEnd = mProperties.Length();
propIdx != propEnd; ++propIdx) {
if (aProperty == mProperties[propIdx].mProperty) {
return true;
return &mProperties[propIdx];
}
}
return false;
return nullptr;
}
void
@ -297,6 +297,16 @@ Animation::ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule,
continue;
}
if (!prop.mWinsInCascade) {
// This isn't the winning declaration, so don't add it to style.
// For transitions, this is important, because it's how we
// implement the rule that CSS transitions don't run when a CSS
// animation is running on the same property and element. For
// animations, this is only skipping things that will otherwise be
// overridden.
continue;
}
aSetProperties.AddProperty(prop.mProperty);
MOZ_ASSERT(prop.mSegments.Length() > 0,

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

@ -150,10 +150,25 @@ struct AnimationPropertySegment
struct AnimationProperty
{
nsCSSProperty mProperty;
// Does this property win in the CSS Cascade?
//
// For CSS transitions, this is true as long as a CSS animation on the
// same property and element is not running, in which case we set this
// to false so that the animation (lower in the cascade) can win. We
// then use this to decide whether to apply the style both in the CSS
// cascade and for OMTA.
//
// FIXME (bug 847287): For CSS Animations, which are overridden by
// !important rules in the cascade, we actually determine this from
// the CSS cascade computations, and then use it for OMTA.
bool mWinsInCascade;
InfallibleTArray<AnimationPropertySegment> mSegments;
bool operator==(const AnimationProperty& aOther) const {
return mProperty == aOther.mProperty &&
mWinsInCascade == aOther.mWinsInCascade &&
mSegments == aOther.mSegments;
}
bool operator!=(const AnimationProperty& aOther) const {
@ -290,7 +305,11 @@ public:
bool IsCurrent() const;
bool IsInEffect() const;
bool HasAnimationOfProperty(nsCSSProperty aProperty) const;
const AnimationProperty*
GetAnimationOfProperty(nsCSSProperty aProperty) const;
bool HasAnimationOfProperty(nsCSSProperty aProperty) const {
return GetAnimationOfProperty(aProperty) != nullptr;
}
const InfallibleTArray<AnimationProperty>& Properties() const {
return mProperties;
}

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

@ -54,10 +54,9 @@ AnimationPlayer::SetStartTime(const Nullable<TimeDuration>& aNewStartTime)
Nullable<TimeDuration> previousCurrentTime = GetCurrentTime();
mStartTime = aNewStartTime;
if (!aNewStartTime.IsNull()) {
// Until bug 1127380 (playbackRate) is implemented, the rate is essentially
// one. Once that bug is fixed we should only SetNull() if the rate is not
// zero.
mHoldTime.SetNull();
if (mPlaybackRate != 0.0) {
mHoldTime.SetNull();
}
} else {
mHoldTime = previousCurrentTime;
}
@ -89,7 +88,8 @@ AnimationPlayer::GetCurrentTime() const
if (!mStartTime.IsNull()) {
Nullable<TimeDuration> timelineTime = mTimeline->GetCurrentTime();
if (!timelineTime.IsNull()) {
result.SetValue(timelineTime.Value() - mStartTime.Value());
result.SetValue((timelineTime.Value() - mStartTime.Value())
.MultDouble(mPlaybackRate));
}
}
return result;
@ -101,15 +101,16 @@ AnimationPlayer::SilentlySetCurrentTime(const TimeDuration& aSeekTime)
{
if (!mHoldTime.IsNull() ||
!mTimeline ||
mTimeline->GetCurrentTime().IsNull()
/*or, once supported, playback rate is 0, or have pending pause task*/) {
mTimeline->GetCurrentTime().IsNull() ||
mPlaybackRate == 0.0
/*or, once supported, if we have a pending pause task*/) {
mHoldTime.SetValue(aSeekTime);
if (!mTimeline || mTimeline->GetCurrentTime().IsNull()) {
mStartTime.SetNull();
}
} else {
// once playback rate is supported, need to account for that here
mStartTime.SetValue(mTimeline->GetCurrentTime().Value() - aSeekTime);
mStartTime.SetValue(mTimeline->GetCurrentTime().Value() -
(aSeekTime / mPlaybackRate));
}
// Once AnimationPlayers store a previous current time, set that to
@ -132,6 +133,30 @@ AnimationPlayer::SetCurrentTime(const TimeDuration& aSeekTime)
// http://w3c.github.io/web-animations/#update-a-players-finished-state
}
void
AnimationPlayer::SetPlaybackRate(double aPlaybackRate)
{
Nullable<TimeDuration> previousTime = GetCurrentTime();
mPlaybackRate = aPlaybackRate;
if (!previousTime.IsNull()) {
ErrorResult rv;
SetCurrentTime(previousTime.Value());
MOZ_ASSERT(!rv.Failed(), "Should not assert for non-null time");
}
}
void
AnimationPlayer::SilentlySetPlaybackRate(double aPlaybackRate)
{
Nullable<TimeDuration> previousTime = GetCurrentTime();
mPlaybackRate = aPlaybackRate;
if (!previousTime.IsNull()) {
ErrorResult rv;
SilentlySetCurrentTime(previousTime.Value());
MOZ_ASSERT(!rv.Failed(), "Should not assert for non-null time");
}
}
AnimationPlayState
AnimationPlayer::PlayState() const
{
@ -148,7 +173,8 @@ AnimationPlayer::PlayState() const
return AnimationPlayState::Paused;
}
if (currentTime.Value() >= SourceContentEnd()) {
if ((mPlaybackRate > 0.0 && currentTime.Value() >= SourceContentEnd()) ||
(mPlaybackRate < 0.0 && currentTime.Value().ToMilliseconds() <= 0.0)) {
return AnimationPlayState::Finished;
}
@ -399,10 +425,17 @@ AnimationPlayer::DoPlay()
// animation-play-state we *don't* trigger finishing behavior.
Nullable<TimeDuration> currentTime = GetCurrentTime();
if (currentTime.IsNull()) {
if (mPlaybackRate > 0.0 &&
(currentTime.IsNull())) {
mHoldTime.SetValue(TimeDuration(0));
} else if (mHoldTime.IsNull()) {
// If the hold time is null, we are already playing normally
} else if (mPlaybackRate < 0.0 &&
(currentTime.IsNull())) {
mHoldTime.SetValue(TimeDuration(SourceContentEnd()));
} else if (mPlaybackRate == 0.0 && currentTime.IsNull()) {
mHoldTime.SetValue(TimeDuration(0));
}
if (mHoldTime.IsNull()) {
return;
}
@ -460,8 +493,12 @@ AnimationPlayer::ResumeAt(const TimeDuration& aResumeTime)
MOZ_ASSERT(!mHoldTime.IsNull(),
"A player in the pending state should have a resolved hold time");
mStartTime.SetValue(aResumeTime - mHoldTime.Value());
mHoldTime.SetNull();
if (mPlaybackRate != 0) {
mStartTime.SetValue(aResumeTime - (mHoldTime.Value() / mPlaybackRate));
mHoldTime.SetNull();
} else {
mStartTime.SetValue(aResumeTime);
}
mIsPending = false;
UpdateSourceContent();

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

@ -53,6 +53,7 @@ protected:
public:
explicit AnimationPlayer(AnimationTimeline* aTimeline)
: mTimeline(aTimeline)
, mPlaybackRate(1.0)
, mIsPending(false)
, mIsRunningOnCompositor(false)
, mIsPreviousStateFinished(false)
@ -77,6 +78,9 @@ public:
Nullable<TimeDuration> GetCurrentTime() const;
void SilentlySetCurrentTime(const TimeDuration& aNewCurrentTime);
void SetCurrentTime(const TimeDuration& aNewCurrentTime);
double PlaybackRate() const { return mPlaybackRate; }
void SetPlaybackRate(double aPlaybackRate);
void SilentlySetPlaybackRate(double aPlaybackRate);
AnimationPlayState PlayState() const;
virtual Promise* GetReady(ErrorResult& aRv);
virtual void Play();
@ -241,6 +245,7 @@ protected:
Nullable<TimeDuration> mStartTime; // Timeline timescale
Nullable<TimeDuration> mHoldTime; // Player timescale
Nullable<TimeDuration> mPendingReadyTime; // Timeline timescale
double mPlaybackRate;
// A Promise that is replaced on each call to Play() (and in future Pause())
// and fulfilled when Play() is successfully completed.

0
dom/apps/Webapps.jsm Executable file → Normal file
Просмотреть файл

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

@ -408,28 +408,43 @@ Element::GetBindingURL(nsIDocument *aDocument, css::URLValue **aResult)
JSObject*
Element::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
{
JS::Rooted<JSObject*> obj(aCx, nsINode::WrapObject(aCx, aGivenProto));
JS::Rooted<JSObject*> givenProto(aCx, aGivenProto);
JS::Rooted<JSObject*> customProto(aCx);
if (!givenProto) {
// Custom element prototype swizzling.
CustomElementData* data = GetCustomElementData();
if (data) {
// If this is a registered custom element then fix the prototype.
nsDocument* document = static_cast<nsDocument*>(OwnerDoc());
document->GetCustomPrototype(NodeInfo()->NamespaceID(), data->mType, &customProto);
if (customProto &&
NodePrincipal()->SubsumesConsideringDomain(nsContentUtils::ObjectPrincipal(customProto))) {
// Just go ahead and create with the right proto up front. Set
// customProto to null to flag that we don't need to do any post-facto
// proto fixups here.
givenProto = customProto;
customProto = nullptr;
}
}
}
JS::Rooted<JSObject*> obj(aCx, nsINode::WrapObject(aCx, givenProto));
if (!obj) {
return nullptr;
}
// Custom element prototype swizzling.
CustomElementData* data = GetCustomElementData();
if (obj && data) {
// If this is a registered custom element then fix the prototype.
nsDocument* document = static_cast<nsDocument*>(OwnerDoc());
JS::Rooted<JSObject*> prototype(aCx);
document->GetCustomPrototype(NodeInfo()->NamespaceID(), data->mType, &prototype);
if (prototype) {
// We want to set the custom prototype in the compartment where it was
// registered. In the case that |obj| and |prototype| are in different
// compartments, this will set the prototype on the |obj|'s wrapper and
// thus only visible in the wrapper's compartment.
JSAutoCompartment ac(aCx, prototype);
if (!JS_WrapObject(aCx, &obj) || !JS_SetPrototype(aCx, obj, prototype)) {
dom::Throw(aCx, NS_ERROR_FAILURE);
return nullptr;
}
if (customProto) {
// We want to set the custom prototype in the compartment where it was
// registered. In the case that |obj| and |prototype| are in different
// compartments, this will set the prototype on the |obj|'s wrapper and
// thus only visible in the wrapper's compartment, since we know obj's
// principal does not subsume customProto's in this case.
JSAutoCompartment ac(aCx, customProto);
JS::Rooted<JSObject*> wrappedObj(aCx, obj);
if (!JS_WrapObject(aCx, &wrappedObj) ||
!JS_SetPrototype(aCx, wrappedObj, customProto)) {
return nullptr;
}
}

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

@ -1982,8 +1982,8 @@ Navigator::OnNavigation()
}
#ifdef MOZ_MEDIA_NAVIGATOR
// Inform MediaManager in case there are live streams or pending callbacks.
MediaManager *manager = MediaManager::Get();
// If MediaManager is open let it inform any live streams or pending callbacks
MediaManager *manager = MediaManager::GetIfExists();
if (manager) {
manager->OnNavigation(mWindow->WindowID());
}

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

@ -1557,7 +1557,7 @@ nsMessageManagerScriptExecutor::LoadScriptInternal(const nsAString& aURL,
JSContext* cx = aes.cx();
if (script) {
if (aRunInGlobalScope) {
JS::CloneAndExecuteScript(cx, global, script);
JS::CloneAndExecuteScript(cx, script);
} else {
JS::Rooted<JSObject*> scope(cx);
bool ok = js::ExecuteInGlobalAndReturnScope(cx, global, script, &scope);
@ -1644,8 +1644,9 @@ nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
return;
}
} else {
// We can't clone compile-and-go scripts.
options.setCompileAndGo(false);
// We're going to run these against some non-global scope.
options.setCompileAndGo(false)
.setHasPollutedScope(true);
if (!JS::Compile(cx, options, srcBuf, &script)) {
return;
}

126
dom/cache/CacheStreamControlChild.cpp поставляемый
Просмотреть файл

@ -9,13 +9,22 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/unused.h"
#include "mozilla/dom/cache/ActorUtils.h"
#include "mozilla/dom/cache/PCacheTypes.h"
#include "mozilla/dom/cache/ReadStream.h"
#include "mozilla/ipc/FileDescriptorSetChild.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "mozilla/ipc/PFileDescriptorSetChild.h"
#include "nsISupportsImpl.h"
namespace mozilla {
namespace dom {
namespace cache {
using mozilla::ipc::FileDescriptor;
using mozilla::ipc::FileDescriptorSetChild;
using mozilla::ipc::OptionalFileDescriptorSet;
using mozilla::ipc::PFileDescriptorSetChild;
// declared in ActorUtils.h
PCacheStreamControlChild*
AllocPCacheStreamControlChild()
@ -42,30 +51,6 @@ CacheStreamControlChild::~CacheStreamControlChild()
MOZ_COUNT_DTOR(cache::CacheStreamControlChild);
}
void
CacheStreamControlChild::AddListener(ReadStream* aListener)
{
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
MOZ_ASSERT(aListener);
MOZ_ASSERT(!mListeners.Contains(aListener));
mListeners.AppendElement(aListener);
}
void
CacheStreamControlChild::RemoveListener(ReadStream* aListener)
{
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
MOZ_ASSERT(aListener);
MOZ_ALWAYS_TRUE(mListeners.RemoveElement(aListener));
}
void
CacheStreamControlChild::NoteClosed(const nsID& aId)
{
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
unused << SendNoteClosed(aId);
}
void
CacheStreamControlChild::StartDestroy()
{
@ -83,19 +68,73 @@ CacheStreamControlChild::StartDestroy()
RecvCloseAll();
}
void
CacheStreamControlChild::SerializeControl(PCacheReadStream* aReadStreamOut)
{
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
aReadStreamOut->controlParent() = nullptr;
aReadStreamOut->controlChild() = this;
}
void
CacheStreamControlChild::SerializeFds(PCacheReadStream* aReadStreamOut,
const nsTArray<FileDescriptor>& aFds)
{
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
PFileDescriptorSetChild* fdSet = nullptr;
if (!aFds.IsEmpty()) {
fdSet = Manager()->SendPFileDescriptorSetConstructor(aFds[0]);
for (uint32_t i = 1; i < aFds.Length(); ++i) {
unused << fdSet->SendAddFileDescriptor(aFds[i]);
}
}
if (fdSet) {
aReadStreamOut->fds() = fdSet;
} else {
aReadStreamOut->fds() = void_t();
}
}
void
CacheStreamControlChild::DeserializeFds(const PCacheReadStream& aReadStream,
nsTArray<FileDescriptor>& aFdsOut)
{
if (aReadStream.fds().type() !=
OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
return;
}
auto fdSetActor = static_cast<FileDescriptorSetChild*>(
aReadStream.fds().get_PFileDescriptorSetChild());
MOZ_ASSERT(fdSetActor);
fdSetActor->ForgetFileDescriptors(aFdsOut);
MOZ_ASSERT(!aFdsOut.IsEmpty());
unused << fdSetActor->Send__delete__(fdSetActor);
}
void
CacheStreamControlChild::NoteClosedAfterForget(const nsID& aId)
{
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
unused << SendNoteClosed(aId);
}
#ifdef DEBUG
void
CacheStreamControlChild::AssertOwningThread()
{
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
}
#endif
void
CacheStreamControlChild::ActorDestroy(ActorDestroyReason aReason)
{
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
// Note, we cannot trigger IPC traffic here. So use
// CloseStreamWithoutReporting().
ReadStreamList::ForwardIterator iter(mListeners);
while (iter.HasMore()) {
nsRefPtr<ReadStream> stream = iter.GetNext();
stream->CloseStreamWithoutReporting();
}
mListeners.Clear();
CloseAllReadStreamsWithoutReporting();
RemoveFeature();
}
@ -103,20 +142,7 @@ bool
CacheStreamControlChild::RecvClose(const nsID& aId)
{
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
DebugOnly<uint32_t> closedCount = 0;
ReadStreamList::ForwardIterator iter(mListeners);
while (iter.HasMore()) {
nsRefPtr<ReadStream> stream = iter.GetNext();
// note, multiple streams may exist for same ID
if (stream->MatchId(aId)) {
stream->CloseStream();
closedCount += 1;
}
}
MOZ_ASSERT(closedCount > 0);
CloseReadStreams(aId);
return true;
}
@ -124,11 +150,7 @@ bool
CacheStreamControlChild::RecvCloseAll()
{
NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
ReadStreamList::ForwardIterator iter(mListeners);
while (iter.HasMore()) {
nsRefPtr<ReadStream> stream = iter.GetNext();
stream->CloseStream();
}
CloseAllReadStreams();
return true;
}

30
dom/cache/CacheStreamControlChild.h поставляемый
Просмотреть файл

@ -9,6 +9,7 @@
#include "mozilla/dom/cache/ActorChild.h"
#include "mozilla/dom/cache/PCacheStreamControlChild.h"
#include "mozilla/dom/cache/StreamControl.h"
#include "nsTObserverArray.h"
namespace mozilla {
@ -18,29 +19,42 @@ namespace cache {
class ReadStream;
class CacheStreamControlChild MOZ_FINAL : public PCacheStreamControlChild
, public StreamControl
, public ActorChild
{
public:
CacheStreamControlChild();
~CacheStreamControlChild();
void AddListener(ReadStream* aListener);
void RemoveListener(ReadStream* aListener);
void NoteClosed(const nsID& aId);
// ActorChild methods
virtual void StartDestroy() MOZ_OVERRIDE;
// StreamControl methods
virtual void
SerializeControl(PCacheReadStream* aReadStreamOut) MOZ_OVERRIDE;
virtual void
SerializeFds(PCacheReadStream* aReadStreamOut,
const nsTArray<mozilla::ipc::FileDescriptor>& aFds) MOZ_OVERRIDE;
virtual void
DeserializeFds(const PCacheReadStream& aReadStream,
nsTArray<mozilla::ipc::FileDescriptor>& aFdsOut) MOZ_OVERRIDE;
private:
virtual void
NoteClosedAfterForget(const nsID& aId) MOZ_OVERRIDE;
#ifdef DEBUG
virtual void
AssertOwningThread() MOZ_OVERRIDE;
#endif
// PCacheStreamControlChild methods
virtual void ActorDestroy(ActorDestroyReason aReason) MOZ_OVERRIDE;
virtual bool RecvClose(const nsID& aId) MOZ_OVERRIDE;
virtual bool RecvCloseAll() MOZ_OVERRIDE;
typedef nsTObserverArray<ReadStream*> ReadStreamList;
ReadStreamList mListeners;
bool mDestroyStarted;
NS_DECL_OWNINGTHREAD

99
dom/cache/CacheStreamControlParent.cpp поставляемый
Просмотреть файл

@ -8,14 +8,23 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/unused.h"
#include "mozilla/dom/cache/PCacheTypes.h"
#include "mozilla/dom/cache/ReadStream.h"
#include "mozilla/dom/cache/StreamList.h"
#include "mozilla/ipc/FileDescriptorSetParent.h"
#include "mozilla/ipc/PBackgroundParent.h"
#include "mozilla/ipc/PFileDescriptorSetParent.h"
#include "nsISupportsImpl.h"
namespace mozilla {
namespace dom {
namespace cache {
using mozilla::ipc::FileDescriptor;
using mozilla::ipc::FileDescriptorSetParent;
using mozilla::ipc::OptionalFileDescriptorSet;
using mozilla::ipc::PFileDescriptorSetParent;
// declared in ActorUtils.h
void
DeallocPCacheStreamControlParent(PCacheStreamControlParent* aActor)
@ -36,33 +45,75 @@ CacheStreamControlParent::~CacheStreamControlParent()
}
void
CacheStreamControlParent::AddListener(ReadStream* aListener)
CacheStreamControlParent::SerializeControl(PCacheReadStream* aReadStreamOut)
{
NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
MOZ_ASSERT(aListener);
MOZ_ASSERT(!mListeners.Contains(aListener));
mListeners.AppendElement(aListener);
aReadStreamOut->controlChild() = nullptr;
aReadStreamOut->controlParent() = this;
}
void
CacheStreamControlParent::RemoveListener(ReadStream* aListener)
CacheStreamControlParent::SerializeFds(PCacheReadStream* aReadStreamOut,
const nsTArray<FileDescriptor>& aFds)
{
NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
MOZ_ASSERT(aListener);
DebugOnly<bool> removed = mListeners.RemoveElement(aListener);
MOZ_ASSERT(removed);
PFileDescriptorSetParent* fdSet = nullptr;
if (!aFds.IsEmpty()) {
fdSet = Manager()->SendPFileDescriptorSetConstructor(aFds[0]);
for (uint32_t i = 1; i < aFds.Length(); ++i) {
unused << fdSet->SendAddFileDescriptor(aFds[i]);
}
}
if (fdSet) {
aReadStreamOut->fds() = fdSet;
} else {
aReadStreamOut->fds() = void_t();
}
}
void
CacheStreamControlParent::DeserializeFds(const PCacheReadStream& aReadStream,
nsTArray<FileDescriptor>& aFdsOut)
{
if (aReadStream.fds().type() !=
OptionalFileDescriptorSet::TPFileDescriptorSetParent) {
return;
}
FileDescriptorSetParent* fdSetActor =
static_cast<FileDescriptorSetParent*>(aReadStream.fds().get_PFileDescriptorSetParent());
MOZ_ASSERT(fdSetActor);
fdSetActor->ForgetFileDescriptors(aFdsOut);
MOZ_ASSERT(!aFdsOut.IsEmpty());
if (!fdSetActor->Send__delete__(fdSetActor)) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("Cache failed to delete fd set actor.");
}
}
void
CacheStreamControlParent::NoteClosedAfterForget(const nsID& aId)
{
NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
RecvNoteClosed(aId);
}
#ifdef DEBUG
void
CacheStreamControlParent::AssertOwningThread()
{
NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
}
#endif
void
CacheStreamControlParent::ActorDestroy(ActorDestroyReason aReason)
{
NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
MOZ_ASSERT(mStreamList);
ReadStreamList::ForwardIterator iter(mListeners);
while (iter.HasMore()) {
nsRefPtr<ReadStream> stream = iter.GetNext();
stream->CloseStreamWithoutReporting();
}
CloseAllReadStreamsWithoutReporting();
mStreamList->RemoveStreamControl(this);
mStreamList->NoteClosedAll();
mStreamList = nullptr;
@ -116,30 +167,14 @@ void
CacheStreamControlParent::NotifyClose(const nsID& aId)
{
NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
DebugOnly<uint32_t> closedCount = 0;
ReadStreamList::ForwardIterator iter(mListeners);
while (iter.HasMore()) {
nsRefPtr<ReadStream> stream = iter.GetNext();
// note, multiple streams may exist for same ID
if (stream->MatchId(aId)) {
stream->CloseStream();
closedCount += 1;
}
}
MOZ_ASSERT(closedCount > 0);
CloseReadStreams(aId);
}
void
CacheStreamControlParent::NotifyCloseAll()
{
NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
ReadStreamList::ForwardIterator iter(mListeners);
while (iter.HasMore()) {
nsRefPtr<ReadStream> stream = iter.GetNext();
stream->CloseStream();
}
CloseAllReadStreams();
}
} // namespace cache

30
dom/cache/CacheStreamControlParent.h поставляемый
Просмотреть файл

@ -8,6 +8,7 @@
#define mozilla_dom_cache_CacheStreamControlParent_h
#include "mozilla/dom/cache/PCacheStreamControlParent.h"
#include "mozilla/dom/cache/StreamControl.h"
#include "nsTObserverArray.h"
namespace mozilla {
@ -18,24 +19,42 @@ class ReadStream;
class StreamList;
class CacheStreamControlParent : public PCacheStreamControlParent
, public StreamControl
{
public:
CacheStreamControlParent();
~CacheStreamControlParent();
void AddListener(ReadStream* aListener);
void RemoveListener(ReadStream* aListener);
void SetStreamList(StreamList* aStreamList);
void Close(const nsID& aId);
void CloseAll();
void Shutdown();
// StreamControl methods
virtual void
SerializeControl(PCacheReadStream* aReadStreamOut) MOZ_OVERRIDE;
virtual void
SerializeFds(PCacheReadStream* aReadStreamOut,
const nsTArray<mozilla::ipc::FileDescriptor>& aFds) MOZ_OVERRIDE;
virtual void
DeserializeFds(const PCacheReadStream& aReadStream,
nsTArray<mozilla::ipc::FileDescriptor>& aFdsOut) MOZ_OVERRIDE;
private:
virtual void
NoteClosedAfterForget(const nsID& aId) MOZ_OVERRIDE;
#ifdef DEBUG
virtual void
AssertOwningThread() MOZ_OVERRIDE;
#endif
// PCacheStreamControlParent methods
virtual void ActorDestroy(ActorDestroyReason aReason) MOZ_OVERRIDE;
virtual bool RecvNoteClosed(const nsID& aId) MOZ_OVERRIDE;
private:
void NotifyClose(const nsID& aId);
void NotifyCloseAll();
@ -44,9 +63,6 @@ private:
// StreamList::RemoveStreamControl() to clear the weak ref.
nsRefPtr<StreamList> mStreamList;
typedef nsTObserverArray<ReadStream*> ReadStreamList;
ReadStreamList mListeners;
NS_DECL_OWNINGTHREAD
};

699
dom/cache/ReadStream.cpp поставляемый
Просмотреть файл

@ -9,234 +9,121 @@
#include "mozilla/unused.h"
#include "mozilla/dom/cache/CacheStreamControlChild.h"
#include "mozilla/dom/cache/CacheStreamControlParent.h"
#include "mozilla/dom/cache/PCacheStreamControlChild.h"
#include "mozilla/dom/cache/PCacheStreamControlParent.h"
#include "mozilla/dom/cache/PCacheTypes.h"
#include "mozilla/ipc/FileDescriptor.h"
#include "mozilla/ipc/FileDescriptorSetChild.h"
#include "mozilla/ipc/FileDescriptorSetParent.h"
#include "mozilla/ipc/InputStreamParams.h"
#include "mozilla/ipc/InputStreamUtils.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "mozilla/ipc/PBackgroundParent.h"
#include "mozilla/ipc/PFileDescriptorSetChild.h"
#include "mozilla/ipc/PFileDescriptorSetParent.h"
#include "mozilla/SnappyUncompressInputStream.h"
#include "nsIAsyncInputStream.h"
#include "nsTArray.h"
namespace {
using mozilla::unused;
using mozilla::void_t;
using mozilla::dom::cache::CacheStreamControlChild;
using mozilla::dom::cache::CacheStreamControlParent;
using mozilla::dom::cache::PCacheReadStream;
using mozilla::dom::cache::PCacheStreamControlChild;
using mozilla::dom::cache::PCacheStreamControlParent;
using mozilla::dom::cache::ReadStream;
using mozilla::ipc::FileDescriptor;
using mozilla::ipc::PFileDescriptorSetChild;
using mozilla::ipc::PFileDescriptorSetParent;
// There are separate concrete implementations of ReadStream for the child
// and parent processes. This is unfortunately necessary because the
// actor types are distinct for these two cases. Also, the interface for
// reporting the close event differs slightly for the child and parent
// StreamControl actors.
// ----------------------------------------------------------------------------
class ReadStreamChild MOZ_FINAL : public ReadStream
{
public:
ReadStreamChild(PCacheStreamControlChild* aControl, const nsID& aId,
nsIInputStream* aStream)
: ReadStream(aId, aStream)
, mControl(static_cast<CacheStreamControlChild*>(aControl))
{
MOZ_ASSERT(mControl);
mControl->AddListener(this);
}
virtual ~ReadStreamChild()
{
NS_ASSERT_OWNINGTHREAD(ReadStream);
NoteClosed();
}
virtual void NoteClosedOnOwningThread() MOZ_OVERRIDE
{
NS_ASSERT_OWNINGTHREAD(ReadStream);
if (mClosed) {
return;
}
mClosed = true;
mControl->RemoveListener(this);
mControl->NoteClosed(mId);
}
virtual void ForgetOnOwningThread() MOZ_OVERRIDE
{
NS_ASSERT_OWNINGTHREAD(ReadStream);
if (mClosed) {
return;
}
mClosed = true;
mControl->RemoveListener(this);
}
virtual void SerializeControl(PCacheReadStream* aReadStreamOut) MOZ_OVERRIDE
{
MOZ_ASSERT(aReadStreamOut);
MOZ_ASSERT(!mClosed);
aReadStreamOut->controlParent() = nullptr;
aReadStreamOut->controlChild() = mControl;
}
virtual void
SerializeFds(PCacheReadStream* aReadStreamOut,
const nsTArray<FileDescriptor>& fds) MOZ_OVERRIDE
{
MOZ_ASSERT(!mClosed);
PFileDescriptorSetChild* fdSet = nullptr;
if (!fds.IsEmpty()) {
fdSet = mControl->Manager()->SendPFileDescriptorSetConstructor(fds[0]);
for (uint32_t i = 1; i < fds.Length(); ++i) {
unused << fdSet->SendAddFileDescriptor(fds[i]);
}
}
if (fdSet) {
aReadStreamOut->fds() = fdSet;
} else {
aReadStreamOut->fds() = void_t();
}
}
private:
CacheStreamControlChild* mControl;
};
// ----------------------------------------------------------------------------
class ReadStreamParent MOZ_FINAL : public ReadStream
{
public:
ReadStreamParent(PCacheStreamControlParent* aControl, const nsID& aId,
nsIInputStream* aStream)
: ReadStream(aId, aStream)
, mControl(static_cast<CacheStreamControlParent*>(aControl))
{
MOZ_ASSERT(mControl);
mControl->AddListener(this);
}
virtual ~ReadStreamParent()
{
NS_ASSERT_OWNINGTHREAD(ReadStream);
NoteClosed();
}
virtual void NoteClosedOnOwningThread() MOZ_OVERRIDE
{
NS_ASSERT_OWNINGTHREAD(ReadStream);
if (mClosed) {
return;
}
mClosed = true;
mControl->RemoveListener(this);
// This can cause mControl to be destructed
mControl->RecvNoteClosed(mId);
mControl = nullptr;
}
virtual void ForgetOnOwningThread() MOZ_OVERRIDE
{
NS_ASSERT_OWNINGTHREAD(ReadStream);
if (mClosed) {
return;
}
mClosed = true;
// This can cause mControl to be destroyed
mControl->RemoveListener(this);
mControl = nullptr;
}
virtual void SerializeControl(PCacheReadStream* aReadStreamOut) MOZ_OVERRIDE
{
MOZ_ASSERT(aReadStreamOut);
MOZ_ASSERT(!mClosed);
MOZ_ASSERT(mControl);
aReadStreamOut->controlChild() = nullptr;
aReadStreamOut->controlParent() = mControl;
}
virtual void
SerializeFds(PCacheReadStream* aReadStreamOut,
const nsTArray<FileDescriptor>& fds) MOZ_OVERRIDE
{
MOZ_ASSERT(!mClosed);
MOZ_ASSERT(mControl);
PFileDescriptorSetParent* fdSet = nullptr;
if (!fds.IsEmpty()) {
fdSet = mControl->Manager()->SendPFileDescriptorSetConstructor(fds[0]);
for (uint32_t i = 1; i < fds.Length(); ++i) {
unused << fdSet->SendAddFileDescriptor(fds[i]);
}
}
if (fdSet) {
aReadStreamOut->fds() = fdSet;
} else {
aReadStreamOut->fds() = void_t();
}
}
private:
CacheStreamControlParent* mControl;
};
// ----------------------------------------------------------------------------
} // anonymous namespace
namespace mozilla {
namespace dom {
namespace cache {
using mozilla::unused;
using mozilla::ipc::FileDescriptor;
using mozilla::ipc::FileDescriptorSetChild;
using mozilla::ipc::FileDescriptorSetParent;
using mozilla::ipc::InputStreamParams;
using mozilla::ipc::OptionalFileDescriptorSet;
using mozilla::ipc::PFileDescriptorSetChild;
// ----------------------------------------------------------------------------
// The inner stream class. This is where all of the real work is done. As
// an invariant Inner::Close() must be called before ~Inner(). This is
// guaranteed by our outer ReadStream class.
class ReadStream::Inner MOZ_FINAL : public ReadStream::Controllable
{
public:
Inner(StreamControl* aControl, const nsID& aId,
nsIInputStream* aStream);
void
Serialize(PCacheReadStreamOrVoid* aReadStreamOut);
void
Serialize(PCacheReadStream* aReadStreamOut);
// ReadStream::Controllable methods
virtual void
CloseStream() MOZ_OVERRIDE;
virtual void
CloseStreamWithoutReporting() MOZ_OVERRIDE;
virtual bool
MatchId(const nsID& aId) const MOZ_OVERRIDE;
// Simulate nsIInputStream methods, but we don't actually inherit from it
NS_METHOD
Close();
NS_METHOD
Available(uint64_t *aNumAvailableOut);
NS_METHOD
Read(char *aBuf, uint32_t aCount, uint32_t *aNumReadOut);
NS_METHOD
ReadSegments(nsWriteSegmentFun aWriter, void *aClosure, uint32_t aCount,
uint32_t *aNumReadOut);
NS_METHOD
IsNonBlocking(bool *aNonBlockingOut);
private:
class NoteClosedRunnable;
class ForgetRunnable;
~Inner();
void
NoteClosed();
void
Forget();
void
NoteClosedOnOwningThread();
void
ForgetOnOwningThread();
// Weak ref to the stream control actor. The actor will always call either
// CloseStream() or CloseStreamWithoutReporting() before it's destroyed. The
// weak ref is cleared in the resulting NoteClosedOnOwningThread() or
// ForgetOnOwningThread() method call.
StreamControl* mControl;
const nsID mId;
nsCOMPtr<nsIInputStream> mStream;
nsCOMPtr<nsIInputStream> mSnappyStream;
nsCOMPtr<nsIThread> mOwningThread;
enum State
{
Open,
Closed,
NumStates
};
Atomic<State> mState;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(cache::ReadStream::Inner, MOZ_OVERRIDE)
};
// ----------------------------------------------------------------------------
// Runnable to notify actors that the ReadStream has closed. This must
// be done on the thread associated with the PBackground actor. Must be
// cancelable to execute on Worker threads (which can occur when the
// ReadStream is constructed on a child process Worker thread).
class ReadStream::NoteClosedRunnable MOZ_FINAL : public nsCancelableRunnable
class ReadStream::Inner::NoteClosedRunnable MOZ_FINAL : public nsCancelableRunnable
{
public:
explicit NoteClosedRunnable(ReadStream* aStream)
explicit NoteClosedRunnable(ReadStream::Inner* aStream)
: mStream(aStream)
{ }
NS_IMETHOD Run()
{
mStream->NoteClosedOnOwningThread();
mStream = nullptr;
return NS_OK;
}
@ -251,24 +138,27 @@ public:
private:
~NoteClosedRunnable() { }
nsRefPtr<ReadStream> mStream;
nsRefPtr<ReadStream::Inner> mStream;
};
// ----------------------------------------------------------------------------
// Runnable to clear actors without reporting that the ReadStream has
// closed. Since this can trigger actor destruction, we need to do
// it on the thread associated with the PBackground actor. Must be
// cancelable to execute on Worker threads (which can occur when the
// ReadStream is constructed on a child process Worker thread).
class ReadStream::ForgetRunnable MOZ_FINAL : public nsCancelableRunnable
class ReadStream::Inner::ForgetRunnable MOZ_FINAL : public nsCancelableRunnable
{
public:
explicit ForgetRunnable(ReadStream* aStream)
explicit ForgetRunnable(ReadStream::Inner* aStream)
: mStream(aStream)
{ }
NS_IMETHOD Run()
{
mStream->ForgetOnOwningThread();
mStream = nullptr;
return NS_OK;
}
@ -283,11 +173,216 @@ public:
private:
~ForgetRunnable() { }
nsRefPtr<ReadStream> mStream;
nsRefPtr<ReadStream::Inner> mStream;
};
NS_IMPL_ISUPPORTS(mozilla::dom::cache::ReadStream, nsIInputStream,
ReadStream);
// ----------------------------------------------------------------------------
ReadStream::Inner::Inner(StreamControl* aControl, const nsID& aId,
nsIInputStream* aStream)
: mControl(aControl)
, mId(aId)
, mStream(aStream)
, mSnappyStream(new SnappyUncompressInputStream(aStream))
, mOwningThread(NS_GetCurrentThread())
, mState(Open)
{
MOZ_ASSERT(mStream);
MOZ_ASSERT(mControl);
mControl->AddReadStream(this);
}
void
ReadStream::Inner::Serialize(PCacheReadStreamOrVoid* aReadStreamOut)
{
MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread);
MOZ_ASSERT(aReadStreamOut);
PCacheReadStream stream;
Serialize(&stream);
*aReadStreamOut = stream;
}
void
ReadStream::Inner::Serialize(PCacheReadStream* aReadStreamOut)
{
MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread);
MOZ_ASSERT(aReadStreamOut);
MOZ_ASSERT(mState == Open);
MOZ_ASSERT(mControl);
aReadStreamOut->id() = mId;
mControl->SerializeControl(aReadStreamOut);
nsAutoTArray<FileDescriptor, 4> fds;
SerializeInputStream(mStream, aReadStreamOut->params(), fds);
mControl->SerializeFds(aReadStreamOut, fds);
// We're passing ownership across the IPC barrier with the control, so
// do not signal that the stream is closed here.
Forget();
}
void
ReadStream::Inner::CloseStream()
{
MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread);
Close();
}
void
ReadStream::Inner::CloseStreamWithoutReporting()
{
MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread);
Forget();
}
bool
ReadStream::Inner::MatchId(const nsID& aId) const
{
MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread);
return mId.Equals(aId);
}
NS_IMETHODIMP
ReadStream::Inner::Close()
{
// stream ops can happen on any thread
nsresult rv = mStream->Close();
NoteClosed();
return rv;
}
NS_IMETHODIMP
ReadStream::Inner::Available(uint64_t* aNumAvailableOut)
{
// stream ops can happen on any thread
nsresult rv = mSnappyStream->Available(aNumAvailableOut);
if (NS_FAILED(rv)) {
Close();
}
return rv;
}
NS_IMETHODIMP
ReadStream::Inner::Read(char* aBuf, uint32_t aCount, uint32_t* aNumReadOut)
{
// stream ops can happen on any thread
MOZ_ASSERT(aNumReadOut);
nsresult rv = mSnappyStream->Read(aBuf, aCount, aNumReadOut);
if ((NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) ||
*aNumReadOut == 0) {
Close();
}
return rv;
}
NS_IMETHODIMP
ReadStream::Inner::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
uint32_t aCount, uint32_t* aNumReadOut)
{
// stream ops can happen on any thread
MOZ_ASSERT(aNumReadOut);
nsresult rv = mSnappyStream->ReadSegments(aWriter, aClosure, aCount,
aNumReadOut);
if ((NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK &&
rv != NS_ERROR_NOT_IMPLEMENTED) || *aNumReadOut == 0) {
Close();
}
return rv;
}
NS_IMETHODIMP
ReadStream::Inner::IsNonBlocking(bool* aNonBlockingOut)
{
// stream ops can happen on any thread
return mSnappyStream->IsNonBlocking(aNonBlockingOut);
}
ReadStream::Inner::~Inner()
{
// Any thread
MOZ_ASSERT(mState == Closed);
MOZ_ASSERT(!mControl);
}
void
ReadStream::Inner::NoteClosed()
{
// Any thread
if (mState == Closed) {
return;
}
if (NS_GetCurrentThread() == mOwningThread) {
NoteClosedOnOwningThread();
return;
}
nsCOMPtr<nsIRunnable> runnable = new NoteClosedRunnable(this);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
mOwningThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL)));
}
void
ReadStream::Inner::Forget()
{
// Any thread
if (mState == Closed) {
return;
}
if (NS_GetCurrentThread() == mOwningThread) {
ForgetOnOwningThread();
return;
}
nsCOMPtr<nsIRunnable> runnable = new ForgetRunnable(this);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
mOwningThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL)));
}
void
ReadStream::Inner::NoteClosedOnOwningThread()
{
MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread);
// Mark closed and do nothing if we were already closed
if (!mState.compareExchange(Open, Closed)) {
return;
}
MOZ_ASSERT(mControl);
mControl->NoteClosed(this, mId);
mControl = nullptr;
}
void
ReadStream::Inner::ForgetOnOwningThread()
{
MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread);
// Mark closed and do nothing if we were already closed
if (!mState.compareExchange(Open, Closed)) {
return;
}
MOZ_ASSERT(mControl);
mControl->ForgetReadStream(this);
mControl = nullptr;
}
// ----------------------------------------------------------------------------
NS_IMPL_ISUPPORTS(cache::ReadStream, nsIInputStream, ReadStream);
// static
already_AddRefed<ReadStream>
@ -311,33 +406,20 @@ ReadStream::Create(const PCacheReadStream& aReadStream)
return nullptr;
}
nsAutoTArray<FileDescriptor, 4> fds;
if (aReadStream.fds().type() ==
OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
FileDescriptorSetChild* fdSetActor =
static_cast<FileDescriptorSetChild*>(aReadStream.fds().get_PFileDescriptorSetChild());
MOZ_ASSERT(fdSetActor);
fdSetActor->ForgetFileDescriptors(fds);
MOZ_ASSERT(!fds.IsEmpty());
unused << fdSetActor->Send__delete__(fdSetActor);
} else if (aReadStream.fds().type() ==
OptionalFileDescriptorSet::TPFileDescriptorSetParent) {
FileDescriptorSetParent* fdSetActor =
static_cast<FileDescriptorSetParent*>(aReadStream.fds().get_PFileDescriptorSetParent());
MOZ_ASSERT(fdSetActor);
fdSetActor->ForgetFileDescriptors(fds);
MOZ_ASSERT(!fds.IsEmpty());
if (!fdSetActor->Send__delete__(fdSetActor)) {
// child process is gone, warn and allow actor to clean up normally
NS_WARNING("Cache failed to delete fd set actor.");
}
// Control is guaranteed to survive this method as ActorDestroy() cannot
// run on this thread until we complete.
StreamControl* control;
if (aReadStream.controlChild()) {
auto actor = static_cast<CacheStreamControlChild*>(aReadStream.controlChild());
control = actor;
} else {
auto actor = static_cast<CacheStreamControlParent*>(aReadStream.controlParent());
control = actor;
}
MOZ_ASSERT(control);
nsAutoTArray<FileDescriptor, 4> fds;
control->DeserializeFds(aReadStream, fds);
nsCOMPtr<nsIInputStream> stream =
DeserializeInputStream(aReadStream.params(), fds);
@ -349,16 +431,8 @@ ReadStream::Create(const PCacheReadStream& aReadStream)
MOZ_ASSERT(!asyncStream);
#endif
nsRefPtr<ReadStream> ref;
if (aReadStream.controlChild()) {
ref = new ReadStreamChild(aReadStream.controlChild(), aReadStream.id(),
stream);
} else {
ref = new ReadStreamParent(aReadStream.controlParent(), aReadStream.id(),
stream);
}
nsRefPtr<Inner> inner = new Inner(control, aReadStream.id(), stream);
nsRefPtr<ReadStream> ref = new ReadStream(inner);
return ref.forget();
}
@ -367,170 +441,67 @@ already_AddRefed<ReadStream>
ReadStream::Create(PCacheStreamControlParent* aControl, const nsID& aId,
nsIInputStream* aStream)
{
nsRefPtr<ReadStream> ref = new ReadStreamParent(aControl, aId, aStream);
MOZ_ASSERT(aControl);
auto actor = static_cast<CacheStreamControlParent*>(aControl);
nsRefPtr<Inner> inner = new Inner(actor, aId, aStream);
nsRefPtr<ReadStream> ref = new ReadStream(inner);
return ref.forget();
}
void
ReadStream::Serialize(PCacheReadStreamOrVoid* aReadStreamOut)
{
MOZ_ASSERT(aReadStreamOut);
PCacheReadStream stream;
Serialize(&stream);
*aReadStreamOut = stream;
mInner->Serialize(aReadStreamOut);
}
void
ReadStream::Serialize(PCacheReadStream* aReadStreamOut)
{
MOZ_ASSERT(aReadStreamOut);
MOZ_ASSERT(!mClosed);
aReadStreamOut->id() = mId;
SerializeControl(aReadStreamOut);
nsAutoTArray<FileDescriptor, 4> fds;
SerializeInputStream(mStream, aReadStreamOut->params(), fds);
SerializeFds(aReadStreamOut, fds);
// We're passing ownership across the IPC barrier with the control, so
// do not signal that the stream is closed here.
Forget();
mInner->Serialize(aReadStreamOut);
}
void
ReadStream::CloseStream()
ReadStream::ReadStream(ReadStream::Inner* aInner)
: mInner(aInner)
{
Close();
}
void
ReadStream::CloseStreamWithoutReporting()
{
Forget();
}
bool
ReadStream::MatchId(const nsID& aId) const
{
return mId.Equals(aId);
}
ReadStream::ReadStream(const nsID& aId, nsIInputStream* aStream)
: mId(aId)
, mStream(aStream)
, mSnappyStream(new SnappyUncompressInputStream(aStream))
, mOwningThread(NS_GetCurrentThread())
, mClosed(false)
{
MOZ_ASSERT(mStream);
MOZ_ASSERT(mInner);
}
ReadStream::~ReadStream()
{
NS_ASSERT_OWNINGTHREAD(ReadStream);
// We cannot directly call NoteClosed() here. The concrete subclasses
// destructors must do this because it takes code paths through virtual
// methods. We don't want to execute these while partially destroyed.
MOZ_ASSERT(mClosed);
}
void
ReadStream::NoteClosed()
{
if (mClosed) {
return;
}
if (NS_GetCurrentThread() == mOwningThread) {
NoteClosedOnOwningThread();
return;
}
nsCOMPtr<nsIRunnable> runnable = new NoteClosedRunnable(this);
nsresult rv = mOwningThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to dispatch Cache ReadStream NoteClosed() runnable.");
}
}
void
ReadStream::Forget()
{
if (mClosed) {
return;
}
if (NS_GetCurrentThread() == mOwningThread) {
ForgetOnOwningThread();
return;
}
nsCOMPtr<nsIRunnable> runnable = new ForgetRunnable(this);
nsresult rv = mOwningThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to dispatch Cache ReadStream Forget() runnable.");
}
// Explicitly close the inner stream so that it does not have to
// deal with implicitly closing at destruction time.
mInner->Close();
}
NS_IMETHODIMP
ReadStream::Close()
{
nsresult rv = mStream->Close();
NoteClosed();
return rv;
return mInner->Close();
}
NS_IMETHODIMP
ReadStream::Available(uint64_t* aNumAvailableOut)
{
nsresult rv = mSnappyStream->Available(aNumAvailableOut);
if (NS_FAILED(rv)) {
Close();
}
return rv;
return mInner->Available(aNumAvailableOut);
}
NS_IMETHODIMP
ReadStream::Read(char* aBuf, uint32_t aCount, uint32_t* aNumReadOut)
{
MOZ_ASSERT(aNumReadOut);
nsresult rv = mSnappyStream->Read(aBuf, aCount, aNumReadOut);
if ((NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) ||
*aNumReadOut == 0) {
Close();
}
return rv;
return mInner->Read(aBuf, aCount, aNumReadOut);
}
NS_IMETHODIMP
ReadStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
uint32_t aCount, uint32_t* aNumReadOut)
{
MOZ_ASSERT(aNumReadOut);
nsresult rv = mSnappyStream->ReadSegments(aWriter, aClosure, aCount,
aNumReadOut);
if ((NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK &&
rv != NS_ERROR_NOT_IMPLEMENTED) || *aNumReadOut == 0) {
Close();
}
return rv;
return mInner->ReadSegments(aWriter, aClosure, aCount, aNumReadOut);
}
NS_IMETHODIMP
ReadStream::IsNonBlocking(bool* aNonBlockingOut)
{
return mSnappyStream->IsNonBlocking(aNonBlockingOut);
return mInner->IsNonBlocking(aNonBlockingOut);
}
} // namespace cache

67
dom/cache/ReadStream.h поставляемый
Просмотреть файл

@ -12,6 +12,7 @@
#include "nsID.h"
#include "nsIInputStream.h"
#include "nsISupportsImpl.h"
#include "nsRefPtr.h"
#include "nsTArrayForwardDeclare.h"
class nsIThread;
@ -29,6 +30,7 @@ class PCacheStreamControlParent;
{0x8e5da7c9, 0x0940, 0x4f1d, \
{0x97, 0x25, 0x5c, 0x59, 0x38, 0xdd, 0xb9, 0x9f}}
// Custom stream class for Request and Response bodies being read from
// a Cache. The main purpose of this class is to report back to the
// Cache's Manager when the stream is closed. This allows the Cache to
@ -40,9 +42,34 @@ class PCacheStreamControlParent;
// stream channel. For example, Cache.put() can detect that the content
// script is passing a Cache-originated-stream back into the Cache
// again. This enables certain optimizations.
class ReadStream : public nsIInputStream
class ReadStream MOZ_FINAL : public nsIInputStream
{
public:
// Interface that lets the StreamControl classes interact with
// our private inner stream.
class Controllable
{
public:
// Closes the stream, notifies the stream control, and then forgets
// the stream control.
virtual void
CloseStream() = 0;
// Closes the stream and then forgets the stream control. Does not
// notify.
virtual void
CloseStreamWithoutReporting() = 0;
virtual bool
MatchId(const nsID& aId) const = 0;
NS_IMETHOD_(MozExternalRefCountType)
AddRef(void) = 0;
NS_IMETHOD_(MozExternalRefCountType)
Release(void) = 0;
};
static already_AddRefed<ReadStream>
Create(const PCacheReadStreamOrVoid& aReadStreamOrVoid);
@ -56,39 +83,21 @@ public:
void Serialize(PCacheReadStreamOrVoid* aReadStreamOut);
void Serialize(PCacheReadStream* aReadStreamOut);
// methods called from the child and parent CacheStreamControl actors
void CloseStream();
void CloseStreamWithoutReporting();
bool MatchId(const nsID& aId) const;
private:
class Inner;
protected:
class NoteClosedRunnable;
class ForgetRunnable;
explicit ReadStream(Inner* aInner);
~ReadStream();
ReadStream(const nsID& aId, nsIInputStream* aStream);
virtual ~ReadStream();
void NoteClosed();
void Forget();
virtual void NoteClosedOnOwningThread() = 0;
virtual void ForgetOnOwningThread() = 0;
virtual void SerializeControl(PCacheReadStream* aReadStreamOut) = 0;
virtual void
SerializeFds(PCacheReadStream* aReadStreamOut,
const nsTArray<mozilla::ipc::FileDescriptor>& fds) = 0;
const nsID mId;
nsCOMPtr<nsIInputStream> mStream;
nsCOMPtr<nsIInputStream> mSnappyStream;
nsCOMPtr<nsIThread> mOwningThread;
bool mClosed;
// Hold a strong ref to an inner class that actually implements the
// majority of the stream logic. Before releasing this ref the outer
// ReadStream guarantees it will call Close() on the inner stream.
// This is essential for the inner stream to avoid dealing with the
// implicit close that can happen when a stream is destroyed.
nsRefPtr<Inner> mInner;
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOM_CACHE_READSTREAM_IID);
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIINPUTSTREAM
};

89
dom/cache/StreamControl.cpp поставляемый Normal file
Просмотреть файл

@ -0,0 +1,89 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=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 "mozilla/dom/cache/StreamControl.h"
namespace mozilla {
namespace dom {
namespace cache {
void
StreamControl::AddReadStream(ReadStream::Controllable* aReadStream)
{
AssertOwningThread();
MOZ_ASSERT(aReadStream);
MOZ_ASSERT(!mReadStreamList.Contains(aReadStream));
mReadStreamList.AppendElement(aReadStream);
}
void
StreamControl::ForgetReadStream(ReadStream::Controllable* aReadStream)
{
AssertOwningThread();
MOZ_ALWAYS_TRUE(mReadStreamList.RemoveElement(aReadStream));
}
void
StreamControl::NoteClosed(ReadStream::Controllable* aReadStream,
const nsID& aId)
{
AssertOwningThread();
ForgetReadStream(aReadStream);
NoteClosedAfterForget(aId);
}
StreamControl::~StreamControl()
{
// owning thread only, but can't call virtual AssertOwningThread in destructor
MOZ_ASSERT(mReadStreamList.IsEmpty());
}
void
StreamControl::CloseReadStreams(const nsID& aId)
{
AssertOwningThread();
DebugOnly<uint32_t> closedCount = 0;
ReadStreamList::ForwardIterator iter(mReadStreamList);
while (iter.HasMore()) {
nsRefPtr<ReadStream::Controllable> stream = iter.GetNext();
if (stream->MatchId(aId)) {
stream->CloseStream();
closedCount += 1;
}
}
MOZ_ASSERT(closedCount > 0);
}
void
StreamControl::CloseAllReadStreams()
{
AssertOwningThread();
ReadStreamList::ForwardIterator iter(mReadStreamList);
while (iter.HasMore()) {
iter.GetNext()->CloseStream();
}
}
void
StreamControl::CloseAllReadStreamsWithoutReporting()
{
AssertOwningThread();
ReadStreamList::ForwardIterator iter(mReadStreamList);
while (iter.HasMore()) {
nsRefPtr<ReadStream::Controllable> stream = iter.GetNext();
// Note, we cannot trigger IPC traffic here. So use
// CloseStreamWithoutReporting().
stream->CloseStreamWithoutReporting();
}
}
} // namespace cache
} // namespace dom
} // namespace mozilla

93
dom/cache/StreamControl.h поставляемый Normal file
Просмотреть файл

@ -0,0 +1,93 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=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_cache_StreamControl_h
#define mozilla_dom_cache_StreamControl_h
#include "mozilla/dom/cache/ReadStream.h"
#include "nsRefPtr.h"
#include "nsTObserverArray.h"
struct nsID;
namespace mozilla {
namespace ipc {
class FileDescriptor;
}
namespace dom {
namespace cache {
class PCacheReadStream;
// Abstract class to help implement the stream control Child and Parent actors.
// This provides an interface to partly help with serialization of IPC types,
// but also an implementation for tracking ReadStream objects.
class StreamControl
{
public:
// abstract interface that must be implemented by child class
virtual void
SerializeControl(PCacheReadStream* aReadStreamOut) = 0;
virtual void
SerializeFds(PCacheReadStream* aReadStreamOut,
const nsTArray<mozilla::ipc::FileDescriptor>& aFds) = 0;
virtual void
DeserializeFds(const PCacheReadStream& aReadStream,
nsTArray<mozilla::ipc::FileDescriptor>& aFdsOut) = 0;
// inherited implementation of the ReadStream::Controllable list
// Begin controlling the given ReadStream. This causes a strong ref to
// be held by the control. The ReadStream must call NoteClosed() or
// ForgetReadStream() to release this ref.
void
AddReadStream(ReadStream::Controllable* aReadStream);
// Forget the ReadStream without notifying the actor.
void
ForgetReadStream(ReadStream::Controllable* aReadStream);
// Forget the ReadStream and then notify the actor the stream is closed.
void
NoteClosed(ReadStream::Controllable* aReadStream, const nsID& aId);
protected:
~StreamControl();
void
CloseReadStreams(const nsID& aId);
void
CloseAllReadStreams();
void
CloseAllReadStreamsWithoutReporting();
// protected parts of the abstract interface
virtual void
NoteClosedAfterForget(const nsID& aId) = 0;
#ifdef DEBUG
virtual void
AssertOwningThread() = 0;
#else
void AssertOwningThread() { }
#endif
private:
// Hold strong references to ReadStream object. When the stream is closed
// it should call NoteClosed() or ForgetReadStream() to release this ref.
typedef nsTObserverArray<nsRefPtr<ReadStream::Controllable>> ReadStreamList;
ReadStreamList mReadStreamList;
};
} // namespace cache
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_cache_StreamControl_h

2
dom/cache/moz.build поставляемый
Просмотреть файл

@ -30,6 +30,7 @@ EXPORTS.mozilla.dom.cache += [
'QuotaClient.h',
'ReadStream.h',
'SavedTypes.h',
'StreamControl.h',
'StreamList.h',
'StreamUtils.h',
'Types.h',
@ -59,6 +60,7 @@ UNIFIED_SOURCES += [
'PrincipalVerifier.cpp',
'QuotaClient.cpp',
'ReadStream.cpp',
'StreamControl.cpp',
'StreamList.cpp',
'StreamUtils.cpp',
'TypeUtils.cpp',

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

@ -101,7 +101,7 @@ function testRequest(request1, request2, request3, unknownRequest,
return checkResponse(r[0], response1, response1Text);
}).then(function() {
return c.matchAll(requestWithAlternateQueryString,
{ignoreSearch: true, cacheName: name});
{ignoreSearch: true});
}).then(function(r) {
is(r.length, 2, "Should find 2 items");
return Promise.all([
@ -122,16 +122,25 @@ function testRequest(request1, request2, request3, unknownRequest,
checkResponse(r[1], response3, response3Text)
]);
}).then(function() {
return c.matchAll({cacheName: name + "mambojambo"});
}).then(function(r) {
is(r.length, 0, "Searching in the wrong cache should not succeed");
return caches.match(request1, {cacheName: name + "mambojambo"})
.then(function() {
ok(false, "Promise should be rejected");
}, function(err) {
is(err.name, "NotFoundError", "Searching in the wrong cache should not succeed");
});
}).then(function() {
return c.matchAll(unknownRequest);
}).then(function(r) {
is(r.length, 0, "Searching for an unknown request should not succeed");
return c.matchAll(unknownRequest, {cacheName: name});
return caches.match(unknownRequest, {cacheName: name});
}).then(function(r) {
is(r.length, 0, "Searching for an unknown request should not succeed");
is(typeof r, "undefined", "Searching for an unknown request should not succeed");
// Make sure that cacheName is ignored on Cache
return c.matchAll(request1, {cacheName: name + "mambojambo"});
}).then(function(r) {
is(r.length, 1, "Should only find 1 item");
return checkResponse(r[0], response1, response1Text);
}).then(function() {
return caches.delete(name);
}).then(function(success) {
ok(success, "We should be able to delete the cache successfully");

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

@ -102,6 +102,11 @@ function testRequest(request, unknownRequest, requestWithAlternateQueryString,
}, function(err) {
is(err.name, "NotFoundError", "Searching in the wrong cache should not succeed");
});
}).then(function() {
// Make sure that cacheName is ignored on Cache
return c.match(request, {cacheName: name + "mambojambo"});
}).then(function(r) {
return checkResponse(r);
}).then(function() {
return c.match(unknownRequest);
}).then(function(r) {

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

@ -4,6 +4,7 @@
# Mark failing tests in mochi-single.html.
[DEFAULT]
subsuite = webgl
skip-if = e10s || os == 'b2g' || ((os == 'linux') && (buildapp == 'b2g')) || ((os == 'linux') && (buildapp == 'mulet'))
support-files = webgl-conformance/../webgl-mochitest/driver-info.js

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

@ -1,3 +1,5 @@
[DEFAULT]
subsuite = webgl
[include:_webgl-conformance.ini]
[include:webgl-mochitest.ini]

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

@ -30,8 +30,9 @@ EXTRA_SUPPORT_FILES = [
]
ACCEPTABLE_ERRATA_KEYS = set([
'skip-if',
'fail-if',
'skip-if',
'subsuite',
])
GENERATED_HEADER = '''

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

@ -5,6 +5,7 @@
# See python/mozbuild/mozbuild/mozinfo.py for incoming data.
[DEFAULT]
subsuite = webgl
# No e10s yet.
# 'B2G Desktop Linux' fails to create WebGL contexts.
# Also skip B2G for now, until we get a handle on the longer tail of emulator

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

@ -1,4 +1,5 @@
[DEFAULT]
subsuite = webgl
skip-if = ((os == 'linux') && (buildapp == 'b2g'))
support-files =

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

@ -183,3 +183,4 @@ skip-if = buildapp == 'b2g' || e10s
support-files =
bug1096146_embedded.html
[test_offsetxy.html]
[test_eventhandler_scoping.html]

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

@ -0,0 +1,17 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Test for event handler scoping</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
var queryResult;
test(function() {
var d = document.createElement("div");
d.setAttribute("onclick", "queryResult = querySelector('span')");
var s = document.createElement("span");
d.appendChild(s);
d.dispatchEvent(new Event("click"));
assert_equals(queryResult, s, "Should have gotten the right object");
}, "Test for bareword calls in an event handler using the element as 'this'");
</script>

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

@ -1335,7 +1335,7 @@ nsresult
IDBDatabase::PostHandleEvent(EventChainPostVisitor& aVisitor)
{
nsresult rv =
IndexedDatabaseManager::CommonPostHandleEvent(this, mFactory, aVisitor);
IndexedDatabaseManager::CommonPostHandleEvent(aVisitor, mFactory);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}

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

@ -43,6 +43,12 @@ namespace indexedDB {
using namespace mozilla::dom::workers;
using namespace mozilla::ipc;
namespace {
NS_DEFINE_IID(kIDBRequestIID, PRIVATE_IDBREQUEST_IID);
} // anonymous namespace
IDBRequest::IDBRequest(IDBDatabase* aDatabase)
: IDBWrapperCache(aDatabase)
{
@ -407,6 +413,9 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(IDBRequest, IDBWrapperCache)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBRequest)
if (aIID.Equals(kIDBRequestIID)) {
foundInterface = this;
} else
NS_INTERFACE_MAP_END_INHERITING(IDBWrapperCache)
NS_IMPL_ADDREF_INHERITED(IDBRequest, IDBWrapperCache)
@ -563,7 +572,7 @@ nsresult
IDBOpenDBRequest::PostHandleEvent(EventChainPostVisitor& aVisitor)
{
nsresult rv =
IndexedDatabaseManager::CommonPostHandleEvent(this, mFactory, aVisitor);
IndexedDatabaseManager::CommonPostHandleEvent(aVisitor, mFactory);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}

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

@ -15,6 +15,9 @@
#include "nsAutoPtr.h"
#include "nsCycleCollectionParticipant.h"
#define PRIVATE_IDBREQUEST_IID \
{0xe68901e5, 0x1d50, 0x4ee9, {0xaf, 0x49, 0x90, 0x99, 0x4a, 0xff, 0xc8, 0x39}}
class nsPIDOMWindow;
struct PRThread;

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

@ -8,9 +8,11 @@
#include "nsIConsoleService.h"
#include "nsIDiskSpaceWatcher.h"
#include "nsIDOMWindow.h"
#include "nsIFile.h"
#include "nsIObserverService.h"
#include "nsIScriptError.h"
#include "nsIScriptGlobalObject.h"
#include "jsapi.h"
#include "mozilla/ClearOnShutdown.h"
@ -117,6 +119,8 @@ private:
namespace {
NS_DEFINE_IID(kIDBRequestIID, PRIVATE_IDBREQUEST_IID);
#define IDB_PREF_BRANCH_ROOT "dom.indexedDB."
const char kTestingPref[] = IDB_PREF_BRANCH_ROOT "testing";
@ -370,38 +374,41 @@ IndexedDatabaseManager::Destroy()
// static
nsresult
IndexedDatabaseManager::CommonPostHandleEvent(
DOMEventTargetHelper* aEventTarget,
IDBFactory* aFactory,
EventChainPostVisitor& aVisitor)
IndexedDatabaseManager::CommonPostHandleEvent(EventChainPostVisitor& aVisitor,
IDBFactory* aFactory)
{
MOZ_ASSERT(aEventTarget);
MOZ_ASSERT(aFactory);
MOZ_ASSERT(aVisitor.mDOMEvent);
MOZ_ASSERT(aFactory);
if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault) {
return NS_OK;
}
nsString type;
nsresult rv = aVisitor.mDOMEvent->GetType(type);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
Event* internalEvent = aVisitor.mDOMEvent->InternalDOMEvent();
MOZ_ASSERT(internalEvent);
NS_NAMED_LITERAL_STRING(errorType, "error");
MOZ_ASSERT(nsDependentString(kErrorEventType) == errorType);
if (type != errorType) {
if (!internalEvent->IsTrusted()) {
return NS_OK;
}
nsCOMPtr<EventTarget> eventTarget =
aVisitor.mDOMEvent->InternalDOMEvent()->GetTarget();
nsString type;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(internalEvent->GetType(type)));
MOZ_ASSERT(nsDependentString(kErrorEventType).EqualsLiteral("error"));
if (!type.EqualsLiteral("error")) {
return NS_OK;
}
nsCOMPtr<EventTarget> eventTarget = internalEvent->GetTarget();
MOZ_ASSERT(eventTarget);
auto* request = static_cast<IDBRequest*>(eventTarget.get());
// Only mess with events that were originally targeted to an IDBRequest.
nsRefPtr<IDBRequest> request;
if (NS_FAILED(eventTarget->QueryInterface(kIDBRequestIID,
getter_AddRefs(request))) ||
!request) {
return NS_OK;
}
nsRefPtr<DOMError> error = request->GetErrorAfterResult();
@ -421,7 +428,7 @@ IndexedDatabaseManager::CommonPostHandleEvent(
nsEventStatus status = nsEventStatus_eIgnore;
if (NS_IsMainThread()) {
if (nsPIDOMWindow* window = aEventTarget->GetOwner()) {
if (nsIDOMWindow* window = eventTarget->GetOwnerGlobal()) {
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(window);
MOZ_ASSERT(sgo);
@ -441,7 +448,9 @@ IndexedDatabaseManager::CommonPostHandleEvent(
MOZ_ASSERT(globalScope);
nsRefPtr<ErrorEvent> errorEvent =
ErrorEvent::Constructor(globalScope, errorType, init);
ErrorEvent::Constructor(globalScope,
nsDependentString(kErrorEventType),
init);
MOZ_ASSERT(errorEvent);
errorEvent->SetTrusted(true);

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

@ -158,9 +158,7 @@ public:
}
static nsresult
CommonPostHandleEvent(DOMEventTargetHelper* aEventTarget,
IDBFactory* aFactory,
EventChainPostVisitor& aVisitor);
CommonPostHandleEvent(EventChainPostVisitor& aVisitor, IDBFactory* aFactory);
static bool
TabContextMayAccessOrigin(const mozilla::dom::TabContext& aContext,

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

@ -551,19 +551,20 @@ InitOnContentProcessCreated()
#ifdef MOZ_NUWA_PROCESS
static void
ResetTransports(void* aUnused) {
ResetTransports(void* aUnused)
{
ContentChild* child = ContentChild::GetSingleton();
mozilla::ipc::Transport* transport = child->GetTransport();
int fd = transport->GetFileDescriptor();
transport->ResetFileDescriptor(fd);
IToplevelProtocol* toplevel = child->GetFirstOpenedActors();
while (toplevel != nullptr) {
nsTArray<IToplevelProtocol*> actors;
child->GetOpenedActors(actors);
for (size_t i = 0; i < actors.Length(); i++) {
IToplevelProtocol* toplevel = actors[i];
transport = toplevel->GetTransport();
fd = transport->GetFileDescriptor();
transport->ResetFileDescriptor(fd);
toplevel = toplevel->getNext();
}
}
#endif
@ -2677,9 +2678,10 @@ GetProtoFdInfos(NuwaProtoFdInfo* aInfoList,
content->GetTransport()->GetFileDescriptor();
i++;
for (IToplevelProtocol* actor = content->GetFirstOpenedActors();
actor != nullptr;
actor = actor->getNext()) {
IToplevelProtocol* actors[NUWA_TOPLEVEL_MAX];
size_t count = content->GetOpenedActorsUnsafe(actors, ArrayLength(actors));
for (size_t j = 0; j < count; j++) {
IToplevelProtocol* actor = actors[j];
if (i >= aInfoListSize) {
NS_RUNTIMEABORT("Too many top level protocols!");
}

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

@ -528,7 +528,6 @@ child:
HandleDoubleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid);
HandleSingleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid);
HandleLongTap(CSSPoint point, Modifiers aModifiers, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
HandleLongTapUp(CSSPoint point, Modifiers aModifiers, ScrollableLayerGuid aGuid);
NotifyAPZStateChange(ViewID aViewId, APZStateChange aChange, int aArg);

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

@ -2113,15 +2113,6 @@ TabChild::RecvHandleLongTap(const CSSPoint& aPoint, const Modifiers& aModifiers,
return true;
}
bool
TabChild::RecvHandleLongTapUp(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid)
{
if (mGlobal && mTabChildGlobal) {
mAPZEventState->ProcessLongTapUp(aPoint, aModifiers, aGuid, GetPresShellResolution());
}
return true;
}
bool
TabChild::RecvNotifyAPZStateChange(const ViewID& aViewId,
const APZStateChange& aChange,

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

@ -335,9 +335,6 @@ public:
const Modifiers& aModifiers,
const mozilla::layers::ScrollableLayerGuid& aGuid,
const uint64_t& aInputBlockId) MOZ_OVERRIDE;
virtual bool RecvHandleLongTapUp(const CSSPoint& aPoint,
const Modifiers& aModifiers,
const mozilla::layers::ScrollableLayerGuid& aGuid) MOZ_OVERRIDE;
virtual bool RecvNotifyAPZStateChange(const ViewID& aViewId,
const APZStateChange& aChange,
const int& aArg) MOZ_OVERRIDE;

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

@ -964,15 +964,6 @@ void TabParent::HandleLongTap(const CSSPoint& aPoint,
}
}
void TabParent::HandleLongTapUp(const CSSPoint& aPoint,
Modifiers aModifiers,
const ScrollableLayerGuid &aGuid)
{
if (!mIsDestroyed) {
unused << SendHandleLongTapUp(aPoint, aModifiers, aGuid);
}
}
void TabParent::NotifyAPZStateChange(ViewID aViewId,
APZStateChange aChange,
int aArg)
@ -1198,15 +1189,6 @@ bool TabParent::SendHandleLongTap(const CSSPoint& aPoint, const Modifiers& aModi
return PBrowserParent::SendHandleLongTap(AdjustTapToChildWidget(aPoint), aModifiers, aGuid, aInputBlockId);
}
bool TabParent::SendHandleLongTapUp(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid)
{
if (mIsDestroyed) {
return false;
}
return PBrowserParent::SendHandleLongTapUp(AdjustTapToChildWidget(aPoint), aModifiers, aGuid);
}
bool TabParent::SendHandleDoubleTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid)
{
if (mIsDestroyed) {

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

@ -239,9 +239,6 @@ public:
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId);
void HandleLongTapUp(const CSSPoint& aPoint,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid);
void NotifyAPZStateChange(ViewID aViewId,
APZStateChange aChange,
int aArg);
@ -268,7 +265,6 @@ public:
bool SendRealTouchEvent(WidgetTouchEvent& event);
bool SendHandleSingleTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid);
bool SendHandleLongTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId);
bool SendHandleLongTapUp(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid);
bool SendHandleDoubleTap(const CSSPoint& aPoint, const Modifiers& aModifiers, const ScrollableLayerGuid& aGuid);
virtual PDocumentRendererParent*

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

@ -1,8 +1,7 @@
/* 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/. */
/*
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ManifestProcessor
* Implementation of processing algorithms from:
* http://www.w3.org/2008/webapps/manifest/
@ -11,347 +10,351 @@
* or individual parts of a manifest object. A manifest is just a
* standard JS object that has been cleaned up.
*
* .process(jsonText, manifestURL, docURL);
* .process({jsonText,manifestURL,docURL});
*
* TODO: The constructor should accept the UA's supported orientations.
* TODO: The constructor should accept the UA's supported display modes.
* TODO: hook up developer tools to issueDeveloperWarning (1086997).
* TODO: hook up developer tools to console. (1086997).
*/
/*globals Components*/
/*exported EXPORTED_SYMBOLS */
/*JSLint options in comment below: */
/*globals Components, XPCOMUtils*/
'use strict';
this.EXPORTED_SYMBOLS = ['ManifestProcessor'];
const imports = {};
const {
utils: Cu,
classes: Cc,
interfaces: Ci
} = Components;
const imports = {};
Cu.import('resource://gre/modules/Services.jsm', imports);
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.importGlobalProperties(['URL']);
const securityManager = imports.Services.scriptSecurityManager;
const netutil = Cc['@mozilla.org/network/util;1'].getService(Ci.nsINetUtil);
const defaultDisplayMode = 'browser';
const displayModes = new Set([
'fullscreen',
'standalone',
'minimal-ui',
XPCOMUtils.defineLazyModuleGetter(imports, 'Services',
'resource://gre/modules/Services.jsm');
imports.netutil = Cc['@mozilla.org/network/util;1'].getService(Ci.nsINetUtil);
// Helper function extracts values from manifest members
// and reports conformance violations.
function extractValue({
objectName,
object,
property,
expectedType,
trim
}, console) {
const value = object[property];
const isArray = Array.isArray(value);
// We need to special-case "array", as it's not a JS primitive.
const type = (isArray) ? 'array' : typeof value;
if (type !== expectedType) {
if (type !== 'undefined') {
let msg = `Expected the ${objectName}'s ${property} `;
msg += `member to a be a ${expectedType}.`;
console.log(msg);
}
return undefined;
}
// Trim string and returned undefined if the empty string.
const shouldTrim = expectedType === 'string' && value && trim;
if (shouldTrim) {
return value.trim() || undefined;
}
return value;
}
const displayModes = new Set(['fullscreen', 'standalone', 'minimal-ui',
'browser'
]);
const orientationTypes = new Set([
'any',
'natural',
'landscape',
'portrait',
'portrait-primary',
'portrait-secondary',
'landscape-primary',
const orientationTypes = new Set(['any', 'natural', 'landscape', 'portrait',
'portrait-primary', 'portrait-secondary', 'landscape-primary',
'landscape-secondary'
]);
const {
ConsoleAPI
} = Cu.import('resource://gre/modules/devtools/Console.jsm');
this.ManifestProcessor = function ManifestProcessor() {};
/**
* process method: processes json text into a clean manifest
* that conforms with the W3C specification.
* @param jsonText - the JSON string to be processd.
* @param manifestURL - the URL of the manifest, to resolve URLs.
* @param docURL - the URL of the owner doc, for security checks
*/
this.ManifestProcessor.prototype.process = function({
jsonText: jsonText,
manifestURL: manifestURL,
docLocation: docURL
}) {
/*
* This helper function is used to extract values from manifest members.
* It also reports conformance violations.
*/
function extractValue(obj) {
let value = obj.object[obj.property];
//we need to special-case "array", as it's not a JS primitive
const type = (Array.isArray(value)) ? 'array' : typeof value;
class ManifestProcessor {
if (type !== obj.expectedType) {
if (type !== 'undefined') {
let msg = `Expected the ${obj.objectName}'s ${obj.property}`;
msg += `member to a be a ${obj.expectedType}.`;
issueDeveloperWarning(msg);
}
value = undefined;
constructor() {}
static get defaultDisplayMode() {
return 'browser';
}
static get displayModes() {
return displayModes;
}
static get orientationTypes() {
return orientationTypes;
}
// process method: processes json text into a clean manifest
// that conforms with the W3C specification. Takes an object
// expecting the following dictionary items:
// * jsonText: the JSON string to be processd.
// * manifestURL: the URL of the manifest, to resolve URLs.
// * docURL: the URL of the owner doc, for security checks.
process({
jsonText, manifestURL, docURL
}) {
const console = new ConsoleAPI({
prefix: 'Web Manifest: '
});
let rawManifest = {};
try {
rawManifest = JSON.parse(jsonText);
} catch (e) {}
if (typeof rawManifest !== 'object' || rawManifest === null) {
let msg = 'Manifest needs to be an object.';
console.warn(msg);
rawManifest = {};
}
return value;
}
function issueDeveloperWarning(msg) {
//https://bugzilla.mozilla.org/show_bug.cgi?id=1086997
}
function processNameMember(manifest) {
const obj = {
objectName: 'manifest',
object: manifest,
property: 'name',
expectedType: 'string'
const processedManifest = {
start_url: processStartURLMember(rawManifest, manifestURL, docURL),
display: processDisplayMember(rawManifest),
orientation: processOrientationMember(rawManifest),
name: processNameMember(rawManifest),
icons: IconsProcessor.process(rawManifest, manifestURL, console),
short_name: processShortNameMember(rawManifest),
};
let value = extractValue(obj);
return (value) ? value.trim() : value;
}
processedManifest.scope = processScopeMember(rawManifest, manifestURL,
docURL, processedManifest.start_url);
return processedManifest;
function processShortNameMember(manifest) {
const obj = {
objectName: 'manifest',
object: manifest,
property: 'short_name',
expectedType: 'string'
};
let value = extractValue(obj);
return (value) ? value.trim() : value;
}
function processOrientationMember(manifest) {
const obj = {
objectName: 'manifest',
object: manifest,
property: 'orientation',
expectedType: 'string'
};
let value = extractValue(obj);
value = (value) ? value.trim() : undefined;
//The spec special-cases orientation to return the empty string
return (orientationTypes.has(value)) ? value : '';
}
function processDisplayMember(manifest) {
const obj = {
objectName: 'manifest',
object: manifest,
property: 'display',
expectedType: 'string'
};
let value = extractValue(obj);
value = (value) ? value.trim() : value;
return (displayModes.has(value)) ? value : defaultDisplayMode;
}
function processScopeMember(manifest, manifestURL, docURL, startURL) {
const spec = {
function processNameMember(aManifest) {
const spec = {
objectName: 'manifest',
object: manifest,
object: aManifest,
property: 'name',
expectedType: 'string',
trim: true
};
return extractValue(spec, console);
}
function processShortNameMember(aManifest) {
const spec = {
objectName: 'manifest',
object: aManifest,
property: 'short_name',
expectedType: 'string',
trim: true
};
return extractValue(spec, console);
}
function processOrientationMember(aManifest) {
const spec = {
objectName: 'manifest',
object: aManifest,
property: 'orientation',
expectedType: 'string',
trim: true
};
const value = extractValue(spec, console);
if (ManifestProcessor.orientationTypes.has(value)) {
return value;
}
// The spec special-cases orientation to return the empty string.
return '';
}
function processDisplayMember(aManifest) {
const spec = {
objectName: 'manifest',
object: aManifest,
property: 'display',
expectedType: 'string',
trim: true
};
const value = extractValue(spec, console);
if (ManifestProcessor.displayModes.has(value)) {
return value;
}
return ManifestProcessor.defaultDisplayMode;
}
function processScopeMember(aManifest, aManifestURL, aDocURL, aStartURL) {
const spec = {
objectName: 'manifest',
object: aManifest,
property: 'scope',
expectedType: 'string',
dontTrim: true
},
value = extractValue(spec);
let scopeURL;
try {
scopeURL = new URL(value, manifestURL);
} catch (e) {
let msg = 'The URL of scope is invalid.';
issueDeveloperWarning(msg);
return undefined;
}
if (scopeURL.origin !== docURL.origin) {
let msg = 'Scope needs to be same-origin as Document.';
issueDeveloperWarning(msg);
return undefined;
}
//If start URL is not within scope of scope URL:
if (startURL && startURL.origin !== scopeURL.origin || !startURL.pathname.startsWith(scopeURL.pathname)) {
let msg = 'The start URL is outside the scope, so scope is invalid.';
issueDeveloperWarning(msg);
return undefined;
}
return scopeURL;
}
function processStartURLMember(manifest, manifestURL, docURL) {
const obj = {
objectName: 'manifest',
object: manifest,
property: 'start_url',
expectedType: 'string'
};
let value = extractValue(obj),
result = new URL(docURL),
targetURI = makeURI(result),
sameOrigin = false,
potentialResult,
referrerURI;
if (value === undefined || value === '') {
return result;
}
try {
potentialResult = new URL(value, manifestURL);
} catch (e) {
issueDeveloperWarning('Invalid URL.');
return result;
}
referrerURI = makeURI(potentialResult);
try {
securityManager.checkSameOriginURI(referrerURI, targetURI, false);
sameOrigin = true;
} catch (e) {}
if (!sameOrigin) {
let msg = 'start_url must be same origin as document.';
issueDeveloperWarning(msg);
} else {
result = potentialResult;
}
return result;
//Converts a URL to a Gecko URI
function makeURI(webURL) {
return imports.Services.io.newURI(webURL.toString(), null, null);
}
}
//Constants used by IconsProcessor
const onlyDecimals = /^\d+$/,
anyRegEx = new RegExp('any', 'i');
function IconsProcessor() {}
IconsProcessor.prototype.processIcons = function(manifest, baseURL) {
const obj = {
objectName: 'manifest',
object: manifest,
property: 'icons',
expectedType: 'array'
},
icons = [];
let value = extractValue(obj);
if (Array.isArray(value)) {
//filter out icons with no "src" or src is empty string
let processableIcons = value.filter(
icon => icon && Object.prototype.hasOwnProperty.call(icon, 'src') && icon.src !== ''
);
for (let potentialIcon of processableIcons) {
let src = processSrcMember(potentialIcon, baseURL)
if(src !== undefined){
let icon = {
src: src,
type: processTypeMember(potentialIcon),
sizes: processSizesMember(potentialIcon),
density: processDensityMember(potentialIcon)
};
icons.push(icon);
}
trim: false
};
const value = extractValue(spec, console);
let scopeURL;
try {
scopeURL = new URL(value, aManifestURL);
} catch (e) {
let msg = 'The URL of scope is invalid.';
console.warn(msg);
return undefined;
}
if (scopeURL.origin !== aDocURL.origin) {
let msg = 'Scope needs to be same-origin as Document.';
console.warn(msg);
return undefined;
}
// If start URL is not within scope of scope URL:
let isSameOrigin = aStartURL && aStartURL.origin !== scopeURL.origin;
if (isSameOrigin || !aStartURL.pathname.startsWith(scopeURL.pathname)) {
let msg =
'The start URL is outside the scope, so scope is invalid.';
console.warn(msg);
return undefined;
}
return scopeURL;
}
function processStartURLMember(aManifest, aManifestURL, aDocURL) {
const spec = {
objectName: 'manifest',
object: aManifest,
property: 'start_url',
expectedType: 'string',
trim: false
};
let result = new URL(aDocURL);
const value = extractValue(spec, console);
if (value === undefined || value === '') {
return result;
}
let potentialResult;
try {
potentialResult = new URL(value, aManifestURL);
} catch (e) {
console.warn('Invalid URL.');
return result;
}
if (potentialResult.origin !== aDocURL.origin) {
let msg = 'start_url must be same origin as document.';
console.warn(msg);
} else {
result = potentialResult;
}
return result;
}
}
}
this.ManifestProcessor = ManifestProcessor;
class IconsProcessor {
constructor() {
throw new Error('Static use only.');
}
static get onlyDecimals() {
return /^\d+$/;
}
static get anyRegEx() {
return new RegExp('any', 'i');
}
static process(aManifest, aBaseURL, console) {
const spec = {
objectName: 'manifest',
object: aManifest,
property: 'icons',
expectedType: 'array',
trim: false
};
const icons = [];
const value = extractValue(spec, console);
if (Array.isArray(value)) {
// Filter out icons whose "src" is not useful.
value.filter(item => !!processSrcMember(item, aBaseURL))
.map(toIconObject)
.forEach(icon => icons.push(icon));
}
return icons;
function processTypeMember(icon) {
const charset = {},
hadCharset = {},
obj = {
objectName: 'icon',
object: icon,
property: 'type',
expectedType: 'string'
};
let value = extractValue(obj),
isParsable = (typeof value === 'string' && value.length > 0);
value = (isParsable) ? netutil.parseContentType(value.trim(), charset, hadCharset) : undefined;
return (value === '') ? undefined : value;
function toIconObject(aIconData) {
return {
src: processSrcMember(aIconData, aBaseURL),
type: processTypeMember(aIconData),
sizes: processSizesMember(aIconData),
density: processDensityMember(aIconData)
};
}
function processDensityMember(icon) {
const hasDensity = Object.prototype.hasOwnProperty.call(icon, 'density'),
rawValue = (hasDensity) ? icon.density : undefined,
value = parseFloat(rawValue),
result = (Number.isNaN(value) || value === +Infinity || value <= 0) ? 1.0 : value;
return result;
function processTypeMember(aIcon) {
const charset = {};
const hadCharset = {};
const spec = {
objectName: 'icon',
object: aIcon,
property: 'type',
expectedType: 'string',
trim: true
};
let value = extractValue(spec, console);
if (value) {
value = imports.netutil.parseContentType(value, charset, hadCharset);
}
return value || undefined;
}
function processSrcMember(icon, baseURL) {
const obj = {
objectName: 'icon',
object: icon,
property: 'src',
expectedType: 'string'
},
value = extractValue(obj);
function processDensityMember(aIcon) {
const value = parseFloat(aIcon.density);
const validNum = Number.isNaN(value) || value === +Infinity || value <=
0;
return (validNum) ? 1.0 : value;
}
function processSrcMember(aIcon, aBaseURL) {
const spec = {
objectName: 'icon',
object: aIcon,
property: 'src',
expectedType: 'string',
trim: false
};
const value = extractValue(spec, console);
let url;
if (typeof value === 'string' && value.trim() !== '') {
if (value && value.length) {
try {
url = new URL(value, baseURL);
url = new URL(value, aBaseURL);
} catch (e) {}
}
return url;
}
function processSizesMember(icon) {
function processSizesMember(aIcon) {
const sizes = new Set(),
obj = {
spec = {
objectName: 'icon',
object: icon,
object: aIcon,
property: 'sizes',
expectedType: 'string'
};
let value = extractValue(obj);
value = (value) ? value.trim() : value;
expectedType: 'string',
trim: true
},
value = extractValue(spec, console);
if (value) {
//split on whitespace and filter out invalid values
let validSizes = value.split(/\s+/).filter(isValidSizeValue);
validSizes.forEach((size) => sizes.add(size));
// Split on whitespace and filter out invalid values.
value.split(/\s+/)
.filter(isValidSizeValue)
.forEach(size => sizes.add(size));
}
return sizes;
/*
* Implementation of HTML's link@size attribute checker
*/
function isValidSizeValue(size) {
if (anyRegEx.test(size)) {
// Implementation of HTML's link@size attribute checker.
function isValidSizeValue(aSize) {
const size = aSize.toLowerCase();
if (IconsProcessor.anyRegEx.test(aSize)) {
return true;
}
size = size.toLowerCase();
if (!size.contains('x') || size.indexOf('x') !== size.lastIndexOf('x')) {
return false;
}
//split left of x for width, after x for height
const width = size.substring(0, size.indexOf('x'));
const height = size.substring(size.indexOf('x') + 1, size.length);
const isValid = !(height.startsWith('0') || width.startsWith('0') || !onlyDecimals.test(width + height));
return isValid;
// Split left of x for width, after x for height.
const widthAndHeight = size.split('x');
const w = widthAndHeight.shift();
const h = widthAndHeight.join('x');
const validStarts = !w.startsWith('0') && !h.startsWith('0');
const validDecimals = IconsProcessor.onlyDecimals.test(w + h);
return (validStarts && validDecimals);
}
}
};
function processIconsMember(manifest, manifestURL) {
const iconsProcessor = new IconsProcessor();
return iconsProcessor.processIcons(manifest, manifestURL);
}
//Processing starts here!
let manifest = {};
try {
manifest = JSON.parse(jsonText);
if (typeof manifest !== 'object' || manifest === null) {
let msg = 'Manifest needs to be an object.';
issueDeveloperWarning(msg);
manifest = {};
}
} catch (e) {
issueDeveloperWarning(e);
}
const processedManifest = {
start_url: processStartURLMember(manifest, manifestURL, docURL),
display: processDisplayMember(manifest),
orientation: processOrientationMember(manifest),
name: processNameMember(manifest),
icons: processIconsMember(manifest, manifestURL),
short_name: processShortNameMember(manifest)
};
processedManifest.scope = processScopeMember(manifest, manifestURL, docURL, processedManifest.start_url);
return processedManifest;
};
}

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

@ -16,5 +16,5 @@ const bsp = SpecialPowers.Cu.import('resource://gre/modules/ManifestProcessor.js
data = {
jsonText: '{}',
manifestURL: manifestURL,
docLocation: docLocation
docURL: docLocation
};

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

@ -221,6 +221,7 @@ static const char* const gOmxTypes[] = {
"audio/mp4",
"audio/amr",
"audio/3gpp",
"audio/flac",
"video/mp4",
"video/3gpp",
"video/3gpp2",

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

@ -1418,7 +1418,11 @@ NS_IMPL_ISUPPORTS(MediaManager, nsIMediaManagerService, nsIObserver)
MediaManager::Get() {
if (!sSingleton) {
NS_ASSERTION(NS_IsMainThread(), "Only create MediaManager on main thread");
#ifdef DEBUG
static int timesCreated = 0;
timesCreated++;
MOZ_ASSERT(timesCreated == 1);
#endif
sSingleton = new MediaManager();
sSingleton->mMediaThread = new base::Thread("MediaManager");
@ -1454,6 +1458,11 @@ MediaManager::Get() {
return sSingleton;
}
/* static */ MediaManager*
MediaManager::GetIfExists() {
return sSingleton;
}
/* static */ already_AddRefed<MediaManager>
MediaManager::GetInstance()
{

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

@ -554,6 +554,7 @@ public:
// thread from the MainThread, as we NS_DISPATCH_SYNC to MainThread
// from MediaManager thread.
static MediaManager* Get();
static MediaManager* GetIfExists();
static MessageLoop* GetMessageLoop();
static bool Exists()

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

@ -6,6 +6,7 @@
#include "GMPVideoDecoder.h"
#include "GMPVideoHost.h"
#include "mozilla/Endian.h"
#include "prsystem.h"
namespace mozilla {
@ -132,13 +133,26 @@ GMPVideoDecoder::CreateFrame(mp4_demuxer::MP4Sample* aSample)
memcpy(frame->Buffer(), aSample->data, frame->Size());
// Convert 4-byte NAL unit lengths to host-endian 4-byte buffer lengths to
// suit the GMP API.
if (mConvertNALUnitLengths) {
const int kNALLengthSize = 4;
uint8_t* buf = frame->Buffer();
while (buf < frame->Buffer() + frame->Size() - kNALLengthSize) {
uint32_t length = BigEndian::readUint32(buf) + kNALLengthSize;
*reinterpret_cast<uint32_t *>(buf) = length;
buf += length;
}
}
frame->SetBufferType(GMP_BufferLength32);
frame->SetEncodedWidth(mConfig.display_width);
frame->SetEncodedHeight(mConfig.display_height);
frame->SetTimeStamp(aSample->composition_timestamp);
frame->SetCompleteFrame(true);
frame->SetDuration(aSample->duration);
frame->SetFrameType(aSample->is_sync_point ? kGMPKeyFrame : kGMPDeltaFrame);
frame->SetBufferType(GMP_BufferLength32);
return frame;
}
@ -157,6 +171,16 @@ GMPVideoDecoder::Init()
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(mHost && mGMP);
// GMP implementations have interpreted the meaning of GMP_BufferLength32
// differently. The OpenH264 GMP expects GMP_BufferLength32 to behave as
// specified in the GMP API, where each buffer is prefixed by a 32-bit
// host-endian buffer length that includes the size of the buffer length
// field. Other existing GMPs currently expect GMP_BufferLength32 (when
// combined with kGMPVideoCodecH264) to mean "like AVCC but restricted to
// 4-byte NAL lengths" (i.e. buffer lengths are specified in big-endian
// and do not include the length of the buffer length field.
mConvertNALUnitLengths = mGMP->GetDisplayName().EqualsLiteral("gmpopenh264");
GMPVideoCodec codec;
memset(&codec, 0, sizeof(codec));

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

@ -62,6 +62,7 @@ protected:
, mGMP(nullptr)
, mHost(nullptr)
, mAdapter(aAdapter)
, mConvertNALUnitLengths(false)
{
}
@ -79,6 +80,7 @@ public:
VideoInfo(aConfig.display_width,
aConfig.display_height),
aImageContainer))
, mConvertNALUnitLengths(false)
{
}
@ -100,9 +102,9 @@ private:
GMPVideoDecoderProxy* mGMP;
GMPVideoHost* mHost;
nsAutoPtr<VideoCallbackAdapter> mAdapter;
bool mConvertNALUnitLengths;
};
} // namespace mozilla
#endif // GMPVideoDecoder_h_

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

@ -34,25 +34,18 @@ using CrashReporter::GetIDFromMinidump;
namespace mozilla {
#ifdef LOG
#undef LOG
#endif
#undef LOGD
#ifdef PR_LOGGING
extern PRLogModuleInfo* GetGMPLog();
#define LOGD(msg) PR_LOG(GetGMPLog(), PR_LOG_DEBUG, msg)
#define LOG(level, msg) PR_LOG(GetGMPLog(), (level), msg)
#define LOG(level, x, ...) PR_LOG(GetGMPLog(), (level), (x, ##__VA_ARGS__))
#define LOGD(x, ...) LOG(PR_LOG_DEBUG, "GMPParent[%p|childPid=%d] " x, this, mChildPid, ##__VA_ARGS__)
#else
#define LOGD(msg)
#define LOG(level, msg)
#define LOG(level, x, ...)
#define LOGD(x, ...)
#endif
#ifdef __CLASS__
#undef __CLASS__
#endif
#define __CLASS__ "GMPParent"
namespace gmp {
GMPParent::GMPParent()
@ -62,13 +55,18 @@ GMPParent::GMPParent()
, mAbnormalShutdownInProgress(false)
, mAsyncShutdownRequired(false)
, mAsyncShutdownInProgress(false)
#ifdef PR_LOGGING
, mChildPid(0)
#endif
{
LOGD("GMPParent ctor");
}
GMPParent::~GMPParent()
{
// Can't Close or Destroy the process here, since destruction is MainThread only
MOZ_ASSERT(NS_IsMainThread());
LOGD("GMPParent dtor");
}
void
@ -107,8 +105,7 @@ GMPParent::Init(GeckoMediaPluginService *aService, nsIFile* aPluginDir)
if (NS_FAILED(rv)) {
return rv;
}
LOGD(("%s::%s: %p for %s", __CLASS__, __FUNCTION__, this,
NS_LossyConvertUTF16toASCII(parentLeafName).get()));
LOGD("%s: for %s", __FUNCTION__, NS_LossyConvertUTF16toASCII(parentLeafName).get());
MOZ_ASSERT(parentLeafName.Length() > 4);
mName = Substring(parentLeafName, 4);
@ -135,7 +132,7 @@ GMPParent::LoadProcess()
if (NS_FAILED(mDirectory->GetPath(path))) {
return NS_ERROR_FAILURE;
}
LOGD(("%s::%s: %p for %s", __CLASS__, __FUNCTION__, this, path.get()));
LOGD("%s: for %s", __FUNCTION__, NS_ConvertUTF16toUTF8(path).get());
if (!mProcess) {
mProcess = new GMPProcessParent(NS_ConvertUTF16toUTF8(path).get());
@ -145,32 +142,36 @@ GMPParent::LoadProcess()
return NS_ERROR_FAILURE;
}
#ifdef PR_LOGGING
mChildPid = base::GetProcId(mProcess->GetChildProcessHandle());
#endif
bool opened = Open(mProcess->GetChannel(), mProcess->GetChildProcessHandle());
if (!opened) {
LOGD(("%s::%s: Failed to create new child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
LOGD("%s: Failed to create new child process", __FUNCTION__);
mProcess->Delete();
mProcess = nullptr;
return NS_ERROR_FAILURE;
}
LOGD(("%s::%s: Created new child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
LOGD("%s: Created new child process", __FUNCTION__);
bool ok = SendSetNodeId(mNodeId);
if (!ok) {
LOGD(("%s::%s: Failed to send node id to child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
LOGD("%s: Failed to send node id to child process", __FUNCTION__);
mProcess->Delete();
mProcess = nullptr;
return NS_ERROR_FAILURE;
}
LOGD(("%s::%s: Sent node id to child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
LOGD("%s: Sent node id to child process", __FUNCTION__);
ok = SendStartPlugin();
if (!ok) {
LOGD(("%s::%s: Failed to send start to child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
LOGD("%s: Failed to send start to child process", __FUNCTION__);
mProcess->Delete();
mProcess = nullptr;
return NS_ERROR_FAILURE;
}
LOGD(("%s::%s: Sent StartPlugin to child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
LOGD("%s: Sent StartPlugin to child process", __FUNCTION__);
}
mState = GMPStateLoaded;
@ -225,8 +226,7 @@ void
GMPParent::CloseIfUnused()
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
LOGD(("%s::%s: %p mAsyncShutdownRequired=%d", __CLASS__, __FUNCTION__, this,
mAsyncShutdownRequired));
LOGD("%s: mAsyncShutdownRequired=%d", __FUNCTION__, mAsyncShutdownRequired);
if ((mDeleteProcessOnlyOnUnload ||
mState == GMPStateLoaded ||
@ -243,8 +243,7 @@ GMPParent::CloseIfUnused()
if (mAsyncShutdownRequired) {
if (!mAsyncShutdownInProgress) {
LOGD(("%s::%s: %p sending async shutdown notification", __CLASS__,
__FUNCTION__, this));
LOGD("%s: sending async shutdown notification", __FUNCTION__);
mAsyncShutdownInProgress = true;
if (!SendBeginAsyncShutdown() ||
NS_FAILED(EnsureAsyncShutdownTimeoutSet())) {
@ -265,7 +264,7 @@ void
GMPParent::AbortAsyncShutdown()
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this));
LOGD("%s", __FUNCTION__);
if (mAsyncShutdownTimeout) {
mAsyncShutdownTimeout->Cancel();
@ -299,7 +298,7 @@ GMPParent::AudioDecoderDestroyed(GMPAudioDecoderParent* aDecoder)
void
GMPParent::CloseActive(bool aDieWhenUnloaded)
{
LOGD(("%s::%s: %p state %d", __CLASS__, __FUNCTION__, this, mState));
LOGD("%s: state %d", __FUNCTION__, mState);
if (aDieWhenUnloaded) {
mDeleteProcessOnlyOnUnload = true; // don't allow this to go back...
}
@ -339,7 +338,7 @@ GMPParent::CloseActive(bool aDieWhenUnloaded)
void
GMPParent::Shutdown()
{
LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this));
LOGD("%s", __FUNCTION__);
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
MOZ_ASSERT(!mAsyncShutdownTimeout, "Should have canceled shutdown timeout");
@ -384,7 +383,7 @@ public:
void
GMPParent::DeleteProcess()
{
LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this));
LOGD("%s", __FUNCTION__);
if (mState != GMPStateClosing) {
// Don't Close() twice!
@ -393,7 +392,7 @@ GMPParent::DeleteProcess()
Close();
}
mProcess->Delete();
LOGD(("%s::%s: Shut down process %p", __CLASS__, __FUNCTION__, (void *) mProcess));
LOGD("%s: Shut down process", __FUNCTION__);
mProcess = nullptr;
mState = GMPStateNotLoaded;
@ -654,7 +653,7 @@ GMPNotifyObservers(nsAString& aData)
void
GMPParent::ActorDestroy(ActorDestroyReason aWhy)
{
LOGD(("%s::%s: %p (%d)", __CLASS__, __FUNCTION__, this, (int) aWhy));
LOGD("%s: (%d)", __FUNCTION__, (int)aWhy);
#ifdef MOZ_CRASHREPORTER
if (AbnormalShutdown == aWhy) {
Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT,
@ -1002,6 +1001,12 @@ GMPParent::SetNodeId(const nsACString& aNodeId)
mNodeId = aNodeId;
}
const nsCString&
GMPParent::GetDisplayName() const
{
return mDisplayName;
}
const nsCString&
GMPParent::GetVersion() const
{
@ -1011,7 +1016,7 @@ GMPParent::GetVersion() const
bool
GMPParent::RecvAsyncShutdownRequired()
{
LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this));
LOGD("%s", __FUNCTION__);
if (mAsyncShutdownRequired) {
NS_WARNING("Received AsyncShutdownRequired message more than once!");
return true;
@ -1024,7 +1029,7 @@ GMPParent::RecvAsyncShutdownRequired()
bool
GMPParent::RecvAsyncShutdownComplete()
{
LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this));
LOGD("%s", __FUNCTION__);
MOZ_ASSERT(mAsyncShutdownRequired);
AbortAsyncShutdown();
@ -1033,3 +1038,6 @@ GMPParent::RecvAsyncShutdownComplete()
} // namespace gmp
} // namespace mozilla
#undef LOG
#undef LOGD

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

@ -115,6 +115,7 @@ public:
void SetNodeId(const nsACString& aNodeId);
const nsACString& GetNodeId() const { return mNodeId; }
const nsCString& GetDisplayName() const;
const nsCString& GetVersion() const;
// Returns true if a plugin can be or is being used across multiple NodeIds.
@ -198,6 +199,10 @@ private:
bool mAsyncShutdownRequired;
bool mAsyncShutdownInProgress;
#ifdef PR_LOGGING
int mChildPid;
#endif
};
} // namespace gmp

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

@ -39,7 +39,7 @@ extern PRLogModuleInfo* GetGMPLog();
#ifdef __CLASS__
#undef __CLASS__
#endif
#define __CLASS__ "GMPParent"
#define __CLASS__ "GMPStorageParent"
namespace gmp {

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

@ -182,6 +182,18 @@ GMPVideoDecoderParent::Drain()
return NS_OK;
}
const nsCString&
GMPVideoDecoderParent::GetDisplayName() const
{
if (!mIsOpen) {
NS_WARNING("Trying to use an dead GMP video decoder");
}
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
return mPlugin->GetDisplayName();
}
// Note: Consider keeping ActorDestroy sync'd up when making changes here.
nsresult
GMPVideoDecoderParent::Shutdown()

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

@ -45,6 +45,7 @@ public:
virtual nsresult Reset() MOZ_OVERRIDE;
virtual nsresult Drain() MOZ_OVERRIDE;
virtual const uint64_t ParentID() MOZ_OVERRIDE { return reinterpret_cast<uint64_t>(mPlugin.get()); }
virtual const nsCString& GetDisplayName() const MOZ_OVERRIDE;
// GMPSharedMemManager
virtual bool Alloc(size_t aSize, Shmem::SharedMemory::SharedMemoryType aType, Shmem* aMem) MOZ_OVERRIDE

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

@ -49,6 +49,8 @@ public:
// Call to tell GMP/plugin the consumer will no longer use this
// interface/codec.
virtual void Close() = 0;
virtual const nsCString& GetDisplayName() const = 0;
};
#endif

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

@ -9,6 +9,7 @@ var gSmallTests = [
{ name:"small-shot.m4a", type:"audio/mp4", duration:0.29 },
{ name:"small-shot.mp3", type:"audio/mpeg", duration:0.27 },
{ name:"small-shot-mp3.mp4", type:"audio/mp4; codecs=mp3", duration:0.34 },
{ name:"small-shot.flac", type:"audio/flac", duration:0.197 },
{ name:"r11025_s16_c1.wav", type:"audio/x-wav", duration:1.0 },
{ name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.266 },
{ name:"seek.webm", type:"video/webm", width:320, height:240, duration:3.966 },

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

@ -247,6 +247,7 @@ support-files =
small-shot.mp3^headers^
small-shot.ogg
small-shot.ogg^headers^
small-shot.flac
sound.ogg
sound.ogg^headers^
spacestorm-1000Hz-100ms.ogg

Двоичные данные
dom/media/test/small-shot.flac Normal file

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

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

@ -742,9 +742,9 @@ function PeerConnectionWrapper(label, configuration, h264) {
this.remoteRequiresTrickleIce = false;
this.localMediaElements = [];
this.expectedLocalTrackTypesById = {};
this.expectedRemoteTrackTypesById = {};
this.observedRemoteTrackTypesById = {};
this.expectedLocalTrackInfoById = {};
this.expectedRemoteTrackInfoById = {};
this.observedRemoteTrackInfoById = {};
this.disableRtpCountChecking = false;
@ -875,7 +875,10 @@ PeerConnectionWrapper.prototype = {
stream.getTracks().forEach(track => {
ok(track.id, "track has id");
ok(track.kind, "track has kind");
this.expectedLocalTrackTypesById[track.id] = track.kind;
this.expectedLocalTrackInfoById[track.id] = {
type: track.kind,
streamId: stream.id
};
});
}
@ -893,14 +896,17 @@ PeerConnectionWrapper.prototype = {
removeSender : function(index) {
var sender = this._pc.getSenders()[index];
delete this.expectedLocalTrackTypesById[sender.track.id];
delete this.expectedLocalTrackInfoById[sender.track.id];
this._pc.removeTrack(sender);
},
senderReplaceTrack : function(index, withTrack) {
senderReplaceTrack : function(index, withTrack, withStreamId) {
var sender = this._pc.getSenders()[index];
delete this.expectedLocalTrackTypesById[sender.track.id];
this.expectedLocalTrackTypesById[withTrack.id] = withTrack.kind;
delete this.expectedLocalTrackInfoById[sender.track.id];
this.expectedLocalTrackInfoById[withTrack.id] = {
type: withTrack.kind,
streamId: withStreamId
};
return sender.replaceTrack(withTrack);
},
@ -1081,20 +1087,23 @@ PeerConnectionWrapper.prototype = {
/**
* Checks whether a given track is expected, has not been observed yet, and
* is of the correct type. Then, moves the track from
* |expectedTrackTypesById| to |observedTrackTypesById|.
* |expectedTrackInfoById| to |observedTrackInfoById|.
*/
checkTrackIsExpected : function(track,
expectedTrackTypesById,
observedTrackTypesById) {
ok(expectedTrackTypesById[track.id], "track id " + track.id + " was expected");
ok(!observedTrackTypesById[track.id], "track id " + track.id + " was not yet observed");
expectedTrackInfoById,
observedTrackInfoById) {
ok(expectedTrackInfoById[track.id], "track id " + track.id + " was expected");
ok(!observedTrackInfoById[track.id], "track id " + track.id + " was not yet observed");
var observedKind = track.kind;
var expectedKind = expectedTrackTypesById[track.id];
var expectedKind = expectedTrackInfoById[track.id].type;
is(observedKind, expectedKind,
"track id " + track.id + " was of kind " +
observedKind + ", which matches " + expectedKind);
observedTrackTypesById[track.id] = expectedTrackTypesById[track.id];
delete expectedTrackTypesById[track.id];
observedTrackInfoById[track.id] = expectedTrackInfoById[track.id];
},
allExpectedTracksAreObserved: function(expected, observed) {
return Object.keys(expected).every(trackId => observed[trackId]);
},
setupAddStreamEventHandler: function() {
@ -1112,11 +1121,12 @@ PeerConnectionWrapper.prototype = {
event.stream.getTracks().forEach(track => {
this.checkTrackIsExpected(track,
this.expectedRemoteTrackTypesById,
this.observedRemoteTrackTypesById);
this.expectedRemoteTrackInfoById,
this.observedRemoteTrackInfoById);
});
if (Object.keys(this.expectedRemoteTrackTypesById).length === 0) {
if (this.allExpectedTracksAreObserved(this.expectedRemoteTrackInfoById,
this.observedRemoteTrackInfoById)) {
resolveAllAddStreamEventsDone();
}
@ -1363,24 +1373,14 @@ PeerConnectionWrapper.prototype = {
},
checkLocalMediaTracks : function() {
var observedLocalTrackTypesById = {};
// We do not want to empty out this.expectedLocalTrackTypesById, so make a
// copy.
var expectedLocalTrackTypesById =
JSON.parse(JSON.stringify((this.expectedLocalTrackTypesById)));
info(this + " Checking local tracks " +
JSON.stringify(expectedLocalTrackTypesById));
this._pc.getLocalStreams().forEach(stream => {
stream.getTracks().forEach(track => {
this.checkTrackIsExpected(track,
expectedLocalTrackTypesById,
observedLocalTrackTypesById);
});
var observed = {};
info(this + " Checking local tracks " + JSON.stringify(this.expectedLocalTrackInfoById));
this._pc.getSenders().forEach(sender => {
this.checkTrackIsExpected(sender.track, this.expectedLocalTrackInfoById, observed);
});
Object.keys(expectedLocalTrackTypesById).forEach(id => {
ok(false, this + " local id " + id + " was observed");
});
Object.keys(this.expectedLocalTrackInfoById).forEach(
id => ok(observed[id], this + " local id " + id + " was observed"));
},
/**
@ -1393,10 +1393,11 @@ PeerConnectionWrapper.prototype = {
this.checkLocalMediaTracks();
info(this + " Checking remote tracks " +
JSON.stringify(this.expectedRemoteTrackTypesById));
JSON.stringify(this.expectedRemoteTrackInfoById));
// No tracks are expected
if (Object.keys(this.expectedRemoteTrackTypesById).length === 0) {
if (this.allExpectedTracksAreObserved(this.expectedRemoteTrackInfoById,
this.observedRemoteTrackInfoById)) {
return;
}
@ -1404,19 +1405,18 @@ PeerConnectionWrapper.prototype = {
},
checkMsids: function() {
var checkSdpForMsids = (desc, streams, side) => {
streams.forEach(stream => {
stream.getTracks().forEach(track => {
ok(desc.sdp.match(new RegExp("a=msid:" + stream.id + " " + track.id)),
this + ": " + side + " SDP contains stream " + stream.id +
" and track " + track.id );
});
var checkSdpForMsids = (desc, expectedTrackInfo, side) => {
Object.keys(expectedTrackInfo).forEach(trackId => {
var streamId = expectedTrackInfo[trackId].streamId;
ok(desc.sdp.match(new RegExp("a=msid:" + streamId + " " + trackId)),
this + ": " + side + " SDP contains stream " + streamId +
" and track " + trackId );
});
};
checkSdpForMsids(this.localDescription, this._pc.getLocalStreams(),
checkSdpForMsids(this.localDescription, this.expectedLocalTrackInfoById,
"local");
checkSdpForMsids(this.remoteDescription, this._pc.getRemoteStreams(),
checkSdpForMsids(this.remoteDescription, this.expectedRemoteTrackInfoById,
"remote");
},
@ -1507,11 +1507,6 @@ PeerConnectionWrapper.prototype = {
*/
checkStats : function(stats, twoMachines) {
var toNum = obj => obj? obj : 0;
var numTracks = streams =>
streams.reduce((count, stream) => count +
stream.getAudioTracks().length +
stream.getVideoTracks().length,
0);
const isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1;
@ -1599,8 +1594,8 @@ PeerConnectionWrapper.prototype = {
});
is(JSON.stringify(counters), JSON.stringify(counters2),
"Spec and MapClass variant of RTCStatsReport enumeration agree");
var nin = numTracks(this._pc.getRemoteStreams());
var nout = numTracks(this._pc.getLocalStreams());
var nin = Object.keys(this.expectedRemoteTrackInfoById).length;
var nout = Object.keys(this.expectedLocalTrackInfoById).length;
var ndata = this.dataChannels.length;
// TODO(Bug 957145): Restore stronger inboundrtp test once Bug 948249 is fixed

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

@ -106,36 +106,32 @@ function waitForAnIceCandidate(pc) {
});
}
function checkTrackStats(pc, audio, outbound) {
var stream = outbound ? pc._pc.getLocalStreams()[0] : pc._pc.getRemoteStreams()[0];
if (!stream) {
return Promise.resolve();
}
var track = audio ? stream.getAudioTracks()[0] : stream.getVideoTracks()[0];
if (!track) {
return Promise.resolve();
}
function checkTrackStats(pc, rtpSenderOrReceiver, outbound) {
var track = rtpSenderOrReceiver.track;
var audio = (track.kind == "audio");
var msg = pc + " stats " + (outbound ? "outbound " : "inbound ") +
(audio ? "audio" : "video") + " rtp ";
(audio ? "audio" : "video") + " rtp track id " + track.id;
return pc.getStats(track).then(stats => {
ok(pc.hasStat(stats, {
type: outbound ? "outboundrtp" : "inboundrtp",
isRemote: false,
mediaType: audio ? "audio" : "video"
}), msg + "1");
}), msg + " - found expected stats");
ok(!pc.hasStat(stats, {
type: outbound ? "inboundrtp" : "outboundrtp",
isRemote: false
}), msg + "2");
}), msg + " - did not find extra stats with wrong direction");
ok(!pc.hasStat(stats, {
mediaType: audio ? "video" : "audio"
}), msg + "3");
}), msg + " - did not find extra stats with wrong media type");
});
}
// checks all stats combinations inbound/outbound, audio/video
var checkAllTrackStats = pc =>
Promise.all([0, 1, 2, 3].map(i => checkTrackStats(pc, i & 1, i & 2)));
var checkAllTrackStats = pc => {
return Promise.all([].concat(
pc._pc.getSenders().map(sender => checkTrackStats(pc, sender, true)),
pc._pc.getReceivers().map(receiver => checkTrackStats(pc, receiver, false))));
}
// Commands run once at the beginning of each test, even when performing a
// renegotiation test.
@ -246,14 +242,14 @@ var commandsPeerConnectionOfferAnswer = [
function PC_LOCAL_STEEPLECHASE_SIGNAL_EXPECTED_LOCAL_TRACKS(test) {
if (test.steeplechase) {
send_message({"type": "local_expected_tracks",
"expected_tracks": test.pcLocal.expectedLocalTrackTypesById});
"expected_tracks": test.pcLocal.expectedLocalTrackInfoById});
}
},
function PC_REMOTE_STEEPLECHASE_SIGNAL_EXPECTED_LOCAL_TRACKS(test) {
if (test.steeplechase) {
send_message({"type": "remote_expected_tracks",
"expected_tracks": test.pcRemote.expectedLocalTrackTypesById});
"expected_tracks": test.pcRemote.expectedLocalTrackInfoById});
}
},
@ -261,36 +257,26 @@ var commandsPeerConnectionOfferAnswer = [
if (test.steeplechase) {
return test.getSignalingMessage("remote_expected_tracks").then(
message => {
test.pcLocal.expectedRemoteTrackTypesById = message.expected_tracks;
test.pcLocal.expectedRemoteTrackInfoById = message.expected_tracks;
});
} else {
// Deep copy, as similar to steeplechase as possible
test.pcLocal.expectedRemoteTrackTypesById =
JSON.parse(JSON.stringify((test.pcRemote.expectedLocalTrackTypesById)));
}
// Remove what we've already observed
Object.keys(test.pcLocal.observedRemoteTrackTypesById).forEach(id => {
delete test.pcLocal.expectedRemoteTrackTypesById[id];
});
// Deep copy, as similar to steeplechase as possible
test.pcLocal.expectedRemoteTrackInfoById =
JSON.parse(JSON.stringify(test.pcRemote.expectedLocalTrackInfoById));
},
function PC_REMOTE_GET_EXPECTED_REMOTE_TRACKS(test) {
if (test.steeplechase) {
return test.getSignalingMessage("local_expected_tracks").then(
message => {
test.pcRemote.expectedRemoteTrackTypesById = message.expected_tracks;
test.pcRemote.expectedRemoteTrackInfoById = message.expected_tracks;
});
} else {
// Deep copy, as similar to steeplechase as possible
test.pcRemote.expectedRemoteTrackTypesById =
JSON.parse(JSON.stringify((test.pcLocal.expectedLocalTrackTypesById)));
}
// Remove what we've already observed
Object.keys(test.pcRemote.observedRemoteTrackTypesById).forEach(id => {
delete test.pcRemote.expectedRemoteTrackTypesById[id];
});
// Deep copy, as similar to steeplechase as possible
test.pcRemote.expectedRemoteTrackInfoById =
JSON.parse(JSON.stringify(test.pcLocal.expectedLocalTrackInfoById));
},
function PC_LOCAL_CREATE_OFFER(test) {

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

@ -31,9 +31,12 @@ runNetworkTest(function() {
.then(() => {
var stream = v1.mozCaptureStreamUntilEnded();
is(stream.getTracks().length, 2, "Captured stream has 2 tracks");
stream.getTracks().forEach(tr => {
test.pcLocal._pc.addTrack(tr, stream);
test.pcLocal.expectedLocalTrackTypesById[tr.id] = tr.kind;
stream.getTracks().forEach(track => {
test.pcLocal._pc.addTrack(track, stream);
test.pcLocal.expectedLocalTrackInfoById[track.id] = {
type: track.kind,
streamId: stream.id
};
});
test.pcLocal.constraints = [{ video: true, audio:true }]; // fool tests
});

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

@ -24,7 +24,7 @@
return navigator.mediaDevices.getUserMedia({video:true, fake:true})
.then(newstream => {
var newtrack = newstream.getVideoTracks()[0];
return test.pcLocal.senderReplaceTrack(0, newtrack);
return test.pcLocal.senderReplaceTrack(0, newtrack, newstream.id);
})
.then(() => {
test.setMediaConstraints([{video: true}, {video: true}],

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

@ -111,7 +111,9 @@ skip-if = toolkit == 'android' # bug 1056706
[test_mediaDecoding.html]
[test_mediaElementAudioSourceNode.html]
[test_mediaElementAudioSourceNodePassThrough.html]
skip-if = toolkit == 'android' # bug 1145816
[test_mediaElementAudioSourceNodeCrossOrigin.html]
skip-if = toolkit == 'android' # bug 1145816
[test_mediaStreamAudioDestinationNode.html]
[test_mediaStreamAudioSourceNode.html]
[test_mediaStreamAudioSourceNodeCrossOrigin.html]

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

@ -941,8 +941,108 @@ bool WebMReader::DecodeAudioData()
return DecodeAudioPacket(holder->mPacket, holder->mOffset);
}
bool WebMReader::FilterPacketByTime(int64_t aEndTime, WebMPacketQueue& aOutput)
{
// Push the video frames to the aOutput which's timestamp is less
// than aEndTime.
while (true) {
nsAutoRef<NesteggPacketHolder> holder(NextPacket(VIDEO));
if (!holder) {
break;
}
uint64_t tstamp = 0;
int r = nestegg_packet_tstamp(holder->mPacket, &tstamp);
if (r == -1) {
break;
}
uint64_t tstamp_usecs = tstamp / NS_PER_USEC;
if (tstamp_usecs >= (uint64_t)aEndTime) {
PushVideoPacket(holder.disown());
return true;
} else {
aOutput.PushFront(holder.disown());
}
}
return false;
}
int64_t WebMReader::GetNextKeyframeTime(int64_t aTimeThreshold)
{
WebMPacketQueue skipPacketQueue;
if (!FilterPacketByTime(aTimeThreshold, skipPacketQueue)) {
// Restore the packets before we return -1.
uint32_t size = skipPacketQueue.GetSize();
for (uint32_t i = 0; i < size; ++i) {
PushVideoPacket(skipPacketQueue.PopFront());
}
return -1;
}
// Find keyframe.
bool foundKeyframe = false;
int64_t keyframeTime = -1;
while (!foundKeyframe) {
nsAutoRef<NesteggPacketHolder> holder(NextPacket(VIDEO));
if (!holder) {
break;
}
unsigned int count = 0;
int r = nestegg_packet_count(holder->mPacket, &count);
if (r == -1) {
break;
}
uint64_t tstamp = 0;
r = nestegg_packet_tstamp(holder->mPacket, &tstamp);
if (r == -1) {
break;
}
uint64_t tstamp_usecs = tstamp / NS_PER_USEC;
for (uint32_t i = 0; i < count; ++i) {
unsigned char* data;
size_t length;
r = nestegg_packet_data(holder->mPacket, i, &data, &length);
if (r == -1) {
foundKeyframe = true;
break;
}
vpx_codec_stream_info_t si;
memset(&si, 0, sizeof(si));
si.sz = sizeof(si);
if (mVideoCodec == NESTEGG_CODEC_VP8) {
vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), data, length, &si);
} else if (mVideoCodec == NESTEGG_CODEC_VP9) {
vpx_codec_peek_stream_info(vpx_codec_vp9_dx(), data, length, &si);
}
if (si.is_kf) {
foundKeyframe = true;
keyframeTime = tstamp_usecs;
break;
}
}
skipPacketQueue.PushFront(holder.disown());
}
uint32_t size = skipPacketQueue.GetSize();
for (uint32_t i = 0; i < size; ++i) {
PushVideoPacket(skipPacketQueue.PopFront());
}
return keyframeTime;
}
bool WebMReader::ShouldSkipVideoFrame(int64_t aTimeThreshold)
{
return GetNextKeyframeTime(aTimeThreshold) != -1;
}
bool WebMReader::DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold)
{
if (!(aKeyframeSkip && ShouldSkipVideoFrame(aTimeThreshold))) {
LOG(PR_LOG_DEBUG, ("Reader [%p]: set the aKeyframeSkip to false.",this));
aKeyframeSkip = false;
}
return mVideoDecoder->DecodeVideoFrame(aKeyframeSkip, aTimeThreshold);
}

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

@ -215,7 +215,15 @@ protected:
// Initializes mLayersBackendType if possible.
void InitLayersBackendType();
bool ShouldSkipVideoFrame(int64_t aTimeThreshold);
private:
// Get the timestamp of keyframe greater than aTimeThreshold.
int64_t GetNextKeyframeTime(int64_t aTimeThreshold);
// Push the packets into aOutput which's timestamp is less than aEndTime.
// Return false if we reach the end of stream or something wrong.
bool FilterPacketByTime(int64_t aEndTime, WebMPacketQueue& aOutput);
// libnestegg context for webm container. Access on state machine thread
// or decoder thread only.
nestegg* mContext;

0
dom/system/NetworkGeolocationProvider.js Executable file → Normal file
Просмотреть файл

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

@ -24,8 +24,7 @@ interface AnimationPlayer {
[SetterThrows, BinaryName="currentTimeAsDouble"]
attribute double? currentTime;
/* Not yet implemented
attribute double playbackRate; */
attribute double playbackRate;
[BinaryName="playStateFromJS"]
readonly attribute AnimationPlayState playState;
[Throws]

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

@ -18,6 +18,7 @@ interface FetchEvent : Event {
readonly attribute boolean isReload;
[Throws] void respondWith(Promise<Response> r);
[Throws] void respondWith(Response r);
};
dictionary FetchEventInit : EventInit {

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

@ -6,6 +6,10 @@
[Global=(WorkerDebugger), Exposed=WorkerDebugger]
interface WorkerDebuggerGlobalScope : EventTarget {
readonly attribute object global;
void postMessage(DOMString message);
attribute EventHandler onmessage;
};
// So you can debug while you debug

0
dom/wifi/WifiWorker.js Executable file → Normal file
Просмотреть файл

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

@ -23,6 +23,8 @@
#include "mozilla/dom/WorkerScope.h"
#include "mozilla/dom/workers/bindings/ServiceWorker.h"
#include "WorkerPrivate.h"
using namespace mozilla::dom;
BEGIN_WORKERS_NAMESPACE
@ -283,6 +285,26 @@ FetchEvent::RespondWith(Promise& aPromise, ErrorResult& aRv)
aPromise.AppendNativeHandler(handler);
}
void
FetchEvent::RespondWith(Response& aResponse, ErrorResult& aRv)
{
if (mWaitToRespond) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(worker);
worker->AssertIsOnWorkerThread();
nsRefPtr<Promise> promise = Promise::Create(worker->GlobalScope(), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
promise->MaybeResolve(&aResponse);
RespondWith(*promise, aRv);
}
already_AddRefed<ServiceWorkerClient>
FetchEvent::GetClient()
{

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

@ -11,6 +11,7 @@
#include "mozilla/dom/FetchEventBinding.h"
#include "mozilla/dom/InstallEventBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/Response.h"
#include "nsProxyRelease.h"
class nsIInterceptedChannel;
@ -83,6 +84,9 @@ public:
void
RespondWith(Promise& aPromise, ErrorResult& aRv);
void
RespondWith(Response& aResponse, ErrorResult& aRv);
already_AddRefed<Promise>
ForwardTo(const nsAString& aUrl);

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

@ -1295,6 +1295,54 @@ private:
}
};
class DebuggerMessageEventRunnable : public WorkerDebuggerRunnable {
nsString mMessage;
public:
DebuggerMessageEventRunnable(WorkerPrivate* aWorkerPrivate,
const nsAString& aMessage)
: WorkerDebuggerRunnable(aWorkerPrivate),
mMessage(aMessage)
{
}
private:
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
{
WorkerDebuggerGlobalScope* globalScope = aWorkerPrivate->DebuggerGlobalScope();
MOZ_ASSERT(globalScope);
JS::Rooted<JSString*> message(aCx, JS_NewUCStringCopyN(aCx, mMessage.get(),
mMessage.Length()));
if (!message) {
return false;
}
JS::Rooted<JS::Value> data(aCx, JS::StringValue(message));
nsRefPtr<MessageEvent> event = new MessageEvent(globalScope, nullptr,
nullptr);
nsresult rv =
event->InitMessageEvent(NS_LITERAL_STRING("message"),
false, // canBubble
true, // cancelable
data,
EmptyString(),
EmptyString(),
nullptr);
if (NS_FAILED(rv)) {
xpc::Throw(aCx, rv);
return false;
}
event->SetTrusted(true);
nsCOMPtr<nsIDOMEvent> domEvent = do_QueryObject(event);
nsEventStatus status = nsEventStatus_eIgnore;
globalScope->DispatchDOMEvent(nullptr, domEvent, nullptr, &status);
return true;
}
};
class NotifyRunnable MOZ_FINAL : public WorkerControlRunnable
{
Status mStatus;
@ -4322,6 +4370,26 @@ WorkerDebugger::Initialize(const nsAString& aURL, JSContext* aCx)
return NS_OK;
}
NS_IMETHODIMP
WorkerDebugger::PostMessageMoz(const nsAString& aMessage, JSContext* aCx)
{
AssertIsOnMainThread();
MutexAutoLock lock(mMutex);
if (!mWorkerPrivate || !mIsInitialized) {
return NS_ERROR_UNEXPECTED;
}
nsRefPtr<DebuggerMessageEventRunnable> runnable =
new DebuggerMessageEventRunnable(mWorkerPrivate, aMessage);
if (!runnable->Dispatch(aCx)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP
WorkerDebugger::AddListener(nsIWorkerDebuggerListener* aListener)
{
@ -4402,6 +4470,35 @@ WorkerDebugger::Disable()
NotifyIsEnabled(false);
}
void
WorkerDebugger::PostMessageToDebugger(const nsAString& aMessage)
{
mWorkerPrivate->AssertIsOnWorkerThread();
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableMethodWithArg<nsString>(this,
&WorkerDebugger::PostMessageToDebuggerOnMainThread, nsString(aMessage));
NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL);
}
void
WorkerDebugger::PostMessageToDebuggerOnMainThread(const nsAString& aMessage)
{
AssertIsOnMainThread();
nsTArray<nsCOMPtr<nsIWorkerDebuggerListener>> listeners;
{
MutexAutoLock lock(mMutex);
listeners.AppendElements(mListeners);
}
for (size_t index = 0; index < listeners.Length(); ++index) {
listeners[index]->OnMessage(aMessage);
}
}
WorkerPrivate::WorkerPrivate(JSContext* aCx,
WorkerPrivate* aParent,
const nsAString& aScriptURL,
@ -6016,6 +6113,12 @@ WorkerPrivate::PostMessageToParentMessagePort(
aMessagePortSerial, aRv);
}
void
WorkerPrivate::PostMessageToDebugger(const nsAString& aMessage)
{
mDebugger->PostMessageToDebugger(aMessage);
}
bool
WorkerPrivate::NotifyInternal(JSContext* aCx, Status aStatus)
{

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

@ -738,18 +738,30 @@ public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIWORKERDEBUGGER
void AssertIsOnParentThread();
void
AssertIsOnParentThread();
void WaitIsEnabled(bool aIsEnabled);
void
WaitIsEnabled(bool aIsEnabled);
void Enable();
void
Enable();
void Disable();
void
Disable();
void
PostMessageToDebugger(const nsAString& aMessage);
private:
virtual ~WorkerDebugger();
virtual
~WorkerDebugger();
void NotifyIsEnabled(bool aIsEnabled);
void
NotifyIsEnabled(bool aIsEnabled);
void
PostMessageToDebuggerOnMainThread(const nsAString& aMessage);
};
class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
@ -950,6 +962,9 @@ public:
const Optional<Sequence<JS::Value>>& aTransferable,
ErrorResult& aRv);
void
PostMessageToDebugger(const nsAString& aMessage);
bool
NotifyInternal(JSContext* aCx, Status aStatus);

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

@ -513,6 +513,12 @@ WorkerDebuggerGlobalScope::GetGlobal(JSContext* aCx,
aGlobal.set(mWorkerPrivate->GetOrCreateGlobalScope(aCx)->GetWrapper());
}
void
WorkerDebuggerGlobalScope::PostMessage(const nsAString& aMessage)
{
mWorkerPrivate->PostMessageToDebugger(aMessage);
}
void
WorkerDebuggerGlobalScope::Dump(JSContext* aCx,
const Optional<nsAString>& aString) const

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

@ -264,6 +264,11 @@ public:
void
GetGlobal(JSContext* aCx, JS::MutableHandle<JSObject*> aGlobal);
void
PostMessage(const nsAString& aMessage);
IMPL_EVENT_HANDLER(message)
void
Dump(JSContext* aCx, const Optional<nsAString>& aString) const;

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

@ -2,13 +2,15 @@
interface nsIDOMWindow;
[scriptable, uuid(54fd2dd3-c01b-4f71-888f-462f37a54f57)]
[scriptable, uuid(ead45621-22a7-48ef-b7db-c4252ae3e6cb)]
interface nsIWorkerDebuggerListener : nsISupports
{
void onClose();
void onMessage(in DOMString message);
};
[scriptable, builtinclass, uuid(b0ea6da8-8bd9-446a-94e2-2ee979903205)]
[scriptable, builtinclass, uuid(28e0a60c-ff10-446c-8c2a-5fbdc01394ea)]
interface nsIWorkerDebugger : nsISupports
{
const unsigned long TYPE_DEDICATED = 0;
@ -30,6 +32,9 @@ interface nsIWorkerDebugger : nsISupports
[implicit_jscontext]
void initialize(in DOMString url);
[implicit_jscontext, binaryname(PostMessageMoz)]
void postMessage(in DOMString message);
void addListener(in nsIWorkerDebuggerListener listener);
void removeListener(in nsIWorkerDebuggerListener listener);

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

@ -0,0 +1,3 @@
"use strict";
self.onmessage = function () {};

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

@ -0,0 +1,9 @@
"use strict"
onmessage = function (event) {
switch (event.data) {
case "ping":
postMessage("pong");
break;
}
};

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

@ -0,0 +1,3 @@
"use strict";
var worker = new Worker("WorkerDebugger.postMessage_childWorker.js");

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