Merge mozilla-central to fx-team

This commit is contained in:
Carsten "Tomcat" Book 2015-03-23 13:35:36 +01:00
commit 8a86055b89
165 changed files with 2682 additions and 884 deletions

View File

@ -12,6 +12,7 @@
#include "nsMai.h" #include "nsMai.h"
#include "nsIAccessibleTypes.h" #include "nsIAccessibleTypes.h"
#include "nsIURI.h" #include "nsIURI.h"
#include "ProxyAccessible.h"
using namespace mozilla; using namespace mozilla;
using namespace mozilla::a11y; using namespace mozilla::a11y;
@ -23,15 +24,19 @@ static void
getImagePositionCB(AtkImage* aImage, gint* aAccX, gint* aAccY, getImagePositionCB(AtkImage* aImage, gint* aAccX, gint* aAccY,
AtkCoordType aCoordType) AtkCoordType aCoordType)
{ {
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aImage)); nsIntPoint pos;
if (!accWrap || !accWrap->IsImage())
return;
ImageAccessible* image = accWrap->AsImage();
uint32_t geckoCoordType = (aCoordType == ATK_XY_WINDOW) ? uint32_t geckoCoordType = (aCoordType == ATK_XY_WINDOW) ?
nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE : nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE :
nsIAccessibleCoordinateType::COORDTYPE_SCREEN_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; *aAccX = pos.x;
*aAccY = pos.y; *aAccY = pos.y;
} }
@ -45,11 +50,14 @@ getImageDescriptionCB(AtkImage* aImage)
static void static void
getImageSizeCB(AtkImage* aImage, gint* aAccWidth, gint* aAccHeight) getImageSizeCB(AtkImage* aImage, gint* aAccWidth, gint* aAccHeight)
{ {
nsIntSize size;
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aImage)); AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aImage));
if (!accWrap || !accWrap->IsImage()) if (accWrap && accWrap->IsImage()) {
return; size = accWrap->AsImage()->Size();
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aImage))) {
size = proxy->ImageSize();
}
nsIntSize size = accWrap->AsImage()->Size();
*aAccWidth = size.width; *aAccWidth = size.width;
*aAccHeight = size.height; *aAccHeight = size.height;
} }

View File

@ -10,6 +10,7 @@
#include "ProxyAccessible.h" #include "ProxyAccessible.h"
#include "Relation.h" #include "Relation.h"
#include "HyperTextAccessible-inl.h" #include "HyperTextAccessible-inl.h"
#include "ImageAccessible.h"
#include "nsIPersistentProperties2.h" #include "nsIPersistentProperties2.h"
#include "nsISimpleEnumerator.h" #include "nsISimpleEnumerator.h"
@ -46,19 +47,26 @@ SerializeTree(Accessible* aRoot, nsTArray<AccessibleData>& aTree)
} }
Accessible* Accessible*
DocAccessibleChild::IdToAccessible(const uint64_t& aID) DocAccessibleChild::IdToAccessible(const uint64_t& aID) const
{ {
return mDoc->GetAccessibleByUniqueID(reinterpret_cast<void*>(aID)); return mDoc->GetAccessibleByUniqueID(reinterpret_cast<void*>(aID));
} }
HyperTextAccessible* HyperTextAccessible*
DocAccessibleChild::IdToHyperTextAccessible(const uint64_t& aID) DocAccessibleChild::IdToHyperTextAccessible(const uint64_t& aID) const
{ {
Accessible* acc = IdToAccessible(aID); Accessible* acc = IdToAccessible(aID);
MOZ_ASSERT(!acc || acc->IsHyperText()); MOZ_ASSERT(!acc || acc->IsHyperText());
return acc ? acc->AsHyperText() : nullptr; 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 void
DocAccessibleChild::ShowEvent(AccShowEvent* aShowEvent) DocAccessibleChild::ShowEvent(AccShowEvent* aShowEvent)
{ {
@ -584,5 +592,31 @@ DocAccessibleChild::RecvPasteText(const uint64_t& aID,
return true; 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;
}
} }
} }

View File

