mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central to fx-team
This commit is contained in:
commit
d502aa61ee
@ -12,6 +12,7 @@
|
||||
#include "nsMai.h"
|
||||
#include "nsIAccessibleTypes.h"
|
||||
#include "nsIURI.h"
|
||||
#include "ProxyAccessible.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::a11y;
|
||||
@ -23,15 +24,19 @@ static void
|
||||
getImagePositionCB(AtkImage* aImage, gint* aAccX, gint* aAccY,
|
||||
AtkCoordType aCoordType)
|
||||
{
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aImage));
|
||||
if (!accWrap || !accWrap->IsImage())
|
||||
return;
|
||||
|
||||
ImageAccessible* image = accWrap->AsImage();
|
||||
nsIntPoint pos;
|
||||
uint32_t geckoCoordType = (aCoordType == ATK_XY_WINDOW) ?
|
||||
nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE :
|
||||
nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE;
|
||||
nsIntPoint pos = image->Position(geckoCoordType);
|
||||
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aImage));
|
||||
if (accWrap && accWrap->IsImage()) {
|
||||
ImageAccessible* image = accWrap->AsImage();
|
||||
pos = image->Position(geckoCoordType);
|
||||
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aImage))) {
|
||||
pos = proxy->ImagePosition(geckoCoordType);
|
||||
}
|
||||
|
||||
*aAccX = pos.x;
|
||||
*aAccY = pos.y;
|
||||
}
|
||||
@ -45,11 +50,14 @@ getImageDescriptionCB(AtkImage* aImage)
|
||||
static void
|
||||
getImageSizeCB(AtkImage* aImage, gint* aAccWidth, gint* aAccHeight)
|
||||
{
|
||||
nsIntSize size;
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aImage));
|
||||
if (!accWrap || !accWrap->IsImage())
|
||||
return;
|
||||
if (accWrap && accWrap->IsImage()) {
|
||||
size = accWrap->AsImage()->Size();
|
||||
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aImage))) {
|
||||
size = proxy->ImageSize();
|
||||
}
|
||||
|
||||
nsIntSize size = accWrap->AsImage()->Size();
|
||||
*aAccWidth = size.width;
|
||||
*aAccHeight = size.height;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "ProxyAccessible.h"
|
||||
#include "Relation.h"
|
||||
#include "HyperTextAccessible-inl.h"
|
||||
#include "ImageAccessible.h"
|
||||
#include "nsIPersistentProperties2.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
|
||||
@ -46,19 +47,26 @@ SerializeTree(Accessible* aRoot, nsTArray<AccessibleData>& aTree)
|
||||
}
|
||||
|
||||
Accessible*
|
||||
DocAccessibleChild::IdToAccessible(const uint64_t& aID)
|
||||
DocAccessibleChild::IdToAccessible(const uint64_t& aID) const
|
||||
{
|
||||
return mDoc->GetAccessibleByUniqueID(reinterpret_cast<void*>(aID));
|
||||
}
|
||||
|
||||
HyperTextAccessible*
|
||||
DocAccessibleChild::IdToHyperTextAccessible(const uint64_t& aID)
|
||||
DocAccessibleChild::IdToHyperTextAccessible(const uint64_t& aID) const
|
||||
{
|
||||
Accessible* acc = IdToAccessible(aID);
|
||||
MOZ_ASSERT(!acc || acc->IsHyperText());
|
||||
return acc ? acc->AsHyperText() : nullptr;
|
||||
}
|
||||
|
||||
ImageAccessible*
|
||||
DocAccessibleChild::IdToImageAccessible(const uint64_t& aID) const
|
||||
{
|
||||
Accessible* acc = IdToAccessible(aID);
|
||||
return (acc && acc->IsImage()) ? acc->AsImage() : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
DocAccessibleChild::ShowEvent(AccShowEvent* aShowEvent)
|
||||
{
|
||||
@ -584,5 +592,31 @@ DocAccessibleChild::RecvPasteText(const uint64_t& aID,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvImagePosition(const uint64_t& aID,
|
||||
const uint32_t& aCoordType,
|
||||
nsIntPoint* aRetVal)
|
||||
{
|
||||
ImageAccessible* acc = IdToImageAccessible(aID);
|
||||
if (acc) {
|
||||
*aRetVal = acc->Position(aCoordType);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvImageSize(const uint64_t& aID,
|
||||
nsIntSize* aRetVal)
|
||||
{
|
||||
|
||||
ImageAccessible* acc = IdToImageAccessible(aID);
|
||||
if (acc) {
|
||||
*aRetVal = acc->Size();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ namespace mozilla {
|
||||
namespace a11y {
|
||||
class Accessible;
|
||||
class HyperTextAccessible;
|
||||
class ImageAccessible;
|
||||
|
||||
class AccShowEvent;
|
||||
|
||||
@ -34,9 +35,6 @@ public:
|
||||
MOZ_COUNT_DTOR(DocAccessibleChild);
|
||||
}
|
||||
|
||||
Accessible* IdToAccessible(const uint64_t& aID);
|
||||
HyperTextAccessible* IdToHyperTextAccessible(const uint64_t& aID);
|
||||
|
||||
void ShowEvent(AccShowEvent* aShowEvent);
|
||||
|
||||
/*
|
||||
@ -184,7 +182,19 @@ public:
|
||||
virtual bool RecvPasteText(const uint64_t& aID,
|
||||
const int32_t& aPosition) override;
|
||||
|
||||
virtual bool RecvImagePosition(const uint64_t& aID,
|
||||
const uint32_t& aCoordType,
|
||||
nsIntPoint* aRetVal) override;
|
||||
|
||||
virtual bool RecvImageSize(const uint64_t& aID,
|
||||
nsIntSize* aRetVal) override;
|
||||
|
||||
private:
|
||||
|
||||
Accessible* IdToAccessible(const uint64_t& aID) const;
|
||||
HyperTextAccessible* IdToHyperTextAccessible(const uint64_t& aID) const;
|
||||
ImageAccessible* IdToImageAccessible(const uint64_t& aID) const;
|
||||
|
||||
bool PersistentPropertiesToArray(nsIPersistentProperties* aProps,
|
||||
nsTArray<Attribute>* aAttributes);
|
||||
|
||||
|
@ -8,6 +8,8 @@ include protocol PContent;
|
||||
|
||||
include "mozilla/GfxMessageUtils.h";
|
||||
|
||||
using struct nsIntPoint from "nsRect.h";
|
||||
using struct nsIntSize from "nsRect.h";
|
||||
using struct nsIntRect from "nsRect.h";
|
||||
|
||||
namespace mozilla {
|
||||
@ -121,6 +123,9 @@ child:
|
||||
prio(high) sync CutText(uint64_t aID, int32_t aStartPos, int32_t aEndPos);
|
||||
prio(high) sync DeleteText(uint64_t aID, int32_t aStartPos, int32_t aEndPos);
|
||||
prio(high) sync PasteText(uint64_t aID, int32_t aPosition);
|
||||
|
||||
prio(high) sync ImagePosition(uint64_t aID, uint32_t aCoordType) returns(nsIntPoint aRetVal);
|
||||
prio(high) sync ImageSize(uint64_t aID) returns(nsIntSize aRetVal);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -363,5 +363,21 @@ ProxyAccessible::PasteText(int32_t aPosition)
|
||||
unused << mDoc->SendPasteText(mID, aPosition);
|
||||
}
|
||||
|
||||
nsIntPoint
|
||||
ProxyAccessible::ImagePosition(uint32_t aCoordType)
|
||||
{
|
||||
nsIntPoint retVal;
|
||||
unused << mDoc->SendImagePosition(mID, aCoordType, &retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
nsIntSize
|
||||
ProxyAccessible::ImageSize()
|
||||
{
|
||||
nsIntSize retVal;
|
||||
unused << mDoc->SendImageSize(mID, &retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -177,6 +177,10 @@ public:
|
||||
|
||||
void PasteText(int32_t aPosition);
|
||||
|
||||
nsIntPoint ImagePosition(uint32_t aCoordType);
|
||||
|
||||
nsIntSize ImageSize();
|
||||
|
||||
/**
|
||||
* Allow the platform to store a pointers worth of data on us.
|
||||
*/
|
||||
|
@ -26,6 +26,24 @@ if CONFIG['ACCESSIBILITY']:
|
||||
'../generic',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_ENABLE_GTK']:
|
||||
LOCAL_INCLUDES += [
|
||||
'/accessible/atk',
|
||||
]
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
LOCAL_INCLUDES += [
|
||||
'/accessible/windows/ia2',
|
||||
'/accessible/windows/msaa',
|
||||
]
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
LOCAL_INCLUDES += [
|
||||
'/accessible/mac',
|
||||
]
|
||||
else:
|
||||
LOCAL_INCLUDES += [
|
||||
'/accessible/other',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="9b6f3024e4d0e62dd057231f4b14abe1782932ab"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8eac260ee81a8aca05770d18c5736536d44ee7a7"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9b6f3024e4d0e62dd057231f4b14abe1782932ab"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="8eac260ee81a8aca05770d18c5736536d44ee7a7"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="9b6f3024e4d0e62dd057231f4b14abe1782932ab"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8eac260ee81a8aca05770d18c5736536d44ee7a7"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b685e3aab4fde7624d78993877a8f7910f2a5f06"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="9b6f3024e4d0e62dd057231f4b14abe1782932ab"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8eac260ee81a8aca05770d18c5736536d44ee7a7"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="9b6f3024e4d0e62dd057231f4b14abe1782932ab"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8eac260ee81a8aca05770d18c5736536d44ee7a7"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9b6f3024e4d0e62dd057231f4b14abe1782932ab"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="8eac260ee81a8aca05770d18c5736536d44ee7a7"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="9b6f3024e4d0e62dd057231f4b14abe1782932ab"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8eac260ee81a8aca05770d18c5736536d44ee7a7"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="9b6f3024e4d0e62dd057231f4b14abe1782932ab"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8eac260ee81a8aca05770d18c5736536d44ee7a7"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b685e3aab4fde7624d78993877a8f7910f2a5f06"/>
|
||||
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"git": {
|
||||
"git_revision": "9b6f3024e4d0e62dd057231f4b14abe1782932ab",
|
||||
"git_revision": "8eac260ee81a8aca05770d18c5736536d44ee7a7",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "4c2751f5fc24ffad381aae2c50b160cba0f33d36",
|
||||
"revision": "1400d176ecef76d06b012fb082c246eb17d1d30f",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="9b6f3024e4d0e62dd057231f4b14abe1782932ab"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8eac260ee81a8aca05770d18c5736536d44ee7a7"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b685e3aab4fde7624d78993877a8f7910f2a5f06"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="9b6f3024e4d0e62dd057231f4b14abe1782932ab"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8eac260ee81a8aca05770d18c5736536d44ee7a7"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -315,8 +315,10 @@ function assert_records(expected, desc) {
|
||||
assert_records([{ added: [firstPlayer], changed: [], removed: [] }],
|
||||
"records after transition start");
|
||||
|
||||
// Wait a bit longer for the transition to take effect.
|
||||
// Wait for the AnimationPlayer to get going, then seek well into
|
||||
// the transition.
|
||||
yield await_frame();
|
||||
firstPlayer.currentTime = 50000;
|
||||
|
||||
// Reverse the transition by setting the background-color back to its
|
||||
// original value.
|
||||
@ -328,6 +330,9 @@ function assert_records(expected, desc) {
|
||||
|
||||
var secondPlayer = players[0];
|
||||
|
||||
ok(firstPlayer != secondPlayer,
|
||||
"second AnimationPlayer should be different from the first");
|
||||
|
||||
// Wait for the single MutationRecord for the removal of the original
|
||||
// AnimationPlayer and the addition of the new AnimationPlayer to
|
||||
// be delivered.
|
||||
@ -365,8 +370,10 @@ function assert_records(expected, desc) {
|
||||
assert_records([{ added: players, changed: [], removed: [] }],
|
||||
"records after transition starts");
|
||||
|
||||
// Wait for the AnimationPlayers to get going.
|
||||
// Wait for the AnimationPlayers to get going, then seek well into
|
||||
// the transitions.
|
||||
yield await_frame();
|
||||
players.forEach(p => p.currentTime = 50000);
|
||||
|
||||
is(players.filter(p => p.playState == "running").length, 3, "number of running AnimationPlayers");
|
||||
|
||||
|
60
dom/cache/AutoUtils.cpp
vendored
60
dom/cache/AutoUtils.cpp
vendored
@ -7,6 +7,7 @@
|
||||
#include "mozilla/dom/cache/AutoUtils.h"
|
||||
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/cache/CachePushStreamChild.h"
|
||||
#include "mozilla/dom/cache/CacheStreamControlParent.h"
|
||||
#include "mozilla/dom/cache/ReadStream.h"
|
||||
#include "mozilla/dom/cache/SavedTypes.h"
|
||||
@ -19,6 +20,7 @@
|
||||
namespace {
|
||||
|
||||
using mozilla::unused;
|
||||
using mozilla::dom::cache::CachePushStreamChild;
|
||||
using mozilla::dom::cache::PCacheReadStream;
|
||||
using mozilla::dom::cache::PCacheReadStreamOrVoid;
|
||||
using mozilla::ipc::FileDescriptor;
|
||||
@ -28,8 +30,8 @@ using mozilla::ipc::OptionalFileDescriptorSet;
|
||||
|
||||
enum CleanupAction
|
||||
{
|
||||
ForgetFds,
|
||||
DeleteFds
|
||||
Forget,
|
||||
Delete
|
||||
};
|
||||
|
||||
void
|
||||
@ -46,7 +48,7 @@ CleanupChildFds(PCacheReadStream& aReadStream, CleanupAction aAction)
|
||||
static_cast<FileDescriptorSetChild*>(aReadStream.fds().get_PFileDescriptorSetChild());
|
||||
MOZ_ASSERT(fdSetActor);
|
||||
|
||||
if (aAction == DeleteFds) {
|
||||
if (aAction == Delete) {
|
||||
unused << fdSetActor->Send__delete__(fdSetActor);
|
||||
}
|
||||
|
||||
@ -57,13 +59,39 @@ CleanupChildFds(PCacheReadStream& aReadStream, CleanupAction aAction)
|
||||
}
|
||||
|
||||
void
|
||||
CleanupChildFds(PCacheReadStreamOrVoid& aReadStreamOrVoid, CleanupAction aAction)
|
||||
CleanupChildPushStream(PCacheReadStream& aReadStream, CleanupAction aAction)
|
||||
{
|
||||
if (!aReadStream.pushStreamChild()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto pushStream =
|
||||
static_cast<CachePushStreamChild*>(aReadStream.pushStreamChild());
|
||||
|
||||
if (aAction == Delete) {
|
||||
pushStream->StartDestroy();
|
||||
return;
|
||||
}
|
||||
|
||||
// If we send the stream, then we need to start it before forgetting about it.
|
||||
pushStream->Start();
|
||||
}
|
||||
|
||||
void
|
||||
CleanupChild(PCacheReadStream& aReadStream, CleanupAction aAction)
|
||||
{
|
||||
CleanupChildFds(aReadStream, aAction);
|
||||
CleanupChildPushStream(aReadStream, aAction);
|
||||
}
|
||||
|
||||
void
|
||||
CleanupChild(PCacheReadStreamOrVoid& aReadStreamOrVoid, CleanupAction aAction)
|
||||
{
|
||||
if (aReadStreamOrVoid.type() == PCacheReadStreamOrVoid::Tvoid_t) {
|
||||
return;
|
||||
}
|
||||
|
||||
CleanupChildFds(aReadStreamOrVoid.get_PCacheReadStream(), aAction);
|
||||
CleanupChild(aReadStreamOrVoid.get_PCacheReadStream(), aAction);
|
||||
}
|
||||
|
||||
void
|
||||
@ -80,7 +108,7 @@ CleanupParentFds(PCacheReadStream& aReadStream, CleanupAction aAction)
|
||||
static_cast<FileDescriptorSetParent*>(aReadStream.fds().get_PFileDescriptorSetParent());
|
||||
MOZ_ASSERT(fdSetActor);
|
||||
|
||||
if (aAction == DeleteFds) {
|
||||
if (aAction == Delete) {
|
||||
unused << fdSetActor->Send__delete__(fdSetActor);
|
||||
}
|
||||
|
||||
@ -133,8 +161,8 @@ AutoChildRequest::~AutoChildRequest()
|
||||
return;
|
||||
}
|
||||
|
||||
CleanupAction action = mSent ? ForgetFds : DeleteFds;
|
||||
CleanupChildFds(mRequestOrVoid.get_PCacheRequest().body(), action);
|
||||
CleanupAction action = mSent ? Forget : Delete;
|
||||
CleanupChild(mRequestOrVoid.get_PCacheRequest().body(), action);
|
||||
}
|
||||
|
||||
void
|
||||
@ -173,9 +201,9 @@ AutoChildRequestList::AutoChildRequestList(TypeUtils* aTypeUtils,
|
||||
|
||||
AutoChildRequestList::~AutoChildRequestList()
|
||||
{
|
||||
CleanupAction action = mSent ? ForgetFds : DeleteFds;
|
||||
CleanupAction action = mSent ? Forget : Delete;
|
||||
for (uint32_t i = 0; i < mRequestList.Length(); ++i) {
|
||||
CleanupChildFds(mRequestList[i].body(), action);
|
||||
CleanupChild(mRequestList[i].body(), action);
|
||||
}
|
||||
}
|
||||
|
||||
@ -223,9 +251,9 @@ AutoChildRequestResponse::AutoChildRequestResponse(TypeUtils* aTypeUtils)
|
||||
|
||||
AutoChildRequestResponse::~AutoChildRequestResponse()
|
||||
{
|
||||
CleanupAction action = mSent ? ForgetFds : DeleteFds;
|
||||
CleanupChildFds(mRequestResponse.request().body(), action);
|
||||
CleanupChildFds(mRequestResponse.response().body(), action);
|
||||
CleanupAction action = mSent ? Forget : Delete;
|
||||
CleanupChild(mRequestResponse.request().body(), action);
|
||||
CleanupChild(mRequestResponse.response().body(), action);
|
||||
}
|
||||
|
||||
void
|
||||
@ -311,7 +339,7 @@ AutoParentRequestList::AutoParentRequestList(PBackgroundParent* aManager,
|
||||
|
||||
AutoParentRequestList::~AutoParentRequestList()
|
||||
{
|
||||
CleanupAction action = mSent ? ForgetFds : DeleteFds;
|
||||
CleanupAction action = mSent ? Forget : Delete;
|
||||
for (uint32_t i = 0; i < mRequestList.Length(); ++i) {
|
||||
CleanupParentFds(mRequestList[i].body(), action);
|
||||
}
|
||||
@ -355,7 +383,7 @@ AutoParentResponseList::AutoParentResponseList(PBackgroundParent* aManager,
|
||||
|
||||
AutoParentResponseList::~AutoParentResponseList()
|
||||
{
|
||||
CleanupAction action = mSent ? ForgetFds : DeleteFds;
|
||||
CleanupAction action = mSent ? Forget : Delete;
|
||||
for (uint32_t i = 0; i < mResponseList.Length(); ++i) {
|
||||
CleanupParentFds(mResponseList[i].body(), action);
|
||||
}
|
||||
@ -402,7 +430,7 @@ AutoParentResponseOrVoid::~AutoParentResponseOrVoid()
|
||||
return;
|
||||
}
|
||||
|
||||
CleanupAction action = mSent ? ForgetFds : DeleteFds;
|
||||
CleanupAction action = mSent ? Forget : Delete;
|
||||
CleanupParentFds(mResponseOrVoid.get_PCacheResponse().body(), action);
|
||||
}
|
||||
|
||||
|
13
dom/cache/Cache.cpp
vendored
13
dom/cache/Cache.cpp
vendored
@ -14,6 +14,7 @@
|
||||
#include "mozilla/dom/CacheBinding.h"
|
||||
#include "mozilla/dom/cache/AutoUtils.h"
|
||||
#include "mozilla/dom/cache/CacheChild.h"
|
||||
#include "mozilla/dom/cache/CachePushStreamChild.h"
|
||||
#include "mozilla/dom/cache/ReadStream.h"
|
||||
#include "mozilla/dom/cache/TypeUtils.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
@ -526,6 +527,18 @@ Cache::AssertOwningThread() const
|
||||
}
|
||||
#endif
|
||||
|
||||
CachePushStreamChild*
|
||||
Cache::CreatePushStream(nsIAsyncInputStream* aStream)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(Cache);
|
||||
MOZ_ASSERT(mActor);
|
||||
MOZ_ASSERT(aStream);
|
||||
auto actor = mActor->SendPCachePushStreamConstructor(
|
||||
new CachePushStreamChild(mActor->GetFeature(), aStream));
|
||||
MOZ_ASSERT(actor);
|
||||
return static_cast<CachePushStreamChild*>(actor);
|
||||
}
|
||||
|
||||
void
|
||||
Cache::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
|
||||
{
|
||||
|
7
dom/cache/Cache.h
vendored
7
dom/cache/Cache.h
vendored
@ -39,8 +39,8 @@ class PCacheResponse;
|
||||
class PCacheResponseOrVoid;
|
||||
|
||||
class Cache final : public PromiseNativeHandler
|
||||
, public nsWrapperCache
|
||||
, public TypeUtils
|
||||
, public nsWrapperCache
|
||||
, public TypeUtils
|
||||
{
|
||||
public:
|
||||
Cache(nsIGlobalObject* aGlobal, CacheChild* aActor);
|
||||
@ -97,6 +97,9 @@ public:
|
||||
virtual void AssertOwningThread() const override;
|
||||
#endif
|
||||
|
||||
virtual CachePushStreamChild*
|
||||
CreatePushStream(nsIAsyncInputStream* aStream) override;
|
||||
|
||||
// PromiseNativeHandler methods
|
||||
virtual void
|
||||
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
|
||||
|
15
dom/cache/CacheChild.cpp
vendored
15
dom/cache/CacheChild.cpp
vendored
@ -9,6 +9,7 @@
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/cache/ActorUtils.h"
|
||||
#include "mozilla/dom/cache/Cache.h"
|
||||
#include "mozilla/dom/cache/PCachePushStreamChild.h"
|
||||
#include "mozilla/dom/cache/StreamUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -94,6 +95,20 @@ CacheChild::ActorDestroy(ActorDestroyReason aReason)
|
||||
RemoveFeature();
|
||||
}
|
||||
|
||||
PCachePushStreamChild*
|
||||
CacheChild::AllocPCachePushStreamChild()
|
||||
{
|
||||
MOZ_CRASH("CachePushStreamChild should be manually constructed.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheChild::DeallocPCachePushStreamChild(PCachePushStreamChild* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheChild::RecvMatchResponse(const RequestId& requestId, const nsresult& aRv,
|
||||
const PCacheResponseOrVoid& aResponse)
|
||||
|
8
dom/cache/CacheChild.h
vendored
8
dom/cache/CacheChild.h
vendored
@ -17,7 +17,7 @@ namespace cache {
|
||||
class Cache;
|
||||
|
||||
class CacheChild final : public PCacheChild
|
||||
, public ActorChild
|
||||
, public ActorChild
|
||||
{
|
||||
public:
|
||||
CacheChild();
|
||||
@ -41,6 +41,12 @@ private:
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aReason) override;
|
||||
|
||||
virtual PCachePushStreamChild*
|
||||
AllocPCachePushStreamChild() override;
|
||||
|
||||
virtual bool
|
||||
DeallocPCachePushStreamChild(PCachePushStreamChild* aActor) override;
|
||||
|
||||
virtual bool
|
||||
RecvMatchResponse(const RequestId& requestId, const nsresult& aRv,
|
||||
const PCacheResponseOrVoid& aResponse) override;
|
||||
|
30
dom/cache/CacheParent.cpp
vendored
30
dom/cache/CacheParent.cpp
vendored
@ -8,6 +8,7 @@
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/dom/cache/AutoUtils.h"
|
||||
#include "mozilla/dom/cache/CachePushStreamParent.h"
|
||||
#include "mozilla/dom/cache/CacheStreamControlParent.h"
|
||||
#include "mozilla/dom/cache/ReadStream.h"
|
||||
#include "mozilla/dom/cache/SavedTypes.h"
|
||||
@ -61,6 +62,19 @@ CacheParent::ActorDestroy(ActorDestroyReason aReason)
|
||||
mManager = nullptr;
|
||||
}
|
||||
|
||||
PCachePushStreamParent*
|
||||
CacheParent::AllocPCachePushStreamParent()
|
||||
{
|
||||
return CachePushStreamParent::Create();
|
||||
}
|
||||
|
||||
bool
|
||||
CacheParent::DeallocPCachePushStreamParent(PCachePushStreamParent* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CacheParent::RecvTeardown()
|
||||
{
|
||||
@ -259,13 +273,27 @@ CacheParent::DeserializeCacheStream(const PCacheReadStreamOrVoid& aStreamOrVoid)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
const PCacheReadStream& readStream = aStreamOrVoid.get_PCacheReadStream();
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream = ReadStream::Create(readStream);
|
||||
// Option 1: A push stream actor was sent for nsPipe data
|
||||
if (readStream.pushStreamParent()) {
|
||||
MOZ_ASSERT(!readStream.controlParent());
|
||||
CachePushStreamParent* pushStream =
|
||||
static_cast<CachePushStreamParent*>(readStream.pushStreamParent());
|
||||
stream = pushStream->TakeReader();
|
||||
MOZ_ASSERT(stream);
|
||||
return stream.forget();
|
||||
}
|
||||
|
||||
// Option 2: One of our own ReadStreams was passed back to us with a stream
|
||||
// control actor.
|
||||
stream = ReadStream::Create(readStream);
|
||||
if (stream) {
|
||||
return stream.forget();
|
||||
}
|
||||
|
||||
// Option 3: A stream was serialized using normal methods.
|
||||
nsAutoTArray<FileDescriptor, 4> fds;
|
||||
if (readStream.fds().type() ==
|
||||
OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
|
||||
|
6
dom/cache/CacheParent.h
vendored
6
dom/cache/CacheParent.h
vendored
@ -22,8 +22,8 @@ namespace cache {
|
||||
struct SavedResponse;
|
||||
|
||||
class CacheParent final : public PCacheParent
|
||||
, public Manager::Listener
|
||||
, public FetchPut::Listener
|
||||
, public Manager::Listener
|
||||
, public FetchPut::Listener
|
||||
{
|
||||
public:
|
||||
CacheParent(cache::Manager* aManager, CacheId aCacheId);
|
||||
@ -32,6 +32,8 @@ public:
|
||||
private:
|
||||
// PCacheParent method
|
||||
virtual void ActorDestroy(ActorDestroyReason aReason) override;
|
||||
virtual PCachePushStreamParent* AllocPCachePushStreamParent() override;
|
||||
virtual bool DeallocPCachePushStreamParent(PCachePushStreamParent* aActor) override;
|
||||
virtual bool RecvTeardown() override;
|
||||
virtual bool
|
||||
RecvMatch(const RequestId& aRequestId, const PCacheRequest& aRequest,
|
||||
|
259
dom/cache/CachePushStreamChild.cpp
vendored
Normal file
259
dom/cache/CachePushStreamChild.cpp
vendored
Normal file
@ -0,0 +1,259 @@
|
||||
/* -*- 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/CachePushStreamChild.h"
|
||||
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsICancelableRunnable.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsStreamUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
class CachePushStreamChild::Callback final : public nsIInputStreamCallback
|
||||
, public nsICancelableRunnable
|
||||
{
|
||||
public:
|
||||
explicit Callback(CachePushStreamChild* aActor)
|
||||
: mActor(aActor)
|
||||
, mOwningThread(NS_GetCurrentThread())
|
||||
{
|
||||
MOZ_ASSERT(mActor);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
OnInputStreamReady(nsIAsyncInputStream* aStream) override
|
||||
{
|
||||
// any thread
|
||||
if (mOwningThread == NS_GetCurrentThread()) {
|
||||
return Run();
|
||||
}
|
||||
|
||||
// If this fails, then it means the owning thread is a Worker that has
|
||||
// been shutdown. Its ok to lose the event in this case because the
|
||||
// CachePushStreamChild listens for this event through the Feature.
|
||||
nsresult rv = mOwningThread->Dispatch(this, nsIThread::DISPATCH_NORMAL);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to dispatch stream readable event to owning thread");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
MOZ_ASSERT(mOwningThread == NS_GetCurrentThread());
|
||||
if (mActor) {
|
||||
mActor->OnStreamReady(this);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Cancel() override
|
||||
{
|
||||
// Cancel() gets called when the Worker thread is being shutdown. We have
|
||||
// nothing to do here because CachePushStreamChild handles this case via
|
||||
// the Feature.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ClearActor()
|
||||
{
|
||||
MOZ_ASSERT(mOwningThread == NS_GetCurrentThread());
|
||||
MOZ_ASSERT(mActor);
|
||||
mActor = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
~Callback()
|
||||
{
|
||||
// called on any thread
|
||||
|
||||
// ClearActor() should be called before the Callback is destroyed
|
||||
MOZ_ASSERT(!mActor);
|
||||
}
|
||||
|
||||
CachePushStreamChild* mActor;
|
||||
nsCOMPtr<nsIThread> mOwningThread;
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(CachePushStreamChild::Callback, nsIInputStreamCallback,
|
||||
nsIRunnable,
|
||||
nsICancelableRunnable);
|
||||
|
||||
CachePushStreamChild::CachePushStreamChild(Feature* aFeature,
|
||||
nsIAsyncInputStream* aStream)
|
||||
: mStream(aStream)
|
||||
, mClosed(false)
|
||||
{
|
||||
MOZ_ASSERT(mStream);
|
||||
MOZ_ASSERT_IF(!NS_IsMainThread(), aFeature);
|
||||
SetFeature(aFeature);
|
||||
}
|
||||
|
||||
CachePushStreamChild::~CachePushStreamChild()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CachePushStreamChild);
|
||||
MOZ_ASSERT(mClosed);
|
||||
MOZ_ASSERT(!mCallback);
|
||||
}
|
||||
|
||||
void
|
||||
CachePushStreamChild::Start()
|
||||
{
|
||||
DoRead();
|
||||
}
|
||||
|
||||
void
|
||||
CachePushStreamChild::StartDestroy()
|
||||
{
|
||||
// called if we are running on a Worker and the thread gets shutdown
|
||||
OnEnd(NS_ERROR_ABORT);
|
||||
}
|
||||
|
||||
void
|
||||
CachePushStreamChild::ActorDestroy(ActorDestroyReason aReason)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CachePushStreamChild);
|
||||
|
||||
// If the parent side runs into a problem then the actor will be destroyed.
|
||||
// In this case we have not run OnEnd(), so still need to close the input
|
||||
// stream.
|
||||
if (!mClosed) {
|
||||
mStream->CloseWithStatus(NS_ERROR_ABORT);
|
||||
mClosed = true;
|
||||
}
|
||||
|
||||
if (mCallback) {
|
||||
mCallback->ClearActor();
|
||||
mCallback = nullptr;
|
||||
}
|
||||
|
||||
RemoveFeature();
|
||||
}
|
||||
|
||||
void
|
||||
CachePushStreamChild::DoRead()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CachePushStreamChild);
|
||||
MOZ_ASSERT(!mClosed);
|
||||
MOZ_ASSERT(!mCallback);
|
||||
|
||||
// The input stream (likely a pipe) probably uses a segment size of
|
||||
// 4kb. If there is data already buffered it would be nice to aggregate
|
||||
// multiple segments into a single IPC call. Conversely, don't send too
|
||||
// too large of a buffer in a single call to avoid spiking memory.
|
||||
static const uint64_t kMaxBytesPerMessage = 32 * 1024;
|
||||
static_assert(kMaxBytesPerMessage <= static_cast<uint64_t>(UINT32_MAX),
|
||||
"kMaxBytesPerMessage must cleanly cast to uint32_t");
|
||||
|
||||
while (!mClosed) {
|
||||
// Use non-auto here as we're unlikely to hit stack storage with the
|
||||
// sizes we are sending. Also, it would be nice to avoid another copy
|
||||
// to the IPC layer which we avoid if we use COW strings. Unfortunately
|
||||
// IPC does not seem to support passing dependent storage types.
|
||||
nsCString buffer;
|
||||
|
||||
uint64_t available = 0;
|
||||
nsresult rv = mStream->Available(&available);
|
||||
if (NS_FAILED(rv)) {
|
||||
OnEnd(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
if (available == 0) {
|
||||
Wait();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t expectedBytes =
|
||||
static_cast<uint32_t>(std::min(available, kMaxBytesPerMessage));
|
||||
|
||||
buffer.SetLength(expectedBytes);
|
||||
|
||||
uint32_t bytesRead = 0;
|
||||
rv = mStream->Read(buffer.BeginWriting(), buffer.Length(), &bytesRead);
|
||||
buffer.SetLength(bytesRead);
|
||||
|
||||
// If we read any data from the stream, send it across.
|
||||
if (!buffer.IsEmpty()) {
|
||||
unused << SendBuffer(buffer);
|
||||
}
|
||||
|
||||
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
|
||||
Wait();
|
||||
return;
|
||||
}
|
||||
|
||||
// Any other error or zero-byte read indicates end-of-stream
|
||||
if (NS_FAILED(rv) || buffer.IsEmpty()) {
|
||||
OnEnd(rv);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CachePushStreamChild::Wait()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CachePushStreamChild);
|
||||
MOZ_ASSERT(!mClosed);
|
||||
MOZ_ASSERT(!mCallback);
|
||||
|
||||
// Set mCallback immediately instead of waiting for success. Its possible
|
||||
// AsyncWait() will callback synchronously.
|
||||
mCallback = new Callback(this);
|
||||
nsresult rv = mStream->AsyncWait(mCallback, 0, 0, nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
OnEnd(rv);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CachePushStreamChild::OnStreamReady(Callback* aCallback)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CachePushStreamChild);
|
||||
MOZ_ASSERT(mCallback);
|
||||
MOZ_ASSERT(aCallback == mCallback);
|
||||
mCallback->ClearActor();
|
||||
mCallback = nullptr;
|
||||
DoRead();
|
||||
}
|
||||
|
||||
void
|
||||
CachePushStreamChild::OnEnd(nsresult aRv)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CachePushStreamChild);
|
||||
MOZ_ASSERT(aRv != NS_BASE_STREAM_WOULD_BLOCK);
|
||||
|
||||
if (mClosed) {
|
||||
return;
|
||||
}
|
||||
|
||||
mClosed = true;
|
||||
|
||||
mStream->CloseWithStatus(aRv);
|
||||
|
||||
if (aRv == NS_BASE_STREAM_CLOSED) {
|
||||
aRv = NS_OK;
|
||||
}
|
||||
|
||||
// This will trigger an ActorDestroy() from the parent side
|
||||
unused << SendClose(aRv);
|
||||
}
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
57
dom/cache/CachePushStreamChild.h
vendored
Normal file
57
dom/cache/CachePushStreamChild.h
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
/* -*- 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_CachePushStreamChild_h
|
||||
#define mozilla_dom_cache_CachePushStreamChild_h
|
||||
|
||||
#include "mozilla/dom/cache/ActorChild.h"
|
||||
#include "mozilla/dom/cache/PCachePushStreamChild.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsIAsyncInputStream;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
class CachePushStreamChild final : public PCachePushStreamChild
|
||||
, public ActorChild
|
||||
{
|
||||
public:
|
||||
CachePushStreamChild(Feature* aFeature, nsIAsyncInputStream* aStream);
|
||||
~CachePushStreamChild();
|
||||
|
||||
virtual void StartDestroy() override;
|
||||
|
||||
void Start();
|
||||
|
||||
private:
|
||||
class Callback;
|
||||
|
||||
// PCachePushStreamChild methods
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aReason) override;
|
||||
|
||||
void DoRead();
|
||||
|
||||
void Wait();
|
||||
|
||||
void OnStreamReady(Callback* aCallback);
|
||||
|
||||
void OnEnd(nsresult aRv);
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> mStream;
|
||||
nsRefPtr<Callback> mCallback;
|
||||
bool mClosed;
|
||||
|
||||
NS_DECL_OWNINGTHREAD
|
||||
};
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_cache_CachePushStreamChild_h
|
97
dom/cache/CachePushStreamParent.cpp
vendored
Normal file
97
dom/cache/CachePushStreamParent.cpp
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
/* -*- 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/CachePushStreamParent.h"
|
||||
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIAsyncOutputStream.h"
|
||||
#include "nsIPipe.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
// static
|
||||
CachePushStreamParent*
|
||||
CachePushStreamParent::Create()
|
||||
{
|
||||
// use async versions for both reader and writer even though we are
|
||||
// opening the writer as an infinite stream. We want to be able to
|
||||
// use CloseWithStatus() to communicate errors through the pipe.
|
||||
nsCOMPtr<nsIAsyncInputStream> reader;
|
||||
nsCOMPtr<nsIAsyncOutputStream> writer;
|
||||
|
||||
// Use an "infinite" pipe because we cannot apply back-pressure through
|
||||
// the async IPC layer at the moment. Blocking the IPC worker thread
|
||||
// is not desirable, either.
|
||||
nsresult rv = NS_NewPipe2(getter_AddRefs(reader),
|
||||
getter_AddRefs(writer),
|
||||
true, true, // non-blocking
|
||||
0, // segment size
|
||||
UINT32_MAX); // "infinite" pipe
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new CachePushStreamParent(reader, writer);
|
||||
}
|
||||
|
||||
CachePushStreamParent::~CachePushStreamParent()
|
||||
{
|
||||
}
|
||||
|
||||
already_AddRefed<nsIInputStream>
|
||||
CachePushStreamParent::TakeReader()
|
||||
{
|
||||
MOZ_ASSERT(mReader);
|
||||
return mReader.forget();
|
||||
}
|
||||
|
||||
void
|
||||
CachePushStreamParent::ActorDestroy(ActorDestroyReason aReason)
|
||||
{
|
||||
// If we were gracefully closed we should have gotten RecvClose(). In
|
||||
// that case, the writer will already be closed and this will have no
|
||||
// effect. This just aborts the writer in the case where the child process
|
||||
// crashes.
|
||||
mWriter->CloseWithStatus(NS_ERROR_ABORT);
|
||||
}
|
||||
|
||||
bool
|
||||
CachePushStreamParent::RecvBuffer(const nsCString& aBuffer)
|
||||
{
|
||||
uint32_t numWritten = 0;
|
||||
|
||||
// This should only fail if we hit an OOM condition.
|
||||
nsresult rv = mWriter->Write(aBuffer.get(), aBuffer.Length(), &numWritten);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
RecvClose(rv);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CachePushStreamParent::RecvClose(const nsresult& aRv)
|
||||
{
|
||||
mWriter->CloseWithStatus(aRv);
|
||||
unused << Send__delete__(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
CachePushStreamParent::CachePushStreamParent(nsIAsyncInputStream* aReader,
|
||||
nsIAsyncOutputStream* aWriter)
|
||||
: mReader(aReader)
|
||||
, mWriter(aWriter)
|
||||
{
|
||||
MOZ_ASSERT(mReader);
|
||||
MOZ_ASSERT(mWriter);
|
||||
}
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
55
dom/cache/CachePushStreamParent.h
vendored
Normal file
55
dom/cache/CachePushStreamParent.h
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
/* -*- 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_CachePushStreamParent_h
|
||||
#define mozilla_dom_cache_CachePushStreamParent_h
|
||||
|
||||
#include "mozilla/dom/cache/PCachePushStreamParent.h"
|
||||
|
||||
class nsIAsyncInputStream;
|
||||
class nsIAsyncOutputStream;
|
||||
class nsIInputStream;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
class CachePushStreamParent final : public PCachePushStreamParent
|
||||
{
|
||||
public:
|
||||
static CachePushStreamParent*
|
||||
Create();
|
||||
|
||||
~CachePushStreamParent();
|
||||
|
||||
already_AddRefed<nsIInputStream>
|
||||
TakeReader();
|
||||
|
||||
private:
|
||||
CachePushStreamParent(nsIAsyncInputStream* aReader,
|
||||
nsIAsyncOutputStream* aWriter);
|
||||
|
||||
// PCachePushStreamParent methods
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aReason) override;
|
||||
|
||||
virtual bool
|
||||
RecvBuffer(const nsCString& aBuffer) override;
|
||||
|
||||
virtual bool
|
||||
RecvClose(const nsresult& aRv) override;
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> mReader;
|
||||
nsCOMPtr<nsIAsyncOutputStream> mWriter;
|
||||
|
||||
NS_DECL_OWNINGTHREAD
|
||||
};
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_cache_CachePushStreamParent_h
|
7
dom/cache/CacheStorage.cpp
vendored
7
dom/cache/CacheStorage.cpp
vendored
@ -516,6 +516,13 @@ CacheStorage::AssertOwningThread() const
|
||||
}
|
||||
#endif
|
||||
|
||||
CachePushStreamChild*
|
||||
CacheStorage::CreatePushStream(nsIAsyncInputStream* aStream)
|
||||
{
|
||||
// This is true because CacheStorage always uses IgnoreBody for requests.
|
||||
MOZ_CRASH("CacheStorage should never create a push stream.");
|
||||
}
|
||||
|
||||
void
|
||||
CacheStorage::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
|
||||
{
|
||||
|
9
dom/cache/CacheStorage.h
vendored
9
dom/cache/CacheStorage.h
vendored
@ -44,9 +44,9 @@ class Feature;
|
||||
class PCacheResponseOrVoid;
|
||||
|
||||
class CacheStorage final : public nsIIPCBackgroundChildCreateCallback
|
||||
, public nsWrapperCache
|
||||
, public TypeUtils
|
||||
, public PromiseNativeHandler
|
||||
, public nsWrapperCache
|
||||
, public TypeUtils
|
||||
, public PromiseNativeHandler
|
||||
{
|
||||
typedef mozilla::ipc::PBackgroundChild PBackgroundChild;
|
||||
|
||||
@ -97,6 +97,9 @@ public:
|
||||
virtual void AssertOwningThread() const override;
|
||||
#endif
|
||||
|
||||
virtual CachePushStreamChild*
|
||||
CreatePushStream(nsIAsyncInputStream* aStream) override;
|
||||
|
||||
// PromiseNativeHandler methods
|
||||
virtual void
|
||||
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
|
||||
|
3
dom/cache/CacheStorageChild.h
vendored
3
dom/cache/CacheStorageChild.h
vendored
@ -20,7 +20,7 @@ class PCacheChild;
|
||||
class Feature;
|
||||
|
||||
class CacheStorageChild final : public PCacheStorageChild
|
||||
, public ActorChild
|
||||
, public ActorChild
|
||||
{
|
||||
public:
|
||||
CacheStorageChild(CacheStorage* aListener, Feature* aFeature);
|
||||
@ -41,6 +41,7 @@ public:
|
||||
private:
|
||||
// PCacheStorageChild methods
|
||||
virtual void ActorDestroy(ActorDestroyReason aReason) override;
|
||||
|
||||
virtual bool RecvMatchResponse(const RequestId& aRequestId,
|
||||
const nsresult& aRv,
|
||||
const PCacheResponseOrVoid& response) override;
|
||||
|
4
dom/cache/CacheStorageParent.h
vendored
4
dom/cache/CacheStorageParent.h
vendored
@ -23,8 +23,8 @@ class CacheStreamControlParent;
|
||||
class ManagerId;
|
||||
|
||||
class CacheStorageParent final : public PCacheStorageParent
|
||||
, public PrincipalVerifier::Listener
|
||||
, public Manager::Listener
|
||||
, public PrincipalVerifier::Listener
|
||||
, public Manager::Listener
|
||||
{
|
||||
public:
|
||||
CacheStorageParent(PBackgroundParent* aManagingActor, Namespace aNamespace,
|
||||
|
4
dom/cache/CacheStreamControlChild.h
vendored
4
dom/cache/CacheStreamControlChild.h
vendored
@ -19,8 +19,8 @@ namespace cache {
|
||||
class ReadStream;
|
||||
|
||||
class CacheStreamControlChild final : public PCacheStreamControlChild
|
||||
, public StreamControl
|
||||
, public ActorChild
|
||||
, public StreamControl
|
||||
, public ActorChild
|
||||
{
|
||||
public:
|
||||
CacheStreamControlChild();
|
||||
|
4
dom/cache/CacheStreamControlParent.h
vendored
4
dom/cache/CacheStreamControlParent.h
vendored
@ -18,8 +18,8 @@ namespace cache {
|
||||
class ReadStream;
|
||||
class StreamList;
|
||||
|
||||
class CacheStreamControlParent : public PCacheStreamControlParent
|
||||
, public StreamControl
|
||||
class CacheStreamControlParent final : public PCacheStreamControlParent
|
||||
, public StreamControl
|
||||
{
|
||||
public:
|
||||
CacheStreamControlParent();
|
||||
|
2
dom/cache/Context.cpp
vendored
2
dom/cache/Context.cpp
vendored
@ -320,7 +320,7 @@ Context::QuotaInitRunnable::Run()
|
||||
// runnable executes the Action on the appropriate threads while the Context
|
||||
// is initialized.
|
||||
class Context::ActionRunnable final : public nsIRunnable
|
||||
, public Action::Resolver
|
||||
, public Action::Resolver
|
||||
{
|
||||
public:
|
||||
ActionRunnable(Context* aContext, nsIEventTarget* aTarget, Action* aAction,
|
||||
|
6
dom/cache/FetchPut.cpp
vendored
6
dom/cache/FetchPut.cpp
vendored
@ -458,6 +458,12 @@ FetchPut::AssertOwningThread() const
|
||||
}
|
||||
#endif
|
||||
|
||||
CachePushStreamChild*
|
||||
FetchPut::CreatePushStream(nsIAsyncInputStream* aStream)
|
||||
{
|
||||
MOZ_CRASH("FetchPut should never create a push stream!");
|
||||
}
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
5
dom/cache/FetchPut.h
vendored
5
dom/cache/FetchPut.h
vendored
@ -30,7 +30,7 @@ class Response;
|
||||
namespace cache {
|
||||
|
||||
class FetchPut final : public Manager::Listener
|
||||
, public TypeUtils
|
||||
, public TypeUtils
|
||||
{
|
||||
public:
|
||||
typedef std::pair<nsRefPtr<Request>, nsRefPtr<Response>> PutPair;
|
||||
@ -94,6 +94,9 @@ private:
|
||||
virtual void AssertOwningThread() const override;
|
||||
#endif
|
||||
|
||||
virtual CachePushStreamChild*
|
||||
CreatePushStream(nsIAsyncInputStream* aStream) override;
|
||||
|
||||
Listener* mListener;
|
||||
nsRefPtr<Manager> mManager;
|
||||
const RequestId mRequestId;
|
||||
|
3
dom/cache/PCache.ipdl
vendored
3
dom/cache/PCache.ipdl
vendored
@ -3,6 +3,7 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PBackground;
|
||||
include protocol PCachePushStream;
|
||||
include PCacheTypes;
|
||||
include protocol PFileDescriptorSet;
|
||||
|
||||
@ -19,8 +20,10 @@ namespace cache {
|
||||
protocol PCache
|
||||
{
|
||||
manager PBackground;
|
||||
manages PCachePushStream;
|
||||
|
||||
parent:
|
||||
PCachePushStream();
|
||||
Teardown();
|
||||
Match(RequestId requestId, PCacheRequest request, PCacheQueryParams params);
|
||||
MatchAll(RequestId requestId, PCacheRequestOrVoid request, PCacheQueryParams params);
|
||||
|
28
dom/cache/PCachePushStream.ipdl
vendored
Normal file
28
dom/cache/PCachePushStream.ipdl
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
/* 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 protocol PCache;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
protocol PCachePushStream
|
||||
{
|
||||
manager PCache;
|
||||
|
||||
parent:
|
||||
Buffer(nsCString aBuffer);
|
||||
Close(nsresult aRv);
|
||||
|
||||
child:
|
||||
// Stream is always destroyed from the parent side. This occurs if the
|
||||
// parent encounters an error while writing to its pipe or if the child
|
||||
// signals the stream should close by SendClose().
|
||||
__delete__();
|
||||
};
|
||||
|
||||
} // namespace cache
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
2
dom/cache/PCacheTypes.ipdlh
vendored
2
dom/cache/PCacheTypes.ipdlh
vendored
@ -2,6 +2,7 @@
|
||||
* 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 protocol PCachePushStream;
|
||||
include protocol PCacheStreamControl;
|
||||
include PHeaders;
|
||||
include InputStreamParams;
|
||||
@ -32,6 +33,7 @@ struct PCacheReadStream
|
||||
OptionalInputStreamParams params;
|
||||
OptionalFileDescriptorSet fds;
|
||||
nullable PCacheStreamControl control;
|
||||
nullable PCachePushStream pushStream;
|
||||
};
|
||||
|
||||
union PCacheReadStreamOrVoid
|
||||
|
8
dom/cache/ReadStream.cpp
vendored
8
dom/cache/ReadStream.cpp
vendored
@ -210,6 +210,11 @@ ReadStream::Inner::Serialize(PCacheReadStream* aReadStreamOut)
|
||||
MOZ_ASSERT(mState == Open);
|
||||
MOZ_ASSERT(mControl);
|
||||
|
||||
// If we are sending a ReadStream, then we never want to set the
|
||||
// pushStream actors at the same time.
|
||||
aReadStreamOut->pushStreamChild() = nullptr;
|
||||
aReadStreamOut->pushStreamParent() = nullptr;
|
||||
|
||||
aReadStreamOut->id() = mId;
|
||||
mControl->SerializeControl(aReadStreamOut);
|
||||
|
||||
@ -406,6 +411,9 @@ ReadStream::Create(const PCacheReadStream& aReadStream)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!aReadStream.pushStreamChild());
|
||||
MOZ_ASSERT(!aReadStream.pushStreamParent());
|
||||
|
||||
// Control is guaranteed to survive this method as ActorDestroy() cannot
|
||||
// run on this thread until we complete.
|
||||
StreamControl* control;
|
||||
|
2
dom/cache/StreamList.h
vendored
2
dom/cache/StreamList.h
vendored
@ -21,7 +21,7 @@ class CacheStreamControlParent;
|
||||
class Context;
|
||||
class Manager;
|
||||
|
||||
class StreamList
|
||||
class StreamList final
|
||||
{
|
||||
public:
|
||||
StreamList(Manager* aManager, Context* aContext);
|
||||
|
106
dom/cache/TypeUtils.cpp
vendored
106
dom/cache/TypeUtils.cpp
vendored
@ -11,6 +11,7 @@
|
||||
#include "mozilla/dom/InternalRequest.h"
|
||||
#include "mozilla/dom/Request.h"
|
||||
#include "mozilla/dom/Response.h"
|
||||
#include "mozilla/dom/cache/CachePushStreamChild.h"
|
||||
#include "mozilla/dom/cache/PCacheTypes.h"
|
||||
#include "mozilla/dom/cache/ReadStream.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
@ -29,6 +30,13 @@
|
||||
namespace {
|
||||
|
||||
using mozilla::ErrorResult;
|
||||
using mozilla::unused;
|
||||
using mozilla::void_t;
|
||||
using mozilla::dom::cache::PCacheReadStream;
|
||||
using mozilla::ipc::BackgroundChild;
|
||||
using mozilla::ipc::FileDescriptor;
|
||||
using mozilla::ipc::PBackgroundChild;
|
||||
using mozilla::ipc::PFileDescriptorSetChild;
|
||||
|
||||
// Utility function to remove the fragment from a URL, check its scheme, and optionally
|
||||
// provide a URL without the query. We're not using nsIURL or URL to do this because
|
||||
@ -96,6 +104,31 @@ ProcessURL(nsAString& aUrl, bool* aSchemeValidOut,
|
||||
*aUrlWithoutQueryOut = Substring(aUrl, 0, queryPos - 1);
|
||||
}
|
||||
|
||||
void
|
||||
SerializeNormalStream(nsIInputStream* aStream, PCacheReadStream& aReadStreamOut)
|
||||
{
|
||||
nsAutoTArray<FileDescriptor, 4> fds;
|
||||
SerializeInputStream(aStream, aReadStreamOut.params(), fds);
|
||||
|
||||
PFileDescriptorSetChild* fdSet = nullptr;
|
||||
if (!fds.IsEmpty()) {
|
||||
// We should not be serializing until we have an actor ready
|
||||
PBackgroundChild* manager = BackgroundChild::GetForCurrentThread();
|
||||
MOZ_ASSERT(manager);
|
||||
|
||||
fdSet = 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();
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace mozilla {
|
||||
@ -413,64 +446,61 @@ TypeUtils::SerializeCacheStream(nsIInputStream* aStream,
|
||||
return;
|
||||
}
|
||||
|
||||
// Option 1: Send a cache-specific ReadStream if we can.
|
||||
nsRefPtr<ReadStream> controlled = do_QueryObject(aStream);
|
||||
if (controlled) {
|
||||
controlled->Serialize(aStreamOut);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: implement CrossProcessPipe if we cannot directly serialize (bug 1110814)
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> serial = do_QueryInterface(aStream);
|
||||
if (!serial) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
PCacheReadStream readStream;
|
||||
readStream.controlChild() = nullptr;
|
||||
readStream.controlParent() = nullptr;
|
||||
readStream.pushStreamChild() = nullptr;
|
||||
readStream.pushStreamParent() = nullptr;
|
||||
|
||||
nsAutoTArray<FileDescriptor, 4> fds;
|
||||
SerializeInputStream(aStream, readStream.params(), fds);
|
||||
// Option 2: Do normal stream serialization if its supported.
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> serial = do_QueryInterface(aStream);
|
||||
if (serial) {
|
||||
SerializeNormalStream(aStream, readStream);
|
||||
|
||||
PFileDescriptorSetChild* fdSet = nullptr;
|
||||
if (!fds.IsEmpty()) {
|
||||
// We should not be serializing until we have an actor ready
|
||||
PBackgroundChild* manager = BackgroundChild::GetForCurrentThread();
|
||||
MOZ_ASSERT(manager);
|
||||
|
||||
fdSet = manager->SendPFileDescriptorSetConstructor(fds[0]);
|
||||
for (uint32_t i = 1; i < fds.Length(); ++i) {
|
||||
unused << fdSet->SendAddFileDescriptor(fds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (fdSet) {
|
||||
readStream.fds() = fdSet;
|
||||
// Option 3: As a last resort push data across manually. Should only be
|
||||
// needed for nsPipe input stream. Only works for async,
|
||||
// non-blocking streams.
|
||||
} else {
|
||||
readStream.fds() = void_t();
|
||||
SerializePushStream(aStream, readStream, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) { return; }
|
||||
}
|
||||
|
||||
*aStreamOut = readStream;
|
||||
}
|
||||
|
||||
nsIThread*
|
||||
TypeUtils::GetStreamThread()
|
||||
void
|
||||
TypeUtils::SerializePushStream(nsIInputStream* aStream,
|
||||
PCacheReadStream& aReadStreamOut,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertOwningThread();
|
||||
|
||||
if (!mStreamThread) {
|
||||
// Named threads only allow 16 bytes for their names. Try to make
|
||||
// it meaningful...
|
||||
// TODO: use a thread pool or singleton thread here (bug 1119864)
|
||||
nsresult rv = NS_NewNamedThread("DOMCacheTypeU",
|
||||
getter_AddRefs(mStreamThread));
|
||||
if (NS_FAILED(rv) || !mStreamThread) {
|
||||
MOZ_CRASH("Failed to create DOM Cache serialization thread.");
|
||||
}
|
||||
nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(aStream);
|
||||
if (NS_WARN_IF(!asyncStream)) {
|
||||
aRv = NS_ERROR_FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
return mStreamThread;
|
||||
bool nonBlocking = false;
|
||||
aRv = asyncStream->IsNonBlocking(&nonBlocking);
|
||||
if (NS_WARN_IF(aRv.Failed())) { return; }
|
||||
if (NS_WARN_IF(!nonBlocking)) {
|
||||
aRv = NS_ERROR_FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
aReadStreamOut.pushStreamChild() = CreatePushStream(asyncStream);
|
||||
MOZ_ASSERT(aReadStreamOut.pushStreamChild());
|
||||
aReadStreamOut.params() = void_t();
|
||||
aReadStreamOut.fds() = void_t();
|
||||
|
||||
// CachePushStreamChild::Start() must be called after sending the stream
|
||||
// across to the parent side.
|
||||
}
|
||||
|
||||
} // namespace cache
|
||||
|
13
dom/cache/TypeUtils.h
vendored
13
dom/cache/TypeUtils.h
vendored
@ -9,10 +9,10 @@
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsError.h"
|
||||
|
||||
class nsIGlobalObject;
|
||||
class nsIAsyncInputStream;
|
||||
class nsIInputStream;
|
||||
|
||||
namespace mozilla {
|
||||
@ -28,7 +28,9 @@ class Response;
|
||||
|
||||
namespace cache {
|
||||
|
||||
class CachePushStreamChild;
|
||||
class PCacheQueryParams;
|
||||
class PCacheReadStream;
|
||||
class PCacheReadStreamOrVoid;
|
||||
class PCacheRequest;
|
||||
class PCacheResponse;
|
||||
@ -63,6 +65,9 @@ public:
|
||||
inline void AssertOwningThread() const { }
|
||||
#endif
|
||||
|
||||
virtual CachePushStreamChild*
|
||||
CreatePushStream(nsIAsyncInputStream* aStream) = 0;
|
||||
|
||||
already_AddRefed<InternalRequest>
|
||||
ToInternalRequest(const RequestOrUSVString& aIn, BodyAction aBodyAction,
|
||||
ErrorResult& aRv);
|
||||
@ -107,9 +112,9 @@ private:
|
||||
SerializeCacheStream(nsIInputStream* aStream, PCacheReadStreamOrVoid* aStreamOut,
|
||||
ErrorResult& aRv);
|
||||
|
||||
nsIThread* GetStreamThread();
|
||||
|
||||
nsCOMPtr<nsIThread> mStreamThread;
|
||||
void
|
||||
SerializePushStream(nsIInputStream* aStream, PCacheReadStream& aReadStreamOut,
|
||||
ErrorResult& aRv);
|
||||
};
|
||||
|
||||
} // namespace cache
|
||||
|
5
dom/cache/moz.build
vendored
5
dom/cache/moz.build
vendored
@ -12,6 +12,8 @@ EXPORTS.mozilla.dom.cache += [
|
||||
'Cache.h',
|
||||
'CacheChild.h',
|
||||
'CacheParent.h',
|
||||
'CachePushStreamChild.h',
|
||||
'CachePushStreamParent.h',
|
||||
'CacheStorage.h',
|
||||
'CacheStorageChild.h',
|
||||
'CacheStorageParent.h',
|
||||
@ -44,6 +46,8 @@ UNIFIED_SOURCES += [
|
||||
'Cache.cpp',
|
||||
'CacheChild.cpp',
|
||||
'CacheParent.cpp',
|
||||
'CachePushStreamChild.cpp',
|
||||
'CachePushStreamParent.cpp',
|
||||
'CacheStorage.cpp',
|
||||
'CacheStorageChild.cpp',
|
||||
'CacheStorageParent.cpp',
|
||||
@ -69,6 +73,7 @@ UNIFIED_SOURCES += [
|
||||
IPDL_SOURCES += [
|
||||
'CacheInitData.ipdlh',
|
||||
'PCache.ipdl',
|
||||
'PCachePushStream.ipdl',
|
||||
'PCacheStorage.ipdl',
|
||||
'PCacheStreamControl.ipdl',
|
||||
'PCacheTypes.ipdlh',
|
||||
|
2
dom/cache/test/mochitest/mochitest.ini
vendored
2
dom/cache/test/mochitest/mochitest.ini
vendored
@ -16,6 +16,7 @@ support-files =
|
||||
vary.sjs
|
||||
test_caches.js
|
||||
test_cache_keys.js
|
||||
test_cache_put.js
|
||||
|
||||
[test_cache.html]
|
||||
[test_cache_add.html]
|
||||
@ -25,3 +26,4 @@ support-files =
|
||||
[test_cache_match_vary.html]
|
||||
[test_caches.html]
|
||||
[test_cache_keys.html]
|
||||
[test_cache_put.html]
|
||||
|
20
dom/cache/test/mochitest/test_cache_put.html
vendored
Normal file
20
dom/cache/test/mochitest/test_cache_put.html
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Validate Interfaces Exposed to Workers</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="text/javascript" src="driver.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<iframe id="frame"></iframe>
|
||||
<script class="testbody" type="text/javascript">
|
||||
runTests("test_cache_put.js")
|
||||
.then(function() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
26
dom/cache/test/mochitest/test_cache_put.js
vendored
Normal file
26
dom/cache/test/mochitest/test_cache_put.js
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
var url = 'test_cache.js';
|
||||
var cache;
|
||||
var fetchResponse;
|
||||
Promise.all([fetch(url),
|
||||
caches.open('putter' + context)]).then(function(results) {
|
||||
fetchResponse = results[0];
|
||||
cache = results[1];
|
||||
return cache.put(url, fetchResponse.clone());
|
||||
}).then(function(result) {
|
||||
is(undefined, result, 'Successful put() should resolve undefined');
|
||||
return cache.match(url);
|
||||
}).then(function(response) {
|
||||
ok(response, 'match() should find resppnse that was previously put()');
|
||||
ok(response.url.endsWith(url), 'matched response should match original url');
|
||||
return Promise.all([fetchResponse.text(),
|
||||
response.text()]);
|
||||
}).then(function(results) {
|
||||
// suppress large assert spam unless its relevent
|
||||
if (results[0] !== results[1]) {
|
||||
is(results[0], results[1], 'stored response body should match original');
|
||||
}
|
||||
return caches.delete('putter' + context);
|
||||
}).then(function(deleted) {
|
||||
ok(deleted, "The cache should be deleted successfully");
|
||||
testDone();
|
||||
});
|
@ -4218,6 +4218,13 @@ CanvasRenderingContext2D::DrawImage(const HTMLImageOrCanvasOrVideoElement& image
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
if (video->ContainsRestrictedContent()) {
|
||||
error.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t readyState;
|
||||
if (NS_SUCCEEDED(video->GetReadyState(&readyState)) &&
|
||||
readyState < nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA) {
|
||||
|
@ -671,14 +671,6 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest,
|
||||
NS_WARNING("Failed to visit all headers.");
|
||||
}
|
||||
|
||||
mResponse = BeginAndGetFilteredResponse(response);
|
||||
|
||||
nsCOMPtr<nsISupports> securityInfo;
|
||||
rv = channel->GetSecurityInfo(getter_AddRefs(securityInfo));
|
||||
if (securityInfo) {
|
||||
mResponse->SetSecurityInfo(securityInfo);
|
||||
}
|
||||
|
||||
// We open a pipe so that we can immediately set the pipe's read end as the
|
||||
// response's body. Setting the segment size to UINT32_MAX means that the
|
||||
// pipe has infinite space. The nsIChannel will continue to buffer data in
|
||||
@ -697,8 +689,17 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest,
|
||||
// Cancel request.
|
||||
return rv;
|
||||
}
|
||||
response->SetBody(pipeInputStream);
|
||||
|
||||
mResponse->SetBody(pipeInputStream);
|
||||
nsCOMPtr<nsISupports> securityInfo;
|
||||
rv = channel->GetSecurityInfo(getter_AddRefs(securityInfo));
|
||||
if (securityInfo) {
|
||||
response->SetSecurityInfo(securityInfo);
|
||||
}
|
||||
|
||||
// Resolves fetch() promise which may trigger code running in a worker. Make
|
||||
// sure the Response is fully initialized before calling this.
|
||||
mResponse = BeginAndGetFilteredResponse(response);
|
||||
|
||||
nsCOMPtr<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -3066,7 +3066,7 @@ void HTMLMediaElement::MetadataLoaded(const MediaInfo* aInfo,
|
||||
nsAutoPtr<const MetadataTags> aTags)
|
||||
{
|
||||
mMediaInfo = *aInfo;
|
||||
mIsEncrypted = aInfo->mIsEncrypted;
|
||||
mIsEncrypted = aInfo->IsEncrypted();
|
||||
mTags = aTags.forget();
|
||||
mLoadedDataFired = false;
|
||||
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
|
||||
@ -3086,6 +3086,16 @@ void HTMLMediaElement::MetadataLoaded(const MediaInfo* aInfo,
|
||||
ProcessMediaFragmentURI();
|
||||
mDecoder->SetFragmentEndTime(mFragmentEnd);
|
||||
}
|
||||
if (mIsEncrypted) {
|
||||
if (!mMediaSource) {
|
||||
DecodeError();
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
DispatchEncrypted(aInfo->mCrypto.mInitData, aInfo->mCrypto.mType);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Expose the tracks to JS directly.
|
||||
for (OutputMediaStream& out : mOutputStreams) {
|
||||
|
@ -571,6 +571,11 @@ child:
|
||||
int32_t aModifiers,
|
||||
bool aPreventDefault);
|
||||
|
||||
/**
|
||||
* APZ notification for mouse scroll testing events.
|
||||
*/
|
||||
MouseScrollTestEvent(ViewID aScrollId, nsString aEvent);
|
||||
|
||||
CompositionEvent(WidgetCompositionEvent event);
|
||||
|
||||
SelectionEvent(WidgetSelectionEvent event);
|
||||
|
@ -2199,6 +2199,13 @@ TabChild::RecvMouseWheelEvent(const WidgetWheelEvent& aEvent,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvMouseScrollTestEvent(const FrameMetrics::ViewID& aScrollId, const nsString& aEvent)
|
||||
{
|
||||
APZCCallbackHelper::NotifyMozMouseScrollEvent(aScrollId, aEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
static Touch*
|
||||
GetTouchForIdentifier(const WidgetTouchEvent& aEvent, int32_t aId)
|
||||
{
|
||||
|
@ -365,6 +365,8 @@ public:
|
||||
const int32_t& aCharCode,
|
||||
const int32_t& aModifiers,
|
||||
const bool& aPreventDefault) override;
|
||||
virtual bool RecvMouseScrollTestEvent(const FrameMetrics::ViewID& aScrollId,
|
||||
const nsString& aEvent) override;
|
||||
virtual bool RecvCompositionEvent(const mozilla::WidgetCompositionEvent& event) override;
|
||||
virtual bool RecvSelectionEvent(const mozilla::WidgetSelectionEvent& event) override;
|
||||
virtual bool RecvActivateFrameEvent(const nsString& aType, const bool& capture) override;
|
||||
|
@ -973,6 +973,14 @@ void TabParent::NotifyAPZStateChange(ViewID aViewId,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::NotifyMouseScrollTestEvent(const ViewID& aScrollId, const nsString& aEvent)
|
||||
{
|
||||
if (!mIsDestroyed) {
|
||||
unused << SendMouseScrollTestEvent(aScrollId, aEvent);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::Activate()
|
||||
{
|
||||
|
@ -242,6 +242,7 @@ public:
|
||||
void NotifyAPZStateChange(ViewID aViewId,
|
||||
APZStateChange aChange,
|
||||
int aArg);
|
||||
void NotifyMouseScrollTestEvent(const ViewID& aScrollId, const nsString& aEvent);
|
||||
void Activate();
|
||||
void Deactivate();
|
||||
|
||||
|
@ -1282,6 +1282,7 @@ static const char* const gMachineStateStr[] = {
|
||||
"NONE",
|
||||
"DECODING_METADATA",
|
||||
"WAIT_FOR_RESOURCES",
|
||||
"WAIT_FOR_CDM",
|
||||
"DECODING_FIRSTFRAME",
|
||||
"DORMANT",
|
||||
"DECODING",
|
||||
@ -1582,13 +1583,19 @@ void MediaDecoderStateMachine::DoNotifyWaitingForResourcesStatusChanged()
|
||||
{
|
||||
NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
if (mState != DECODER_STATE_WAIT_FOR_RESOURCES) {
|
||||
return;
|
||||
}
|
||||
|
||||
DECODER_LOG("DoNotifyWaitingForResourcesStatusChanged");
|
||||
// The reader is no longer waiting for resources (say a hardware decoder),
|
||||
// we can now proceed to decode metadata.
|
||||
SetState(DECODER_STATE_DECODING_NONE);
|
||||
|
||||
if (mState == DECODER_STATE_WAIT_FOR_RESOURCES) {
|
||||
// The reader is no longer waiting for resources (say a hardware decoder),
|
||||
// we can now proceed to decode metadata.
|
||||
SetState(DECODER_STATE_DECODING_NONE);
|
||||
} else if (mState == DECODER_STATE_WAIT_FOR_CDM &&
|
||||
!mReader->IsWaitingOnCDMResource()) {
|
||||
SetState(DECODER_STATE_DECODING_FIRSTFRAME);
|
||||
EnqueueDecodeFirstFrameTask();
|
||||
}
|
||||
|
||||
ScheduleStateMachine();
|
||||
}
|
||||
|
||||
@ -2269,6 +2276,13 @@ nsresult MediaDecoderStateMachine::DecodeMetadata()
|
||||
}
|
||||
|
||||
if (mState == DECODER_STATE_DECODING_METADATA) {
|
||||
if (mReader->IsWaitingOnCDMResource()) {
|
||||
// Metadata parsing was successful but we're still waiting for CDM caps
|
||||
// to become available so that we can build the correct decryptor/decoder.
|
||||
SetState(DECODER_STATE_WAIT_FOR_CDM);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
SetState(DECODER_STATE_DECODING_FIRSTFRAME);
|
||||
res = EnqueueDecodeFirstFrameTask();
|
||||
if (NS_FAILED(res)) {
|
||||
@ -2678,6 +2692,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
case DECODER_STATE_WAIT_FOR_CDM:
|
||||
case DECODER_STATE_WAIT_FOR_RESOURCES: {
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -139,6 +139,7 @@ public:
|
||||
DECODER_STATE_DECODING_NONE,
|
||||
DECODER_STATE_DECODING_METADATA,
|
||||
DECODER_STATE_WAIT_FOR_RESOURCES,
|
||||
DECODER_STATE_WAIT_FOR_CDM,
|
||||
DECODER_STATE_DECODING_FIRSTFRAME,
|
||||
DECODER_STATE_DORMANT,
|
||||
DECODER_STATE_DECODING,
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "nsRect.h"
|
||||
#include "ImageTypes.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "StreamBuffer.h" // for TrackID
|
||||
|
||||
namespace mozilla {
|
||||
@ -102,10 +103,22 @@ public:
|
||||
TrackInfo mTrackInfo;
|
||||
};
|
||||
|
||||
class EncryptionInfo {
|
||||
public:
|
||||
EncryptionInfo() : mIsEncrypted(false) {}
|
||||
|
||||
// Encryption type to be passed to JS. Usually `cenc'.
|
||||
nsString mType;
|
||||
|
||||
// Encryption data.
|
||||
nsTArray<uint8_t> mInitData;
|
||||
|
||||
// True if the stream has encryption metadata
|
||||
bool mIsEncrypted;
|
||||
};
|
||||
|
||||
class MediaInfo {
|
||||
public:
|
||||
MediaInfo() : mIsEncrypted(false) {}
|
||||
|
||||
bool HasVideo() const
|
||||
{
|
||||
return mVideo.mHasVideo;
|
||||
@ -116,16 +129,21 @@ public:
|
||||
return mAudio.mHasAudio;
|
||||
}
|
||||
|
||||
bool IsEncrypted() const
|
||||
{
|
||||
return mCrypto.mIsEncrypted;
|
||||
}
|
||||
|
||||
bool HasValidMedia() const
|
||||
{
|
||||
return HasVideo() || HasAudio();
|
||||
}
|
||||
|
||||
bool mIsEncrypted;
|
||||
|
||||
// TODO: Store VideoInfo and AudioIndo in arrays to support multi-tracks.
|
||||
VideoInfo mVideo;
|
||||
AudioInfo mAudio;
|
||||
|
||||
EncryptionInfo mCrypto;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -2213,6 +2213,7 @@ MediaStream::RunAfterPendingUpdates(already_AddRefed<nsIRunnable> aRunnable)
|
||||
// runnable will run in finite time.
|
||||
if (!(graph->mRealtime || graph->mNonRealtimeProcessing)) {
|
||||
runnable->Run();
|
||||
return;
|
||||
}
|
||||
|
||||
class Message : public ControlMessage {
|
||||
|
@ -265,12 +265,6 @@ AVCCDecoderModule::Startup()
|
||||
return mPDM->Startup();
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCDecoderModule::Shutdown()
|
||||
{
|
||||
return mPDM->Shutdown();
|
||||
}
|
||||
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
AVCCDecoderModule::CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
|
@ -28,7 +28,6 @@ public:
|
||||
virtual ~AVCCDecoderModule();
|
||||
|
||||
virtual nsresult Startup() override;
|
||||
virtual nsresult Shutdown() override;
|
||||
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
|
@ -206,11 +206,6 @@ private:
|
||||
class BlankDecoderModule : public PlatformDecoderModule {
|
||||
public:
|
||||
|
||||
// Called when the decoders have shutdown. Main thread only.
|
||||
virtual nsresult Shutdown() override {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Decode thread.
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
|
@ -156,6 +156,7 @@ MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder)
|
||||
, mDemuxerInitialized(false)
|
||||
, mFoundSPSForTelemetry(false)
|
||||
, mIsEncrypted(false)
|
||||
, mAreDecodersSetup(false)
|
||||
, mIndexReady(false)
|
||||
, mDemuxerMonitor("MP4 Demuxer")
|
||||
#if defined(MP4_READER_DORMANT_HEURISTIC)
|
||||
@ -204,10 +205,7 @@ MP4Reader::Shutdown()
|
||||
// Dispose of the queued sample before shutting down the demuxer
|
||||
mQueuedVideoSample = nullptr;
|
||||
|
||||
if (mPlatform) {
|
||||
mPlatform->Shutdown();
|
||||
mPlatform = nullptr;
|
||||
}
|
||||
mPlatform = nullptr;
|
||||
|
||||
return MediaDecoderReader::Shutdown();
|
||||
}
|
||||
@ -266,41 +264,13 @@ MP4Reader::Init(MediaDecoderReader* aCloneDonor)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
class DispatchKeyNeededEvent : public nsRunnable {
|
||||
public:
|
||||
DispatchKeyNeededEvent(AbstractMediaDecoder* aDecoder,
|
||||
nsTArray<uint8_t>& aInitData,
|
||||
const nsString& aInitDataType)
|
||||
: mDecoder(aDecoder)
|
||||
, mInitData(aInitData)
|
||||
, mInitDataType(aInitDataType)
|
||||
{
|
||||
}
|
||||
NS_IMETHOD Run() {
|
||||
// Note: Null check the owner, as the decoder could have been shutdown
|
||||
// since this event was dispatched.
|
||||
MediaDecoderOwner* owner = mDecoder->GetOwner();
|
||||
if (owner) {
|
||||
owner->DispatchEncrypted(mInitData, mInitDataType);
|
||||
}
|
||||
mDecoder = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
nsRefPtr<AbstractMediaDecoder> mDecoder;
|
||||
nsTArray<uint8_t> mInitData;
|
||||
nsString mInitDataType;
|
||||
};
|
||||
#endif
|
||||
|
||||
void MP4Reader::RequestCodecResource() {
|
||||
if (mVideo.mDecoder) {
|
||||
mVideo.mDecoder->AllocateMediaResources();
|
||||
}
|
||||
}
|
||||
|
||||
bool MP4Reader::IsWaitingOnCodecResource() {
|
||||
bool MP4Reader::IsWaitingMediaResources() {
|
||||
return mVideo.mDecoder && mVideo.mDecoder->IsWaitingMediaResources();
|
||||
}
|
||||
|
||||
@ -330,15 +300,6 @@ bool MP4Reader::IsWaitingOnCDMResource() {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MP4Reader::IsWaitingMediaResources()
|
||||
{
|
||||
// IsWaitingOnCDMResource() *must* come first, because we don't know whether
|
||||
// we can create a decoder until the CDM is initialized and it has told us
|
||||
// whether *it* will decode, or whether we need to create a PDM to do the
|
||||
// decoding
|
||||
return IsWaitingOnCDMResource() || IsWaitingOnCodecResource();
|
||||
}
|
||||
|
||||
void
|
||||
MP4Reader::ExtractCryptoInitData(nsTArray<uint8_t>& aInitData)
|
||||
{
|
||||
@ -407,7 +368,7 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
|
||||
{
|
||||
MonitorAutoUnlock unlock(mDemuxerMonitor);
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
mInfo.mIsEncrypted = mIsEncrypted = mCrypto.valid;
|
||||
mInfo.mCrypto.mIsEncrypted = mIsEncrypted = mCrypto.valid;
|
||||
}
|
||||
|
||||
// Remember that we've initialized the demuxer, so that if we're decoding
|
||||
@ -420,90 +381,18 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mCrypto.valid) {
|
||||
#ifdef MOZ_EME
|
||||
// We have encrypted audio or video. We'll need a CDM to decrypt and
|
||||
// possibly decode this. Wait until we've received a CDM from the
|
||||
// JavaScript player app. Note: we still go through the motions here
|
||||
// even if EME is disabled, so that if script tries and fails to create
|
||||
// a CDM, we can detect that and notify chrome and show some UI explaining
|
||||
// that we failed due to EME being disabled.
|
||||
nsRefPtr<CDMProxy> proxy;
|
||||
nsTArray<uint8_t> initData;
|
||||
ExtractCryptoInitData(initData);
|
||||
if (initData.Length() == 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (!mInitDataEncountered.Contains(initData)) {
|
||||
mInitDataEncountered.AppendElement(initData);
|
||||
NS_DispatchToMainThread(new DispatchKeyNeededEvent(mDecoder, initData, NS_LITERAL_STRING("cenc")));
|
||||
}
|
||||
if (IsWaitingMediaResources()) {
|
||||
return NS_OK;
|
||||
}
|
||||
MOZ_ASSERT(!IsWaitingMediaResources());
|
||||
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
proxy = mDecoder->GetCDMProxy();
|
||||
}
|
||||
MOZ_ASSERT(proxy);
|
||||
|
||||
mPlatform = PlatformDecoderModule::CreateCDMWrapper(proxy,
|
||||
HasAudio(),
|
||||
HasVideo());
|
||||
NS_ENSURE_TRUE(mPlatform, NS_ERROR_FAILURE);
|
||||
#else
|
||||
// EME not supported.
|
||||
return NS_ERROR_FAILURE;
|
||||
#endif
|
||||
} else {
|
||||
mPlatform = PlatformDecoderModule::Create();
|
||||
NS_ENSURE_TRUE(mPlatform, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
if (HasAudio()) {
|
||||
const AudioDecoderConfig& audio = mDemuxer->AudioConfig();
|
||||
if (mInfo.mAudio.mHasAudio && !IsSupportedAudioMimeType(audio.mime_type)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mInfo.mAudio.mRate = audio.samples_per_second;
|
||||
mInfo.mAudio.mChannels = audio.channel_count;
|
||||
mAudio.mCallback = new DecoderCallback(this, kAudio);
|
||||
mAudio.mDecoder = mPlatform->CreateAudioDecoder(audio,
|
||||
mAudio.mTaskQueue,
|
||||
mAudio.mCallback);
|
||||
NS_ENSURE_TRUE(mAudio.mDecoder != nullptr, NS_ERROR_FAILURE);
|
||||
nsresult rv = mAudio.mDecoder->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (HasVideo()) {
|
||||
const VideoDecoderConfig& video = mDemuxer->VideoConfig();
|
||||
if (mInfo.mVideo.mHasVideo && !IsSupportedVideoMimeType(video.mime_type)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mInfo.mVideo.mDisplay =
|
||||
nsIntSize(video.display_width, video.display_height);
|
||||
mVideo.mCallback = new DecoderCallback(this, kVideo);
|
||||
if (mSharedDecoderManager && mPlatform->SupportsSharedDecoders(video)) {
|
||||
mVideo.mDecoder =
|
||||
mSharedDecoderManager->CreateVideoDecoder(mPlatform,
|
||||
video,
|
||||
mLayersBackendType,
|
||||
mDecoder->GetImageContainer(),
|
||||
mVideo.mTaskQueue,
|
||||
mVideo.mCallback);
|
||||
} else {
|
||||
mVideo.mDecoder = mPlatform->CreateVideoDecoder(video,
|
||||
mLayersBackendType,
|
||||
mDecoder->GetImageContainer(),
|
||||
mVideo.mTaskQueue,
|
||||
mVideo.mCallback);
|
||||
}
|
||||
NS_ENSURE_TRUE(mVideo.mDecoder != nullptr, NS_ERROR_FAILURE);
|
||||
nsresult rv = mVideo.mDecoder->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Collect telemetry from h264 AVCC SPS.
|
||||
if (!mFoundSPSForTelemetry) {
|
||||
@ -511,6 +400,17 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
|
||||
}
|
||||
}
|
||||
|
||||
if (mIsEncrypted) {
|
||||
nsTArray<uint8_t> initData;
|
||||
ExtractCryptoInitData(initData);
|
||||
if (initData.Length() == 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mInfo.mCrypto.mInitData = initData;
|
||||
mInfo.mCrypto.mType = NS_LITERAL_STRING("cenc");
|
||||
}
|
||||
|
||||
// Get the duration, and report it to the decoder if we have it.
|
||||
Microseconds duration;
|
||||
{
|
||||
@ -525,12 +425,96 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
|
||||
*aInfo = mInfo;
|
||||
*aTags = nullptr;
|
||||
|
||||
if (!IsWaitingMediaResources() && !IsWaitingOnCDMResource()) {
|
||||
NS_ENSURE_TRUE(EnsureDecodersSetup(), NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
MonitorAutoLock mon(mDemuxerMonitor);
|
||||
UpdateIndex();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Reader::EnsureDecodersSetup()
|
||||
{
|
||||
if (mAreDecodersSetup) {
|
||||
return !!mPlatform;
|
||||
}
|
||||
|
||||
if (mIsEncrypted) {
|
||||
#ifdef MOZ_EME
|
||||
// We have encrypted audio or video. We'll need a CDM to decrypt and
|
||||
// possibly decode this. Wait until we've received a CDM from the
|
||||
// JavaScript player app. Note: we still go through the motions here
|
||||
// even if EME is disabled, so that if script tries and fails to create
|
||||
// a CDM, we can detect that and notify chrome and show some UI explaining
|
||||
// that we failed due to EME being disabled.
|
||||
nsRefPtr<CDMProxy> proxy;
|
||||
if (IsWaitingMediaResources()) {
|
||||
return true;
|
||||
}
|
||||
MOZ_ASSERT(!IsWaitingMediaResources());
|
||||
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
proxy = mDecoder->GetCDMProxy();
|
||||
}
|
||||
MOZ_ASSERT(proxy);
|
||||
|
||||
mPlatform = PlatformDecoderModule::CreateCDMWrapper(proxy,
|
||||
HasAudio(),
|
||||
HasVideo());
|
||||
NS_ENSURE_TRUE(mPlatform, false);
|
||||
#else
|
||||
// EME not supported.
|
||||
return false;
|
||||
#endif
|
||||
} else {
|
||||
mPlatform = PlatformDecoderModule::Create();
|
||||
NS_ENSURE_TRUE(mPlatform, false);
|
||||
}
|
||||
|
||||
if (HasAudio()) {
|
||||
NS_ENSURE_TRUE(IsSupportedAudioMimeType(mDemuxer->AudioConfig().mime_type),
|
||||
false);
|
||||
|
||||
mAudio.mDecoder = mPlatform->CreateAudioDecoder(mDemuxer->AudioConfig(),
|
||||
mAudio.mTaskQueue,
|
||||
mAudio.mCallback);
|
||||
NS_ENSURE_TRUE(mAudio.mDecoder != nullptr, false);
|
||||
nsresult rv = mAudio.mDecoder->Init();
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
}
|
||||
|
||||
if (HasVideo()) {
|
||||
NS_ENSURE_TRUE(IsSupportedVideoMimeType(mDemuxer->VideoConfig().mime_type),
|
||||
false);
|
||||
|
||||
if (mSharedDecoderManager && mPlatform->SupportsSharedDecoders(mDemuxer->VideoConfig())) {
|
||||
mVideo.mDecoder =
|
||||
mSharedDecoderManager->CreateVideoDecoder(mPlatform,
|
||||
mDemuxer->VideoConfig(),
|
||||
mLayersBackendType,
|
||||
mDecoder->GetImageContainer(),
|
||||
mVideo.mTaskQueue,
|
||||
mVideo.mCallback);
|
||||
} else {
|
||||
mVideo.mDecoder = mPlatform->CreateVideoDecoder(mDemuxer->VideoConfig(),
|
||||
mLayersBackendType,
|
||||
mDecoder->GetImageContainer(),
|
||||
mVideo.mTaskQueue,
|
||||
mVideo.mCallback);
|
||||
}
|
||||
NS_ENSURE_TRUE(mVideo.mDecoder != nullptr, false);
|
||||
nsresult rv = mVideo.mDecoder->Init();
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
}
|
||||
|
||||
mAreDecodersSetup = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MP4Reader::ReadUpdatedMetadata(MediaInfo* aInfo)
|
||||
{
|
||||
@ -579,10 +563,10 @@ void
|
||||
MP4Reader::DisableHardwareAcceleration()
|
||||
{
|
||||
if (HasVideo() && mSharedDecoderManager) {
|
||||
mPlatform->DisableHardwareAcceleration();
|
||||
mSharedDecoderManager->DisableHardwareAcceleration();
|
||||
|
||||
const VideoDecoderConfig& video = mDemuxer->VideoConfig();
|
||||
if (!mSharedDecoderManager->Recreate(mPlatform, video, mLayersBackendType, mDecoder->GetImageContainer())) {
|
||||
if (!mSharedDecoderManager->Recreate(video, mLayersBackendType, mDecoder->GetImageContainer())) {
|
||||
MonitorAutoLock mon(mVideo.mMonitor);
|
||||
mVideo.mError = true;
|
||||
if (mVideo.HasPromise()) {
|
||||
@ -618,6 +602,11 @@ MP4Reader::RequestVideoData(bool aSkipToNextKeyframe,
|
||||
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
||||
VLOG("skip=%d time=%lld", aSkipToNextKeyframe, aTimeThreshold);
|
||||
|
||||
if (!EnsureDecodersSetup()) {
|
||||
NS_WARNING("Error constructing MP4 decoders");
|
||||
return VideoDataPromise::CreateAndReject(DECODE_ERROR, __func__);
|
||||
}
|
||||
|
||||
if (mShutdown) {
|
||||
NS_WARNING("RequestVideoData on shutdown MP4Reader!");
|
||||
return VideoDataPromise::CreateAndReject(CANCELED, __func__);
|
||||
@ -653,6 +642,12 @@ MP4Reader::RequestAudioData()
|
||||
{
|
||||
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
||||
VLOG("");
|
||||
|
||||
if (!EnsureDecodersSetup()) {
|
||||
NS_WARNING("Error constructing MP4 decoders");
|
||||
return AudioDataPromise::CreateAndReject(DECODE_ERROR, __func__);
|
||||
}
|
||||
|
||||
if (mShutdown) {
|
||||
NS_WARNING("RequestAudioData on shutdown MP4Reader!");
|
||||
return AudioDataPromise::CreateAndReject(CANCELED, __func__);
|
||||
|
@ -103,6 +103,8 @@ private:
|
||||
bool InitDemuxer();
|
||||
void ReturnOutput(MediaData* aData, TrackType aTrack);
|
||||
|
||||
bool EnsureDecodersSetup();
|
||||
|
||||
// Sends input to decoder for aTrack, and output to the state machine,
|
||||
// if necessary.
|
||||
void Update(TrackType aTrack);
|
||||
@ -135,7 +137,6 @@ private:
|
||||
bool IsSupportedVideoMimeType(const char* aMimeType);
|
||||
void NotifyResourcesStatusChanged();
|
||||
void RequestCodecResource();
|
||||
bool IsWaitingOnCodecResource();
|
||||
virtual bool IsWaitingOnCDMResource() override;
|
||||
|
||||
Microseconds GetNextKeyframeTime();
|
||||
@ -285,6 +286,8 @@ private:
|
||||
// Synchronized by decoder monitor.
|
||||
bool mIsEncrypted;
|
||||
|
||||
bool mAreDecodersSetup;
|
||||
|
||||
bool mIndexReady;
|
||||
Monitor mDemuxerMonitor;
|
||||
nsRefPtr<SharedDecoderManager> mSharedDecoderManager;
|
||||
|
@ -86,13 +86,6 @@ public:
|
||||
bool aHasVideo);
|
||||
#endif
|
||||
|
||||
// Called to shutdown the decoder module and cleanup state. The PDM
|
||||
// is deleted immediately after Shutdown() is called. Shutdown() is
|
||||
// called after Shutdown() has been called on all MediaDataDecoders
|
||||
// created from this PlatformDecoderModule.
|
||||
// This is called on the decode task queue.
|
||||
virtual nsresult Shutdown() = 0;
|
||||
|
||||
// Creates an H.264 decoder. The layers backend is passed in so that
|
||||
// decoders can determine whether hardware accelerated decoding can be used.
|
||||
// Asynchronous decoding of video should be done in runnables dispatched
|
||||
|
@ -12,7 +12,10 @@ namespace mozilla {
|
||||
class SharedDecoderCallback : public MediaDataDecoderCallback
|
||||
{
|
||||
public:
|
||||
explicit SharedDecoderCallback(SharedDecoderManager* aManager) : mManager(aManager) {}
|
||||
explicit SharedDecoderCallback(SharedDecoderManager* aManager)
|
||||
: mManager(aManager)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Output(MediaData* aData) override
|
||||
{
|
||||
@ -66,25 +69,34 @@ SharedDecoderManager::SharedDecoderManager()
|
||||
mCallback = new SharedDecoderCallback(this);
|
||||
}
|
||||
|
||||
SharedDecoderManager::~SharedDecoderManager() {}
|
||||
SharedDecoderManager::~SharedDecoderManager()
|
||||
{
|
||||
}
|
||||
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
SharedDecoderManager::CreateVideoDecoder(
|
||||
PlatformDecoderModule* aPDM,
|
||||
const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer,
|
||||
FlushableMediaTaskQueue* aVideoTaskQueue, MediaDataDecoderCallback* aCallback)
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
FlushableMediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
{
|
||||
if (!mDecoder) {
|
||||
// We use the manager's task queue for the decoder, rather than the one
|
||||
// passed in, so that none of the objects sharing the decoder can shutdown
|
||||
// the task queue while we're potentially still using it for a *different*
|
||||
// object also sharing the decoder.
|
||||
mDecoder = aPDM->CreateVideoDecoder(
|
||||
aConfig, aLayersBackend, aImageContainer, mTaskQueue, mCallback);
|
||||
mDecoder = aPDM->CreateVideoDecoder(aConfig,
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
mTaskQueue,
|
||||
mCallback);
|
||||
if (!mDecoder) {
|
||||
mPDM = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
mPDM = aPDM;
|
||||
nsresult rv = mDecoder->Init();
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
}
|
||||
@ -93,15 +105,25 @@ SharedDecoderManager::CreateVideoDecoder(
|
||||
return proxy.forget();
|
||||
}
|
||||
|
||||
void
|
||||
SharedDecoderManager::DisableHardwareAcceleration()
|
||||
{
|
||||
MOZ_ASSERT(mPDM);
|
||||
mPDM->DisableHardwareAcceleration();
|
||||
}
|
||||
|
||||
bool
|
||||
SharedDecoderManager::Recreate(PlatformDecoderModule* aPDM,
|
||||
const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
SharedDecoderManager::Recreate(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer)
|
||||
{
|
||||
mDecoder->Flush();
|
||||
mDecoder->Shutdown();
|
||||
mDecoder = aPDM->CreateVideoDecoder(aConfig, aLayersBackend, aImageContainer, mTaskQueue, mCallback);
|
||||
mDecoder = mPDM->CreateVideoDecoder(aConfig,
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
mTaskQueue,
|
||||
mCallback);
|
||||
if (!mDecoder) {
|
||||
return false;
|
||||
}
|
||||
@ -168,6 +190,7 @@ SharedDecoderManager::Shutdown()
|
||||
mDecoder->Shutdown();
|
||||
mDecoder = nullptr;
|
||||
}
|
||||
mPDM = nullptr;
|
||||
if (mTaskQueue) {
|
||||
mTaskQueue->BeginShutdown();
|
||||
mTaskQueue->AwaitShutdownAndIdle();
|
||||
@ -175,13 +198,17 @@ SharedDecoderManager::Shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
SharedDecoderProxy::SharedDecoderProxy(
|
||||
SharedDecoderManager* aManager, MediaDataDecoderCallback* aCallback)
|
||||
: mManager(aManager), mCallback(aCallback)
|
||||
SharedDecoderProxy::SharedDecoderProxy(SharedDecoderManager* aManager,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
: mManager(aManager)
|
||||
, mCallback(aCallback)
|
||||
{
|
||||
}
|
||||
|
||||
SharedDecoderProxy::~SharedDecoderProxy() { Shutdown(); }
|
||||
SharedDecoderProxy::~SharedDecoderProxy()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
nsresult
|
||||
SharedDecoderProxy::Init()
|
||||
|
@ -28,7 +28,8 @@ public:
|
||||
PlatformDecoderModule* aPDM,
|
||||
const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer, FlushableMediaTaskQueue* aVideoTaskQueue,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
FlushableMediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback);
|
||||
|
||||
void SetReader(MediaDecoderReader* aReader);
|
||||
@ -40,15 +41,16 @@ public:
|
||||
friend class SharedDecoderProxy;
|
||||
friend class SharedDecoderCallback;
|
||||
|
||||
bool Recreate(PlatformDecoderModule* aPDM,
|
||||
const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer);
|
||||
void DisableHardwareAcceleration();
|
||||
bool Recreate(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer);
|
||||
|
||||
private:
|
||||
virtual ~SharedDecoderManager();
|
||||
void DrainComplete();
|
||||
|
||||
nsRefPtr<PlatformDecoderModule> mPDM;
|
||||
nsRefPtr<MediaDataDecoder> mDecoder;
|
||||
nsRefPtr<FlushableMediaTaskQueue> mTaskQueue;
|
||||
SharedDecoderProxy* mActiveProxy;
|
||||
|
@ -299,12 +299,6 @@ AndroidDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig&
|
||||
|
||||
}
|
||||
|
||||
|
||||
nsresult AndroidDecoderModule::Shutdown()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MediaCodecDataDecoder::MediaCodecDataDecoder(MediaData::Type aType,
|
||||
const char* aMimeType,
|
||||
MediaFormat::Param aFormat,
|
||||
|
@ -19,8 +19,6 @@ typedef std::queue<mp4_demuxer::MP4Sample*> SampleQueue;
|
||||
|
||||
class AndroidDecoderModule : public PlatformDecoderModule {
|
||||
public:
|
||||
virtual nsresult Shutdown() override;
|
||||
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
|
@ -36,12 +36,46 @@ bool AppleDecoderModule::sIsVTHWAvailable = false;
|
||||
bool AppleDecoderModule::sIsVDAAvailable = false;
|
||||
bool AppleDecoderModule::sForceVDA = false;
|
||||
|
||||
class LinkTask : public nsRunnable {
|
||||
public:
|
||||
NS_IMETHOD Run() override {
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
|
||||
MOZ_ASSERT(AppleDecoderModule::sInitialized);
|
||||
if (AppleDecoderModule::sIsVDAAvailable) {
|
||||
AppleVDALinker::Link();
|
||||
}
|
||||
if (AppleDecoderModule::sIsVTAvailable) {
|
||||
AppleVTLinker::Link();
|
||||
AppleCMLinker::Link();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
class UnlinkTask : public nsRunnable {
|
||||
public:
|
||||
NS_IMETHOD Run() override {
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
|
||||
MOZ_ASSERT(AppleDecoderModule::sInitialized);
|
||||
if (AppleDecoderModule::sIsVDAAvailable) {
|
||||
AppleVDALinker::Unlink();
|
||||
}
|
||||
if (AppleDecoderModule::sIsVTAvailable) {
|
||||
AppleVTLinker::Unlink();
|
||||
AppleCMLinker::Unlink();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
AppleDecoderModule::AppleDecoderModule()
|
||||
{
|
||||
}
|
||||
|
||||
AppleDecoderModule::~AppleDecoderModule()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> task(new UnlinkTask());
|
||||
NS_DispatchToMainThread(task);
|
||||
}
|
||||
|
||||
/* static */
|
||||
@ -104,22 +138,6 @@ AppleDecoderModule::CanDecode()
|
||||
return (sIsVDAAvailable || sIsVTAvailable) ? NS_OK : NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
class LinkTask : public nsRunnable {
|
||||
public:
|
||||
NS_IMETHOD Run() override {
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
|
||||
MOZ_ASSERT(AppleDecoderModule::sInitialized);
|
||||
if (AppleDecoderModule::sIsVDAAvailable) {
|
||||
AppleVDALinker::Link();
|
||||
}
|
||||
if (AppleDecoderModule::sIsVTAvailable) {
|
||||
AppleVTLinker::Link();
|
||||
AppleCMLinker::Link();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
nsresult
|
||||
AppleDecoderModule::Startup()
|
||||
{
|
||||
@ -133,30 +151,6 @@ AppleDecoderModule::Startup()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class UnlinkTask : public nsRunnable {
|
||||
public:
|
||||
NS_IMETHOD Run() override {
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
|
||||
MOZ_ASSERT(AppleDecoderModule::sInitialized);
|
||||
if (AppleDecoderModule::sIsVDAAvailable) {
|
||||
AppleVDALinker::Unlink();
|
||||
}
|
||||
if (AppleDecoderModule::sIsVTAvailable) {
|
||||
AppleVTLinker::Unlink();
|
||||
AppleCMLinker::Unlink();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
nsresult
|
||||
AppleDecoderModule::Shutdown()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> task(new UnlinkTask());
|
||||
NS_DispatchToMainThread(task);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
AppleDecoderModule::CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
|
@ -18,10 +18,6 @@ public:
|
||||
|
||||
virtual nsresult Startup() override;
|
||||
|
||||
// Called when the decoders have shutdown. Main thread only.
|
||||
// Does this really need to be main thread only????
|
||||
virtual nsresult Shutdown() override;
|
||||
|
||||
// Decode thread.
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
|
@ -94,7 +94,11 @@ AppleVDALinker::Unlink()
|
||||
MOZ_ASSERT(sRefCount > 0, "Unbalanced Unlink()");
|
||||
--sRefCount;
|
||||
if (sLink && sRefCount < 1) {
|
||||
LOG("Unlinking VideoToolbox framework.");
|
||||
LOG("Unlinking VideoDecodeAcceleration framework.");
|
||||
#define LINK_FUNC(func) \
|
||||
func = nullptr;
|
||||
#include "AppleVDAFunctions.h"
|
||||
#undef LINK_FUNC
|
||||
dlclose(sLink);
|
||||
sLink = nullptr;
|
||||
skPropWidth = nullptr;
|
||||
|
@ -98,6 +98,10 @@ AppleVTLinker::Unlink()
|
||||
--sRefCount;
|
||||
if (sLink && sRefCount < 1) {
|
||||
LOG("Unlinking VideoToolbox framework.");
|
||||
#define LINK_FUNC(func) \
|
||||
func = nullptr;
|
||||
#include "AppleVTFunctions.h"
|
||||
#undef LINK_FUNC
|
||||
dlclose(sLink);
|
||||
sLink = nullptr;
|
||||
skPropEnableHWAccel = nullptr;
|
||||
|
@ -208,15 +208,6 @@ EMEDecoderModule::~EMEDecoderModule()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
EMEDecoderModule::Shutdown()
|
||||
{
|
||||
if (mPDM) {
|
||||
return mPDM->Shutdown();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static already_AddRefed<MediaDataDecoderProxy>
|
||||
CreateDecoderWrapper(MediaDataDecoderCallback* aCallback, CDMProxy* aProxy, FlushableMediaTaskQueue* aTaskQueue)
|
||||
{
|
||||
|
@ -28,9 +28,6 @@ public:
|
||||
|
||||
virtual ~EMEDecoderModule();
|
||||
|
||||
// Called when the decoders have shutdown. Main thread only.
|
||||
virtual nsresult Shutdown() override;
|
||||
|
||||
// Decode thread.
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
|
@ -28,8 +28,6 @@ public:
|
||||
FFmpegDecoderModule() {}
|
||||
virtual ~FFmpegDecoderModule() {}
|
||||
|
||||
virtual nsresult Shutdown() override { return NS_OK; }
|
||||
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
|
@ -21,12 +21,6 @@ GMPDecoderModule::~GMPDecoderModule()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
GMPDecoderModule::Shutdown()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static already_AddRefed<MediaDataDecoderProxy>
|
||||
CreateDecoderWrapper(MediaDataDecoderCallback* aCallback)
|
||||
{
|
||||
|
@ -17,9 +17,6 @@ public:
|
||||
|
||||
virtual ~GMPDecoderModule();
|
||||
|
||||
// Called when the decoders have shutdown. Main thread only.
|
||||
virtual nsresult Shutdown() override;
|
||||
|
||||
// Decode thread.
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
|
@ -26,12 +26,6 @@ GonkDecoderModule::Init()
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkDecoderModule::Shutdown()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
GonkDecoderModule::CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
mozilla::layers::LayersBackend aLayersBackend,
|
||||
|
@ -16,9 +16,6 @@ public:
|
||||
GonkDecoderModule();
|
||||
virtual ~GonkDecoderModule();
|
||||
|
||||
// Called when the decoders have shutdown.
|
||||
virtual nsresult Shutdown() override;
|
||||
|
||||
// Decode thread.
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
|
@ -28,6 +28,8 @@ WMFDecoderModule::WMFDecoderModule()
|
||||
|
||||
WMFDecoderModule::~WMFDecoderModule()
|
||||
{
|
||||
DebugOnly<HRESULT> hr = wmf::MFShutdown();
|
||||
NS_ASSERTION(SUCCEEDED(hr), "MFShutdown failed");
|
||||
}
|
||||
|
||||
/* static */
|
||||
@ -58,14 +60,6 @@ WMFDecoderModule::Startup()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
WMFDecoderModule::Shutdown()
|
||||
{
|
||||
DebugOnly<HRESULT> hr = wmf::MFShutdown();
|
||||
NS_ASSERTION(SUCCEEDED(hr), "MFShutdown failed");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
WMFDecoderModule::CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
|
@ -19,9 +19,6 @@ public:
|
||||
// Initializes the module, loads required dynamic libraries, etc.
|
||||
virtual nsresult Startup() override;
|
||||
|
||||
// Called when the decoders have shutdown.
|
||||
virtual nsresult Shutdown() override;
|
||||
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
|
@ -665,10 +665,11 @@ GeckoMediaPluginService::LoadFromEnvironment()
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::PathRunnable::Run()
|
||||
{
|
||||
if (mAdd) {
|
||||
if (mOperation == ADD) {
|
||||
mService->AddOnGMPThread(mPath);
|
||||
} else {
|
||||
mService->RemoveOnGMPThread(mPath);
|
||||
mService->RemoveOnGMPThread(mPath,
|
||||
mOperation == REMOVE_AND_DELETE_FROM_DISK);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -677,14 +678,26 @@ NS_IMETHODIMP
|
||||
GeckoMediaPluginService::AddPluginDirectory(const nsAString& aDirectory)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return GMPDispatch(new PathRunnable(this, aDirectory, true));
|
||||
return GMPDispatch(new PathRunnable(this, aDirectory,
|
||||
PathRunnable::EOperation::ADD));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::RemovePluginDirectory(const nsAString& aDirectory)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return GMPDispatch(new PathRunnable(this, aDirectory, false));
|
||||
return GMPDispatch(new PathRunnable(this, aDirectory,
|
||||
PathRunnable::EOperation::REMOVE));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::RemoveAndDeletePluginDirectory(
|
||||
const nsAString& aDirectory)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return GMPDispatch(
|
||||
new PathRunnable(this, aDirectory,
|
||||
PathRunnable::EOperation::REMOVE_AND_DELETE_FROM_DISK));
|
||||
}
|
||||
|
||||
class DummyRunnable : public nsRunnable {
|
||||
@ -915,7 +928,8 @@ GeckoMediaPluginService::AddOnGMPThread(const nsAString& aDirectory)
|
||||
}
|
||||
|
||||
void
|
||||
GeckoMediaPluginService::RemoveOnGMPThread(const nsAString& aDirectory)
|
||||
GeckoMediaPluginService::RemoveOnGMPThread(const nsAString& aDirectory,
|
||||
const bool aDeleteFromDisk)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
LOGD(("%s::%s: %s", __CLASS__, __FUNCTION__, NS_LossyConvertUTF16toASCII(aDirectory).get()));
|
||||
@ -931,7 +945,11 @@ GeckoMediaPluginService::RemoveOnGMPThread(const nsAString& aDirectory)
|
||||
nsCOMPtr<nsIFile> pluginpath = mPlugins[i]->GetDirectory();
|
||||
bool equals;
|
||||
if (NS_SUCCEEDED(directory->Equals(pluginpath, &equals)) && equals) {
|
||||
mPlugins[i]->AbortAsyncShutdown();
|
||||
mPlugins[i]->CloseActive(true);
|
||||
if (aDeleteFromDisk) {
|
||||
pluginpath->Remove(true);
|
||||
}
|
||||
mPlugins.RemoveElementAt(i);
|
||||
return;
|
||||
}
|
||||
|
@ -71,8 +71,9 @@ private:
|
||||
void LoadFromEnvironment();
|
||||
void ProcessPossiblePlugin(nsIFile* aDir);
|
||||
|
||||
void AddOnGMPThread(const nsAString& aSearchDir);
|
||||
void RemoveOnGMPThread(const nsAString& aSearchDir);
|
||||
void AddOnGMPThread(const nsAString& aDirectory);
|
||||
void RemoveOnGMPThread(const nsAString& aDirectory,
|
||||
const bool aDeleteFromDisk);
|
||||
|
||||
nsresult SetAsyncShutdownTimeout();
|
||||
|
||||
@ -96,11 +97,17 @@ private:
|
||||
class PathRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
PathRunnable(GeckoMediaPluginService* service, const nsAString& path,
|
||||
bool add)
|
||||
: mService(service)
|
||||
, mPath(path)
|
||||
, mAdd(add)
|
||||
enum EOperation {
|
||||
ADD,
|
||||
REMOVE,
|
||||
REMOVE_AND_DELETE_FROM_DISK,
|
||||
};
|
||||
|
||||
PathRunnable(GeckoMediaPluginService* aService, const nsAString& aPath,
|
||||
EOperation aOperation)
|
||||
: mService(aService)
|
||||
, mPath(aPath)
|
||||
, mOperation(aOperation)
|
||||
{ }
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
@ -108,7 +115,7 @@ private:
|
||||
private:
|
||||
nsRefPtr<GeckoMediaPluginService> mService;
|
||||
nsString mPath;
|
||||
bool mAdd;
|
||||
EOperation mOperation;
|
||||
};
|
||||
|
||||
Mutex mMutex; // Protects mGMPThread and mShuttingDown and mPlugins
|
||||
|
@ -26,7 +26,7 @@ class GMPVideoHost;
|
||||
[ptr] native GMPDecryptorProxy(GMPDecryptorProxy);
|
||||
[ptr] native GMPAudioDecoderProxy(GMPAudioDecoderProxy);
|
||||
|
||||
[scriptable, uuid(56cc105f-dd27-4752-83e0-371908edba04)]
|
||||
[scriptable, uuid(f71e6e57-5175-4cf3-8cc2-629273a75b67)]
|
||||
interface mozIGeckoMediaPluginService : nsISupports
|
||||
{
|
||||
|
||||
@ -97,6 +97,12 @@ interface mozIGeckoMediaPluginService : nsISupports
|
||||
*/
|
||||
void removePluginDirectory(in AString directory);
|
||||
|
||||
/**
|
||||
* Remove a directory for gecko media plugins and delete it from disk.
|
||||
* @note Main-thread API.
|
||||
*/
|
||||
void removeAndDeletePluginDirectory(in AString directory);
|
||||
|
||||
/**
|
||||
* Gets the NodeId for a (origin, urlbarOrigin, isInprivateBrowsing) tuple.
|
||||
*/
|
||||
|
@ -93,6 +93,25 @@ MediaSourceReader::IsWaitingMediaResources()
|
||||
return !mHasEssentialTrackBuffers;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaSourceReader::IsWaitingOnCDMResource()
|
||||
{
|
||||
#ifdef MOZ_EME
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
MOZ_ASSERT(!IsWaitingMediaResources());
|
||||
|
||||
for (auto& trackBuffer : mTrackBuffers) {
|
||||
if (trackBuffer->IsWaitingOnCDMResource()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return mInfo.IsEncrypted() && !mCDMProxy;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t
|
||||
MediaSourceReader::SizeOfVideoQueueInFrames()
|
||||
{
|
||||
@ -1020,6 +1039,22 @@ MediaSourceReader::MaybeNotifyHaveData()
|
||||
IsSeeking(), haveAudio, haveVideo);
|
||||
}
|
||||
|
||||
static void
|
||||
CombineEncryptionData(EncryptionInfo& aTo, const EncryptionInfo& aFrom)
|
||||
{
|
||||
if (!aFrom.mIsEncrypted) {
|
||||
return;
|
||||
}
|
||||
aTo.mIsEncrypted = true;
|
||||
|
||||
if (!aTo.mType.IsEmpty() && !aTo.mType.Equals(aFrom.mType)) {
|
||||
NS_WARNING("mismatched encryption types");
|
||||
}
|
||||
|
||||
aTo.mType = aFrom.mType;
|
||||
aTo.mInitData.AppendElements(aFrom.mInitData);
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
|
||||
{
|
||||
@ -1043,7 +1078,7 @@ MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
|
||||
const MediaInfo& info = GetAudioReader()->GetMediaInfo();
|
||||
MOZ_ASSERT(info.HasAudio());
|
||||
mInfo.mAudio = info.mAudio;
|
||||
mInfo.mIsEncrypted = mInfo.mIsEncrypted || info.mIsEncrypted;
|
||||
CombineEncryptionData(mInfo.mCrypto, info.mCrypto);
|
||||
MSE_DEBUG("audio reader=%p duration=%lld",
|
||||
mAudioSourceDecoder.get(),
|
||||
mAudioSourceDecoder->GetReader()->GetDecoder()->GetMediaDuration());
|
||||
@ -1056,7 +1091,7 @@ MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
|
||||
const MediaInfo& info = GetVideoReader()->GetMediaInfo();
|
||||
MOZ_ASSERT(info.HasVideo());
|
||||
mInfo.mVideo = info.mVideo;
|
||||
mInfo.mIsEncrypted = mInfo.mIsEncrypted || info.mIsEncrypted;
|
||||
CombineEncryptionData(mInfo.mCrypto, info.mCrypto);
|
||||
MSE_DEBUG("video reader=%p duration=%lld",
|
||||
GetVideoReader(),
|
||||
GetVideoReader()->GetDecoder()->GetMediaDuration());
|
||||
|
@ -45,6 +45,7 @@ public:
|
||||
void PrepareInitialization();
|
||||
|
||||
bool IsWaitingMediaResources() override;
|
||||
bool IsWaitingOnCDMResource() override;
|
||||
|
||||
nsRefPtr<AudioDataPromise> RequestAudioData() override;
|
||||
nsRefPtr<VideoDataPromise>
|
||||
|
@ -47,6 +47,7 @@ TrackBuffer::TrackBuffer(MediaSourceDecoder* aParentDecoder, const nsACString& a
|
||||
, mLastStartTimestamp(0)
|
||||
, mLastTimestampOffset(0)
|
||||
, mAdjustedTimestamp(0)
|
||||
, mIsWaitingOnCDM(false)
|
||||
, mShutdown(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(TrackBuffer);
|
||||
@ -588,6 +589,7 @@ TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder)
|
||||
|
||||
if (mCurrentDecoder != aDecoder) {
|
||||
MSE_DEBUG("append was cancelled. Aborting initialization.");
|
||||
RemoveDecoder(aDecoder);
|
||||
// If we reached this point, the SourceBuffer would have disconnected
|
||||
// the promise. So no need to reject it.
|
||||
return;
|
||||
@ -641,12 +643,12 @@ TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder)
|
||||
}
|
||||
if (mCurrentDecoder != aDecoder) {
|
||||
MSE_DEBUG("append was cancelled. Aborting initialization.");
|
||||
RemoveDecoder(aDecoder);
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv) && reader->IsWaitingOnCDMResource()) {
|
||||
mWaitingDecoders.AppendElement(aDecoder);
|
||||
return;
|
||||
mIsWaitingOnCDM = true;
|
||||
}
|
||||
|
||||
aDecoder->SetTaskQueue(nullptr);
|
||||
@ -693,6 +695,7 @@ TrackBuffer::CompleteInitializeDecoder(SourceBufferDecoder* aDecoder)
|
||||
MSE_DEBUG("append was cancelled. Aborting initialization.");
|
||||
// If we reached this point, the SourceBuffer would have disconnected
|
||||
// the promise. So no need to reject it.
|
||||
RemoveDecoder(aDecoder);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -807,6 +810,12 @@ TrackBuffer::IsReady()
|
||||
return mInfo.HasAudio() || mInfo.HasVideo();
|
||||
}
|
||||
|
||||
bool
|
||||
TrackBuffer::IsWaitingOnCDMResource()
|
||||
{
|
||||
return mIsWaitingOnCDM;
|
||||
}
|
||||
|
||||
bool
|
||||
TrackBuffer::ContainsTime(int64_t aTime, int64_t aTolerance)
|
||||
{
|
||||
@ -875,21 +884,12 @@ TrackBuffer::SetCDMProxy(CDMProxy* aProxy)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
|
||||
|
||||
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
|
||||
nsresult rv = mDecoders[i]->SetCDMProxy(aProxy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
for (auto& decoder : mDecoders) {
|
||||
decoder->SetCDMProxy(aProxy);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mWaitingDecoders.Length(); ++i) {
|
||||
CDMCaps::AutoLock caps(aProxy->Capabilites());
|
||||
caps.CallOnMainThreadWhenCapsAvailable(
|
||||
NS_NewRunnableMethodWithArg<SourceBufferDecoder*>(this,
|
||||
&TrackBuffer::QueueInitializeDecoder,
|
||||
mWaitingDecoders[i]));
|
||||
}
|
||||
|
||||
mWaitingDecoders.Clear();
|
||||
|
||||
mIsWaitingOnCDM = false;
|
||||
mParentDecoder->NotifyWaitingForResourcesStatusChanged();
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
@ -76,6 +76,8 @@ public:
|
||||
// segment has successfully initialized by setting mHas{Audio,Video}..
|
||||
bool IsReady();
|
||||
|
||||
bool IsWaitingOnCDMResource();
|
||||
|
||||
// Returns true if any of the decoders managed by this track buffer
|
||||
// contain aTime in their buffered ranges.
|
||||
bool ContainsTime(int64_t aTime, int64_t aTolerance);
|
||||
@ -185,10 +187,6 @@ private:
|
||||
// Access protected by mParentDecoder's monitor.
|
||||
nsTArray<nsRefPtr<SourceBufferDecoder>> mInitializedDecoders;
|
||||
|
||||
// Decoders which are waiting on a Content Decryption Module to be able to
|
||||
// finish ReadMetadata.
|
||||
nsTArray<nsRefPtr<SourceBufferDecoder>> mWaitingDecoders;
|
||||
|
||||
// The decoder that the owning SourceBuffer is currently appending data to.
|
||||
// Modified on the main thread only.
|
||||
nsRefPtr<SourceBufferDecoder> mCurrentDecoder;
|
||||
@ -206,6 +204,9 @@ private:
|
||||
int64_t mLastTimestampOffset;
|
||||
int64_t mAdjustedTimestamp;
|
||||
|
||||
// True if at least one of our decoders has encrypted content.
|
||||
bool mIsWaitingOnCDM;
|
||||
|
||||
// Set when the first decoder used by this TrackBuffer is initialized.
|
||||
// Protected by mParentDecoder's monitor.
|
||||
MediaInfo mInfo;
|
||||
|
@ -370,8 +370,6 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
skip-if = buildapp == 'b2g' && toolkit != 'gonk' # bug 1082984
|
||||
[test_dormant_playback.html]
|
||||
skip-if = (os == 'win' && os_version == '5.1') || (os != 'win' && toolkit != 'gonk')
|
||||
[test_eme_access_control.html]
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908
|
||||
[test_eme_canvas_blocked.html]
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s || (os == 'win' && !debug) # bug 1043403, bug 1057908, bug 1140675
|
||||
[test_eme_non_mse_fails.html]
|
||||
|
@ -1,112 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test EME blocked cross-origin</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
<script type="text/javascript" src="eme.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
var manager = new MediaTestManager;
|
||||
|
||||
function TestNoCORS(test, token)
|
||||
{
|
||||
var token = token + "_nocors";
|
||||
|
||||
manager.started(token);
|
||||
|
||||
var v = document.createElement("video");
|
||||
|
||||
v.addEventListener("encrypted", function(ev) {
|
||||
is(ev.initDataType, "", "initDataType should be empty for CORS cross-origin media");
|
||||
is(ev.initData, null, "initData should be null for CORS cross-origin media");
|
||||
|
||||
manager.finished(token);
|
||||
});
|
||||
|
||||
v.addEventListener("error", function() {
|
||||
ok(false, "Should not receive error loading cross-origin media without crossorigin attribute");
|
||||
});
|
||||
|
||||
v.src = test.uri;
|
||||
}
|
||||
|
||||
function TestCORSFailure(test, token)
|
||||
{
|
||||
var token = token + "_corsfail";
|
||||
|
||||
manager.started(token);
|
||||
|
||||
var v = document.createElement("video");
|
||||
v.crossOrigin = true;
|
||||
|
||||
v.addEventListener("error", function(ev) {
|
||||
ok(true, "Should get error loading cross-origin media");
|
||||
manager.finished(token);
|
||||
});
|
||||
|
||||
v.addEventListener("encrypted", function() {
|
||||
ok(false, "Should not receive encrypted event loading cross-origin media");
|
||||
});
|
||||
|
||||
v.src = test.uri;
|
||||
}
|
||||
|
||||
function TestCORSSuccess(test, token)
|
||||
{
|
||||
var token = token + "_corsok";
|
||||
|
||||
manager.started(token);
|
||||
|
||||
var v = document.createElement("video");
|
||||
v.crossOrigin = true;
|
||||
|
||||
v.addEventListener("error", function(ev) {
|
||||
ok(false, "Should not get error loading cross-origin media");
|
||||
});
|
||||
|
||||
v.addEventListener("encrypted", function(ev) {
|
||||
ok(ev.initData.byteLength > 0, "Should get encryption initData loading cross-origin media");
|
||||
is(ev.initDataType, "cenc", "Should get correct encryption initDataType loading cross-origin media");
|
||||
manager.finished(token);
|
||||
});
|
||||
|
||||
v.src = test.uri;
|
||||
}
|
||||
|
||||
function startTest(test, token)
|
||||
{
|
||||
test.uri = "http://test1.mochi.test:8888/tests/dom/media/test/" + test.name;
|
||||
TestNoCORS(test, token);
|
||||
TestCORSFailure(test, token);
|
||||
|
||||
test.uri = "http://test1.mochi.test:8888/tests/dom/media/test/allowed.sjs?" + test.name;
|
||||
TestCORSSuccess(test, token);
|
||||
}
|
||||
|
||||
function beginTest() {
|
||||
manager.runTests(gEMETests.filter(t => t.crossOrigin), startTest);
|
||||
}
|
||||
|
||||
var prefs = [
|
||||
[ "media.mediasource.enabled", true ],
|
||||
[ "media.mediasource.whitelist", false ],
|
||||
[ "media.mediasource.mp4.enabled", true ],
|
||||
];
|
||||
|
||||
if (/Linux/.test(navigator.userAgent) ||
|
||||
!document.createElement('video').canPlayType("video/mp4")) {
|
||||
// XXX remove once we have mp4 PlatformDecoderModules on all platforms.
|
||||
prefs.push([ "media.fragmented-mp4.exposed", true ]);
|
||||
prefs.push([ "media.fragmented-mp4.use-blank-decoder", true ]);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({ "set" : prefs }, beginTest);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -40,17 +40,19 @@ function TestSetMediaKeys(test, token)
|
||||
|
||||
var v = document.createElement("video");
|
||||
|
||||
// XXX the encrypted event should never fire here after bug 1134434
|
||||
v.addEventListener("encrypted", function() {
|
||||
DoSetMediaKeys(v)
|
||||
ok(false, token + " should not fire encrypted event");
|
||||
});
|
||||
|
||||
.then(function() {
|
||||
ok(false, token + " expected setMediaKeys to fail.");
|
||||
manager.finished(token);
|
||||
}, function(err) {
|
||||
is(err.name, "NotSupportedError", token + " should return correct error");
|
||||
manager.finished(token);
|
||||
});
|
||||
var loadedMetadata = false;
|
||||
v.addEventListener("loadedmetadata", function() {
|
||||
loadedMetadata = true;
|
||||
});
|
||||
|
||||
v.addEventListener("error", function() {
|
||||
ok(true, token + " expected error event");
|
||||
ok(loadedMetadata, token + " expected loadedmetadata to have fired");
|
||||
manager.finished(token);
|
||||
});
|
||||
|
||||
v.src = test.name;
|
||||
|
@ -244,6 +244,9 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
|
||||
if (NS_WARN_IF(!stsThread)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// XXXnsm, Fix for Bug 1141332 means that if we decide to make this
|
||||
// streaming at some point, we'll need a different solution to that bug.
|
||||
rv = NS_AsyncCopy(body, responseBody, stsThread, NS_ASYNCCOPY_VIA_READSEGMENTS, 4096,
|
||||
RespondWithCopyComplete, closure.forget());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
17
dom/workers/test/serviceworkers/fetch/deliver-gzip.sjs
Normal file
17
dom/workers/test/serviceworkers/fetch/deliver-gzip.sjs
Normal file
@ -0,0 +1,17 @@
|
||||
function handleRequest(request, response) {
|
||||
// The string "hello" repeated 10 times followed by newline. Compressed using gzip.
|
||||
var bytes = [0x1f, 0x8b, 0x08, 0x08, 0x4d, 0xe2, 0xf9, 0x54, 0x00, 0x03, 0x68,
|
||||
0x65, 0x6c, 0x6c, 0x6f, 0x00, 0xcb, 0x48, 0xcd, 0xc9, 0xc9, 0xcf,
|
||||
0x20, 0x85, 0xe0, 0x02, 0x00, 0xf5, 0x4b, 0x38, 0xcf, 0x33, 0x00,
|
||||
0x00, 0x00];
|
||||
|
||||
response.setHeader("Content-Encoding", "gzip", false);
|
||||
response.setHeader("Content-Length", "" + bytes.length, false);
|
||||
response.setHeader("Content-Type", "text/plain", false);
|
||||
|
||||
var bos = Components.classes["@mozilla.org/binaryoutputstream;1"]
|
||||
.createInstance(Components.interfaces.nsIBinaryOutputStream);
|
||||
bos.setOutputStream(response.bodyOutputStream);
|
||||
|
||||
bos.writeByteArray(bytes, bytes.length);
|
||||
}
|
@ -71,3 +71,35 @@ fetch('headers.txt', function(xhr) {
|
||||
my_ok(xhr.responseText == "1", "request header checks should have passed");
|
||||
finish();
|
||||
}, null, [["X-Test1", "header1"], ["X-Test2", "header2"]]);
|
||||
|
||||
var expectedUncompressedResponse = "";
|
||||
for (var i = 0; i < 10; ++i) {
|
||||
expectedUncompressedResponse += "hello";
|
||||
}
|
||||
expectedUncompressedResponse += "\n";
|
||||
|
||||
// ServiceWorker does not intercept, at which point the network request should
|
||||
// be correctly decoded.
|
||||
fetch('deliver-gzip.sjs', function(xhr) {
|
||||
my_ok(xhr.status == 200, "network gzip load should be successful");
|
||||
my_ok(xhr.responseText == expectedUncompressedResponse, "network gzip load should have synthesized response.");
|
||||
my_ok(xhr.getResponseHeader("Content-Encoding") == "gzip", "network Content-Encoding should be gzip.");
|
||||
my_ok(xhr.getResponseHeader("Content-Length") == "35", "network Content-Length should be of original gzipped file.");
|
||||
finish();
|
||||
});
|
||||
|
||||
fetch('hello.gz', function(xhr) {
|
||||
my_ok(xhr.status == 200, "gzip load should be successful");
|
||||
my_ok(xhr.responseText == expectedUncompressedResponse, "gzip load should have synthesized response.");
|
||||
my_ok(xhr.getResponseHeader("Content-Encoding") == "gzip", "Content-Encoding should be gzip.");
|
||||
my_ok(xhr.getResponseHeader("Content-Length") == "35", "Content-Length should be of original gzipped file.");
|
||||
finish();
|
||||
});
|
||||
|
||||
fetch('hello-after-extracting.gz', function(xhr) {
|
||||
my_ok(xhr.status == 200, "gzip load should be successful");
|
||||
my_ok(xhr.responseText == expectedUncompressedResponse, "gzip load should have synthesized response.");
|
||||
my_ok(xhr.getResponseHeader("Content-Encoding") == "gzip", "Content-Encoding should be gzip.");
|
||||
my_ok(xhr.getResponseHeader("Content-Length") == "35", "Content-Length should be of original gzipped file.");
|
||||
finish();
|
||||
});
|
||||
|
@ -96,4 +96,23 @@ onfetch = function(ev) {
|
||||
new Response("check_intercepted_script();", {})
|
||||
));
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("deliver-gzip")) {
|
||||
// Don't handle the request, this will make Necko perform a network request, at
|
||||
// which point SetApplyConversion must be re-enabled, otherwise the request
|
||||
// will fail.
|
||||
return;
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("hello.gz")) {
|
||||
ev.respondWith(fetch("fetch/deliver-gzip.sjs"));
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("hello-after-extracting.gz")) {
|
||||
ev.respondWith(fetch("fetch/deliver-gzip.sjs").then(function(res) {
|
||||
return res.text().then(function(body) {
|
||||
return new Response(body, { status: res.status, statusText: res.statusText, headers: res.headers });
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ support-files =
|
||||
fetch/index.html
|
||||
fetch/fetch_worker_script.js
|
||||
fetch/fetch_tests.js
|
||||
fetch/deliver-gzip.sjs
|
||||
fetch/https/index.html
|
||||
fetch/https/register.html
|
||||
fetch/https/unregister.html
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user