@ -15,6 +15,7 @@ namespace mozilla {
namespace a11y { namespace a11y {
class Accessible; class Accessible;
class HyperTextAccessible; class HyperTextAccessible;
class ImageAccessible;
class AccShowEvent; class AccShowEvent;
@ -34,9 +35,6 @@ public:
MOZ_COUNT_DTOR(DocAccessibleChild); MOZ_COUNT_DTOR(DocAccessibleChild);
} }
Accessible* IdToAccessible(const uint64_t& aID);
HyperTextAccessible* IdToHyperTextAccessible(const uint64_t& aID);
void ShowEvent(AccShowEvent* aShowEvent); void ShowEvent(AccShowEvent* aShowEvent);
/* /*
@ -184,7 +182,19 @@ public:
virtual bool RecvPasteText(const uint64_t& aID, virtual bool RecvPasteText(const uint64_t& aID,
const int32_t& aPosition) override; 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: 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, bool PersistentPropertiesToArray(nsIPersistentProperties* aProps,
nsTArray<Attribute>* aAttributes); nsTArray<Attribute>* aAttributes);

View File

@ -8,6 +8,8 @@ include protocol PContent;
include "mozilla/GfxMessageUtils.h"; include "mozilla/GfxMessageUtils.h";
using struct nsIntPoint from "nsRect.h";
using struct nsIntSize from "nsRect.h";
using struct nsIntRect from "nsRect.h"; using struct nsIntRect from "nsRect.h";
namespace mozilla { namespace mozilla {
@ -121,6 +123,9 @@ child:
prio(high) sync CutText(uint64_t aID, int32_t aStartPos, int32_t aEndPos); 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 DeleteText(uint64_t aID, int32_t aStartPos, int32_t aEndPos);
prio(high) sync PasteText(uint64_t aID, int32_t aPosition); 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);
}; };
} }

View File

@ -363,5 +363,21 @@ ProxyAccessible::PasteText(int32_t aPosition)
unused << mDoc->SendPasteText(mID, 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;
}
} }
} }

View File

@ -177,6 +177,10 @@ public:
void PasteText(int32_t aPosition); void PasteText(int32_t aPosition);
nsIntPoint ImagePosition(uint32_t aCoordType);
nsIntSize ImageSize();
/** /**
* Allow the platform to store a pointers worth of data on us. * Allow the platform to store a pointers worth of data on us.
*/ */

View File

@ -26,6 +26,24 @@ if CONFIG['ACCESSIBILITY']:
'../generic', '../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' FINAL_LIBRARY = 'xul'
include('/ipc/chromium/chromium-config.mozbuild') include('/ipc/chromium/chromium-config.mozbuild')

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db"> <project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </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="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> <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="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>

View File

@ -17,7 +17,7 @@
</project> </project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <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="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/> <project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b685e3aab4fde7624d78993877a8f7910f2a5f06"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="b685e3aab4fde7624d78993877a8f7910f2a5f06"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db"> <project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </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="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3"> <project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </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="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> <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="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db"> <project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </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="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -17,7 +17,7 @@
</project> </project>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <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="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/> <project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b685e3aab4fde7624d78993877a8f7910f2a5f06"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="b685e3aab4fde7624d78993877a8f7910f2a5f06"/>

View File

@ -1,9 +1,9 @@
{ {
"git": { "git": {
"git_revision": "9b6f3024e4d0e62dd057231f4b14abe1782932ab", "git_revision": "8eac260ee81a8aca05770d18c5736536d44ee7a7",
"remote": "https://git.mozilla.org/releases/gaia.git", "remote": "https://git.mozilla.org/releases/gaia.git",
"branch": "" "branch": ""
}, },
"revision": "4c2751f5fc24ffad381aae2c50b160cba0f33d36", "revision": "1400d176ecef76d06b012fb082c246eb17d1d30f",
"repo_path": "integration/gaia-central" "repo_path": "integration/gaia-central"
} }

View File

@ -17,7 +17,7 @@
</project> </project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <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="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/> <project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b685e3aab4fde7624d78993877a8f7910f2a5f06"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="b685e3aab4fde7624d78993877a8f7910f2a5f06"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3"> <project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </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="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="86cd7486d8e50eaac8ef6fe2f51f09d25194577b"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -315,8 +315,10 @@ function assert_records(expected, desc) {
assert_records([{ added: [firstPlayer], changed: [], removed: [] }], assert_records([{ added: [firstPlayer], changed: [], removed: [] }],
"records after transition start"); "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(); yield await_frame();
firstPlayer.currentTime = 50000;
// Reverse the transition by setting the background-color back to its // Reverse the transition by setting the background-color back to its
// original value. // original value.
@ -328,6 +330,9 @@ function assert_records(expected, desc) {
var secondPlayer = players[0]; 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 // Wait for the single MutationRecord for the removal of the original
// AnimationPlayer and the addition of the new AnimationPlayer to // AnimationPlayer and the addition of the new AnimationPlayer to
// be delivered. // be delivered.
@ -365,8 +370,10 @@ function assert_records(expected, desc) {
assert_records([{ added: players, changed: [], removed: [] }], assert_records([{ added: players, changed: [], removed: [] }],
"records after transition starts"); "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(); yield await_frame();
players.forEach(p => p.currentTime = 50000);
is(players.filter(p => p.playState == "running").length, 3, "number of running AnimationPlayers"); is(players.filter(p => p.playState == "running").length, 3, "number of running AnimationPlayers");

View File

@ -7,6 +7,7 @@
#include "mozilla/dom/cache/AutoUtils.h" #include "mozilla/dom/cache/AutoUtils.h"
#include "mozilla/unused.h" #include "mozilla/unused.h"
#include "mozilla/dom/cache/CachePushStreamChild.h"
#include "mozilla/dom/cache/CacheStreamControlParent.h" #include "mozilla/dom/cache/CacheStreamControlParent.h"
#include "mozilla/dom/cache/ReadStream.h" #include "mozilla/dom/cache/ReadStream.h"
#include "mozilla/dom/cache/SavedTypes.h" #include "mozilla/dom/cache/SavedTypes.h"
@ -19,6 +20,7 @@
namespace { namespace {
using mozilla::unused; using mozilla::unused;
using mozilla::dom::cache::CachePushStreamChild;
using mozilla::dom::cache::PCacheReadStream; using mozilla::dom::cache::PCacheReadStream;
using mozilla::dom::cache::PCacheReadStreamOrVoid; using mozilla::dom::cache::PCacheReadStreamOrVoid;
using mozilla::ipc::FileDescriptor; using mozilla::ipc::FileDescriptor;
@ -28,8 +30,8 @@ using mozilla::ipc::OptionalFileDescriptorSet;
enum CleanupAction enum CleanupAction
{ {
ForgetFds, Forget,
DeleteFds Delete
}; };
void void
@ -46,7 +48,7 @@ CleanupChildFds(PCacheReadStream& aReadStream, CleanupAction aAction)
static_cast<FileDescriptorSetChild*>(aReadStream.fds().get_PFileDescriptorSetChild()); static_cast<FileDescriptorSetChild*>(aReadStream.fds().get_PFileDescriptorSetChild());
MOZ_ASSERT(fdSetActor); MOZ_ASSERT(fdSetActor);
if (aAction == DeleteFds) { if (aAction == Delete) {
unused << fdSetActor->Send__delete__(fdSetActor); unused << fdSetActor->Send__delete__(fdSetActor);
} }
@ -57,13 +59,39 @@ CleanupChildFds(PCacheReadStream& aReadStream, CleanupAction aAction)
} }
void 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) { if (aReadStreamOrVoid.type() == PCacheReadStreamOrVoid::Tvoid_t) {
return; return;
} }
CleanupChildFds(aReadStreamOrVoid.get_PCacheReadStream(), aAction); CleanupChild(aReadStreamOrVoid.get_PCacheReadStream(), aAction);
} }
void void
@ -80,7 +108,7 @@ CleanupParentFds(PCacheReadStream& aReadStream, CleanupAction aAction)
static_cast<FileDescriptorSetParent*>(aReadStream.fds().get_PFileDescriptorSetParent()); static_cast<FileDescriptorSetParent*>(aReadStream.fds().get_PFileDescriptorSetParent());
MOZ_ASSERT(fdSetActor); MOZ_ASSERT(fdSetActor);
if (aAction == DeleteFds) { if (aAction == Delete) {
unused << fdSetActor->Send__delete__(fdSetActor); unused << fdSetActor->Send__delete__(fdSetActor);
} }
@ -133,8 +161,8 @@ AutoChildRequest::~AutoChildRequest()
return; return;
} }
CleanupAction action = mSent ? ForgetFds : DeleteFds; CleanupAction action = mSent ? Forget : Delete;
CleanupChildFds(mRequestOrVoid.get_PCacheRequest().body(), action); CleanupChild(mRequestOrVoid.get_PCacheRequest().body(), action);
} }
void void
@ -173,9 +201,9 @@ AutoChildRequestList::AutoChildRequestList(TypeUtils* aTypeUtils,
AutoChildRequestList::~AutoChildRequestList() AutoChildRequestList::~AutoChildRequestList()
{ {
CleanupAction action = mSent ? ForgetFds : DeleteFds; CleanupAction action = mSent ? Forget : Delete;
for (uint32_t i = 0; i < mRequestList.Length(); ++i) { 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() AutoChildRequestResponse::~AutoChildRequestResponse()
{ {
CleanupAction action = mSent ? ForgetFds : DeleteFds; CleanupAction action = mSent ? Forget : Delete;
CleanupChildFds(mRequestResponse.request().body(), action); CleanupChild(mRequestResponse.request().body(), action);
CleanupChildFds(mRequestResponse.response().body(), action); CleanupChild(mRequestResponse.response().body(), action);
} }
void void
@ -311,7 +339,7 @@ AutoParentRequestList::AutoParentRequestList(PBackgroundParent* aManager,
AutoParentRequestList::~AutoParentRequestList() AutoParentRequestList::~AutoParentRequestList()
{ {
CleanupAction action = mSent ? ForgetFds : DeleteFds; CleanupAction action = mSent ? Forget : Delete;
for (uint32_t i = 0; i < mRequestList.Length(); ++i) { for (uint32_t i = 0; i < mRequestList.Length(); ++i) {
CleanupParentFds(mRequestList[i].body(), action); CleanupParentFds(mRequestList[i].body(), action);
} }
@ -355,7 +383,7 @@ AutoParentResponseList::AutoParentResponseList(PBackgroundParent* aManager,
AutoParentResponseList::~AutoParentResponseList() AutoParentResponseList::~AutoParentResponseList()
{ {
CleanupAction action = mSent ? ForgetFds : DeleteFds; CleanupAction action = mSent ? Forget : Delete;
for (uint32_t i = 0; i < mResponseList.Length(); ++i) { for (uint32_t i = 0; i < mResponseList.Length(); ++i) {
CleanupParentFds(mResponseList[i].body(), action); CleanupParentFds(mResponseList[i].body(), action);
} }
@ -402,7 +430,7 @@ AutoParentResponseOrVoid::~AutoParentResponseOrVoid()
return; return;
} }
CleanupAction action = mSent ? ForgetFds : DeleteFds; CleanupAction action = mSent ? Forget : Delete;
CleanupParentFds(mResponseOrVoid.get_PCacheResponse().body(), action); CleanupParentFds(mResponseOrVoid.get_PCacheResponse().body(), action);
} }

13
dom/cache/Cache.cpp vendored
View File

@ -14,6 +14,7 @@
#include "mozilla/dom/CacheBinding.h" #include "mozilla/dom/CacheBinding.h"
#include "mozilla/dom/cache/AutoUtils.h" #include "mozilla/dom/cache/AutoUtils.h"
#include "mozilla/dom/cache/CacheChild.h" #include "mozilla/dom/cache/CacheChild.h"
#include "mozilla/dom/cache/CachePushStreamChild.h"
#include "mozilla/dom/cache/ReadStream.h" #include "mozilla/dom/cache/ReadStream.h"
#include "mozilla/dom/cache/TypeUtils.h" #include "mozilla/dom/cache/TypeUtils.h"
#include "mozilla/ErrorResult.h" #include "mozilla/ErrorResult.h"
@ -526,6 +527,18 @@ Cache::AssertOwningThread() const
} }
#endif #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 void
Cache::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) Cache::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
{ {

7
dom/cache/Cache.h vendored
View File

@ -39,8 +39,8 @@ class PCacheResponse;
class PCacheResponseOrVoid; class PCacheResponseOrVoid;
class Cache final : public PromiseNativeHandler class Cache final : public PromiseNativeHandler
, public nsWrapperCache , public nsWrapperCache
, public TypeUtils , public TypeUtils
{ {
public: public:
Cache(nsIGlobalObject* aGlobal, CacheChild* aActor); Cache(nsIGlobalObject* aGlobal, CacheChild* aActor);
@ -97,6 +97,9 @@ public:
virtual void AssertOwningThread() const override; virtual void AssertOwningThread() const override;
#endif #endif
virtual CachePushStreamChild*
CreatePushStream(nsIAsyncInputStream* aStream) override;
// PromiseNativeHandler methods // PromiseNativeHandler methods
virtual void virtual void
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override; ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;

View File

@ -9,6 +9,7 @@
#include "mozilla/unused.h" #include "mozilla/unused.h"
#include "mozilla/dom/cache/ActorUtils.h" #include "mozilla/dom/cache/ActorUtils.h"
#include "mozilla/dom/cache/Cache.h" #include "mozilla/dom/cache/Cache.h"
#include "mozilla/dom/cache/PCachePushStreamChild.h"
#include "mozilla/dom/cache/StreamUtils.h" #include "mozilla/dom/cache/StreamUtils.h"
namespace mozilla { namespace mozilla {
@ -94,6 +95,20 @@ CacheChild::ActorDestroy(ActorDestroyReason aReason)
RemoveFeature(); RemoveFeature();
} }
PCachePushStreamChild*
CacheChild::AllocPCachePushStreamChild()
{
MOZ_CRASH("CachePushStreamChild should be manually constructed.");
return nullptr;
}
bool
CacheChild::DeallocPCachePushStreamChild(PCachePushStreamChild* aActor)
{
delete aActor;
return true;
}
bool bool
CacheChild::RecvMatchResponse(const RequestId& requestId, const nsresult& aRv, CacheChild::RecvMatchResponse(const RequestId& requestId, const nsresult& aRv,
const PCacheResponseOrVoid& aResponse) const PCacheResponseOrVoid& aResponse)

View File

@ -17,7 +17,7 @@ namespace cache {
class Cache; class Cache;
class CacheChild final : public PCacheChild class CacheChild final : public PCacheChild
, public ActorChild , public ActorChild
{ {
public: public:
CacheChild(); CacheChild();
@ -41,6 +41,12 @@ private:
virtual void virtual void
ActorDestroy(ActorDestroyReason aReason) override; ActorDestroy(ActorDestroyReason aReason) override;
virtual PCachePushStreamChild*
AllocPCachePushStreamChild() override;
virtual bool
DeallocPCachePushStreamChild(PCachePushStreamChild* aActor) override;
virtual bool virtual bool
RecvMatchResponse(const RequestId& requestId, const nsresult& aRv, RecvMatchResponse(const RequestId& requestId, const nsresult& aRv,
const PCacheResponseOrVoid& aResponse) override; const PCacheResponseOrVoid& aResponse) override;

View File

@ -8,6 +8,7 @@
#include "mozilla/DebugOnly.h" #include "mozilla/DebugOnly.h"
#include "mozilla/dom/cache/AutoUtils.h" #include "mozilla/dom/cache/AutoUtils.h"
#include "mozilla/dom/cache/CachePushStreamParent.h"
#include "mozilla/dom/cache/CacheStreamControlParent.h" #include "mozilla/dom/cache/CacheStreamControlParent.h"
#include "mozilla/dom/cache/ReadStream.h" #include "mozilla/dom/cache/ReadStream.h"
#include "mozilla/dom/cache/SavedTypes.h" #include "mozilla/dom/cache/SavedTypes.h"
@ -61,6 +62,19 @@ CacheParent::ActorDestroy(ActorDestroyReason aReason)
mManager = nullptr; mManager = nullptr;
} }
PCachePushStreamParent*
CacheParent::AllocPCachePushStreamParent()
{
return CachePushStreamParent::Create();
}
bool
CacheParent::DeallocPCachePushStreamParent(PCachePushStreamParent* aActor)
{
delete aActor;
return true;
}
bool bool
CacheParent::RecvTeardown() CacheParent::RecvTeardown()
{ {
@ -259,13 +273,27 @@ CacheParent::DeserializeCacheStream(const PCacheReadStreamOrVoid& aStreamOrVoid)
return nullptr; return nullptr;
} }
nsCOMPtr<nsIInputStream> stream;
const PCacheReadStream& readStream = aStreamOrVoid.get_PCacheReadStream(); 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) { if (stream) {
return stream.forget(); return stream.forget();
} }
// Option 3: A stream was serialized using normal methods.
nsAutoTArray<FileDescriptor, 4> fds; nsAutoTArray<FileDescriptor, 4> fds;
if (readStream.fds().type() == if (readStream.fds().type() ==
OptionalFileDescriptorSet::TPFileDescriptorSetChild) { OptionalFileDescriptorSet::TPFileDescriptorSetChild) {

View File

@ -22,8 +22,8 @@ namespace cache {
struct SavedResponse; struct SavedResponse;
class CacheParent final : public PCacheParent class CacheParent final : public PCacheParent
, public Manager::Listener , public Manager::Listener
, public FetchPut::Listener , public FetchPut::Listener
{ {
public: public:
CacheParent(cache::Manager* aManager, CacheId aCacheId); CacheParent(cache::Manager* aManager, CacheId aCacheId);
@ -32,6 +32,8 @@ public:
private: private:
// PCacheParent method // PCacheParent method
virtual void ActorDestroy(ActorDestroyReason aReason) override; virtual void ActorDestroy(ActorDestroyReason aReason) override;
virtual PCachePushStreamParent* AllocPCachePushStreamParent() override;
virtual bool DeallocPCachePushStreamParent(PCachePushStreamParent* aActor) override;
virtual bool RecvTeardown() override; virtual bool RecvTeardown() override;
virtual bool virtual bool
RecvMatch(const RequestId& aRequestId, const PCacheRequest& aRequest, RecvMatch(const RequestId& aRequestId, const PCacheRequest& aRequest,

259
dom/cache/CachePushStreamChild.cpp vendored Normal file
View 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
View 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
View 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
View 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

View File

@ -516,6 +516,13 @@ CacheStorage::AssertOwningThread() const
} }
#endif #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 void
CacheStorage::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) CacheStorage::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
{ {

View File

@ -44,9 +44,9 @@ class Feature;
class PCacheResponseOrVoid; class PCacheResponseOrVoid;
class CacheStorage final : public nsIIPCBackgroundChildCreateCallback class CacheStorage final : public nsIIPCBackgroundChildCreateCallback
, public nsWrapperCache , public nsWrapperCache
, public TypeUtils , public TypeUtils
, public PromiseNativeHandler , public PromiseNativeHandler
{ {
typedef mozilla::ipc::PBackgroundChild PBackgroundChild; typedef mozilla::ipc::PBackgroundChild PBackgroundChild;
@ -97,6 +97,9 @@ public:
virtual void AssertOwningThread() const override; virtual void AssertOwningThread() const override;
#endif #endif
virtual CachePushStreamChild*
CreatePushStream(nsIAsyncInputStream* aStream) override;
// PromiseNativeHandler methods // PromiseNativeHandler methods
virtual void virtual void
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override; ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;

View File

@ -20,7 +20,7 @@ class PCacheChild;
class Feature; class Feature;
class CacheStorageChild final : public PCacheStorageChild class CacheStorageChild final : public PCacheStorageChild
, public ActorChild , public ActorChild
{ {
public: public:
CacheStorageChild(CacheStorage* aListener, Feature* aFeature); CacheStorageChild(CacheStorage* aListener, Feature* aFeature);
@ -41,6 +41,7 @@ public:
private: private:
// PCacheStorageChild methods // PCacheStorageChild methods
virtual void ActorDestroy(ActorDestroyReason aReason) override; virtual void ActorDestroy(ActorDestroyReason aReason) override;
virtual bool RecvMatchResponse(const RequestId& aRequestId, virtual bool RecvMatchResponse(const RequestId& aRequestId,
const nsresult& aRv, const nsresult& aRv,
const PCacheResponseOrVoid& response) override; const PCacheResponseOrVoid& response) override;

View File

@ -23,8 +23,8 @@ class CacheStreamControlParent;
class ManagerId; class ManagerId;
class CacheStorageParent final : public PCacheStorageParent class CacheStorageParent final : public PCacheStorageParent
, public PrincipalVerifier::Listener , public PrincipalVerifier::Listener
, public Manager::Listener , public Manager::Listener
{ {
public: public:
CacheStorageParent(PBackgroundParent* aManagingActor, Namespace aNamespace, CacheStorageParent(PBackgroundParent* aManagingActor, Namespace aNamespace,

View File

@ -19,8 +19,8 @@ namespace cache {
class ReadStream; class ReadStream;
class CacheStreamControlChild final : public PCacheStreamControlChild class CacheStreamControlChild final : public PCacheStreamControlChild
, public StreamControl , public StreamControl
, public ActorChild , public ActorChild
{ {
public: public:
CacheStreamControlChild(); CacheStreamControlChild();

View File

@ -18,8 +18,8 @@ namespace cache {
class ReadStream; class ReadStream;
class StreamList; class StreamList;
class CacheStreamControlParent : public PCacheStreamControlParent class CacheStreamControlParent final : public PCacheStreamControlParent
, public StreamControl , public StreamControl
{ {
public: public:
CacheStreamControlParent(); CacheStreamControlParent();

View File

@ -320,7 +320,7 @@ Context::QuotaInitRunnable::Run()
// runnable executes the Action on the appropriate threads while the Context // runnable executes the Action on the appropriate threads while the Context
// is initialized. // is initialized.
class Context::ActionRunnable final : public nsIRunnable class Context::ActionRunnable final : public nsIRunnable
, public Action::Resolver , public Action::Resolver
{ {
public: public:
ActionRunnable(Context* aContext, nsIEventTarget* aTarget, Action* aAction, ActionRunnable(Context* aContext, nsIEventTarget* aTarget, Action* aAction,

View File

@ -458,6 +458,12 @@ FetchPut::AssertOwningThread() const
} }
#endif #endif
CachePushStreamChild*
FetchPut::CreatePushStream(nsIAsyncInputStream* aStream)
{
MOZ_CRASH("FetchPut should never create a push stream!");
}
} // namespace cache } // namespace cache
} // namespace dom } // namespace dom
} // namespace mozilla } // namespace mozilla

View File

@ -30,7 +30,7 @@ class Response;
namespace cache { namespace cache {
class FetchPut final : public Manager::Listener class FetchPut final : public Manager::Listener
, public TypeUtils , public TypeUtils
{ {
public: public:
typedef std::pair<nsRefPtr<Request>, nsRefPtr<Response>> PutPair; typedef std::pair<nsRefPtr<Request>, nsRefPtr<Response>> PutPair;
@ -94,6 +94,9 @@ private:
virtual void AssertOwningThread() const override; virtual void AssertOwningThread() const override;
#endif #endif
virtual CachePushStreamChild*
CreatePushStream(nsIAsyncInputStream* aStream) override;
Listener* mListener; Listener* mListener;
nsRefPtr<Manager> mManager; nsRefPtr<Manager> mManager;
const RequestId mRequestId; const RequestId mRequestId;

View File

@ -3,6 +3,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */ * You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PBackground; include protocol PBackground;
include protocol PCachePushStream;
include PCacheTypes; include PCacheTypes;
include protocol PFileDescriptorSet; include protocol PFileDescriptorSet;
@ -19,8 +20,10 @@ namespace cache {
protocol PCache protocol PCache
{ {
manager PBackground; manager PBackground;
manages PCachePushStream;
parent: parent:
PCachePushStream();
Teardown(); Teardown();
Match(RequestId requestId, PCacheRequest request, PCacheQueryParams params); Match(RequestId requestId, PCacheRequest request, PCacheQueryParams params);
MatchAll(RequestId requestId, PCacheRequestOrVoid request, PCacheQueryParams params); MatchAll(RequestId requestId, PCacheRequestOrVoid request, PCacheQueryParams params);

28
dom/cache/PCachePushStream.ipdl vendored Normal file
View 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

View File

@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PCachePushStream;
include protocol PCacheStreamControl; include protocol PCacheStreamControl;
include PHeaders; include PHeaders;
include InputStreamParams; include InputStreamParams;
@ -32,6 +33,7 @@ struct PCacheReadStream
OptionalInputStreamParams params; OptionalInputStreamParams params;
OptionalFileDescriptorSet fds; OptionalFileDescriptorSet fds;
nullable PCacheStreamControl control; nullable PCacheStreamControl control;
nullable PCachePushStream pushStream;
}; };
union PCacheReadStreamOrVoid union PCacheReadStreamOrVoid

View File

@ -210,6 +210,11 @@ ReadStream::Inner::Serialize(PCacheReadStream* aReadStreamOut)
MOZ_ASSERT(mState == Open); MOZ_ASSERT(mState == Open);
MOZ_ASSERT(mControl); 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; aReadStreamOut->id() = mId;
mControl->SerializeControl(aReadStreamOut); mControl->SerializeControl(aReadStreamOut);
@ -406,6 +411,9 @@ ReadStream::Create(const PCacheReadStream& aReadStream)
return nullptr; return nullptr;
} }
MOZ_ASSERT(!aReadStream.pushStreamChild());
MOZ_ASSERT(!aReadStream.pushStreamParent());
// Control is guaranteed to survive this method as ActorDestroy() cannot // Control is guaranteed to survive this method as ActorDestroy() cannot
// run on this thread until we complete. // run on this thread until we complete.
StreamControl* control; StreamControl* control;

View File

@ -21,7 +21,7 @@ class CacheStreamControlParent;
class Context; class Context;
class Manager; class Manager;
class StreamList class StreamList final
{ {
public: public:
StreamList(Manager* aManager, Context* aContext); StreamList(Manager* aManager, Context* aContext);

View File

@ -11,6 +11,7 @@
#include "mozilla/dom/InternalRequest.h" #include "mozilla/dom/InternalRequest.h"
#include "mozilla/dom/Request.h" #include "mozilla/dom/Request.h"
#include "mozilla/dom/Response.h" #include "mozilla/dom/Response.h"
#include "mozilla/dom/cache/CachePushStreamChild.h"
#include "mozilla/dom/cache/PCacheTypes.h" #include "mozilla/dom/cache/PCacheTypes.h"
#include "mozilla/dom/cache/ReadStream.h" #include "mozilla/dom/cache/ReadStream.h"
#include "mozilla/ipc/BackgroundChild.h" #include "mozilla/ipc/BackgroundChild.h"
@ -29,6 +30,13 @@
namespace { namespace {
using mozilla::ErrorResult; 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 // 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 // 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); *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 } // anonymous namespace
namespace mozilla { namespace mozilla {
@ -413,64 +446,61 @@ TypeUtils::SerializeCacheStream(nsIInputStream* aStream,
return; return;
} }
// Option 1: Send a cache-specific ReadStream if we can.
nsRefPtr<ReadStream> controlled = do_QueryObject(aStream); nsRefPtr<ReadStream> controlled = do_QueryObject(aStream);
if (controlled) { if (controlled) {
controlled->Serialize(aStreamOut); controlled->Serialize(aStreamOut);
return; 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; PCacheReadStream readStream;
readStream.controlChild() = nullptr; readStream.controlChild() = nullptr;
readStream.controlParent() = nullptr; readStream.controlParent() = nullptr;
readStream.pushStreamChild() = nullptr;
readStream.pushStreamParent() = nullptr;
nsAutoTArray<FileDescriptor, 4> fds; // Option 2: Do normal stream serialization if its supported.
SerializeInputStream(aStream, readStream.params(), fds); nsCOMPtr<nsIIPCSerializableInputStream> serial = do_QueryInterface(aStream);
if (serial) {
SerializeNormalStream(aStream, readStream);
PFileDescriptorSetChild* fdSet = nullptr; // Option 3: As a last resort push data across manually. Should only be
if (!fds.IsEmpty()) { // needed for nsPipe input stream. Only works for async,
// We should not be serializing until we have an actor ready // non-blocking streams.
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;
} else { } else {
readStream.fds() = void_t(); SerializePushStream(aStream, readStream, aRv);
if (NS_WARN_IF(aRv.Failed())) { return; }
} }
*aStreamOut = readStream; *aStreamOut = readStream;
} }
nsIThread* void
TypeUtils::GetStreamThread() TypeUtils::SerializePushStream(nsIInputStream* aStream,
PCacheReadStream& aReadStreamOut,
ErrorResult& aRv)
{ {
AssertOwningThread(); nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(aStream);
if (NS_WARN_IF(!asyncStream)) {
if (!mStreamThread) { aRv = NS_ERROR_FAILURE;
// Named threads only allow 16 bytes for their names. Try to make return;
// 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.");
}
} }
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 } // namespace cache

13
dom/cache/TypeUtils.h vendored
View File

@ -9,10 +9,10 @@
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/BindingUtils.h"
#include "nsCOMPtr.h"
#include "nsError.h" #include "nsError.h"
class nsIGlobalObject; class nsIGlobalObject;
class nsIAsyncInputStream;
class nsIInputStream; class nsIInputStream;
namespace mozilla { namespace mozilla {
@ -28,7 +28,9 @@ class Response;
namespace cache { namespace cache {
class CachePushStreamChild;
class PCacheQueryParams; class PCacheQueryParams;
class PCacheReadStream;
class PCacheReadStreamOrVoid; class PCacheReadStreamOrVoid;
class PCacheRequest; class PCacheRequest;
class PCacheResponse; class PCacheResponse;
@ -63,6 +65,9 @@ public:
inline void AssertOwningThread() const { } inline void AssertOwningThread() const { }
#endif #endif
virtual CachePushStreamChild*
CreatePushStream(nsIAsyncInputStream* aStream) = 0;
already_AddRefed<InternalRequest> already_AddRefed<InternalRequest>
ToInternalRequest(const RequestOrUSVString& aIn, BodyAction aBodyAction, ToInternalRequest(const RequestOrUSVString& aIn, BodyAction aBodyAction,
ErrorResult& aRv); ErrorResult& aRv);
@ -107,9 +112,9 @@ private:
SerializeCacheStream(nsIInputStream* aStream, PCacheReadStreamOrVoid* aStreamOut, SerializeCacheStream(nsIInputStream* aStream, PCacheReadStreamOrVoid* aStreamOut,
ErrorResult& aRv); ErrorResult& aRv);
nsIThread* GetStreamThread(); void
SerializePushStream(nsIInputStream* aStream, PCacheReadStream& aReadStreamOut,
nsCOMPtr<nsIThread> mStreamThread; ErrorResult& aRv);
}; };
} // namespace cache } // namespace cache

5
dom/cache/moz.build vendored
View File

@ -12,6 +12,8 @@ EXPORTS.mozilla.dom.cache += [
'Cache.h', 'Cache.h',
'CacheChild.h', 'CacheChild.h',
'CacheParent.h', 'CacheParent.h',
'CachePushStreamChild.h',
'CachePushStreamParent.h',
'CacheStorage.h', 'CacheStorage.h',
'CacheStorageChild.h', 'CacheStorageChild.h',
'CacheStorageParent.h', 'CacheStorageParent.h',
@ -44,6 +46,8 @@ UNIFIED_SOURCES += [
'Cache.cpp', 'Cache.cpp',
'CacheChild.cpp', 'CacheChild.cpp',
'CacheParent.cpp', 'CacheParent.cpp',
'CachePushStreamChild.cpp',
'CachePushStreamParent.cpp',
'CacheStorage.cpp', 'CacheStorage.cpp',
'CacheStorageChild.cpp', 'CacheStorageChild.cpp',
'CacheStorageParent.cpp', 'CacheStorageParent.cpp',
@ -69,6 +73,7 @@ UNIFIED_SOURCES += [
IPDL_SOURCES += [ IPDL_SOURCES += [
'CacheInitData.ipdlh', 'CacheInitData.ipdlh',
'PCache.ipdl', 'PCache.ipdl',
'PCachePushStream.ipdl',
'PCacheStorage.ipdl', 'PCacheStorage.ipdl',
'PCacheStreamControl.ipdl', 'PCacheStreamControl.ipdl',
'PCacheTypes.ipdlh', 'PCacheTypes.ipdlh',

View File

@ -16,6 +16,7 @@ support-files =
vary.sjs vary.sjs
test_caches.js test_caches.js
test_cache_keys.js test_cache_keys.js
test_cache_put.js
[test_cache.html] [test_cache.html]
[test_cache_add.html] [test_cache_add.html]
@ -25,3 +26,4 @@ support-files =
[test_cache_match_vary.html] [test_cache_match_vary.html]
[test_caches.html] [test_caches.html]
[test_cache_keys.html] [test_cache_keys.html]
[test_cache_put.html]

View 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>

View 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();
});

View File

@ -4218,6 +4218,13 @@ CanvasRenderingContext2D::DrawImage(const HTMLImageOrCanvasOrVideoElement& image
return; return;
} }
#ifdef MOZ_EME
if (video->ContainsRestrictedContent()) {
error.Throw(NS_ERROR_NOT_AVAILABLE);
return;
}
#endif
uint16_t readyState; uint16_t readyState;
if (NS_SUCCEEDED(video->GetReadyState(&readyState)) && if (NS_SUCCEEDED(video->GetReadyState(&readyState)) &&
readyState < nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA) { readyState < nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA) {

View File

@ -671,14 +671,6 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest,
NS_WARNING("Failed to visit all headers."); 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 // 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 // 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 // pipe has infinite space. The nsIChannel will continue to buffer data in
@ -697,8 +689,17 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest,
// Cancel request. // Cancel request.
return rv; 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); nsCOMPtr<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {

View File

@ -3066,7 +3066,7 @@ void HTMLMediaElement::MetadataLoaded(const MediaInfo* aInfo,
nsAutoPtr<const MetadataTags> aTags) nsAutoPtr<const MetadataTags> aTags)
{ {
mMediaInfo = *aInfo; mMediaInfo = *aInfo;
mIsEncrypted = aInfo->mIsEncrypted; mIsEncrypted = aInfo->IsEncrypted();
mTags = aTags.forget(); mTags = aTags.forget();
mLoadedDataFired = false; mLoadedDataFired = false;
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA); ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
@ -3086,6 +3086,16 @@ void HTMLMediaElement::MetadataLoaded(const MediaInfo* aInfo,
ProcessMediaFragmentURI(); ProcessMediaFragmentURI();
mDecoder->SetFragmentEndTime(mFragmentEnd); 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. // Expose the tracks to JS directly.
for (OutputMediaStream& out : mOutputStreams) { for (OutputMediaStream& out : mOutputStreams) {

View File

@ -571,6 +571,11 @@ child:
int32_t aModifiers, int32_t aModifiers,
bool aPreventDefault); bool aPreventDefault);
/**
* APZ notification for mouse scroll testing events.
*/
MouseScrollTestEvent(ViewID aScrollId, nsString aEvent);
CompositionEvent(WidgetCompositionEvent event); CompositionEvent(WidgetCompositionEvent event);
SelectionEvent(WidgetSelectionEvent event); SelectionEvent(WidgetSelectionEvent event);

View File

@ -2199,6 +2199,13 @@ TabChild::RecvMouseWheelEvent(const WidgetWheelEvent& aEvent,
return true; return true;
} }
bool
TabChild::RecvMouseScrollTestEvent(const FrameMetrics::ViewID& aScrollId, const nsString& aEvent)
{
APZCCallbackHelper::NotifyMozMouseScrollEvent(aScrollId, aEvent);
return true;
}
static Touch* static Touch*
GetTouchForIdentifier(const WidgetTouchEvent& aEvent, int32_t aId) GetTouchForIdentifier(const WidgetTouchEvent& aEvent, int32_t aId)
{ {

View File

@ -365,6 +365,8 @@ public:
const int32_t& aCharCode, const int32_t& aCharCode,
const int32_t& aModifiers, const int32_t& aModifiers,
const bool& aPreventDefault) override; 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 RecvCompositionEvent(const mozilla::WidgetCompositionEvent& event) override;
virtual bool RecvSelectionEvent(const mozilla::WidgetSelectionEvent& event) override; virtual bool RecvSelectionEvent(const mozilla::WidgetSelectionEvent& event) override;
virtual bool RecvActivateFrameEvent(const nsString& aType, const bool& capture) override; virtual bool RecvActivateFrameEvent(const nsString& aType, const bool& capture) override;

View File

@ -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 void
TabParent::Activate() TabParent::Activate()
{ {

View File

@ -242,6 +242,7 @@ public:
void NotifyAPZStateChange(ViewID aViewId, void NotifyAPZStateChange(ViewID aViewId,
APZStateChange aChange, APZStateChange aChange,
int aArg); int aArg);
void NotifyMouseScrollTestEvent(const ViewID& aScrollId, const nsString& aEvent);
void Activate(); void Activate();
void Deactivate(); void Deactivate();

View File

@ -1282,6 +1282,7 @@ static const char* const gMachineStateStr[] = {
"NONE", "NONE",
"DECODING_METADATA", "DECODING_METADATA",
"WAIT_FOR_RESOURCES", "WAIT_FOR_RESOURCES",
"WAIT_FOR_CDM",
"DECODING_FIRSTFRAME", "DECODING_FIRSTFRAME",
"DORMANT", "DORMANT",
"DECODING", "DECODING",
@ -1582,13 +1583,19 @@ void MediaDecoderStateMachine::DoNotifyWaitingForResourcesStatusChanged()
{ {
NS_ASSERTION(OnDecodeThread(), "Should be on decode thread."); NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
if (mState != DECODER_STATE_WAIT_FOR_RESOURCES) {
return;
}
DECODER_LOG("DoNotifyWaitingForResourcesStatusChanged"); DECODER_LOG("DoNotifyWaitingForResourcesStatusChanged");
// The reader is no longer waiting for resources (say a hardware decoder),
// we can now proceed to decode metadata. if (mState == DECODER_STATE_WAIT_FOR_RESOURCES) {
SetState(DECODER_STATE_DECODING_NONE); // 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(); ScheduleStateMachine();
} }
@ -2269,6 +2276,13 @@ nsresult MediaDecoderStateMachine::DecodeMetadata()
} }
if (mState == DECODER_STATE_DECODING_METADATA) { 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); SetState(DECODER_STATE_DECODING_FIRSTFRAME);
res = EnqueueDecodeFirstFrameTask(); res = EnqueueDecodeFirstFrameTask();
if (NS_FAILED(res)) { if (NS_FAILED(res)) {
@ -2678,6 +2692,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
return NS_OK; return NS_OK;
} }
case DECODER_STATE_WAIT_FOR_CDM:
case DECODER_STATE_WAIT_FOR_RESOURCES: { case DECODER_STATE_WAIT_FOR_RESOURCES: {
return NS_OK; return NS_OK;
} }

View File

@ -139,6 +139,7 @@ public:
DECODER_STATE_DECODING_NONE, DECODER_STATE_DECODING_NONE,
DECODER_STATE_DECODING_METADATA, DECODER_STATE_DECODING_METADATA,
DECODER_STATE_WAIT_FOR_RESOURCES, DECODER_STATE_WAIT_FOR_RESOURCES,
DECODER_STATE_WAIT_FOR_CDM,
DECODER_STATE_DECODING_FIRSTFRAME, DECODER_STATE_DECODING_FIRSTFRAME,
DECODER_STATE_DORMANT, DECODER_STATE_DORMANT,
DECODER_STATE_DECODING, DECODER_STATE_DECODING,

View File

@ -10,6 +10,7 @@
#include "nsRect.h" #include "nsRect.h"
#include "ImageTypes.h" #include "ImageTypes.h"
#include "nsString.h" #include "nsString.h"
#include "nsTArray.h"
#include "StreamBuffer.h" // for TrackID #include "StreamBuffer.h" // for TrackID
namespace mozilla { namespace mozilla {
@ -102,10 +103,22 @@ public:
TrackInfo mTrackInfo; 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 { class MediaInfo {
public: public:
MediaInfo() : mIsEncrypted(false) {}
bool HasVideo() const bool HasVideo() const
{ {
return mVideo.mHasVideo; return mVideo.mHasVideo;
@ -116,16 +129,21 @@ public:
return mAudio.mHasAudio; return mAudio.mHasAudio;
} }
bool IsEncrypted() const
{
return mCrypto.mIsEncrypted;
}
bool HasValidMedia() const bool HasValidMedia() const
{ {
return HasVideo() || HasAudio(); return HasVideo() || HasAudio();
} }
bool mIsEncrypted;
// TODO: Store VideoInfo and AudioIndo in arrays to support multi-tracks. // TODO: Store VideoInfo and AudioIndo in arrays to support multi-tracks.
VideoInfo mVideo; VideoInfo mVideo;
AudioInfo mAudio; AudioInfo mAudio;
EncryptionInfo mCrypto;
}; };
} // namespace mozilla } // namespace mozilla

View File

@ -2213,6 +2213,7 @@ MediaStream::RunAfterPendingUpdates(already_AddRefed<nsIRunnable> aRunnable)
// runnable will run in finite time. // runnable will run in finite time.
if (!(graph->mRealtime || graph->mNonRealtimeProcessing)) { if (!(graph->mRealtime || graph->mNonRealtimeProcessing)) {
runnable->Run(); runnable->Run();
return;
} }
class Message : public ControlMessage { class Message : public ControlMessage {

View File

@ -265,12 +265,6 @@ AVCCDecoderModule::Startup()
return mPDM->Startup(); return mPDM->Startup();
} }
nsresult
AVCCDecoderModule::Shutdown()
{
return mPDM->Shutdown();
}
already_AddRefed<MediaDataDecoder> already_AddRefed<MediaDataDecoder>
AVCCDecoderModule::CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig, AVCCDecoderModule::CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend, layers::LayersBackend aLayersBackend,

View File

@ -28,7 +28,6 @@ public:
virtual ~AVCCDecoderModule(); virtual ~AVCCDecoderModule();
virtual nsresult Startup() override; virtual nsresult Startup() override;
virtual nsresult Shutdown() override;
virtual already_AddRefed<MediaDataDecoder> virtual already_AddRefed<MediaDataDecoder>
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig, CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,

View File

@ -206,11 +206,6 @@ private:
class BlankDecoderModule : public PlatformDecoderModule { class BlankDecoderModule : public PlatformDecoderModule {
public: public:
// Called when the decoders have shutdown. Main thread only.
virtual nsresult Shutdown() override {
return NS_OK;
}
// Decode thread. // Decode thread.
virtual already_AddRefed<MediaDataDecoder> virtual already_AddRefed<MediaDataDecoder>
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig, CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,

View File

@ -156,6 +156,7 @@ MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder)
, mDemuxerInitialized(false) , mDemuxerInitialized(false)
, mFoundSPSForTelemetry(false) , mFoundSPSForTelemetry(false)
, mIsEncrypted(false) , mIsEncrypted(false)
, mAreDecodersSetup(false)
, mIndexReady(false) , mIndexReady(false)
, mDemuxerMonitor("MP4 Demuxer") , mDemuxerMonitor("MP4 Demuxer")
#if defined(MP4_READER_DORMANT_HEURISTIC) #if defined(MP4_READER_DORMANT_HEURISTIC)
@ -204,10 +205,7 @@ MP4Reader::Shutdown()
// Dispose of the queued sample before shutting down the demuxer // Dispose of the queued sample before shutting down the demuxer
mQueuedVideoSample = nullptr; mQueuedVideoSample = nullptr;
if (mPlatform) { mPlatform = nullptr;
mPlatform->Shutdown();
mPlatform = nullptr;
}
return MediaDecoderReader::Shutdown(); return MediaDecoderReader::Shutdown();
} }
@ -266,41 +264,13 @@ MP4Reader::Init(MediaDecoderReader* aCloneDonor)
return NS_OK; 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() { void MP4Reader::RequestCodecResource() {
if (mVideo.mDecoder) { if (mVideo.mDecoder) {
mVideo.mDecoder->AllocateMediaResources(); mVideo.mDecoder->AllocateMediaResources();
} }
} }
bool MP4Reader::IsWaitingOnCodecResource() { bool MP4Reader::IsWaitingMediaResources() {
return mVideo.mDecoder && mVideo.mDecoder->IsWaitingMediaResources(); return mVideo.mDecoder && mVideo.mDecoder->IsWaitingMediaResources();
} }
@ -330,15 +300,6 @@ bool MP4Reader::IsWaitingOnCDMResource() {
#endif #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 void
MP4Reader::ExtractCryptoInitData(nsTArray<uint8_t>& aInitData) MP4Reader::ExtractCryptoInitData(nsTArray<uint8_t>& aInitData)
{ {
@ -407,7 +368,7 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
{ {
MonitorAutoUnlock unlock(mDemuxerMonitor); MonitorAutoUnlock unlock(mDemuxerMonitor);
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); 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 // Remember that we've initialized the demuxer, so that if we're decoding
@ -420,90 +381,18 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
return NS_OK; 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()) { if (HasAudio()) {
const AudioDecoderConfig& audio = mDemuxer->AudioConfig(); 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.mRate = audio.samples_per_second;
mInfo.mAudio.mChannels = audio.channel_count; mInfo.mAudio.mChannels = audio.channel_count;
mAudio.mCallback = new DecoderCallback(this, kAudio); 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()) { if (HasVideo()) {
const VideoDecoderConfig& video = mDemuxer->VideoConfig(); const VideoDecoderConfig& video = mDemuxer->VideoConfig();
if (mInfo.mVideo.mHasVideo && !IsSupportedVideoMimeType(video.mime_type)) {
return NS_ERROR_FAILURE;
}
mInfo.mVideo.mDisplay = mInfo.mVideo.mDisplay =
nsIntSize(video.display_width, video.display_height); nsIntSize(video.display_width, video.display_height);
mVideo.mCallback = new DecoderCallback(this, kVideo); 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. // Collect telemetry from h264 AVCC SPS.
if (!mFoundSPSForTelemetry) { 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. // Get the duration, and report it to the decoder if we have it.
Microseconds duration; Microseconds duration;
{ {
@ -525,12 +425,96 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
*aInfo = mInfo; *aInfo = mInfo;
*aTags = nullptr; *aTags = nullptr;
if (!IsWaitingMediaResources() && !IsWaitingOnCDMResource()) {
NS_ENSURE_TRUE(EnsureDecodersSetup(), NS_ERROR_FAILURE);
}
MonitorAutoLock mon(mDemuxerMonitor); MonitorAutoLock mon(mDemuxerMonitor);
UpdateIndex(); UpdateIndex();
return NS_OK; 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 void
MP4Reader::ReadUpdatedMetadata(MediaInfo* aInfo) MP4Reader::ReadUpdatedMetadata(MediaInfo* aInfo)
{ {
@ -579,10 +563,10 @@ void
MP4Reader::DisableHardwareAcceleration() MP4Reader::DisableHardwareAcceleration()
{ {
if (HasVideo() && mSharedDecoderManager) { if (HasVideo() && mSharedDecoderManager) {
mPlatform->DisableHardwareAcceleration(); mSharedDecoderManager->DisableHardwareAcceleration();
const VideoDecoderConfig& video = mDemuxer->VideoConfig(); const VideoDecoderConfig& video = mDemuxer->VideoConfig();
if (!mSharedDecoderManager->Recreate(mPlatform, video, mLayersBackendType, mDecoder->GetImageContainer())) { if (!mSharedDecoderManager->Recreate(video, mLayersBackendType, mDecoder->GetImageContainer())) {
MonitorAutoLock mon(mVideo.mMonitor); MonitorAutoLock mon(mVideo.mMonitor);
mVideo.mError = true; mVideo.mError = true;
if (mVideo.HasPromise()) { if (mVideo.HasPromise()) {
@ -618,6 +602,11 @@ MP4Reader::RequestVideoData(bool aSkipToNextKeyframe,
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn()); MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
VLOG("skip=%d time=%lld", aSkipToNextKeyframe, aTimeThreshold); VLOG("skip=%d time=%lld", aSkipToNextKeyframe, aTimeThreshold);
if (!EnsureDecodersSetup()) {
NS_WARNING("Error constructing MP4 decoders");
return VideoDataPromise::CreateAndReject(DECODE_ERROR, __func__);
}
if (mShutdown) { if (mShutdown) {
NS_WARNING("RequestVideoData on shutdown MP4Reader!"); NS_WARNING("RequestVideoData on shutdown MP4Reader!");
return VideoDataPromise::CreateAndReject(CANCELED, __func__); return VideoDataPromise::CreateAndReject(CANCELED, __func__);
@ -653,6 +642,12 @@ MP4Reader::RequestAudioData()
{ {
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn()); MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
VLOG(""); VLOG("");
if (!EnsureDecodersSetup()) {
NS_WARNING("Error constructing MP4 decoders");
return AudioDataPromise::CreateAndReject(DECODE_ERROR, __func__);
}
if (mShutdown) { if (mShutdown) {
NS_WARNING("RequestAudioData on shutdown MP4Reader!"); NS_WARNING("RequestAudioData on shutdown MP4Reader!");
return AudioDataPromise::CreateAndReject(CANCELED, __func__); return AudioDataPromise::CreateAndReject(CANCELED, __func__);

View File

@ -103,6 +103,8 @@ private:
bool InitDemuxer(); bool InitDemuxer();
void ReturnOutput(MediaData* aData, TrackType aTrack); void ReturnOutput(MediaData* aData, TrackType aTrack);
bool EnsureDecodersSetup();
// Sends input to decoder for aTrack, and output to the state machine, // Sends input to decoder for aTrack, and output to the state machine,
// if necessary. // if necessary.
void Update(TrackType aTrack); void Update(TrackType aTrack);
@ -135,7 +137,6 @@ private:
bool IsSupportedVideoMimeType(const char* aMimeType); bool IsSupportedVideoMimeType(const char* aMimeType);
void NotifyResourcesStatusChanged(); void NotifyResourcesStatusChanged();
void RequestCodecResource(); void RequestCodecResource();
bool IsWaitingOnCodecResource();
virtual bool IsWaitingOnCDMResource() override; virtual bool IsWaitingOnCDMResource() override;
Microseconds GetNextKeyframeTime(); Microseconds GetNextKeyframeTime();
@ -285,6 +286,8 @@ private:
// Synchronized by decoder monitor. // Synchronized by decoder monitor.
bool mIsEncrypted; bool mIsEncrypted;
bool mAreDecodersSetup;
bool mIndexReady; bool mIndexReady;
Monitor mDemuxerMonitor; Monitor mDemuxerMonitor;
nsRefPtr<SharedDecoderManager> mSharedDecoderManager; nsRefPtr<SharedDecoderManager> mSharedDecoderManager;

View File

@ -86,13 +86,6 @@ public:
bool aHasVideo); bool aHasVideo);
#endif #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 // Creates an H.264 decoder. The layers backend is passed in so that
// decoders can determine whether hardware accelerated decoding can be used. // decoders can determine whether hardware accelerated decoding can be used.
// Asynchronous decoding of video should be done in runnables dispatched // Asynchronous decoding of video should be done in runnables dispatched

View File

@ -12,7 +12,10 @@ namespace mozilla {
class SharedDecoderCallback : public MediaDataDecoderCallback class SharedDecoderCallback : public MediaDataDecoderCallback
{ {
public: public:
explicit SharedDecoderCallback(SharedDecoderManager* aManager) : mManager(aManager) {} explicit SharedDecoderCallback(SharedDecoderManager* aManager)
: mManager(aManager)
{
}
virtual void Output(MediaData* aData) override virtual void Output(MediaData* aData) override
{ {
@ -66,25 +69,34 @@ SharedDecoderManager::SharedDecoderManager()
mCallback = new SharedDecoderCallback(this); mCallback = new SharedDecoderCallback(this);
} }
SharedDecoderManager::~SharedDecoderManager() {} SharedDecoderManager::~SharedDecoderManager()
{
}
already_AddRefed<MediaDataDecoder> already_AddRefed<MediaDataDecoder>
SharedDecoderManager::CreateVideoDecoder( SharedDecoderManager::CreateVideoDecoder(
PlatformDecoderModule* aPDM, PlatformDecoderModule* aPDM,
const mp4_demuxer::VideoDecoderConfig& aConfig, const mp4_demuxer::VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer, layers::LayersBackend aLayersBackend,
FlushableMediaTaskQueue* aVideoTaskQueue, MediaDataDecoderCallback* aCallback) layers::ImageContainer* aImageContainer,
FlushableMediaTaskQueue* aVideoTaskQueue,
MediaDataDecoderCallback* aCallback)
{ {
if (!mDecoder) { if (!mDecoder) {
// We use the manager's task queue for the decoder, rather than the one // 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 // 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* // the task queue while we're potentially still using it for a *different*
// object also sharing the decoder. // object also sharing the decoder.
mDecoder = aPDM->CreateVideoDecoder( mDecoder = aPDM->CreateVideoDecoder(aConfig,
aConfig, aLayersBackend, aImageContainer, mTaskQueue, mCallback); aLayersBackend,
aImageContainer,
mTaskQueue,
mCallback);
if (!mDecoder) { if (!mDecoder) {
mPDM = nullptr;
return nullptr; return nullptr;
} }
mPDM = aPDM;
nsresult rv = mDecoder->Init(); nsresult rv = mDecoder->Init();
NS_ENSURE_SUCCESS(rv, nullptr); NS_ENSURE_SUCCESS(rv, nullptr);
} }
@ -93,15 +105,25 @@ SharedDecoderManager::CreateVideoDecoder(
return proxy.forget(); return proxy.forget();
} }
void
SharedDecoderManager::DisableHardwareAcceleration()
{
MOZ_ASSERT(mPDM);
mPDM->DisableHardwareAcceleration();
}
bool bool
SharedDecoderManager::Recreate(PlatformDecoderModule* aPDM, SharedDecoderManager::Recreate(const mp4_demuxer::VideoDecoderConfig& aConfig,
const mp4_demuxer::VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend, layers::LayersBackend aLayersBackend,
layers::ImageContainer* aImageContainer) layers::ImageContainer* aImageContainer)
{ {
mDecoder->Flush(); mDecoder->Flush();
mDecoder->Shutdown(); mDecoder->Shutdown();
mDecoder = aPDM->CreateVideoDecoder(aConfig, aLayersBackend, aImageContainer, mTaskQueue, mCallback); mDecoder = mPDM->CreateVideoDecoder(aConfig,
aLayersBackend,
aImageContainer,
mTaskQueue,
mCallback);
if (!mDecoder) { if (!mDecoder) {
return false; return false;
} }
@ -168,6 +190,7 @@ SharedDecoderManager::Shutdown()
mDecoder->Shutdown(); mDecoder->Shutdown();
mDecoder = nullptr; mDecoder = nullptr;
} }
mPDM = nullptr;
if (mTaskQueue) { if (mTaskQueue) {
mTaskQueue->BeginShutdown(); mTaskQueue->BeginShutdown();
mTaskQueue->AwaitShutdownAndIdle(); mTaskQueue->AwaitShutdownAndIdle();
@ -175,13 +198,17 @@ SharedDecoderManager::Shutdown()
} }
} }
SharedDecoderProxy::SharedDecoderProxy( SharedDecoderProxy::SharedDecoderProxy(SharedDecoderManager* aManager,
SharedDecoderManager* aManager, MediaDataDecoderCallback* aCallback) MediaDataDecoderCallback* aCallback)
: mManager(aManager), mCallback(aCallback) : mManager(aManager)
, mCallback(aCallback)
{ {
} }
SharedDecoderProxy::~SharedDecoderProxy() { Shutdown(); } SharedDecoderProxy::~SharedDecoderProxy()
{
Shutdown();
}
nsresult nsresult
SharedDecoderProxy::Init() SharedDecoderProxy::Init()

View File

@ -28,7 +28,8 @@ public:
PlatformDecoderModule* aPDM, PlatformDecoderModule* aPDM,
const mp4_demuxer::VideoDecoderConfig& aConfig, const mp4_demuxer::VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend, layers::LayersBackend aLayersBackend,
layers::ImageContainer* aImageContainer, FlushableMediaTaskQueue* aVideoTaskQueue, layers::ImageContainer* aImageContainer,
FlushableMediaTaskQueue* aVideoTaskQueue,
MediaDataDecoderCallback* aCallback); MediaDataDecoderCallback* aCallback);
void SetReader(MediaDecoderReader* aReader); void SetReader(MediaDecoderReader* aReader);
@ -40,15 +41,16 @@ public:
friend class SharedDecoderProxy; friend class SharedDecoderProxy;
friend class SharedDecoderCallback; friend class SharedDecoderCallback;
bool Recreate(PlatformDecoderModule* aPDM, void DisableHardwareAcceleration();
const mp4_demuxer::VideoDecoderConfig& aConfig, bool Recreate(const mp4_demuxer::VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend, layers::LayersBackend aLayersBackend,
layers::ImageContainer* aImageContainer); layers::ImageContainer* aImageContainer);
private: private:
virtual ~SharedDecoderManager(); virtual ~SharedDecoderManager();
void DrainComplete(); void DrainComplete();
nsRefPtr<PlatformDecoderModule> mPDM;
nsRefPtr<MediaDataDecoder> mDecoder; nsRefPtr<MediaDataDecoder> mDecoder;
nsRefPtr<FlushableMediaTaskQueue> mTaskQueue; nsRefPtr<FlushableMediaTaskQueue> mTaskQueue;
SharedDecoderProxy* mActiveProxy; SharedDecoderProxy* mActiveProxy;

View File

@ -299,12 +299,6 @@ AndroidDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig&
} }
nsresult AndroidDecoderModule::Shutdown()
{
return NS_OK;
}
MediaCodecDataDecoder::MediaCodecDataDecoder(MediaData::Type aType, MediaCodecDataDecoder::MediaCodecDataDecoder(MediaData::Type aType,
const char* aMimeType, const char* aMimeType,
MediaFormat::Param aFormat, MediaFormat::Param aFormat,

View File

@ -19,8 +19,6 @@ typedef std::queue<mp4_demuxer::MP4Sample*> SampleQueue;
class AndroidDecoderModule : public PlatformDecoderModule { class AndroidDecoderModule : public PlatformDecoderModule {
public: public:
virtual nsresult Shutdown() override;
virtual already_AddRefed<MediaDataDecoder> virtual already_AddRefed<MediaDataDecoder>
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig, CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend, layers::LayersBackend aLayersBackend,

View File

@ -36,12 +36,46 @@ bool AppleDecoderModule::sIsVTHWAvailable = false;
bool AppleDecoderModule::sIsVDAAvailable = false; bool AppleDecoderModule::sIsVDAAvailable = false;
bool AppleDecoderModule::sForceVDA = 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()
{ {
} }
AppleDecoderModule::~AppleDecoderModule() AppleDecoderModule::~AppleDecoderModule()
{ {
nsCOMPtr<nsIRunnable> task(new UnlinkTask());
NS_DispatchToMainThread(task);
} }
/* static */ /* static */
@ -104,22 +138,6 @@ AppleDecoderModule::CanDecode()
return (sIsVDAAvailable || sIsVTAvailable) ? NS_OK : NS_ERROR_NO_INTERFACE; 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 nsresult
AppleDecoderModule::Startup() AppleDecoderModule::Startup()
{ {
@ -133,30 +151,6 @@ AppleDecoderModule::Startup()
return NS_OK; 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> already_AddRefed<MediaDataDecoder>
AppleDecoderModule::CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig, AppleDecoderModule::CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend, layers::LayersBackend aLayersBackend,

View File

@ -18,10 +18,6 @@ public:
virtual nsresult Startup() override; 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. // Decode thread.
virtual already_AddRefed<MediaDataDecoder> virtual already_AddRefed<MediaDataDecoder>
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig, CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,

View File

@ -94,7 +94,11 @@ AppleVDALinker::Unlink()
MOZ_ASSERT(sRefCount > 0, "Unbalanced Unlink()"); MOZ_ASSERT(sRefCount > 0, "Unbalanced Unlink()");
--sRefCount; --sRefCount;
if (sLink && sRefCount < 1) { 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); dlclose(sLink);
sLink = nullptr; sLink = nullptr;
skPropWidth = nullptr; skPropWidth = nullptr;

View File

@ -98,6 +98,10 @@ AppleVTLinker::Unlink()
--sRefCount; --sRefCount;
if (sLink && sRefCount < 1) { if (sLink && sRefCount < 1) {
LOG("Unlinking VideoToolbox framework."); LOG("Unlinking VideoToolbox framework.");
#define LINK_FUNC(func) \
func = nullptr;
#include "AppleVTFunctions.h"
#undef LINK_FUNC
dlclose(sLink); dlclose(sLink);
sLink = nullptr; sLink = nullptr;
skPropEnableHWAccel = nullptr; skPropEnableHWAccel = nullptr;

View File

@ -208,15 +208,6 @@ EMEDecoderModule::~EMEDecoderModule()
{ {
} }
nsresult
EMEDecoderModule::Shutdown()
{
if (mPDM) {
return mPDM->Shutdown();
}
return NS_OK;
}
static already_AddRefed<MediaDataDecoderProxy> static already_AddRefed<MediaDataDecoderProxy>
CreateDecoderWrapper(MediaDataDecoderCallback* aCallback, CDMProxy* aProxy, FlushableMediaTaskQueue* aTaskQueue) CreateDecoderWrapper(MediaDataDecoderCallback* aCallback, CDMProxy* aProxy, FlushableMediaTaskQueue* aTaskQueue)
{ {

View File

@ -28,9 +28,6 @@ public:
virtual ~EMEDecoderModule(); virtual ~EMEDecoderModule();
// Called when the decoders have shutdown. Main thread only.
virtual nsresult Shutdown() override;
// Decode thread. // Decode thread.
virtual already_AddRefed<MediaDataDecoder> virtual already_AddRefed<MediaDataDecoder>
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig, CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,

View File

@ -28,8 +28,6 @@ public:
FFmpegDecoderModule() {} FFmpegDecoderModule() {}
virtual ~FFmpegDecoderModule() {} virtual ~FFmpegDecoderModule() {}
virtual nsresult Shutdown() override { return NS_OK; }
virtual already_AddRefed<MediaDataDecoder> virtual already_AddRefed<MediaDataDecoder>
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig, CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend, layers::LayersBackend aLayersBackend,

View File

@ -21,12 +21,6 @@ GMPDecoderModule::~GMPDecoderModule()
{ {
} }
nsresult
GMPDecoderModule::Shutdown()
{
return NS_OK;
}
static already_AddRefed<MediaDataDecoderProxy> static already_AddRefed<MediaDataDecoderProxy>
CreateDecoderWrapper(MediaDataDecoderCallback* aCallback) CreateDecoderWrapper(MediaDataDecoderCallback* aCallback)
{ {

View File

@ -17,9 +17,6 @@ public:
virtual ~GMPDecoderModule(); virtual ~GMPDecoderModule();
// Called when the decoders have shutdown. Main thread only.
virtual nsresult Shutdown() override;
// Decode thread. // Decode thread.
virtual already_AddRefed<MediaDataDecoder> virtual already_AddRefed<MediaDataDecoder>
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig, CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,

View File

@ -26,12 +26,6 @@ GonkDecoderModule::Init()
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
} }
nsresult
GonkDecoderModule::Shutdown()
{
return NS_OK;
}
already_AddRefed<MediaDataDecoder> already_AddRefed<MediaDataDecoder>
GonkDecoderModule::CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig, GonkDecoderModule::CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
mozilla::layers::LayersBackend aLayersBackend, mozilla::layers::LayersBackend aLayersBackend,

View File

@ -16,9 +16,6 @@ public:
GonkDecoderModule(); GonkDecoderModule();
virtual ~GonkDecoderModule(); virtual ~GonkDecoderModule();
// Called when the decoders have shutdown.
virtual nsresult Shutdown() override;
// Decode thread. // Decode thread.
virtual already_AddRefed<MediaDataDecoder> virtual already_AddRefed<MediaDataDecoder>
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig, CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,

View File

@ -28,6 +28,8 @@ WMFDecoderModule::WMFDecoderModule()
WMFDecoderModule::~WMFDecoderModule() WMFDecoderModule::~WMFDecoderModule()
{ {
DebugOnly<HRESULT> hr = wmf::MFShutdown();
NS_ASSERTION(SUCCEEDED(hr), "MFShutdown failed");
} }
/* static */ /* static */
@ -58,14 +60,6 @@ WMFDecoderModule::Startup()
return NS_OK; return NS_OK;
} }
nsresult
WMFDecoderModule::Shutdown()
{
DebugOnly<HRESULT> hr = wmf::MFShutdown();
NS_ASSERTION(SUCCEEDED(hr), "MFShutdown failed");
return NS_OK;
}
already_AddRefed<MediaDataDecoder> already_AddRefed<MediaDataDecoder>
WMFDecoderModule::CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig, WMFDecoderModule::CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend, layers::LayersBackend aLayersBackend,

View File

@ -19,9 +19,6 @@ public:
// Initializes the module, loads required dynamic libraries, etc. // Initializes the module, loads required dynamic libraries, etc.
virtual nsresult Startup() override; virtual nsresult Startup() override;
// Called when the decoders have shutdown.
virtual nsresult Shutdown() override;
virtual already_AddRefed<MediaDataDecoder> virtual already_AddRefed<MediaDataDecoder>
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig, CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend, layers::LayersBackend aLayersBackend,

View File

@ -665,10 +665,11 @@ GeckoMediaPluginService::LoadFromEnvironment()
NS_IMETHODIMP NS_IMETHODIMP
GeckoMediaPluginService::PathRunnable::Run() GeckoMediaPluginService::PathRunnable::Run()
{ {
if (mAdd) { if (mOperation == ADD) {
mService->AddOnGMPThread(mPath); mService->AddOnGMPThread(mPath);
} else { } else {
mService->RemoveOnGMPThread(mPath); mService->RemoveOnGMPThread(mPath,
mOperation == REMOVE_AND_DELETE_FROM_DISK);
} }
return NS_OK; return NS_OK;
} }
@ -677,14 +678,26 @@ NS_IMETHODIMP
GeckoMediaPluginService::AddPluginDirectory(const nsAString& aDirectory) GeckoMediaPluginService::AddPluginDirectory(const nsAString& aDirectory)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
return GMPDispatch(new PathRunnable(this, aDirectory, true)); return GMPDispatch(new PathRunnable(this, aDirectory,
PathRunnable::EOperation::ADD));
} }
NS_IMETHODIMP NS_IMETHODIMP
GeckoMediaPluginService::RemovePluginDirectory(const nsAString& aDirectory) GeckoMediaPluginService::RemovePluginDirectory(const nsAString& aDirectory)
{ {
MOZ_ASSERT(NS_IsMainThread()); 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 { class DummyRunnable : public nsRunnable {
@ -915,7 +928,8 @@ GeckoMediaPluginService::AddOnGMPThread(const nsAString& aDirectory)
} }
void void
GeckoMediaPluginService::RemoveOnGMPThread(const nsAString& aDirectory) GeckoMediaPluginService::RemoveOnGMPThread(const nsAString& aDirectory,
const bool aDeleteFromDisk)
{ {
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread); MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
LOGD(("%s::%s: %s", __CLASS__, __FUNCTION__, NS_LossyConvertUTF16toASCII(aDirectory).get())); 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(); nsCOMPtr<nsIFile> pluginpath = mPlugins[i]->GetDirectory();
bool equals; bool equals;
if (NS_SUCCEEDED(directory->Equals(pluginpath, &equals)) && equals) { if (NS_SUCCEEDED(directory->Equals(pluginpath, &equals)) && equals) {
mPlugins[i]->AbortAsyncShutdown();
mPlugins[i]->CloseActive(true); mPlugins[i]->CloseActive(true);
if (aDeleteFromDisk) {
pluginpath->Remove(true);
}
mPlugins.RemoveElementAt(i); mPlugins.RemoveElementAt(i);
return; return;
} }

View File

@ -71,8 +71,9 @@ private:
void LoadFromEnvironment(); void LoadFromEnvironment();
void ProcessPossiblePlugin(nsIFile* aDir); void ProcessPossiblePlugin(nsIFile* aDir);
void AddOnGMPThread(const nsAString& aSearchDir); void AddOnGMPThread(const nsAString& aDirectory);
void RemoveOnGMPThread(const nsAString& aSearchDir); void RemoveOnGMPThread(const nsAString& aDirectory,
const bool aDeleteFromDisk);
nsresult SetAsyncShutdownTimeout(); nsresult SetAsyncShutdownTimeout();
@ -96,11 +97,17 @@ private:
class PathRunnable : public nsRunnable class PathRunnable : public nsRunnable
{ {
public: public:
PathRunnable(GeckoMediaPluginService* service, const nsAString& path, enum EOperation {
bool add) ADD,
: mService(service) REMOVE,
, mPath(path) REMOVE_AND_DELETE_FROM_DISK,
, mAdd(add) };
PathRunnable(GeckoMediaPluginService* aService, const nsAString& aPath,
EOperation aOperation)
: mService(aService)
, mPath(aPath)
, mOperation(aOperation)
{ } { }
NS_DECL_NSIRUNNABLE NS_DECL_NSIRUNNABLE
@ -108,7 +115,7 @@ private:
private: private:
nsRefPtr<GeckoMediaPluginService> mService; nsRefPtr<GeckoMediaPluginService> mService;
nsString mPath; nsString mPath;
bool mAdd; EOperation mOperation;
}; };
Mutex mMutex; // Protects mGMPThread and mShuttingDown and mPlugins Mutex mMutex; // Protects mGMPThread and mShuttingDown and mPlugins

View File

@ -26,7 +26,7 @@ class GMPVideoHost;
[ptr] native GMPDecryptorProxy(GMPDecryptorProxy); [ptr] native GMPDecryptorProxy(GMPDecryptorProxy);
[ptr] native GMPAudioDecoderProxy(GMPAudioDecoderProxy); [ptr] native GMPAudioDecoderProxy(GMPAudioDecoderProxy);
[scriptable, uuid(56cc105f-dd27-4752-83e0-371908edba04)] [scriptable, uuid(f71e6e57-5175-4cf3-8cc2-629273a75b67)]
interface mozIGeckoMediaPluginService : nsISupports interface mozIGeckoMediaPluginService : nsISupports
{ {
@ -97,6 +97,12 @@ interface mozIGeckoMediaPluginService : nsISupports
*/ */
void removePluginDirectory(in AString directory); 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. * Gets the NodeId for a (origin, urlbarOrigin, isInprivateBrowsing) tuple.
*/ */

View File

@ -93,6 +93,25 @@ MediaSourceReader::IsWaitingMediaResources()
return !mHasEssentialTrackBuffers; 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 size_t
MediaSourceReader::SizeOfVideoQueueInFrames() MediaSourceReader::SizeOfVideoQueueInFrames()
{ {
@ -1020,6 +1039,22 @@ MediaSourceReader::MaybeNotifyHaveData()
IsSeeking(), haveAudio, haveVideo); 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 nsresult
MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
{ {
@ -1043,7 +1078,7 @@ MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
const MediaInfo& info = GetAudioReader()->GetMediaInfo(); const MediaInfo& info = GetAudioReader()->GetMediaInfo();
MOZ_ASSERT(info.HasAudio()); MOZ_ASSERT(info.HasAudio());
mInfo.mAudio = info.mAudio; mInfo.mAudio = info.mAudio;
mInfo.mIsEncrypted = mInfo.mIsEncrypted || info.mIsEncrypted; CombineEncryptionData(mInfo.mCrypto, info.mCrypto);
MSE_DEBUG("audio reader=%p duration=%lld", MSE_DEBUG("audio reader=%p duration=%lld",
mAudioSourceDecoder.get(), mAudioSourceDecoder.get(),
mAudioSourceDecoder->GetReader()->GetDecoder()->GetMediaDuration()); mAudioSourceDecoder->GetReader()->GetDecoder()->GetMediaDuration());
@ -1056,7 +1091,7 @@ MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
const MediaInfo& info = GetVideoReader()->GetMediaInfo(); const MediaInfo& info = GetVideoReader()->GetMediaInfo();
MOZ_ASSERT(info.HasVideo()); MOZ_ASSERT(info.HasVideo());
mInfo.mVideo = info.mVideo; mInfo.mVideo = info.mVideo;
mInfo.mIsEncrypted = mInfo.mIsEncrypted || info.mIsEncrypted; CombineEncryptionData(mInfo.mCrypto, info.mCrypto);
MSE_DEBUG("video reader=%p duration=%lld", MSE_DEBUG("video reader=%p duration=%lld",
GetVideoReader(), GetVideoReader(),
GetVideoReader()->GetDecoder()->GetMediaDuration()); GetVideoReader()->GetDecoder()->GetMediaDuration());

View File

@ -45,6 +45,7 @@ public:
void PrepareInitialization(); void PrepareInitialization();
bool IsWaitingMediaResources() override; bool IsWaitingMediaResources() override;
bool IsWaitingOnCDMResource() override;
nsRefPtr<AudioDataPromise> RequestAudioData() override; nsRefPtr<AudioDataPromise> RequestAudioData() override;
nsRefPtr<VideoDataPromise> nsRefPtr<VideoDataPromise>

View File

@ -47,6 +47,7 @@ TrackBuffer::TrackBuffer(MediaSourceDecoder* aParentDecoder, const nsACString& a
, mLastStartTimestamp(0) , mLastStartTimestamp(0)
, mLastTimestampOffset(0) , mLastTimestampOffset(0)
, mAdjustedTimestamp(0) , mAdjustedTimestamp(0)
, mIsWaitingOnCDM(false)
, mShutdown(false) , mShutdown(false)
{ {
MOZ_COUNT_CTOR(TrackBuffer); MOZ_COUNT_CTOR(TrackBuffer);
@ -588,6 +589,7 @@ TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder)
if (mCurrentDecoder != aDecoder) { if (mCurrentDecoder != aDecoder) {
MSE_DEBUG("append was cancelled. Aborting initialization."); MSE_DEBUG("append was cancelled. Aborting initialization.");
RemoveDecoder(aDecoder);
// If we reached this point, the SourceBuffer would have disconnected // If we reached this point, the SourceBuffer would have disconnected
// the promise. So no need to reject it. // the promise. So no need to reject it.
return; return;
@ -641,12 +643,12 @@ TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder)
} }
if (mCurrentDecoder != aDecoder) { if (mCurrentDecoder != aDecoder) {
MSE_DEBUG("append was cancelled. Aborting initialization."); MSE_DEBUG("append was cancelled. Aborting initialization.");
RemoveDecoder(aDecoder);
return; return;
} }
if (NS_SUCCEEDED(rv) && reader->IsWaitingOnCDMResource()) { if (NS_SUCCEEDED(rv) && reader->IsWaitingOnCDMResource()) {
mWaitingDecoders.AppendElement(aDecoder); mIsWaitingOnCDM = true;
return;
} }
aDecoder->SetTaskQueue(nullptr); aDecoder->SetTaskQueue(nullptr);
@ -693,6 +695,7 @@ TrackBuffer::CompleteInitializeDecoder(SourceBufferDecoder* aDecoder)
MSE_DEBUG("append was cancelled. Aborting initialization."); MSE_DEBUG("append was cancelled. Aborting initialization.");
// If we reached this point, the SourceBuffer would have disconnected // If we reached this point, the SourceBuffer would have disconnected
// the promise. So no need to reject it. // the promise. So no need to reject it.
RemoveDecoder(aDecoder);
return; return;
} }
@ -807,6 +810,12 @@ TrackBuffer::IsReady()
return mInfo.HasAudio() || mInfo.HasVideo(); return mInfo.HasAudio() || mInfo.HasVideo();
} }
bool
TrackBuffer::IsWaitingOnCDMResource()
{
return mIsWaitingOnCDM;
}
bool bool
TrackBuffer::ContainsTime(int64_t aTime, int64_t aTolerance) TrackBuffer::ContainsTime(int64_t aTime, int64_t aTolerance)
{ {
@ -875,21 +884,12 @@ TrackBuffer::SetCDMProxy(CDMProxy* aProxy)
{ {
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor()); ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
for (uint32_t i = 0; i < mDecoders.Length(); ++i) { for (auto& decoder : mDecoders) {
nsresult rv = mDecoders[i]->SetCDMProxy(aProxy); decoder->SetCDMProxy(aProxy);
NS_ENSURE_SUCCESS(rv, rv);
} }
for (uint32_t i = 0; i < mWaitingDecoders.Length(); ++i) { mIsWaitingOnCDM = false;
CDMCaps::AutoLock caps(aProxy->Capabilites()); mParentDecoder->NotifyWaitingForResourcesStatusChanged();
caps.CallOnMainThreadWhenCapsAvailable(
NS_NewRunnableMethodWithArg<SourceBufferDecoder*>(this,
&TrackBuffer::QueueInitializeDecoder,
mWaitingDecoders[i]));
}
mWaitingDecoders.Clear();
return NS_OK; return NS_OK;
} }
#endif #endif

View File

@ -76,6 +76,8 @@ public:
// segment has successfully initialized by setting mHas{Audio,Video}.. // segment has successfully initialized by setting mHas{Audio,Video}..
bool IsReady(); bool IsReady();
bool IsWaitingOnCDMResource();
// Returns true if any of the decoders managed by this track buffer // Returns true if any of the decoders managed by this track buffer
// contain aTime in their buffered ranges. // contain aTime in their buffered ranges.
bool ContainsTime(int64_t aTime, int64_t aTolerance); bool ContainsTime(int64_t aTime, int64_t aTolerance);
@ -185,10 +187,6 @@ private:
// Access protected by mParentDecoder's monitor. // Access protected by mParentDecoder's monitor.
nsTArray<nsRefPtr<SourceBufferDecoder>> mInitializedDecoders; 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. // The decoder that the owning SourceBuffer is currently appending data to.
// Modified on the main thread only. // Modified on the main thread only.
nsRefPtr<SourceBufferDecoder> mCurrentDecoder; nsRefPtr<SourceBufferDecoder> mCurrentDecoder;
@ -206,6 +204,9 @@ private:
int64_t mLastTimestampOffset; int64_t mLastTimestampOffset;
int64_t mAdjustedTimestamp; 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. // Set when the first decoder used by this TrackBuffer is initialized.
// Protected by mParentDecoder's monitor. // Protected by mParentDecoder's monitor.
MediaInfo mInfo; MediaInfo mInfo;

View File

@ -370,8 +370,6 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
skip-if = buildapp == 'b2g' && toolkit != 'gonk' # bug 1082984 skip-if = buildapp == 'b2g' && toolkit != 'gonk' # bug 1082984
[test_dormant_playback.html] [test_dormant_playback.html]
skip-if = (os == 'win' && os_version == '5.1') || (os != 'win' && toolkit != 'gonk') 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] [test_eme_canvas_blocked.html]
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s || (os == 'win' && !debug) # bug 1043403, bug 1057908, bug 1140675 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s || (os == 'win' && !debug) # bug 1043403, bug 1057908, bug 1140675
[test_eme_non_mse_fails.html] [test_eme_non_mse_fails.html]

View File

@ -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>

View File

@ -40,17 +40,19 @@ function TestSetMediaKeys(test, token)
var v = document.createElement("video"); var v = document.createElement("video");
// XXX the encrypted event should never fire here after bug 1134434
v.addEventListener("encrypted", function() { v.addEventListener("encrypted", function() {
DoSetMediaKeys(v) ok(false, token + " should not fire encrypted event");
});
.then(function() { var loadedMetadata = false;
ok(false, token + " expected setMediaKeys to fail."); v.addEventListener("loadedmetadata", function() {
manager.finished(token); loadedMetadata = true;
}, function(err) { });
is(err.name, "NotSupportedError", token + " should return correct error");
manager.finished(token); 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; v.src = test.name;

View File

@ -244,6 +244,9 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
if (NS_WARN_IF(!stsThread)) { if (NS_WARN_IF(!stsThread)) {
return; 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, rv = NS_AsyncCopy(body, responseBody, stsThread, NS_ASYNCCOPY_VIA_READSEGMENTS, 4096,
RespondWithCopyComplete, closure.forget()); RespondWithCopyComplete, closure.forget());
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {

View 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);
}

View File

@ -71,3 +71,35 @@ fetch('headers.txt', function(xhr) {
my_ok(xhr.responseText == "1", "request header checks should have passed"); my_ok(xhr.responseText == "1", "request header checks should have passed");
finish(); finish();
}, null, [["X-Test1", "header1"], ["X-Test2", "header2"]]); }, 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();
});

View File

@ -96,4 +96,23 @@ onfetch = function(ev) {
new Response("check_intercepted_script();", {}) 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 });
});
}));
}
} }

View File

@ -25,6 +25,7 @@ support-files =
fetch/index.html fetch/index.html
fetch/fetch_worker_script.js fetch/fetch_worker_script.js
fetch/fetch_tests.js fetch/fetch_tests.js
fetch/deliver-gzip.sjs
fetch/https/index.html fetch/https/index.html
fetch/https/register.html fetch/https/register.html
fetch/https/unregister.html fetch/https/unregister.html

Some files were not shown because too many files have changed in this diff Show More