This commit is contained in:
Ryan VanderMeulen 2016-01-06 09:52:22 -05:00
Родитель 13fb21d300 ceb519e5ff
Коммит d8044bfc25
339 изменённых файлов: 5285 добавлений и 3496 удалений

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

@ -104,8 +104,8 @@ AccReorderEvent::IsShowHideEventTarget(const Accessible* aTarget) const
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
AccHideEvent:: AccHideEvent::
AccHideEvent(Accessible* aTarget, nsINode* aTargetNode, bool aNeedsShutdown) : AccHideEvent(Accessible* aTarget, bool aNeedsShutdown) :
AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget, aTargetNode), AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget),
mNeedsShutdown(aNeedsShutdown) mNeedsShutdown(aNeedsShutdown)
{ {
mNextSibling = mAccessible->NextSibling(); mNextSibling = mAccessible->NextSibling();
@ -118,8 +118,8 @@ AccHideEvent::
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
AccShowEvent:: AccShowEvent::
AccShowEvent(Accessible* aTarget, nsINode* aTargetNode) : AccShowEvent(Accessible* aTarget) :
AccMutationEvent(::nsIAccessibleEvent::EVENT_SHOW, aTarget, aTargetNode) AccMutationEvent(::nsIAccessibleEvent::EVENT_SHOW, aTarget)
{ {
} }

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

@ -212,8 +212,7 @@ private:
class AccMutationEvent: public AccEvent class AccMutationEvent: public AccEvent
{ {
public: public:
AccMutationEvent(uint32_t aEventType, Accessible* aTarget, AccMutationEvent(uint32_t aEventType, Accessible* aTarget) :
nsINode* aTargetNode) :
AccEvent(aEventType, aTarget, eAutoDetect, eCoalesceMutationTextChange) AccEvent(aEventType, aTarget, eAutoDetect, eCoalesceMutationTextChange)
{ {
// Don't coalesce these since they are coalesced by reorder event. Coalesce // Don't coalesce these since they are coalesced by reorder event. Coalesce
@ -250,8 +249,7 @@ protected:
class AccHideEvent: public AccMutationEvent class AccHideEvent: public AccMutationEvent
{ {
public: public:
AccHideEvent(Accessible* aTarget, nsINode* aTargetNode, explicit AccHideEvent(Accessible* aTarget, bool aNeedsShutdown = true);
bool aNeedsShutdown = true);
// Event // Event
static const EventGroup kEventGroup = eHideEvent; static const EventGroup kEventGroup = eHideEvent;
@ -281,7 +279,7 @@ protected:
class AccShowEvent: public AccMutationEvent class AccShowEvent: public AccMutationEvent
{ {
public: public:
AccShowEvent(Accessible* aTarget, nsINode* aTargetNode); explicit AccShowEvent(Accessible* aTarget);
// Event // Event
static const EventGroup kEventGroup = eShowEvent; static const EventGroup kEventGroup = eShowEvent;

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

@ -1511,7 +1511,7 @@ DocAccessible::DoInitialUpdate()
uint32_t childCount = ChildCount(); uint32_t childCount = ChildCount();
for (uint32_t i = 0; i < childCount; i++) { for (uint32_t i = 0; i < childCount; i++) {
Accessible* child = GetChildAt(i); Accessible* child = GetChildAt(i);
RefPtr<AccShowEvent> event = new AccShowEvent(child, child->GetContent()); RefPtr<AccShowEvent> event = new AccShowEvent(child);
FireDelayedEvent(event); FireDelayedEvent(event);
} }
} }
@ -1892,7 +1892,6 @@ DocAccessible::UpdateTreeInternal(Accessible* aChild, bool aIsInsert,
// this node already then it will be suppressed by this one. // this node already then it will be suppressed by this one.
Accessible* focusedAcc = nullptr; Accessible* focusedAcc = nullptr;
nsINode* node = aChild->GetNode();
if (aIsInsert) { if (aIsInsert) {
// Create accessible tree for shown accessible. // Create accessible tree for shown accessible.
CacheChildrenInSubtree(aChild, &focusedAcc); CacheChildrenInSubtree(aChild, &focusedAcc);
@ -1914,9 +1913,9 @@ DocAccessible::UpdateTreeInternal(Accessible* aChild, bool aIsInsert,
// Fire show/hide event. // Fire show/hide event.
RefPtr<AccMutationEvent> event; RefPtr<AccMutationEvent> event;
if (aIsInsert) if (aIsInsert)
event = new AccShowEvent(aChild, node); event = new AccShowEvent(aChild);
else else
event = new AccHideEvent(aChild, node); event = new AccHideEvent(aChild);
FireDelayedEvent(event); FireDelayedEvent(event);
aReorderEvent->AddSubMutationEvent(event); aReorderEvent->AddSubMutationEvent(event);
@ -2089,8 +2088,7 @@ DocAccessible::SeizeChild(Accessible* aNewParent, Accessible* aChild,
int32_t oldIdxInParent = aChild->IndexInParent(); int32_t oldIdxInParent = aChild->IndexInParent();
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(oldParent); RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(oldParent);
RefPtr<AccMutationEvent> hideEvent = RefPtr<AccMutationEvent> hideEvent = new AccHideEvent(aChild, false);
new AccHideEvent(aChild, aChild->GetContent(), false);
reorderEvent->AddSubMutationEvent(hideEvent); reorderEvent->AddSubMutationEvent(hideEvent);
{ {
@ -2121,8 +2119,7 @@ DocAccessible::SeizeChild(Accessible* aNewParent, Accessible* aChild,
FireDelayedEvent(reorderEvent); FireDelayedEvent(reorderEvent);
reorderEvent = new AccReorderEvent(aNewParent); reorderEvent = new AccReorderEvent(aNewParent);
RefPtr<AccMutationEvent> showEvent = RefPtr<AccMutationEvent> showEvent = new AccShowEvent(aChild);
new AccShowEvent(aChild, aChild->GetContent());
reorderEvent->AddSubMutationEvent(showEvent); reorderEvent->AddSubMutationEvent(showEvent);
FireDelayedEvent(showEvent); FireDelayedEvent(showEvent);
@ -2140,8 +2137,7 @@ DocAccessible::MoveChild(Accessible* aChild, int32_t aIdxInParent)
Accessible* parent = aChild->Parent(); Accessible* parent = aChild->Parent();
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(parent); RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(parent);
RefPtr<AccMutationEvent> hideEvent = RefPtr<AccMutationEvent> hideEvent = new AccHideEvent(aChild, false);
new AccHideEvent(aChild, aChild->GetContent(), false);
reorderEvent->AddSubMutationEvent(hideEvent); reorderEvent->AddSubMutationEvent(hideEvent);
AutoTreeMutation mut(parent); AutoTreeMutation mut(parent);
@ -2152,8 +2148,7 @@ DocAccessible::MoveChild(Accessible* aChild, int32_t aIdxInParent)
FireDelayedEvent(hideEvent); FireDelayedEvent(hideEvent);
RefPtr<AccMutationEvent> showEvent = RefPtr<AccMutationEvent> showEvent = new AccShowEvent(aChild);
new AccShowEvent(aChild, aChild->GetContent());
reorderEvent->AddSubMutationEvent(showEvent); reorderEvent->AddSubMutationEvent(showEvent);
FireDelayedEvent(showEvent); FireDelayedEvent(showEvent);
@ -2177,8 +2172,7 @@ DocAccessible::PutChildrenBack(nsTArray<RefPtr<Accessible> >* aChildren,
continue; continue;
} }
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(owner); RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(owner);
RefPtr<AccMutationEvent> hideEvent = RefPtr<AccMutationEvent> hideEvent = new AccHideEvent(child, false);
new AccHideEvent(child, child->GetContent(), false);
reorderEvent->AddSubMutationEvent(hideEvent); reorderEvent->AddSubMutationEvent(hideEvent);
{ {

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

@ -121,7 +121,7 @@ HTMLImageMapAccessible::UpdateChildAreas(bool aDoFireEvents)
} }
if (aDoFireEvents) { if (aDoFireEvents) {
RefPtr<AccShowEvent> event = new AccShowEvent(area, areaContent); RefPtr<AccShowEvent> event = new AccShowEvent(area);
mDoc->FireDelayedEvent(event); mDoc->FireDelayedEvent(event);
reorderEvent->AddSubMutationEvent(event); reorderEvent->AddSubMutationEvent(event);
} }

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

@ -111,7 +111,7 @@ HTMLLIAccessible::UpdateBullet(bool aHasBullet)
document->BindToDocument(mBullet, nullptr); document->BindToDocument(mBullet, nullptr);
InsertChildAt(0, mBullet); InsertChildAt(0, mBullet);
RefPtr<AccShowEvent> event = new AccShowEvent(mBullet, mBullet->GetContent()); RefPtr<AccShowEvent> event = new AccShowEvent(mBullet);
mDoc->FireDelayedEvent(event); mDoc->FireDelayedEvent(event);
reorderEvent->AddSubMutationEvent(event); reorderEvent->AddSubMutationEvent(event);
} else { } else {

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

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets B2G repositories for all targets
--> -->
<project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/> <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets B2G repositories for all targets
--> -->
<project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/> <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets B2G repositories for all targets
--> -->
<project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/> <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets B2G repositories for all targets
--> -->
<project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/> <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets B2G repositories for all targets
--> -->
<project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/> <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets B2G repositories for all targets
--> -->
<project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/> <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets B2G repositories for all targets
--> -->
<project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/> <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets B2G repositories for all targets
--> -->
<project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/> <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -1,9 +1,9 @@
{ {
"git": { "git": {
"git_revision": "16ebbfb6ce62c14573982b0aa87537ef8f857047", "git_revision": "81c021654c657f6995e5e70ef02ee067d4bfedbd",
"remote": "https://git.mozilla.org/releases/gaia.git", "remote": "https://git.mozilla.org/releases/gaia.git",
"branch": "" "branch": ""
}, },
"revision": "8668ab0c480334a48e1935cce440e33dff23b33a", "revision": "e651f5b571034436b7bc8eb8099033dff5623a20",
"repo_path": "integration/gaia-central" "repo_path": "integration/gaia-central"
} }

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

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets B2G repositories for all targets
--> -->
<project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/> <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets B2G repositories for all targets
--> -->
<project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/> <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -21,7 +21,7 @@
<!-- <!--
B2G repositories for all targets B2G repositories for all targets
--> -->
<project name="gaia" path="gaia" remote="mozillaorg" revision="16ebbfb6ce62c14573982b0aa87537ef8f857047"/> <project name="gaia" path="gaia" remote="mozillaorg" revision="81c021654c657f6995e5e70ef02ee067d4bfedbd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
<project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>

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

@ -1014,8 +1014,6 @@ pref("browser.sessionstore.interval", 15000);
// on which sites to save text data, POSTDATA and cookies // on which sites to save text data, POSTDATA and cookies
// 0 = everywhere, 1 = unencrypted sites, 2 = nowhere // 0 = everywhere, 1 = unencrypted sites, 2 = nowhere
pref("browser.sessionstore.privacy_level", 0); pref("browser.sessionstore.privacy_level", 0);
// the same as browser.sessionstore.privacy_level, but for saving deferred session data
pref("browser.sessionstore.privacy_level_deferred", 1);
// how many tabs can be reopened (per window) // how many tabs can be reopened (per window)
pref("browser.sessionstore.max_tabs_undo", 10); pref("browser.sessionstore.max_tabs_undo", 10);
// how many windows can be reopened (per session) - on non-OS X platforms this // how many windows can be reopened (per session) - on non-OS X platforms this
@ -1405,8 +1403,8 @@ pref("security.insecure_password.ui.enabled", false);
// 1 = allow MITM for certificate pinning checks. // 1 = allow MITM for certificate pinning checks.
pref("security.cert_pinning.enforcement_level", 1); pref("security.cert_pinning.enforcement_level", 1);
// 2 = allow SHA-1 only before 2016-01-01 // 0 = allow SHA-1
pref("security.pki.sha1_enforcement_level", 2); pref("security.pki.sha1_enforcement_level", 0);
// Required blocklist freshness for OneCRL OCSP bypass // Required blocklist freshness for OneCRL OCSP bypass
// (default is 1.25x extensions.blocklist.interval, or 30 hours) // (default is 1.25x extensions.blocklist.interval, or 30 hours)
@ -1502,7 +1500,8 @@ pref("media.eme.apiVisible", true);
// Decode using Gecko Media Plugins in <video>, if a system decoder is not // Decode using Gecko Media Plugins in <video>, if a system decoder is not
// availble and the preferred GMP is available. // availble and the preferred GMP is available.
pref("media.gmp.decoder.enabled", true); // NOTE: Disabled until Bug 1236756 is fixed by Adobe.
pref("media.gmp.decoder.enabled", false);
// If decoding-via-GMP is turned on for <video>, use Adobe's GMP for decoding, // If decoding-via-GMP is turned on for <video>, use Adobe's GMP for decoding,
// if it's available. Note: We won't fallback to another GMP if Adobe's is not // if it's available. Note: We won't fallback to another GMP if Adobe's is not

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

@ -6132,6 +6132,16 @@
]]> ]]>
</body> </body>
</method> </method>
<method name="setUserContextId">
<parameter name="aUserContextId"/>
<body>
<![CDATA[
this.linkedBrowser.setAttribute("usercontextid", aUserContextId);
this.setAttribute("usercontextid", aUserContextId);
]]>
</body>
</method>
</implementation> </implementation>
<handlers> <handlers>

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

@ -80,8 +80,7 @@ add_task(function* test() {
// check each item in the title and validate it meets expectatations // check each item in the title and validate it meets expectatations
for (let part of title) { for (let part of title) {
let [storageMethodName, value] = part.split("="); let [storageMethodName, value] = part.split("=");
let is_f = storageMethodName == "cookie" ? is : todo_is; is(value, expectedContext,
is_f(value, expectedContext,
"the title reflects the expected contextual identity of " + "the title reflects the expected contextual identity of " +
expectedContext + " for method " + storageMethodName + ": " + value); expectedContext + " for method " + storageMethodName + ": " + value);
} }

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

@ -18,12 +18,11 @@ XPCOMUtils.defineLazyModuleGetter(this, "PrivacyLevel",
* |url|. * |url|.
* *
* @param url The URL we want to save data for. * @param url The URL we want to save data for.
* @param isPinned Whether the given |url| is contained in a pinned tab.
* @return bool * @return bool
*/ */
function checkPrivacyLevel(url, isPinned) { function checkPrivacyLevel(url) {
let isHttps = url.startsWith("https:"); let isHttps = url.startsWith("https:");
return PrivacyLevel.canSave({isHttps: isHttps, isPinned: isPinned}); return PrivacyLevel.canSave({isHttps});
} }
/** /**
@ -37,14 +36,13 @@ this.PrivacyFilter = Object.freeze({
* we're allowed to store. * we're allowed to store.
* *
* @param data The session storage data as collected from a tab. * @param data The session storage data as collected from a tab.
* @param isPinned Whether the tab we collected from is pinned.
* @return object * @return object
*/ */
filterSessionStorageData: function (data, isPinned) { filterSessionStorageData: function (data) {
let retval = {}; let retval = {};
for (let host of Object.keys(data)) { for (let host of Object.keys(data)) {
if (checkPrivacyLevel(host, isPinned)) { if (checkPrivacyLevel(host)) {
retval[host] = data[host]; retval[host] = data[host];
} }
} }
@ -58,14 +56,13 @@ this.PrivacyFilter = Object.freeze({
* allowed to store. * allowed to store.
* *
* @param data The form data as collected from a tab. * @param data The form data as collected from a tab.
* @param isPinned Whether the tab we collected from is pinned.
* @return object * @return object
*/ */
filterFormData: function (data, isPinned) { filterFormData: function (data) {
// If the given form data object has an associated URL that we are not // If the given form data object has an associated URL that we are not
// allowed to store data for, bail out. We explicitly discard data for any // allowed to store data for, bail out. We explicitly discard data for any
// children as well even if storing data for those frames would be allowed. // children as well even if storing data for those frames would be allowed.
if (data.url && !checkPrivacyLevel(data.url, isPinned)) { if (data.url && !checkPrivacyLevel(data.url)) {
return; return;
} }
@ -73,7 +70,7 @@ this.PrivacyFilter = Object.freeze({
for (let key of Object.keys(data)) { for (let key of Object.keys(data)) {
if (key === "children") { if (key === "children") {
let recurse = child => this.filterFormData(child, isPinned); let recurse = child => this.filterFormData(child);
let children = data.children.map(recurse).filter(child => child); let children = data.children.map(recurse).filter(child => child);
if (children.length) { if (children.length) {

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

@ -14,8 +14,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "gSessionStartup", XPCOMUtils.defineLazyServiceGetter(this, "gSessionStartup",
"@mozilla.org/browser/sessionstartup;1", "nsISessionStartup"); "@mozilla.org/browser/sessionstartup;1", "nsISessionStartup");
const PREF_NORMAL = "browser.sessionstore.privacy_level"; const PREF = "browser.sessionstore.privacy_level";
const PREF_DEFERRED = "browser.sessionstore.privacy_level_deferred";
// The following constants represent the different possible privacy levels that // The following constants represent the different possible privacy levels that
// can be set by the user and that we need to consider when collecting text // can be set by the user and that we need to consider when collecting text
@ -28,25 +27,6 @@ const PRIVACY_ENCRYPTED = 1;
// Collect no data. // Collect no data.
const PRIVACY_FULL = 2; const PRIVACY_FULL = 2;
/**
* Determines the current privacy level as set by the user.
*
* @param isPinned
* Whether to return the privacy level for pinned tabs.
* @return {int} The privacy level as read from the user's preferences.
*/
function getCurrentLevel(isPinned) {
let pref = PREF_NORMAL;
// If we're in the process of quitting and we're not autoresuming the session
// then we will use the deferred privacy level for non-pinned tabs.
if (!isPinned && Services.startup.shuttingDown && !gSessionStartup.isAutomaticRestoreEnabled()) {
pref = PREF_DEFERRED;
}
return Services.prefs.getIntPref(pref);
}
/** /**
* The external API as exposed by this module. * The external API as exposed by this module.
*/ */
@ -54,14 +34,13 @@ var PrivacyLevel = Object.freeze({
/** /**
* Checks whether we're allowed to save data for a specific site. * Checks whether we're allowed to save data for a specific site.
* *
* @param {isHttps: boolean, isPinned: boolean} * @param {isHttps: boolean}
* An object that must have two properties: 'isHttps' and 'isPinned'. * An object that must have one property: 'isHttps'.
* 'isHttps' tells whether the site us secure communication (HTTPS). * 'isHttps' tells whether the site us secure communication (HTTPS).
* 'isPinned' tells whether the site is loaded in a pinned tab.
* @return {bool} Whether we can save data for the specified site. * @return {bool} Whether we can save data for the specified site.
*/ */
canSave: function ({isHttps, isPinned}) { canSave: function ({isHttps}) {
let level = getCurrentLevel(isPinned); let level = Services.prefs.getIntPref(PREF);
// Never save any data when full privacy is requested. // Never save any data when full privacy is requested.
if (level == PRIVACY_FULL) { if (level == PRIVACY_FULL) {

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

@ -64,7 +64,7 @@ var SessionHistoryInternal = {
* The docShell that owns the session history. * The docShell that owns the session history.
*/ */
collect: function (docShell) { collect: function (docShell) {
let data = {entries: []}; let data = {entries: [], userContextId: docShell.userContextId };
let webNavigation = docShell.QueryInterface(Ci.nsIWebNavigation); let webNavigation = docShell.QueryInterface(Ci.nsIWebNavigation);
let history = webNavigation.sessionHistory.QueryInterface(Ci.nsISHistoryInternal); let history = webNavigation.sessionHistory.QueryInterface(Ci.nsISHistoryInternal);
@ -253,6 +253,10 @@ var SessionHistoryInternal = {
let webNavigation = docShell.QueryInterface(Ci.nsIWebNavigation); let webNavigation = docShell.QueryInterface(Ci.nsIWebNavigation);
let history = webNavigation.sessionHistory; let history = webNavigation.sessionHistory;
if ("userContextId" in tabData) {
docShell.userContextId = tabData.userContextId;
}
if (history.count > 0) { if (history.count > 0) {
history.PurgeHistory(history.count); history.PurgeHistory(history.count);
} }

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

@ -3189,6 +3189,10 @@ var SessionStoreInternal = {
tabbrowser.showTab(tab); tabbrowser.showTab(tab);
} }
if (tabData.userContextId) {
tab.setUserContextId(tabData.userContextId);
}
if (!!tabData.muted != browser.audioMuted) { if (!!tabData.muted != browser.audioMuted) {
tab.toggleMuteAudio(); tab.toggleMuteAudio();
} }

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

@ -224,15 +224,19 @@ var TabStateInternal = {
// Filter sensitive data according to the current privacy level. // Filter sensitive data according to the current privacy level.
if (!includePrivateData) { if (!includePrivateData) {
if (key === "storage") { if (key === "storage") {
value = PrivacyFilter.filterSessionStorageData(value, isPinned); value = PrivacyFilter.filterSessionStorageData(value);
} else if (key === "formdata") { } else if (key === "formdata") {
value = PrivacyFilter.filterFormData(value, isPinned); value = PrivacyFilter.filterFormData(value);
} }
} }
if (key === "history") { if (key === "history") {
tabData.entries = value.entries; tabData.entries = value.entries;
if (value.hasOwnProperty("userContextId")) {
tabData.userContextId = value.userContextId;
}
if (value.hasOwnProperty("index")) { if (value.hasOwnProperty("index")) {
tabData.index = value.index; tabData.index = value.index;
} }

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

@ -219,3 +219,4 @@ skip-if = os == "mac"
run-if = e10s run-if = e10s
[browser_async_window_flushing.js] [browser_async_window_flushing.js]
[browser_forget_async_closings.js] [browser_forget_async_closings.js]
[browser_sessionStoreContainer.js]

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

@ -0,0 +1,24 @@
/* 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/. */
function retrieveUserContextId(browser) {
return ContentTask.spawn(browser, null, function* () {
return docShell.userContextId;
});
}
add_task(function() {
for (let i = 0; i < 3; ++i) {
let tab = gBrowser.addTab("about:blank");
let browser = tab.linkedBrowser;
yield promiseBrowserLoaded(browser);
yield promiseTabState(tab, { userContextId: i, entries: [{ url: "http://example.com/" }] });
let userContextId = yield retrieveUserContextId(browser);
is(userContextId, i, "The docShell has the correct userContextId");
yield promiseRemoveTab(tab);
}
});

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

@ -132,6 +132,7 @@ OriginAttributes::CreateSuffix(nsACString& aStr) const
} }
if (!mSignedPkg.IsEmpty()) { if (!mSignedPkg.IsEmpty()) {
MOZ_RELEASE_ASSERT(mSignedPkg.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) == kNotFound);
params->Set(NS_LITERAL_STRING("signedPkg"), mSignedPkg); params->Set(NS_LITERAL_STRING("signedPkg"), mSignedPkg);
} }

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

@ -10072,6 +10072,11 @@ nsDocShell::InternalLoad(nsIURI* aURI,
} }
} }
// If we're doing a history load, use its scroll restoration state.
if (aSHEntry) {
aSHEntry->GetScrollRestorationIsManual(&scrollRestorationIsManual);
}
/* Assign mOSHE to mLSHE. This will either be a new entry created /* Assign mOSHE to mLSHE. This will either be a new entry created
* by OnNewURI() for normal loads or aSHEntry for history loads. * by OnNewURI() for normal loads or aSHEntry for history loads.
*/ */
@ -13831,6 +13836,17 @@ nsDocShell::SetIsSignedPackage(const nsAString& aSignedPkg)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsDocShell::GetUserContextId(uint32_t* aUserContextId)
{
if (!aUserContextId) {
return NS_ERROR_FAILURE;
}
*aUserContextId = mUserContextId;
return NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
nsDocShell::SetUserContextId(uint32_t aUserContextId) nsDocShell::SetUserContextId(uint32_t aUserContextId)
{ {
@ -14181,55 +14197,8 @@ nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, bool aIsNonSubresourceReques
return NS_OK; return NS_OK;
} }
namespace {
class FetchEventDispatcher final : public nsIFetchEventDispatcher
{
public:
FetchEventDispatcher(nsIInterceptedChannel* aChannel,
nsIRunnable* aContinueRunnable)
: mChannel(aChannel)
, mContinueRunnable(aContinueRunnable)
{
}
NS_DECL_ISUPPORTS
NS_DECL_NSIFETCHEVENTDISPATCHER
private:
~FetchEventDispatcher()
{
}
nsCOMPtr<nsIInterceptedChannel> mChannel;
nsCOMPtr<nsIRunnable> mContinueRunnable;
};
NS_IMPL_ISUPPORTS(FetchEventDispatcher, nsIFetchEventDispatcher)
NS_IMETHODIMP NS_IMETHODIMP
FetchEventDispatcher::Dispatch() nsDocShell::ChannelIntercepted(nsIInterceptedChannel* aChannel)
{
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (!swm) {
mChannel->Cancel(NS_ERROR_INTERCEPTION_FAILED);
return NS_OK;
}
ErrorResult error;
swm->DispatchPreparedFetchEvent(mChannel, mContinueRunnable, error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
return NS_OK;
}
}
NS_IMETHODIMP
nsDocShell::ChannelIntercepted(nsIInterceptedChannel* aChannel,
nsIFetchEventDispatcher** aFetchDispatcher)
{ {
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (!swm) { if (!swm) {
@ -14266,18 +14235,12 @@ nsDocShell::ChannelIntercepted(nsIInterceptedChannel* aChannel,
attrs.InheritFromDocShellToDoc(GetOriginAttributes(), uri); attrs.InheritFromDocShellToDoc(GetOriginAttributes(), uri);
ErrorResult error; ErrorResult error;
nsCOMPtr<nsIRunnable> runnable = swm->DispatchFetchEvent(attrs, doc, mInterceptedDocumentId, aChannel,
swm->PrepareFetchEvent(attrs, doc, mInterceptedDocumentId, aChannel, isReload, isSubresourceLoad, error);
isReload, isSubresourceLoad, error);
if (NS_WARN_IF(error.Failed())) { if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult(); return error.StealNSResult();
} }
MOZ_ASSERT(runnable);
RefPtr<FetchEventDispatcher> dispatcher =
new FetchEventDispatcher(aChannel, runnable);
dispatcher.forget(aFetchDispatcher);
return NS_OK; return NS_OK;
} }

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

@ -232,7 +232,6 @@ public:
NS_IMETHOD GetUseRemoteTabs(bool*) override; NS_IMETHOD GetUseRemoteTabs(bool*) override;
NS_IMETHOD SetRemoteTabs(bool) override; NS_IMETHOD SetRemoteTabs(bool) override;
NS_IMETHOD GetOriginAttributes(JS::MutableHandle<JS::Value>) override; NS_IMETHOD GetOriginAttributes(JS::MutableHandle<JS::Value>) override;
NS_IMETHOD SetUserContextId(uint32_t);
// Restores a cached presentation from history (mLSHE). // Restores a cached presentation from history (mLSHE).
// This method swaps out the content viewer and simulates loads for // This method swaps out the content viewer and simulates loads for

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

@ -43,7 +43,7 @@ interface nsITabParent;
typedef unsigned long nsLoadFlags; typedef unsigned long nsLoadFlags;
[scriptable, builtinclass, uuid(811aa3e1-7c4d-45ae-89da-ea1b107c60ed)] [scriptable, builtinclass, uuid(258a8a33-219f-42f8-8fa8-f8f2dcd2358b)]
interface nsIDocShell : nsIDocShellTreeItem interface nsIDocShell : nsIDocShellTreeItem
{ {
/** /**
@ -1096,4 +1096,9 @@ interface nsIDocShell : nsIDocShellTreeItem
* @see https://html.spec.whatwg.org/#dom-history-scroll-restoration * @see https://html.spec.whatwg.org/#dom-history-scroll-restoration
*/ */
attribute boolean currentScrollRestorationIsManual; attribute boolean currentScrollRestorationIsManual;
/**
* Sets/gets the user context ID for this docshell.
*/
attribute unsigned long userContextId;
}; };

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

@ -82,6 +82,15 @@
opener.is(window.scrollY, 0, "Shouldn't have scrolled back to the state3's position"); opener.is(window.scrollY, 0, "Shouldn't have scrolled back to the state3's position");
opener.is(history.state.state, "state3", "Unexpected state."); opener.is(history.state.state, "state3", "Unexpected state.");
history.pushState({ state: "state5" }, "state5");
history.scrollRestoration = "auto";
document.getElementById("bottom").scrollIntoView();
opener.isnot(window.scrollY, 0, "Should have scrolled to 'bottom'.");
history.back();
window.scrollTo(0, 0);
history.forward();
opener.isnot(window.scrollY, 0, "Should have scrolled back to the state5's position");
var ifr = document.createElement("iframe"); var ifr = document.createElement("iframe");
ifr.src = "data:text/html,"; ifr.src = "data:text/html,";
document.body.appendChild(ifr); document.body.appendChild(ifr);

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

@ -47,7 +47,7 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop spec
[test_popup-navigates-children.html] [test_popup-navigates-children.html]
skip-if = buildapp == 'b2g' # b2g(Needs multiple window.open support, also uses docshelltreenode) b2g-debug(Needs multiple window.open support, also uses docshelltreenode) b2g-desktop(Needs multiple window.open support, also uses docshelltreenode) skip-if = buildapp == 'b2g' # b2g(Needs multiple window.open support, also uses docshelltreenode) b2g-debug(Needs multiple window.open support, also uses docshelltreenode) b2g-desktop(Needs multiple window.open support, also uses docshelltreenode)
[test_reserved.html] [test_reserved.html]
skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || android_version == '10' || android_version == '18' #too slow on Android 2.3 and 4.3 aws only; bug 1030403 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || android_version == '10' || android_version == '18' || (e10s && debug && os == 'win') #too slow on Android 2.3 and 4.3 aws only; bug 1030403
[test_sessionhistory.html] [test_sessionhistory.html]
skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'android' #RANDOM # b2g-debug(Perma-orange on debug emulator builds) b2g-desktop(Bug 931116, b2g desktop specific, initial triage) skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'android' #RANDOM # b2g-debug(Perma-orange on debug emulator builds) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
[test_sibling-matching-parent.html] [test_sibling-matching-parent.html]

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

@ -0,0 +1,81 @@
/* -*- 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 "AnimValuesStyleRule.h"
#include "nsRuleData.h"
#include "nsStyleContext.h"
namespace mozilla {
NS_IMPL_ISUPPORTS(AnimValuesStyleRule, nsIStyleRule)
void
AnimValuesStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
{
nsStyleContext *contextParent = aRuleData->mStyleContext->GetParent();
if (contextParent && contextParent->HasPseudoElementData()) {
// Don't apply transitions or animations to things inside of
// pseudo-elements.
// FIXME (Bug 522599): Add tests for this.
// Prevent structs from being cached on the rule node since we're inside
// a pseudo-element, as we could determine cacheability differently
// when walking the rule tree for a style context that is not inside
// a pseudo-element. Note that nsRuleNode::GetStyle##name_ and GetStyleData
// will never look at cached structs when we're animating things inside
// a pseduo-element, so that we don't incorrectly return a struct that
// is only appropriate for non-pseudo-elements.
aRuleData->mConditions.SetUncacheable();
return;
}
for (uint32_t i = 0, i_end = mPropertyValuePairs.Length(); i < i_end; ++i) {
PropertyValuePair &cv = mPropertyValuePairs[i];
if (aRuleData->mSIDs & nsCachedStyleData::GetBitForSID(
nsCSSProps::kSIDTable[cv.mProperty]))
{
nsCSSValue *prop = aRuleData->ValueFor(cv.mProperty);
if (prop->GetUnit() == eCSSUnit_Null) {
#ifdef DEBUG
bool ok =
#endif
StyleAnimationValue::UncomputeValue(cv.mProperty, cv.mValue, *prop);
MOZ_ASSERT(ok, "could not store computed value");
}
}
}
}
bool
AnimValuesStyleRule::MightMapInheritedStyleData()
{
return mStyleBits & NS_STYLE_INHERITED_STRUCT_MASK;
}
#ifdef DEBUG
void
AnimValuesStyleRule::List(FILE* out, int32_t aIndent) const
{
nsAutoCString str;
for (int32_t index = aIndent; --index >= 0; ) {
str.AppendLiteral(" ");
}
str.AppendLiteral("[anim values] { ");
for (uint32_t i = 0, i_end = mPropertyValuePairs.Length(); i < i_end; ++i) {
const PropertyValuePair &pair = mPropertyValuePairs[i];
str.Append(nsCSSProps::GetStringValue(pair.mProperty));
str.AppendLiteral(": ");
nsAutoString value;
StyleAnimationValue::UncomputeValue(pair.mProperty, pair.mValue, value);
AppendUTF16toUTF8(value, str);
str.AppendLiteral("; ");
}
str.AppendLiteral("}\n");
fprintf_stderr(out, "%s", str.get());
}
#endif
} // namespace mozilla

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

@ -0,0 +1,79 @@
/* -*- 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_AnimValuesStyleRule_h
#define mozilla_AnimValuesStyleRule_h
#include "mozilla/StyleAnimationValue.h"
#include "nsCSSProperty.h"
#include "nsCSSPropertySet.h"
#include "nsIStyleRule.h"
#include "nsISupportsImpl.h" // For NS_DECL_ISUPPORTS
#include "nsRuleNode.h" // For nsCachedStyleData
#include "nsTArray.h" // For nsTArray
namespace mozilla {
/**
* A style rule that maps property-StyleAnimationValue pairs.
*/
class AnimValuesStyleRule final : public nsIStyleRule
{
public:
AnimValuesStyleRule()
: mStyleBits(0) {}
// nsISupports implementation
NS_DECL_ISUPPORTS
// nsIStyleRule implementation
void MapRuleInfoInto(nsRuleData* aRuleData) override;
bool MightMapInheritedStyleData() override;
#ifdef DEBUG
void List(FILE* out = stdout, int32_t aIndent = 0) const override;
#endif
void AddValue(nsCSSProperty aProperty, StyleAnimationValue &aStartValue)
{
PropertyValuePair v = { aProperty, aStartValue };
mPropertyValuePairs.AppendElement(v);
mStyleBits |=
nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[aProperty]);
}
// Caller must fill in returned value.
StyleAnimationValue* AddEmptyValue(nsCSSProperty aProperty)
{
PropertyValuePair *p = mPropertyValuePairs.AppendElement();
p->mProperty = aProperty;
mStyleBits |=
nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[aProperty]);
return &p->mValue;
}
struct PropertyValuePair {
nsCSSProperty mProperty;
StyleAnimationValue mValue;
};
void AddPropertiesToSet(nsCSSPropertySet& aSet) const
{
for (size_t i = 0, i_end = mPropertyValuePairs.Length(); i < i_end; ++i) {
const PropertyValuePair &cv = mPropertyValuePairs[i];
aSet.AddProperty(cv.mProperty);
}
}
private:
~AnimValuesStyleRule() {}
InfallibleTArray<PropertyValuePair> mPropertyValuePairs;
uint32_t mStyleBits;
};
} // namespace mozilla
#endif // mozilla_AnimValuesStyleRule_h

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

@ -477,14 +477,12 @@ Animation::Tick()
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async); UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
// FIXME: Detect the no-change case and don't request a restyle at all // Update layers if we are newly finished.
// FIXME: Detect changes to IsPlaying() state and request RestyleType::Layer if (mEffect &&
// so that layers get updated immediately !mEffect->Properties().IsEmpty() &&
AnimationCollection* collection = GetCollection(); !mFinishedAtLastComposeStyle &&
if (collection) { PlayState() == AnimationPlayState::Finished) {
collection->RequestRestyle(CanThrottle() ? PostUpdate();
AnimationCollection::RestyleType::Throttled :
AnimationCollection::RestyleType::Standard);
} }
} }
@ -673,41 +671,6 @@ Animation::HasLowerCompositeOrderThan(const Animation& aOther) const
return mAnimationIndex < aOther.mAnimationIndex; return mAnimationIndex < aOther.mAnimationIndex;
} }
bool
Animation::CanThrottle() const
{
// This method answers the question, "Can we get away with NOT updating
// style on the main thread for this animation on this tick?"
// Ignore animations that were never going to have any effect anyway.
if (!mEffect || mEffect->Properties().IsEmpty()) {
return true;
}
// Finished animations can be throttled unless this is the first
// sample since finishing. In that case we need an unthrottled sample
// so we can apply the correct end-of-animation behavior on the main
// thread (either removing the animation style or applying the fill mode).
if (PlayState() == AnimationPlayState::Finished) {
return mFinishedAtLastComposeStyle;
}
// We should also ignore animations which are not "in effect"--i.e. not
// producing an output. This includes animations that are idle or in their
// delay phase but with no backwards fill.
//
// Note that unlike newly-finished animations, we don't need to worry about
// special handling for newly-idle animations or animations that are newly
// yet-to-start since any operation that would cause that change (e.g. a call
// to cancel() on the animation, or seeking its current time) will trigger an
// unthrottled sample.
if (!IsInEffect()) {
return true;
}
return mEffect->CanThrottle();
}
void void
Animation::ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule, Animation::ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
nsCSSPropertySet& aSetProperties, nsCSSPropertySet& aSetProperties,

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

@ -10,6 +10,7 @@
#include "nsWrapperCache.h" #include "nsWrapperCache.h"
#include "nsCycleCollectionParticipant.h" #include "nsCycleCollectionParticipant.h"
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/EffectCompositor.h" // For EffectCompositor::CascadeLevel
#include "mozilla/LinkedList.h" #include "mozilla/LinkedList.h"
#include "mozilla/TimeStamp.h" // for TimeStamp, TimeDuration #include "mozilla/TimeStamp.h" // for TimeStamp, TimeDuration
#include "mozilla/dom/AnimationBinding.h" // for AnimationPlayState #include "mozilla/dom/AnimationBinding.h" // for AnimationPlayState
@ -285,6 +286,15 @@ public:
*/ */
virtual bool HasLowerCompositeOrderThan(const Animation& aOther) const; virtual bool HasLowerCompositeOrderThan(const Animation& aOther) const;
/**
* Returns the level at which the effect(s) associated with this Animation
* are applied to the CSS cascade.
*/
virtual EffectCompositor::CascadeLevel CascadeLevel() const
{
return EffectCompositor::CascadeLevel::Animations;
}
/** /**
* Returns true if this animation does not currently need to update * Returns true if this animation does not currently need to update
* style on the main thread (e.g. because it is empty, or is * style on the main thread (e.g. because it is empty, or is

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

@ -7,12 +7,24 @@
#include "EffectCompositor.h" #include "EffectCompositor.h"
#include "mozilla/dom/Animation.h" #include "mozilla/dom/Animation.h"
#include "mozilla/dom/KeyframeEffect.h" #include "mozilla/dom/Element.h"
#include "mozilla/dom/KeyframeEffect.h" // For KeyframeEffectReadOnly
#include "mozilla/AnimationUtils.h" #include "mozilla/AnimationUtils.h"
#include "mozilla/EffectSet.h" #include "mozilla/EffectSet.h"
#include "mozilla/LayerAnimationInfo.h"
#include "AnimationCommon.h" // For AnimationCollection
#include "nsAnimationManager.h"
#include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetPresShellForContent
#include "nsCSSPropertySet.h"
#include "nsCSSProps.h"
#include "nsIPresShell.h"
#include "nsLayoutUtils.h" #include "nsLayoutUtils.h"
#include "nsRuleNode.h" // For nsRuleNode::ComputePropertiesOverridingAnimation
#include "nsTArray.h"
#include "nsTransitionManager.h"
using mozilla::dom::Animation; using mozilla::dom::Animation;
using mozilla::dom::Element;
using mozilla::dom::KeyframeEffectReadOnly; using mozilla::dom::KeyframeEffectReadOnly;
namespace mozilla { namespace mozilla {
@ -40,6 +52,21 @@ FindAnimationsForCompositor(const nsIFrame* aFrame,
return false; return false;
} }
// The animation cascade will almost always be up-to-date by this point
// but there are some cases such as when we are restoring the refresh driver
// from test control after seeking where it might not be the case.
//
// Those cases are probably not important but just to be safe, let's make
// sure the cascade is up to date since if it *is* up to date, this is
// basically a no-op.
Maybe<Pair<dom::Element*, nsCSSPseudoElements::Type>> pseudoElement =
EffectCompositor::GetAnimationElementAndPseudoForFrame(aFrame);
if (pseudoElement) {
EffectCompositor::MaybeUpdateCascadeResults(pseudoElement->first(),
pseudoElement->second(),
aFrame->StyleContext());
}
if (!nsLayoutUtils::AreAsyncAnimationsEnabled()) { if (!nsLayoutUtils::AreAsyncAnimationsEnabled()) {
if (nsLayoutUtils::IsAnimationLoggingEnabled()) { if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
nsCString message; nsCString message;
@ -104,4 +131,288 @@ EffectCompositor::GetAnimationsForCompositor(const nsIFrame* aFrame,
return result; return result;
} }
/* static */ void
EffectCompositor::MaybeUpdateCascadeResults(Element* aElement,
nsCSSPseudoElements::Type
aPseudoType,
nsStyleContext* aStyleContext)
{
EffectSet* effects = EffectSet::GetEffectSet(aElement, aPseudoType);
if (!effects || !effects->CascadeNeedsUpdate()) {
return;
}
UpdateCascadeResults(*effects, aElement, aPseudoType, aStyleContext);
MOZ_ASSERT(!effects->CascadeNeedsUpdate(), "Failed to update cascade state");
}
namespace {
class EffectCompositeOrderComparator {
public:
bool Equals(const KeyframeEffectReadOnly* a,
const KeyframeEffectReadOnly* b) const
{
return a == b;
}
bool LessThan(const KeyframeEffectReadOnly* a,
const KeyframeEffectReadOnly* b) const
{
MOZ_ASSERT(a->GetAnimation() && b->GetAnimation());
MOZ_ASSERT(
Equals(a, b) ||
a->GetAnimation()->HasLowerCompositeOrderThan(*b->GetAnimation()) !=
b->GetAnimation()->HasLowerCompositeOrderThan(*a->GetAnimation()));
return a->GetAnimation()->HasLowerCompositeOrderThan(*b->GetAnimation());
}
};
}
/* static */ void
EffectCompositor::UpdateCascadeResults(Element* aElement,
nsCSSPseudoElements::Type aPseudoType,
nsStyleContext* aStyleContext)
{
EffectSet* effects = EffectSet::GetEffectSet(aElement, aPseudoType);
if (!effects) {
return;
}
UpdateCascadeResults(*effects, aElement, aPseudoType, aStyleContext);
}
/* static */ Maybe<Pair<Element*, nsCSSPseudoElements::Type>>
EffectCompositor::GetAnimationElementAndPseudoForFrame(const nsIFrame* aFrame)
{
// Always return the same object to benefit from return-value optimization.
Maybe<Pair<Element*, nsCSSPseudoElements::Type>> result;
nsIContent* content = aFrame->GetContent();
if (!content) {
return result;
}
nsCSSPseudoElements::Type pseudoType =
nsCSSPseudoElements::ePseudo_NotPseudoElement;
if (aFrame->IsGeneratedContentFrame()) {
nsIFrame* parent = aFrame->GetParent();
if (parent->IsGeneratedContentFrame()) {
return result;
}
nsIAtom* name = content->NodeInfo()->NameAtom();
if (name == nsGkAtoms::mozgeneratedcontentbefore) {
pseudoType = nsCSSPseudoElements::ePseudo_before;
} else if (name == nsGkAtoms::mozgeneratedcontentafter) {
pseudoType = nsCSSPseudoElements::ePseudo_after;
} else {
return result;
}
content = content->GetParent();
if (!content) {
return result;
}
}
if (!content->IsElement()) {
return result;
}
result = Some(MakePair(content->AsElement(), pseudoType));
return result;
}
/* static */ void
EffectCompositor::ComposeAnimationRule(dom::Element* aElement,
nsCSSPseudoElements::Type aPseudoType,
CascadeLevel aCascadeLevel,
bool& aStyleChanging)
{
EffectSet* effects = EffectSet::GetEffectSet(aElement, aPseudoType);
if (!effects) {
return;
}
// The caller is responsible for calling MaybeUpdateCascadeResults first.
MOZ_ASSERT(!effects->CascadeNeedsUpdate(),
"Animation cascade out of date when composing animation rule");
// Get a list of effects for the current level sorted by composite order.
nsTArray<KeyframeEffectReadOnly*> sortedEffectList;
for (KeyframeEffectReadOnly* effect : *effects) {
MOZ_ASSERT(effect->GetAnimation());
if (effect->GetAnimation()->CascadeLevel() == aCascadeLevel) {
sortedEffectList.AppendElement(effect);
}
}
sortedEffectList.Sort(EffectCompositeOrderComparator());
RefPtr<AnimValuesStyleRule>& animationRule =
effects->AnimationRule(aCascadeLevel);
animationRule = nullptr;
// We'll set aStyleChanging to true below if necessary.
aStyleChanging = false;
// If multiple animations specify behavior for the same property the
// animation with the *highest* composite order wins.
// As a result, we iterate from last animation to first and, if a
// property has already been set, we don't change it.
nsCSSPropertySet properties;
for (KeyframeEffectReadOnly* effect : Reversed(sortedEffectList)) {
effect->GetAnimation()->ComposeStyle(animationRule, properties,
aStyleChanging);
}
}
/* static */ void
EffectCompositor::GetOverriddenProperties(nsStyleContext* aStyleContext,
EffectSet& aEffectSet,
nsCSSPropertySet&
aPropertiesOverridden)
{
nsAutoTArray<nsCSSProperty, LayerAnimationInfo::kRecords> propertiesToTrack;
{
nsCSSPropertySet propertiesToTrackAsSet;
for (KeyframeEffectReadOnly* effect : aEffectSet) {
for (const AnimationProperty& property : effect->Properties()) {
if (nsCSSProps::PropHasFlags(property.mProperty,
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR) &&
!propertiesToTrackAsSet.HasProperty(property.mProperty)) {
propertiesToTrackAsSet.AddProperty(property.mProperty);
propertiesToTrack.AppendElement(property.mProperty);
}
}
// Skip iterating over the rest of the effects if we've already
// found all the compositor-animatable properties.
if (propertiesToTrack.Length() == LayerAnimationInfo::kRecords) {
break;
}
}
}
if (propertiesToTrack.IsEmpty()) {
return;
}
nsRuleNode::ComputePropertiesOverridingAnimation(propertiesToTrack,
aStyleContext,
aPropertiesOverridden);
}
/* static */ void
EffectCompositor::UpdateCascadeResults(EffectSet& aEffectSet,
Element* aElement,
nsCSSPseudoElements::Type aPseudoType,
nsStyleContext* aStyleContext)
{
MOZ_ASSERT(EffectSet::GetEffectSet(aElement, aPseudoType) == &aEffectSet,
"Effect set should correspond to the specified (pseudo-)element");
if (aEffectSet.IsEmpty()) {
aEffectSet.MarkCascadeUpdated();
return;
}
// Get a list of effects sorted by composite order.
nsTArray<KeyframeEffectReadOnly*> sortedEffectList;
for (KeyframeEffectReadOnly* effect : aEffectSet) {
sortedEffectList.AppendElement(effect);
}
sortedEffectList.Sort(EffectCompositeOrderComparator());
// Get properties that override the *animations* level of the cascade.
//
// We only do this for properties that we can animate on the compositor
// since we will apply other properties on the main thread where the usual
// cascade applies.
nsCSSPropertySet overriddenProperties;
if (aStyleContext) {
GetOverriddenProperties(aStyleContext, aEffectSet, overriddenProperties);
}
bool changed = false;
nsCSSPropertySet animatedProperties;
// Iterate from highest to lowest composite order.
for (KeyframeEffectReadOnly* effect : Reversed(sortedEffectList)) {
MOZ_ASSERT(effect->GetAnimation(),
"Effects on a target element should have an Animation");
bool inEffect = effect->IsInEffect();
for (AnimationProperty& prop : effect->Properties()) {
bool winsInCascade = !animatedProperties.HasProperty(prop.mProperty) &&
inEffect;
// If this property wins in the cascade, add it to the set of animated
// properties. We need to do this even if the property is overridden
// (in which case we set winsInCascade to false below) since we don't
// want to fire transitions on these properties.
if (winsInCascade) {
animatedProperties.AddProperty(prop.mProperty);
}
// For effects that will be applied to the animations level of the
// cascade, we need to check that the property isn't being set by
// something with higher priority in the cascade.
//
// We only do this, however, for properties that can be animated on
// the compositor. For properties animated on the main thread the usual
// cascade ensures these animations will be correctly overridden.
if (winsInCascade &&
effect->GetAnimation()->CascadeLevel() == CascadeLevel::Animations &&
overriddenProperties.HasProperty(prop.mProperty)) {
winsInCascade = false;
}
if (winsInCascade != prop.mWinsInCascade) {
changed = true;
}
prop.mWinsInCascade = winsInCascade;
}
}
aEffectSet.MarkCascadeUpdated();
// If there is any change in the cascade result, update animations on
// layers with the winning animations.
nsPresContext* presContext = GetPresContext(aElement);
if (changed && presContext) {
// We currently unconditionally update both animations and transitions
// even if we could, for example, get away with only updating animations.
// This is a temporary measure until we unify all animation style updating
// under EffectCompositor.
AnimationCollection* animations =
presContext->AnimationManager()->GetAnimationCollection(aElement,
aPseudoType,
false);
/* don't create */
if (animations) {
animations->RequestRestyle(AnimationCollection::RestyleType::Layer);
}
AnimationCollection* transitions =
presContext->TransitionManager()->GetAnimationCollection(aElement,
aPseudoType,
false);
/* don't create */
if (transitions) {
transitions->RequestRestyle(AnimationCollection::RestyleType::Layer);
}
}
}
/* static */ nsPresContext*
EffectCompositor::GetPresContext(Element* aElement)
{
MOZ_ASSERT(aElement);
nsIPresShell* shell = nsComputedDOMStyle::GetPresShellForContent(aElement);
if (!shell) {
return nullptr;
}
return shell->GetPresContext();
}
} // namespace mozilla } // namespace mozilla

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

@ -7,24 +7,109 @@
#ifndef mozilla_EffectCompositor_h #ifndef mozilla_EffectCompositor_h
#define mozilla_EffectCompositor_h #define mozilla_EffectCompositor_h
#include "mozilla/Maybe.h"
#include "mozilla/Pair.h"
#include "mozilla/RefPtr.h" #include "mozilla/RefPtr.h"
#include "nsCSSProperty.h"
#include "nsCSSPseudoElements.h"
#include "nsTArray.h" #include "nsTArray.h"
class nsCSSPropertySet;
class nsIFrame;
class nsPresContext;
class nsStyleContext;
namespace mozilla { namespace mozilla {
class EffectSet;
namespace dom { namespace dom {
class Animation; class Animation;
class Element;
} }
class EffectCompositor class EffectCompositor
{ {
public: public:
// Animations can be applied at two different levels in the CSS cascade:
enum class CascadeLevel {
// The animations sheet (CSS animations, script-generated animations,
// and CSS transitions that are no longer tied to CSS markup)
Animations,
// The transitions sheet (CSS transitions that are tied to CSS markup)
Transitions
};
// We don't define this as part of CascadeLevel as then we'd have to add
// explicit checks for the Count enum value everywhere CascadeLevel is used.
static const size_t kCascadeLevelCount =
static_cast<size_t>(CascadeLevel::Transitions) + 1;
static bool HasAnimationsForCompositor(const nsIFrame* aFrame, static bool HasAnimationsForCompositor(const nsIFrame* aFrame,
nsCSSProperty aProperty); nsCSSProperty aProperty);
static nsTArray<RefPtr<dom::Animation>> static nsTArray<RefPtr<dom::Animation>>
GetAnimationsForCompositor(const nsIFrame* aFrame, GetAnimationsForCompositor(const nsIFrame* aFrame,
nsCSSProperty aProperty); nsCSSProperty aProperty);
// Update animation cascade results for the specified (pseudo-)element
// but only if we have marked the cascade as needing an update due a
// the change in the set of effects or a change in one of the effects'
// "in effect" state.
//
// This method does NOT detect if other styles that apply above the
// animation level of the cascade have changed.
static void
MaybeUpdateCascadeResults(dom::Element* aElement,
nsCSSPseudoElements::Type aPseudoType,
nsStyleContext* aStyleContext);
// Update the mWinsInCascade member for each property in effects targetting
// the specified (pseudo-)element.
//
// This can be expensive so we should only call it if styles that apply
// above the animation level of the cascade might have changed. For all
// other cases we should call MaybeUpdateCascadeResults.
static void
UpdateCascadeResults(dom::Element* aElement,
nsCSSPseudoElements::Type aPseudoType,
nsStyleContext* aStyleContext);
// Helper to fetch the corresponding element and pseudo-type from a frame.
//
// For frames corresponding to pseudo-elements, the returned element is the
// element on which we store the animations (i.e. the EffectSet and/or
// AnimationCollection), *not* the generated content.
//
// Returns an empty result when a suitable element cannot be found including
// when the frame represents a pseudo-element on which we do not support
// animations.
static Maybe<Pair<dom::Element*, nsCSSPseudoElements::Type>>
GetAnimationElementAndPseudoForFrame(const nsIFrame* aFrame);
// Rebuilds the animation rule corresponding to |aCascadeLevel| on the
// EffectSet associated with the specified (pseudo-)element.
static void ComposeAnimationRule(dom::Element* aElement,
nsCSSPseudoElements::Type aPseudoType,
CascadeLevel aCascadeLevel,
bool& aStyleChanging);
private:
// Get the properties in |aEffectSet| that we are able to animate on the
// compositor but which are also specified at a higher level in the cascade
// than the animations level in |aStyleContext|.
static void
GetOverriddenProperties(nsStyleContext* aStyleContext,
EffectSet& aEffectSet,
nsCSSPropertySet& aPropertiesOverridden);
static void
UpdateCascadeResults(EffectSet& aEffectSet,
dom::Element* aElement,
nsCSSPseudoElements::Type aPseudoType,
nsStyleContext* aStyleContext);
static nsPresContext* GetPresContext(dom::Element* aElement);
}; };
} // namespace mozilla } // namespace mozilla

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

@ -6,7 +6,9 @@
#include "EffectSet.h" #include "EffectSet.h"
#include "mozilla/dom/Element.h" // For Element #include "mozilla/dom/Element.h" // For Element
#include "RestyleManager.h"
#include "nsCycleCollectionNoteChild.h" // For CycleCollectionNoteChild #include "nsCycleCollectionNoteChild.h" // For CycleCollectionNoteChild
#include "nsPresContext.h"
namespace mozilla { namespace mozilla {
@ -106,6 +108,13 @@ EffectSet::GetOrCreateEffectSet(dom::Element* aElement,
return effectSet; return effectSet;
} }
void
EffectSet::UpdateAnimationGeneration(nsPresContext* aPresContext)
{
mAnimationGeneration =
aPresContext->RestyleManager()->GetAnimationGeneration();
}
/* static */ nsIAtom** /* static */ nsIAtom**
EffectSet::GetEffectSetPropertyAtoms() EffectSet::GetEffectSetPropertyAtoms()
{ {
@ -143,13 +152,23 @@ EffectSet::GetEffectSetPropertyAtom(nsCSSPseudoElements::Type aPseudoType)
void void
EffectSet::AddEffect(dom::KeyframeEffectReadOnly& aEffect) EffectSet::AddEffect(dom::KeyframeEffectReadOnly& aEffect)
{ {
if (mEffects.Contains(&aEffect)) {
return;
}
mEffects.PutEntry(&aEffect); mEffects.PutEntry(&aEffect);
MarkCascadeNeedsUpdate();
} }
void void
EffectSet::RemoveEffect(dom::KeyframeEffectReadOnly& aEffect) EffectSet::RemoveEffect(dom::KeyframeEffectReadOnly& aEffect)
{ {
if (!mEffects.Contains(&aEffect)) {
return;
}
mEffects.RemoveEntry(&aEffect); mEffects.RemoveEntry(&aEffect);
MarkCascadeNeedsUpdate();
} }
} // namespace mozilla } // namespace mozilla

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

@ -7,10 +7,15 @@
#ifndef mozilla_EffectSet_h #ifndef mozilla_EffectSet_h
#define mozilla_EffectSet_h #define mozilla_EffectSet_h
#include "mozilla/AnimValuesStyleRule.h"
#include "mozilla/EffectCompositor.h"
#include "mozilla/EnumeratedArray.h"
#include "nsCSSPseudoElements.h" // For nsCSSPseudoElements::Type #include "nsCSSPseudoElements.h" // For nsCSSPseudoElements::Type
#include "nsHashKeys.h" // For nsPtrHashKey #include "nsHashKeys.h" // For nsPtrHashKey
#include "nsTHashtable.h" // For nsTHashtable #include "nsTHashtable.h" // For nsTHashtable
class nsPresContext;
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
@ -24,8 +29,10 @@ class EffectSet
{ {
public: public:
EffectSet() EffectSet()
: mCascadeNeedsUpdate(false)
, mAnimationGeneration(0)
#ifdef DEBUG #ifdef DEBUG
: mCalledPropertyDtor(false) , mCalledPropertyDtor(false)
#endif #endif
{ {
MOZ_COUNT_CTOR(EffectSet); MOZ_COUNT_CTOR(EffectSet);
@ -120,6 +127,19 @@ public:
} }
bool IsEmpty() const { return mEffects.IsEmpty(); } bool IsEmpty() const { return mEffects.IsEmpty(); }
RefPtr<AnimValuesStyleRule>& AnimationRule(EffectCompositor::CascadeLevel
aCascadeLevel)
{
return mAnimationRule[aCascadeLevel];
}
bool CascadeNeedsUpdate() const { return mCascadeNeedsUpdate; }
void MarkCascadeNeedsUpdate() { mCascadeNeedsUpdate = true; }
void MarkCascadeUpdated() { mCascadeNeedsUpdate = false; }
void UpdateAnimationGeneration(nsPresContext* aPresContext);
uint64_t GetAnimationGeneration() const { return mAnimationGeneration; }
static nsIAtom** GetEffectSetPropertyAtoms(); static nsIAtom** GetEffectSetPropertyAtoms();
private: private:
@ -128,6 +148,31 @@ private:
OwningEffectSet mEffects; OwningEffectSet mEffects;
// These style rules contain the style data for currently animating
// values. They only match when styling with animation. When we
// style without animation, we need to not use them so that we can
// detect any new changes; if necessary we restyle immediately
// afterwards with animation.
EnumeratedArray<EffectCompositor::CascadeLevel,
EffectCompositor::CascadeLevel(
EffectCompositor::kCascadeLevelCount),
RefPtr<AnimValuesStyleRule>> mAnimationRule;
// Dirty flag to represent when the mWinsInCascade flag on effects in
// this set might need to be updated.
//
// Set to true any time the set of effects is changed or when
// one the effects goes in or out of the "in effect" state.
bool mCascadeNeedsUpdate;
// RestyleManager keeps track of the number of animation restyles.
// 'mini-flushes' (see nsTransitionManager::UpdateAllThrottledStyles()).
// mAnimationGeneration is the sequence number of the last flush where a
// transition/animation changed. We keep a similar count on the
// corresponding layer so we can check that the layer is up to date with
// the animation manager.
uint64_t mAnimationGeneration;
#ifdef DEBUG #ifdef DEBUG
bool mCalledPropertyDtor; bool mCalledPropertyDtor;
#endif #endif

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

@ -20,7 +20,7 @@
#include "nsCSSProps.h" // For nsCSSProps::PropHasFlags #include "nsCSSProps.h" // For nsCSSProps::PropHasFlags
#include "nsCSSValue.h" #include "nsCSSValue.h"
#include "nsStyleUtil.h" #include "nsStyleUtil.h"
#include <algorithm> // std::max #include <algorithm> // For std::max
namespace mozilla { namespace mozilla {
@ -94,6 +94,7 @@ KeyframeEffectReadOnly::KeyframeEffectReadOnly(
, mTarget(aTarget) , mTarget(aTarget)
, mTiming(aTiming) , mTiming(aTiming)
, mPseudoType(aPseudoType) , mPseudoType(aPseudoType)
, mInEffectOnLastAnimationTimingUpdate(false)
{ {
MOZ_ASSERT(aTarget, "null animation target is not yet supported"); MOZ_ASSERT(aTarget, "null animation target is not yet supported");
} }
@ -132,6 +133,56 @@ KeyframeEffectReadOnly::SetTiming(const AnimationTiming& aTiming)
// update our registration with the target element. // update our registration with the target element.
} }
void
KeyframeEffectReadOnly::NotifyAnimationTimingUpdated()
{
UpdateTargetRegistration();
// If the effect is not relevant it will be removed from the target
// element's effect set. However, effects not in the effect set
// will not be included in the set of candidate effects for running on
// the compositor and hence they won't have their compositor status
// updated. As a result, we need to make sure we clear their compositor
// status here.
bool isRelevant = mAnimation && mAnimation->IsRelevant();
if (!isRelevant) {
ResetIsRunningOnCompositor();
}
// Detect changes to "in effect" status since we need to recalculate the
// animation cascade for this element whenever that changes.
bool inEffect = IsInEffect();
if (inEffect != mInEffectOnLastAnimationTimingUpdate) {
if (mTarget) {
EffectSet* effectSet = EffectSet::GetEffectSet(mTarget, mPseudoType);
if (effectSet) {
effectSet->MarkCascadeNeedsUpdate();
}
}
mInEffectOnLastAnimationTimingUpdate = inEffect;
}
// Request restyle if necessary.
ComputedTiming computedTiming = GetComputedTiming();
AnimationCollection* collection = GetCollection();
// Bug 1235002: We should skip requesting a restyle when mProperties is empty.
// However, currently we don't properly encapsulate mProperties so we can't
// detect when it changes. As a result, if we skip requesting restyles when
// mProperties is empty and we play an animation and *then* add properties to
// it (as we currently do when building CSS animations), we will fail to
// request a restyle at all. Since animations without properties are rare, we
// currently just request the restyle regardless of whether mProperties is
// empty or not.
if (collection &&
// Bug 1216843: When we implement iteration composite modes, we need to
// also detect if the current iteration has changed.
computedTiming.mProgress != mProgressOnLastCompose) {
collection->RequestRestyle(CanThrottle() ?
AnimationCollection::RestyleType::Throttled :
AnimationCollection::RestyleType::Standard);
}
}
Nullable<TimeDuration> Nullable<TimeDuration>
KeyframeEffectReadOnly::GetLocalTime() const KeyframeEffectReadOnly::GetLocalTime() const
{ {
@ -376,6 +427,7 @@ KeyframeEffectReadOnly::ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
nsCSSPropertySet& aSetProperties) nsCSSPropertySet& aSetProperties)
{ {
ComputedTiming computedTiming = GetComputedTiming(); ComputedTiming computedTiming = GetComputedTiming();
mProgressOnLastCompose = computedTiming.mProgress;
// If the progress is null, we don't have fill data for the current // If the progress is null, we don't have fill data for the current
// time so we shouldn't animate. // time so we shouldn't animate.
@ -533,10 +585,6 @@ KeyframeEffectReadOnly::UpdateTargetRegistration()
if (effectSet) { if (effectSet) {
effectSet->RemoveEffect(*this); effectSet->RemoveEffect(*this);
} }
// Any effects not in the effect set will not be included in the set of
// candidate effects for running on the compositor and hence they won't
// have their compositor status updated so we should do that now.
ResetIsRunningOnCompositor();
} }
} }
@ -1776,15 +1824,14 @@ KeyframeEffectReadOnly::OverflowRegionRefreshInterval()
bool bool
KeyframeEffectReadOnly::CanThrottle() const KeyframeEffectReadOnly::CanThrottle() const
{ {
// Animation::CanThrottle checks for not in effect animations // Unthrottle if we are not in effect or current. This will be the case when
// before calling this. // our owning animation has finished, is idle, or when we are in the delay
MOZ_ASSERT(IsInEffect(), "Effect should be in effect"); // phase (but without a backwards fill). In each case the computed progress
// value produced on each tick will be the same so we will skip requesting
// Unthrottle if this animation is not current (i.e. it has passed the end). // unnecessary restyles in NotifyAnimationTimingUpdated. Any calls we *do* get
// In future we may be able to throttle this case too, but we should only get // here will be because of a change in state (e.g. we are newly finished or
// occasional ticks while the animation is in this state so it doesn't matter // newly no longer in effect) in which case we shouldn't throttle the sample.
// too much. if (!IsInEffect() || !IsCurrent()) {
if (!IsCurrent()) {
return false; return false;
} }
@ -1812,14 +1859,15 @@ KeyframeEffectReadOnly::CanThrottle() const
continue; continue;
} }
AnimationCollection* collection = GetCollection(); EffectSet* effectSet = EffectSet::GetEffectSet(mTarget, mPseudoType);
MOZ_ASSERT(collection, MOZ_ASSERT(effectSet, "CanThrottle should be called on an effect "
"CanThrottle should be called on an effect associated with an animation"); "associated with a target element");
layers::Layer* layer = layers::Layer* layer =
FrameLayerBuilder::GetDedicatedLayer(frame, record.mLayerType); FrameLayerBuilder::GetDedicatedLayer(frame, record.mLayerType);
// Unthrottle if the layer needs to be brought up to date with the animation. // Unthrottle if the layer needs to be brought up to date
if (!layer || if (!layer ||
collection->mAnimationGeneration > layer->GetAnimationGeneration()) { effectSet->GetAnimationGeneration() !=
layer->GetAnimationGeneration()) {
return false; return false;
} }

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

@ -131,10 +131,7 @@ struct AnimationProperty
// For CSS Animations, which are overridden by !important rules in the // For CSS Animations, which are overridden by !important rules in the
// cascade, we actually determine this from the CSS cascade // cascade, we actually determine this from the CSS cascade
// computations, and then use it for OMTA. // computations, and then use it for OMTA.
// **NOTE**: For CSS animations, we only bother setting mWinsInCascade // **NOTE**: This member is not included when comparing AnimationProperty
// accurately for properties that we can animate on the compositor.
// For other properties, we make it always be true.
// **NOTE 2**: This member is not included when comparing AnimationProperty
// objects for equality. // objects for equality.
bool mWinsInCascade = true; bool mWinsInCascade = true;
@ -229,7 +226,7 @@ public:
const AnimationTiming& Timing() const { return mTiming; } const AnimationTiming& Timing() const { return mTiming; }
AnimationTiming& Timing() { return mTiming; } AnimationTiming& Timing() { return mTiming; }
void SetTiming(const AnimationTiming& aTiming); void SetTiming(const AnimationTiming& aTiming);
void NotifyAnimationTimingUpdated() { UpdateTargetRegistration(); } void NotifyAnimationTimingUpdated();
Nullable<TimeDuration> GetLocalTime() const; Nullable<TimeDuration> GetLocalTime() const;
@ -293,8 +290,6 @@ public:
bool IsRunningOnCompositor() const; bool IsRunningOnCompositor() const;
void SetIsRunningOnCompositor(nsCSSProperty aProperty, bool aIsRunning); void SetIsRunningOnCompositor(nsCSSProperty aProperty, bool aIsRunning);
bool CanThrottle() const;
// Returns true if this effect, applied to |aFrame|, contains // Returns true if this effect, applied to |aFrame|, contains
// properties that mean we shouldn't run *any* compositor animations on this // properties that mean we shouldn't run *any* compositor animations on this
// element. // element.
@ -349,9 +344,19 @@ protected:
InfallibleTArray<AnimationProperty> mProperties; InfallibleTArray<AnimationProperty> mProperties;
// The computed progress last time we composed the style rule. This is
// used to detect when the progress is not changing (e.g. due to a step
// timing function) so we can avoid unnecessary style updates.
Nullable<double> mProgressOnLastCompose;
// We need to track when we go to or from being "in effect" since
// we need to re-evaluate the cascade of animations when that changes.
bool mInEffectOnLastAnimationTimingUpdate;
private: private:
nsIFrame* GetAnimationFrame() const; nsIFrame* GetAnimationFrame() const;
bool CanThrottle() const;
bool CanThrottleTransformChanges(nsIFrame& aFrame) const; bool CanThrottleTransformChanges(nsIFrame& aFrame) const;
// Returns true unless Gecko limitations prevent performing transform // Returns true unless Gecko limitations prevent performing transform

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

@ -18,6 +18,7 @@ EXPORTS.mozilla.dom += [
EXPORTS.mozilla += [ EXPORTS.mozilla += [
'AnimationComparator.h', 'AnimationComparator.h',
'AnimationUtils.h', 'AnimationUtils.h',
'AnimValuesStyleRule.h',
'ComputedTimingFunction.h', 'ComputedTimingFunction.h',
'EffectCompositor.h', 'EffectCompositor.h',
'EffectSet.h', 'EffectSet.h',
@ -29,6 +30,7 @@ UNIFIED_SOURCES += [
'AnimationEffectReadOnly.cpp', 'AnimationEffectReadOnly.cpp',
'AnimationTimeline.cpp', 'AnimationTimeline.cpp',
'AnimationUtils.cpp', 'AnimationUtils.cpp',
'AnimValuesStyleRule.cpp',
'ComputedTimingFunction.cpp', 'ComputedTimingFunction.cpp',
'DocumentTimeline.cpp', 'DocumentTimeline.cpp',
'EffectCompositor.cpp', 'EffectCompositor.cpp',
@ -39,6 +41,8 @@ UNIFIED_SOURCES += [
LOCAL_INCLUDES += [ LOCAL_INCLUDES += [
'/dom/base', '/dom/base',
'/layout/base',
'/layout/style',
] ]
FINAL_LIBRARY = 'xul' FINAL_LIBRARY = 'xul'

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

@ -80,6 +80,12 @@ this.UserCustomizations = {
}, },
isFromExtension: function(aURI) { isFromExtension: function(aURI) {
if (!aURI && Services.prefs.getBoolPref("webextensions.tests")) {
// That's the case in mochitests because of the packaging setup:
// aURI is expected to be the appURI from the jarChannel but there is
// no real app associated to mochitest's jar:remoteopenfile:/// uris.
return true;
}
return this.appId.has(aURI.host); return this.appId.has(aURI.host);
}, },

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

@ -700,9 +700,9 @@ public:
// (on element that have status pointer capture override // (on element that have status pointer capture override
// or on element that have status pending pointer capture) // or on element that have status pending pointer capture)
if (pointerCaptureInfo->mOverrideContent == this) { if (pointerCaptureInfo->mOverrideContent == this) {
nsIPresShell::ReleasePointerCapturingContent(aPointerId, this); nsIPresShell::ReleasePointerCapturingContent(aPointerId);
} else if (pointerCaptureInfo->mPendingContent == this) { } else if (pointerCaptureInfo->mPendingContent == this) {
nsIPresShell::ReleasePointerCapturingContent(aPointerId, this); nsIPresShell::ReleasePointerCapturingContent(aPointerId);
} }
} }
} }

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

@ -742,8 +742,7 @@ nsDOMStyleSheetList::NodeWillBeDestroyed(const nsINode *aNode)
} }
void void
nsDOMStyleSheetList::StyleSheetAdded(nsIDocument *aDocument, nsDOMStyleSheetList::StyleSheetAdded(CSSStyleSheet* aStyleSheet,
CSSStyleSheet* aStyleSheet,
bool aDocumentSheet) bool aDocumentSheet)
{ {
if (aDocumentSheet && -1 != mLength) { if (aDocumentSheet && -1 != mLength) {
@ -752,8 +751,7 @@ nsDOMStyleSheetList::StyleSheetAdded(nsIDocument *aDocument,
} }
void void
nsDOMStyleSheetList::StyleSheetRemoved(nsIDocument *aDocument, nsDOMStyleSheetList::StyleSheetRemoved(CSSStyleSheet* aStyleSheet,
CSSStyleSheet* aStyleSheet,
bool aDocumentSheet) bool aDocumentSheet)
{ {
if (aDocumentSheet && -1 != mLength) { if (aDocumentSheet && -1 != mLength) {
@ -3666,14 +3664,12 @@ nsDocument::CreateShell(nsPresContext* aContext, nsViewManager* aViewManager,
// Don't add anything here. Add it to |doCreateShell| instead. // Don't add anything here. Add it to |doCreateShell| instead.
// This exists so that subclasses can pass other values for the 4th // This exists so that subclasses can pass other values for the 4th
// parameter some of the time. // parameter some of the time.
return doCreateShell(aContext, aViewManager, aStyleSet, return doCreateShell(aContext, aViewManager, aStyleSet);
eCompatibility_FullStandards);
} }
already_AddRefed<nsIPresShell> already_AddRefed<nsIPresShell>
nsDocument::doCreateShell(nsPresContext* aContext, nsDocument::doCreateShell(nsPresContext* aContext,
nsViewManager* aViewManager, nsStyleSet* aStyleSet, nsViewManager* aViewManager, nsStyleSet* aStyleSet)
nsCompatibility aCompatMode)
{ {
NS_ASSERTION(!mPresShell, "We have a presshell already!"); NS_ASSERTION(!mPresShell, "We have a presshell already!");
@ -3682,7 +3678,7 @@ nsDocument::doCreateShell(nsPresContext* aContext,
FillStyleSet(aStyleSet); FillStyleSet(aStyleSet);
RefPtr<PresShell> shell = new PresShell; RefPtr<PresShell> shell = new PresShell;
shell->Init(this, aContext, aViewManager, aStyleSet, aCompatMode); shell->Init(this, aContext, aViewManager, aStyleSet);
// Note: we don't hold a ref to the shell (it holds a ref to us) // Note: we don't hold a ref to the shell (it holds a ref to us)
mPresShell = shell; mPresShell = shell;
@ -4075,7 +4071,7 @@ nsDocument::AddStyleSheetToStyleSets(CSSStyleSheet* aSheet)
void void
nsDocument::NotifyStyleSheetAdded(CSSStyleSheet* aSheet, bool aDocumentSheet) nsDocument::NotifyStyleSheetAdded(CSSStyleSheet* aSheet, bool aDocumentSheet)
{ {
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded, (this, aSheet, aDocumentSheet)); NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded, (aSheet, aDocumentSheet));
if (StyleSheetChangeEventsEnabled()) { if (StyleSheetChangeEventsEnabled()) {
DO_STYLESHEET_NOTIFICATION(StyleSheetChangeEvent, DO_STYLESHEET_NOTIFICATION(StyleSheetChangeEvent,
@ -4088,7 +4084,7 @@ nsDocument::NotifyStyleSheetAdded(CSSStyleSheet* aSheet, bool aDocumentSheet)
void void
nsDocument::NotifyStyleSheetRemoved(CSSStyleSheet* aSheet, bool aDocumentSheet) nsDocument::NotifyStyleSheetRemoved(CSSStyleSheet* aSheet, bool aDocumentSheet)
{ {
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetRemoved, (this, aSheet, aDocumentSheet)); NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetRemoved, (aSheet, aDocumentSheet));
if (StyleSheetChangeEventsEnabled()) { if (StyleSheetChangeEventsEnabled()) {
DO_STYLESHEET_NOTIFICATION(StyleSheetChangeEvent, DO_STYLESHEET_NOTIFICATION(StyleSheetChangeEvent,
@ -4216,8 +4212,7 @@ nsDocument::SetStyleSheetApplicableState(CSSStyleSheet* aSheet,
// that are children of sheets in our style set, as well as some // that are children of sheets in our style set, as well as some
// sheets for nsHTMLEditor. // sheets for nsHTMLEditor.
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetApplicableStateChanged, NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetApplicableStateChanged, (aSheet));
(this, aSheet, aApplicable));
if (StyleSheetChangeEventsEnabled()) { if (StyleSheetChangeEventsEnabled()) {
DO_STYLESHEET_NOTIFICATION(StyleSheetApplicableStateChangeEvent, DO_STYLESHEET_NOTIFICATION(StyleSheetApplicableStateChangeEvent,
@ -5140,9 +5135,7 @@ void
nsDocument::StyleRuleChanged(CSSStyleSheet* aSheet, nsDocument::StyleRuleChanged(CSSStyleSheet* aSheet,
css::Rule* aStyleRule) css::Rule* aStyleRule)
{ {
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleChanged, NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleChanged, (aSheet));
(this, aSheet,
aStyleRule));
if (StyleSheetChangeEventsEnabled()) { if (StyleSheetChangeEventsEnabled()) {
DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent, DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent,
@ -5156,8 +5149,7 @@ void
nsDocument::StyleRuleAdded(CSSStyleSheet* aSheet, nsDocument::StyleRuleAdded(CSSStyleSheet* aSheet,
css::Rule* aStyleRule) css::Rule* aStyleRule)
{ {
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleAdded, NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleAdded, (aSheet));
(this, aSheet, aStyleRule));
if (StyleSheetChangeEventsEnabled()) { if (StyleSheetChangeEventsEnabled()) {
DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent, DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent,
@ -5172,8 +5164,7 @@ void
nsDocument::StyleRuleRemoved(CSSStyleSheet* aSheet, nsDocument::StyleRuleRemoved(CSSStyleSheet* aSheet,
css::Rule* aStyleRule) css::Rule* aStyleRule)
{ {
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleRemoved, NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleRemoved, (aSheet));
(this, aSheet, aStyleRule));
if (StyleSheetChangeEventsEnabled()) { if (StyleSheetChangeEventsEnabled()) {
DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent, DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent,
@ -8758,6 +8749,13 @@ nsDocument::CanSavePresentation(nsIRequest *aNewRequest)
} }
} }
#ifdef MOZ_WEBSPEECH
nsGlobalWindow* globalWindow = static_cast<nsGlobalWindow*>(win);
if (globalWindow->HasActiveSpeechSynthesis()) {
return false;
}
#endif
return true; return true;
} }

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

@ -1494,8 +1494,7 @@ public:
protected: protected:
already_AddRefed<nsIPresShell> doCreateShell(nsPresContext* aContext, already_AddRefed<nsIPresShell> doCreateShell(nsPresContext* aContext,
nsViewManager* aViewManager, nsViewManager* aViewManager,
nsStyleSet* aStyleSet, nsStyleSet* aStyleSet);
nsCompatibility aCompatMode);
void RemoveDocStyleSheetsFromStyleSets(); void RemoveDocStyleSheetsFromStyleSets();
void RemoveStyleSheetsFromStyleSets( void RemoveStyleSheetsFromStyleSets(

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

@ -3760,6 +3760,19 @@ nsGlobalWindow::GetSpeechSynthesis(ErrorResult& aError)
return mSpeechSynthesis; return mSpeechSynthesis;
} }
bool
nsGlobalWindow::HasActiveSpeechSynthesis()
{
MOZ_ASSERT(IsInnerWindow());
if (mSpeechSynthesis) {
return !mSpeechSynthesis->HasEmptyQueue();
}
return false;
}
#endif #endif
already_AddRefed<nsIDOMWindow> already_AddRefed<nsIDOMWindow>

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

@ -1045,6 +1045,7 @@ public:
#ifdef MOZ_WEBSPEECH #ifdef MOZ_WEBSPEECH
mozilla::dom::SpeechSynthesis* mozilla::dom::SpeechSynthesis*
GetSpeechSynthesis(mozilla::ErrorResult& aError); GetSpeechSynthesis(mozilla::ErrorResult& aError);
bool HasActiveSpeechSynthesis();
#endif #endif
already_AddRefed<nsICSSDeclaration> already_AddRefed<nsICSSDeclaration>
GetDefaultComputedStyle(mozilla::dom::Element& aElt, GetDefaultComputedStyle(mozilla::dom::Element& aElt,

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

@ -94,15 +94,13 @@ public:
* A StyleSheet has just been added to the document. This method is * A StyleSheet has just been added to the document. This method is
* called automatically when a StyleSheet gets added to the * called automatically when a StyleSheet gets added to the
* document, even if the stylesheet is not applicable. The * document, even if the stylesheet is not applicable. The
* notification is passed on to all of the document observers. * notification is passed on to all of the document observers.
* *
* @param aDocument The document being observed
* @param aStyleSheet the StyleSheet that has been added * @param aStyleSheet the StyleSheet that has been added
* @param aDocumentSheet True if sheet is in document's style sheet list, * @param aDocumentSheet True if sheet is in document's style sheet list,
* false if sheet is not (i.e., UA or user sheet) * false if sheet is not (i.e., UA or user sheet)
*/ */
virtual void StyleSheetAdded(nsIDocument *aDocument, virtual void StyleSheetAdded(mozilla::CSSStyleSheet* aStyleSheet,
mozilla::CSSStyleSheet* aStyleSheet,
bool aDocumentSheet) = 0; bool aDocumentSheet) = 0;
/** /**
@ -111,13 +109,11 @@ public:
* from the document, even if the stylesheet is not applicable. The * from the document, even if the stylesheet is not applicable. The
* notification is passed on to all of the document observers. * notification is passed on to all of the document observers.
* *
* @param aDocument The document being observed
* @param aStyleSheet the StyleSheet that has been removed * @param aStyleSheet the StyleSheet that has been removed
* @param aDocumentSheet True if sheet is in document's style sheet list, * @param aDocumentSheet True if sheet is in document's style sheet list,
* false if sheet is not (i.e., UA or user sheet) * false if sheet is not (i.e., UA or user sheet)
*/ */
virtual void StyleSheetRemoved(nsIDocument *aDocument, virtual void StyleSheetRemoved(mozilla::CSSStyleSheet* aStyleSheet,
mozilla::CSSStyleSheet* aStyleSheet,
bool aDocumentSheet) = 0; bool aDocumentSheet) = 0;
/** /**
@ -127,14 +123,9 @@ public:
* notification to the document. The notification is passed on * notification to the document. The notification is passed on
* to all of the document observers. * to all of the document observers.
* *
* @param aDocument The document being observed
* @param aStyleSheet the StyleSheet that has changed state * @param aStyleSheet the StyleSheet that has changed state
* @param aApplicable true if the sheet is applicable, false if
* it is not applicable
*/ */
virtual void StyleSheetApplicableStateChanged(nsIDocument *aDocument, virtual void StyleSheetApplicableStateChanged(mozilla::CSSStyleSheet* aStyleSheet) = 0;
mozilla::CSSStyleSheet* aStyleSheet,
bool aApplicable) = 0;
/** /**
* A StyleRule has just been modified within a style sheet. * A StyleRule has just been modified within a style sheet.
@ -143,13 +134,9 @@ public:
* the document. The notification is passed on to all of * the document. The notification is passed on to all of
* the document observers. * the document observers.
* *
* @param aDocument The document being observed
* @param aStyleSheet the StyleSheet that contians the rule * @param aStyleSheet the StyleSheet that contians the rule
* @param aStyleRule The rule being changed.
*/ */
virtual void StyleRuleChanged(nsIDocument *aDocument, virtual void StyleRuleChanged(mozilla::CSSStyleSheet* aStyleSheet) = 0;
mozilla::CSSStyleSheet* aStyleSheet,
mozilla::css::Rule* aStyleRule) = 0;
/** /**
* A StyleRule has just been added to a style sheet. * A StyleRule has just been added to a style sheet.
@ -158,13 +145,9 @@ public:
* notification to the document. The notification is passed on * notification to the document. The notification is passed on
* to all of the document observers. * to all of the document observers.
* *
* @param aDocument The document being observed
* @param aStyleSheet the StyleSheet that has been modified * @param aStyleSheet the StyleSheet that has been modified
* @param aStyleRule the rule that was added
*/ */
virtual void StyleRuleAdded(nsIDocument *aDocument, virtual void StyleRuleAdded(mozilla::CSSStyleSheet* aStyleSheet) = 0;
mozilla::CSSStyleSheet* aStyleSheet,
mozilla::css::Rule* aStyleRule) = 0;
/** /**
* A StyleRule has just been removed from a style sheet. * A StyleRule has just been removed from a style sheet.
@ -173,13 +156,9 @@ public:
* notification to the document. The notification is passed on * notification to the document. The notification is passed on
* to all of the document observers. * to all of the document observers.
* *
* @param aDocument The document being observed
* @param aStyleSheet the StyleSheet that has been modified * @param aStyleSheet the StyleSheet that has been modified
* @param aStyleRule the rule that was removed
*/ */
virtual void StyleRuleRemoved(nsIDocument *aDocument, virtual void StyleRuleRemoved(mozilla::CSSStyleSheet* aStyleSheet) = 0;
mozilla::CSSStyleSheet* aStyleSheet,
mozilla::css::Rule* aStyleRule) = 0;
}; };
NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocumentObserver, NS_IDOCUMENT_OBSERVER_IID) NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocumentObserver, NS_IDOCUMENT_OBSERVER_IID)
@ -207,35 +186,25 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocumentObserver, NS_IDOCUMENT_OBSERVER_IID)
mozilla::EventStates aStateMask) override; mozilla::EventStates aStateMask) override;
#define NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETADDED \ #define NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETADDED \
virtual void StyleSheetAdded(nsIDocument* aDocument, \ virtual void StyleSheetAdded(mozilla::CSSStyleSheet* aStyleSheet, \
mozilla::CSSStyleSheet* aStyleSheet, \
bool aDocumentSheet) override; bool aDocumentSheet) override;
#define NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETREMOVED \ #define NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETREMOVED \
virtual void StyleSheetRemoved(nsIDocument* aDocument, \ virtual void StyleSheetRemoved(mozilla::CSSStyleSheet* aStyleSheet, \
mozilla::CSSStyleSheet* aStyleSheet, \
bool aDocumentSheet) override; bool aDocumentSheet) override;
#define NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETAPPLICABLESTATECHANGED \ #define NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETAPPLICABLESTATECHANGED \
virtual void StyleSheetApplicableStateChanged( \ virtual void StyleSheetApplicableStateChanged( \
nsIDocument* aDocument, \ mozilla::CSSStyleSheet* aStyleSheet) override;
mozilla::CSSStyleSheet* aStyleSheet, \
bool aApplicable) override;
#define NS_DECL_NSIDOCUMENTOBSERVER_STYLERULECHANGED \ #define NS_DECL_NSIDOCUMENTOBSERVER_STYLERULECHANGED \
virtual void StyleRuleChanged(nsIDocument* aDocument, \ virtual void StyleRuleChanged(mozilla::CSSStyleSheet* aStyleSheet) override;
mozilla::CSSStyleSheet* aStyleSheet, \
mozilla::css::Rule* aStyleRule) override;
#define NS_DECL_NSIDOCUMENTOBSERVER_STYLERULEADDED \ #define NS_DECL_NSIDOCUMENTOBSERVER_STYLERULEADDED \
virtual void StyleRuleAdded(nsIDocument* aDocument, \ virtual void StyleRuleAdded(mozilla::CSSStyleSheet* aStyleSheet) override;
mozilla::CSSStyleSheet* aStyleSheet, \
mozilla::css::Rule* aStyleRule) override;
#define NS_DECL_NSIDOCUMENTOBSERVER_STYLERULEREMOVED \ #define NS_DECL_NSIDOCUMENTOBSERVER_STYLERULEREMOVED \
virtual void StyleRuleRemoved(nsIDocument* aDocument, \ virtual void StyleRuleRemoved(mozilla::CSSStyleSheet* aStyleSheet) override;
mozilla::CSSStyleSheet* aStyleSheet, \
mozilla::css::Rule* aStyleRule) override;
#define NS_DECL_NSIDOCUMENTOBSERVER \ #define NS_DECL_NSIDOCUMENTOBSERVER \
NS_DECL_NSIDOCUMENTOBSERVER_BEGINUPDATE \ NS_DECL_NSIDOCUMENTOBSERVER_BEGINUPDATE \
@ -293,39 +262,29 @@ NS_IMPL_NSIMUTATIONOBSERVER_CONTENT(_class)
#define NS_IMPL_NSIDOCUMENTOBSERVER_STYLE_STUB(_class) \ #define NS_IMPL_NSIDOCUMENTOBSERVER_STYLE_STUB(_class) \
void \ void \
_class::StyleSheetAdded(nsIDocument* aDocument, \ _class::StyleSheetAdded(mozilla::CSSStyleSheet* aStyleSheet, \
mozilla::CSSStyleSheet* aStyleSheet, \
bool aDocumentSheet) \ bool aDocumentSheet) \
{ \ { \
} \ } \
void \ void \
_class::StyleSheetRemoved(nsIDocument* aDocument, \ _class::StyleSheetRemoved(mozilla::CSSStyleSheet* aStyleSheet, \
mozilla::CSSStyleSheet* aStyleSheet, \
bool aDocumentSheet) \ bool aDocumentSheet) \
{ \ { \
} \ } \
void \ void \
_class::StyleSheetApplicableStateChanged(nsIDocument* aDocument, \ _class::StyleSheetApplicableStateChanged(mozilla::CSSStyleSheet* aStyleSheet) \
mozilla::CSSStyleSheet* aStyleSheet,\
bool aApplicable) \
{ \ { \
} \ } \
void \ void \
_class::StyleRuleChanged(nsIDocument* aDocument, \ _class::StyleRuleChanged(mozilla::CSSStyleSheet* aStyleSheet) \
mozilla::CSSStyleSheet* aStyleSheet, \
mozilla::css::Rule* aStyleRule) \
{ \ { \
} \ } \
void \ void \
_class::StyleRuleAdded(nsIDocument* aDocument, \ _class::StyleRuleAdded(mozilla::CSSStyleSheet* aStyleSheet) \
mozilla::CSSStyleSheet* aStyleSheet, \
mozilla::css::Rule* aStyleRule) \
{ \ { \
} \ } \
void \ void \
_class::StyleRuleRemoved(nsIDocument* aDocument, \ _class::StyleRuleRemoved(mozilla::CSSStyleSheet* aStyleSheet) \
mozilla::CSSStyleSheet* aStyleSheet, \
mozilla::css::Rule* aStyleRule) \
{ \ { \
} }

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

@ -0,0 +1,126 @@
"use strict";
SimpleTest.waitForExplicitFinish();
browserElementTestHelpers.setEnabledPref(true);
browserElementTestHelpers.addPermission();
var fileURL = 'http://example.org/tests/dom/browser-element/mochitest/file_browserElement_ActiveStateChangeOnChangingMutedOrVolume.html';
var generator = runTests();
var testFrame;
var ac;
function assert(aVal, aMessage) {
return (!aVal) ? error(aMessage) : 0;
}
function error(aMessage) {
ok(false, "Error : " + aMessage);
finish();
}
function continueTest() {
try {
generator.next();
} catch (e if e instanceof StopIteration) {
error("Stop test because of exception!");
}
}
function finish() {
document.body.removeChild(testFrame);
SimpleTest.finish();
}
function setCommand(aArg) {
assert(!!ac, "Audio channel doesn't exist!");
info("# Command = " + aArg);
testFrame.src = fileURL + '#' + aArg;
var expectedActive = false;
switch (aArg) {
case 'play':
case 'unmute':
case 'volume-1':
expectedActive = true;
break;
case 'pause':
case 'mute':
case 'volume-0':
expectedActive = false;
break;
default :
error("Undefined command!");
}
ac.onactivestatechanged = () => {
ac.onactivestatechanged = null;
ac.isActive().onsuccess = (e) => {
is(expectedActive, e.target.result,
"Correct active state = " + expectedActive);
continueTest();
}
};
}
function runTests() {
setCommand('play');
yield undefined;
setCommand('mute');
yield undefined;
setCommand('unmute');
yield undefined;
setCommand('volume-0');
yield undefined;
setCommand('volume-1');
yield undefined;
setCommand('pause');
yield undefined;
finish();
yield undefined;
}
function setupTestFrame() {
testFrame = document.createElement('iframe');
testFrame.setAttribute('mozbrowser', 'true');
testFrame.setAttribute('mozapp', 'http://example.org/manifest.webapp');
testFrame.src = fileURL;
function loadend() {
testFrame.removeEventListener('mozbrowserloadend', loadend);
ok("allowedAudioChannels" in testFrame, "allowedAudioChannels exist");
var channels = testFrame.allowedAudioChannels;
is(channels.length, 1, "1 audio channel by default");
ac = channels[0];
ok(ac instanceof BrowserElementAudioChannel, "Correct class");
ok("isActive" in ac, "isActive exists");
ok("onactivestatechanged" in ac, "onactivestatechanged exists");
generator.next();
}
function alertError(e) {
testFrame.removeEventListener('mozbrowsershowmodalprompt', alertError);
var message = e.detail.message
error(message);
}
testFrame.addEventListener('mozbrowserloadend', loadend);
testFrame.addEventListener('mozbrowsershowmodalprompt', alertError);
document.body.appendChild(testFrame);
}
addEventListener('testready', function() {
SpecialPowers.pushPrefEnv({'set': [["b2g.system_manifest_url", "http://mochi.test:8888/manifest.webapp"]]},
function() {
SimpleTest.executeSoon(setupTestFrame);
});
});

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

@ -182,60 +182,7 @@ function audio() {
document.body.appendChild(iframe); document.body.appendChild(iframe);
} }
function audioMutedByDefault() { var tests = [ noaudio, audio ];
info("Test : audio-muted-by-default");
SpecialPowers.pushPrefEnv(
{'set': [["dom.audiochannel.mutedByDefault", true]]}, function () {
var iframe = document.createElement('iframe');
iframe.setAttribute('mozbrowser', 'true');
iframe.setAttribute('mozapp', 'http://example.org/manifest.webapp');
iframe.src = 'http://example.org/tests/dom/browser-element/mochitest/file_processingAudioSample.html';
function audio_loadend_MutedByDefault() {
ok("allowedAudioChannels" in iframe, "allowedAudioChannels exist");
var channels = iframe.allowedAudioChannels;
is(channels.length, 1, "1 audio channel by default");
var ac = channels[0];
ok(ac instanceof BrowserElementAudioChannel, "Correct class");
ok("getMuted" in ac, "ac.getMuted exists");
ok("setMuted" in ac, "ac.setMuted exists");
ac.onactivestatechanged = function() {
ok(true, "activestatechanged event received.");
ac.onactivestatechanged = null;
new Promise(function(r, rr) {
ac.getMuted().onsuccess = function(e) {
is(e.target.result, true, "Muted channel by default");
r();
}
})
.then(function() {
ac.setMuted(false).onsuccess = function(e) {
ok(true, "Unmuted the channel.");
}
})
}
var complete = false;
iframe.addEventListener("mozbrowsershowmodalprompt", function (e) {
is(e.detail.message, "playback-success", "Audio playback success!");
if (!complete) {
document.body.removeChild(iframe);
SpecialPowers.popPrefEnv(runTests);
complete = true;
}
});
}
iframe.addEventListener('mozbrowserloadend', audio_loadend_MutedByDefault);
document.body.appendChild(iframe);
});
}
var tests = [ noaudio, audio, audioMutedByDefault ];
function runTests() { function runTests() {
if (tests.length == 0) { if (tests.length == 0) {

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

@ -0,0 +1,105 @@
"use strict";
SimpleTest.waitForExplicitFinish();
browserElementTestHelpers.setEnabledPref(true);
browserElementTestHelpers.addPermission();
var fileURL = 'http://example.org/tests/dom/browser-element/mochitest/file_browserElement_AudioChannelMutedByDefault.html';
var testFrame;
var ac;
function alertListener(e) {
var message = e.detail.message
if (/^OK/.exec(message)) {
ok(true, "Message from file : " + message);
} else if (/^KO/.exec(message)) {
error(message);
} else if (/DONE/.exec(message)) {
ok(true, "Audio playback success!");
finish();
} else {
error("Undefined event.");
}
}
function assert(aVal, aMessage) {
return (!aVal) ? error(aMessage) : 0;
}
function error(aMessage) {
ok(false, "Error : " + aMessage);
finish();
}
function finish() {
testFrame.removeEventListener('mozbrowsershowmodalprompt', alertListener);
document.body.removeChild(testFrame);
SimpleTest.finish();
}
function setCommand(aArg) {
assert(!!ac, "Audio channel doesn't exist!");
info("# Command = " + aArg);
testFrame.src = fileURL + '#' + aArg;
switch (aArg) {
case 'play':
ac.onactivestatechanged = () => {
ac.onactivestatechanged = null;
ok(true, "activestatechanged event received.");
new Promise(function(r, rr) {
ac.getMuted().onsuccess = function(e) {
is(e.target.result, true, "Muted channel by default");
r();
}
}).then(function() {
ac.setMuted(false).onsuccess = function(e) {
ok(true, "Unmuted the channel.");
}
});
};
break;
default :
error("Undefined command!");
}
}
function runTests() {
setCommand('play');
}
function setupTestFrame() {
testFrame = document.createElement('iframe');
testFrame.setAttribute('mozbrowser', 'true');
testFrame.setAttribute('mozapp', 'http://example.org/manifest.webapp');
testFrame.src = fileURL;
function loadend() {
testFrame.removeEventListener('mozbrowserloadend', loadend);
ok("allowedAudioChannels" in testFrame, "allowedAudioChannels exist");
var channels = testFrame.allowedAudioChannels;
is(channels.length, 1, "1 audio channel by default");
ac = channels[0];
ok(ac instanceof BrowserElementAudioChannel, "Correct class");
ok("getMuted" in ac, "ac.getMuted exists");
ok("setMuted" in ac, "ac.setMuted exists");
ok("onactivestatechanged" in ac, "onactivestatechanged exists");
runTests();
}
info("Set EventListeners.");
testFrame.addEventListener('mozbrowsershowmodalprompt', alertListener);
testFrame.addEventListener('mozbrowserloadend', loadend);
document.body.appendChild(testFrame);
}
addEventListener('testready', function() {
SpecialPowers.pushPrefEnv({'set': [["b2g.system_manifest_url", "http://mochi.test:8888/manifest.webapp"],
["dom.audiochannel.mutedByDefault", true]]},
function() {
SimpleTest.executeSoon(setupTestFrame);
});
});

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

@ -47,6 +47,20 @@ function registerPage(aEvent) {
ioService.newURI(manifestURI, null, null)); ioService.newURI(manifestURI, null, null));
} }
function uninstallApp() {
if (app) {
var request = navigator.mozApps.mgmt.uninstall(app);
app = null;
request.onerror = () => {
error("Uninstall app failed!");
};
request.onsuccess = () => {
is(request.result, manifestURI, "App uninstalled.");
runNextTest();
}
}
}
function runTest(aEnable) { function runTest(aEnable) {
var request = navigator.mozApps.install(manifestURI, {}); var request = navigator.mozApps.install(manifestURI, {});
request.onerror = () => { request.onerror = () => {
@ -63,9 +77,10 @@ function runTest(aEnable) {
iframe.setAttribute('remote', aEnable); iframe.setAttribute('remote', aEnable);
iframe.setAttribute('mozapp', manifestURI); iframe.setAttribute('mozapp', manifestURI);
iframe.src = srcURI; iframe.src = srcURI;
document.body.appendChild(iframe);
iframe.addEventListener('mozbrowserloadend', () => { function loadend() {
iframe.removeEventListener('mozbrowserloadend', loadend);
iframe.addEventListener("mozbrowsershowmodalprompt", getInterruption);
var channels = iframe.allowedAudioChannels; var channels = iframe.allowedAudioChannels;
is(channels.length, 1, "1 audio channel by default"); is(channels.length, 1, "1 audio channel by default");
@ -76,23 +91,19 @@ function runTest(aEnable) {
var message = "audiochannel-interruption-begin"; var message = "audiochannel-interruption-begin";
registerPage(message); registerPage(message);
ac.notifyChannel(message); ac.notifyChannel(message);
iframe.addEventListener("mozbrowsershowmodalprompt", function (e) {
function getInterruption(e) {
e.target.removeEventListener("mozbrowsershowmodalprompt", getInterruption);
is(e.detail.message, message, is(e.detail.message, message,
"App got audiochannel-interruption-begin."); "App got audiochannel-interruption-begin.");
if (app) { document.body.removeChild(iframe);
request = navigator.mozApps.mgmt.uninstall(app); uninstallApp();
app = null; }
request.onerror = () => { };
error("Uninstall app failed!");
}; iframe.addEventListener("mozbrowserloadend", loadend);
request.onsuccess = () => { document.body.appendChild(iframe);
is(request.result, manifestURI, "App uninstalled.");
runNextTest();
}
}
});
});
}; };
} }

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

@ -0,0 +1,37 @@
<!DOCTYPE HTML>
<html>
<body>
<script type="application/javascript;version=1.7">
var audio = new Audio();
audio.src = "audio.ogg";
audio.loop = true;
function runCommands()
{
switch(location.hash) {
case '#play':
audio.play();
break;
case '#mute':
audio.muted = true;
break;
case '#unmute':
audio.muted = false;
break;
case '#volume-0':
audio.volume = 0.0;
break;
case '#volume-1':
audio.volume = 1.0;
break;
case '#pause':
audio.pause();
break;
default :
alert("Undefined command!");
}
}
window.addEventListener('hashchange', runCommands);
</script>
</body>
</html>

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

@ -0,0 +1,65 @@
<html>
<body>
<script>
var audio = new Audio("audio.ogg");
var context = new AudioContext();
var node = context.createMediaElementSource(audio);
var sp = context.createScriptProcessor(2048, 1);
node.connect(sp);
var expectedSamplesCount;
var nonzeroSamplesCount = 0;
var isStarted = false;
function ok(aVal, aMsg) {
alert((!!aVal ? "OK" : "KO") + ", " + aMsg);
}
function finish() {
audio.onended = null;
audio.pause();
alert("DONE");
}
function processSamples(e) {
var buf = e.inputBuffer.getChannelData(0);
for (var i = 0; i < buf.length; ++i) {
if (buf[i] != 0) {
if (!isStarted) {
isStarted = true;
ok(true, "Start process audio sample.");
}
nonzeroSamplesCount++;
}
}
if (nonzeroSamplesCount >= expectedSamplesCount) {
finish();
}
}
audio.oncanplaythrough = function() {
var testDuration = audio.duration > 1.0 ? 1.0 : audio.duration * 0.5;
expectedSamplesCount = Math.floor(testDuration * context.sampleRate);
sp.onaudioprocess = processSamples;
};
function runCommands()
{
switch(location.hash) {
case '#play':
ok(true, "Audio starts playing.")
audio.play();
audio.onended = () => {
audio.onended = null;
ok(false, "Audio shouldn't go ended in this test!")
};
break;
default :
ok(false, "Undefined command!");
}
}
window.addEventListener('hashchange', runCommands);
</script>
</body>
</html>

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

@ -1,45 +0,0 @@
<html>
<body>
<script>
var audio = new Audio("audio.ogg");
var context = new AudioContext();
var node = context.createMediaElementSource(audio);
var sp = context.createScriptProcessor(2048, 1);
node.connect(sp);
var expectedSamplesCount;
var nonzeroSamplesCount = 0;
var complete = false;
var iterationCount = 0;
function processSamples(e) {
if (complete) {
return;
}
// Start playing the audio until the AudioContext is connected and running.
if (iterationCount++ == 0) {
audio.play();
}
var buf = e.inputBuffer.getChannelData(0);
for (var i = 0; i < buf.length; ++i) {
if (buf[i] != 0) {
nonzeroSamplesCount++;
}
}
if (nonzeroSamplesCount >= expectedSamplesCount && !complete) {
alert("playback-success");
complete = true;
}
}
audio.oncanplaythrough = function() {
var testDuration = audio.duration > 2.0 ? 2.0 : audio.duration;
expectedSamplesCount = Math.floor(testDuration * context.sampleRate) ;
sp.onaudioprocess = processSamples;
};
</script>
</body>
</html>

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

@ -27,6 +27,7 @@ skip-if = toolkit=='gonk'
skip-if = (toolkit == 'gonk' && !debug) skip-if = (toolkit == 'gonk' && !debug)
[test_browserElement_oop_AppWindowNamespace.html] [test_browserElement_oop_AppWindowNamespace.html]
skip-if = (toolkit == 'gonk' && !debug) skip-if = (toolkit == 'gonk' && !debug)
[test_browserElement_oop_AudioChannelMutedByDefault.html]
[test_browserElement_oop_Auth.html] [test_browserElement_oop_Auth.html]
skip-if = (toolkit == 'gonk' && !debug) skip-if = (toolkit == 'gonk' && !debug)
[test_browserElement_oop_BackForward.html] [test_browserElement_oop_BackForward.html]
@ -124,3 +125,4 @@ disabled = bug 924771
[test_browserElement_oop_getWebManifest.html] [test_browserElement_oop_getWebManifest.html]
[test_browserElement_oop_OpenWindowEmpty.html] [test_browserElement_oop_OpenWindowEmpty.html]
skip-if = (toolkit == 'gonk') # Test doesn't work on B2G emulator skip-if = (toolkit == 'gonk') # Test doesn't work on B2G emulator
[test_browserElement_oop_ActiveStateChangeOnChangingMutedOrVolume.html]

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

@ -5,11 +5,13 @@ support-files =
../../../dom/media/test/short-video.ogv ../../../dom/media/test/short-video.ogv
async.js async.js
browserElementTestHelpers.js browserElementTestHelpers.js
browserElement_ActiveStateChangeOnChangingMutedOrVolume.js
browserElement_Alert.js browserElement_Alert.js
browserElement_AlertInFrame.js browserElement_AlertInFrame.js
browserElement_AllowEmbedAppsInNestedOOIframe.js browserElement_AllowEmbedAppsInNestedOOIframe.js
browserElement_AppFramePermission.js browserElement_AppFramePermission.js
browserElement_AppWindowNamespace.js browserElement_AppWindowNamespace.js
browserElement_AudioChannelMutedByDefault.js
browserElement_AudioPlayback.js browserElement_AudioPlayback.js
browserElement_Auth.js browserElement_Auth.js
browserElement_BackForward.js browserElement_BackForward.js
@ -84,12 +86,14 @@ support-files =
browserElement_GetContentDimensions.js browserElement_GetContentDimensions.js
browserElement_AudioChannel.js browserElement_AudioChannel.js
browserElement_AudioChannel_nested.js browserElement_AudioChannel_nested.js
file_browserElement_ActiveStateChangeOnChangingMutedOrVolume.html
file_browserElement_AlertInFrame.html file_browserElement_AlertInFrame.html
file_browserElement_AlertInFrame_Inner.html file_browserElement_AlertInFrame_Inner.html
file_browserElement_AllowEmbedAppsInNestedOOIframe.html file_browserElement_AllowEmbedAppsInNestedOOIframe.html
file_browserElement_AppFramePermission.html file_browserElement_AppFramePermission.html
file_browserElement_AppWindowNamespace.html file_browserElement_AppWindowNamespace.html
file_browserElement_AudioChannel_nested.html file_browserElement_AudioChannel_nested.html
file_browserElement_AudioChannelMutedByDefault.html
file_browserElement_Viewmode.html file_browserElement_Viewmode.html
file_browserElement_ThemeColor.html file_browserElement_ThemeColor.html
file_browserElement_BrowserWindowNamespace.html file_browserElement_BrowserWindowNamespace.html
@ -143,7 +147,6 @@ support-files =
file_web_manifest.html file_web_manifest.html
file_web_manifest.json file_web_manifest.json
file_illegal_web_manifest.html file_illegal_web_manifest.html
file_processingAudioSample.html
noaudio.webm noaudio.webm
# Note: browserElementTestHelpers.js looks at the test's filename to determine # Note: browserElementTestHelpers.js looks at the test's filename to determine
@ -162,6 +165,8 @@ skip-if = buildapp == 'b2g'
skip-if = toolkit == 'android' || buildapp == 'b2g' skip-if = toolkit == 'android' || buildapp == 'b2g'
[test_browserElement_inproc_AppWindowNamespace.html] [test_browserElement_inproc_AppWindowNamespace.html]
skip-if = toolkit == 'android' || buildapp == 'b2g' # android(TIMED_OUT, bug 783509) androidx86(TIMED_OUT, bug 783509) skip-if = toolkit == 'android' || buildapp == 'b2g' # android(TIMED_OUT, bug 783509) androidx86(TIMED_OUT, bug 783509)
[test_browserElement_inproc_AudioChannelMutedByDefault.html]
skip-if = toolkit == 'android'
[test_browserElement_inproc_AudioPlayback.html] [test_browserElement_inproc_AudioPlayback.html]
[test_browserElement_inproc_Auth.html] [test_browserElement_inproc_Auth.html]
skip-if = buildapp == 'b2g' skip-if = buildapp == 'b2g'
@ -258,3 +263,4 @@ disabled = bug 774100
[test_browserElement_inproc_getStructuredData.html] [test_browserElement_inproc_getStructuredData.html]
[test_browserElement_inproc_OpenWindowEmpty.html] [test_browserElement_inproc_OpenWindowEmpty.html]
skip-if = (toolkit == 'gonk') # Test doesn't work on B2G emulator skip-if = (toolkit == 'gonk') # Test doesn't work on B2G emulator
[test_browserElement_inproc_ActiveStateChangeOnChangingMutedOrVolume.html]

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

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test ActiveStateChangeOnChangingMutedOrVolume</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7" src="browserElement_ActiveStateChangeOnChangingMutedOrVolume.js">
</script>
</body>
</html>

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

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1235535 - Audio Channel Muted-By-Default.</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7" src="browserElement_AudioChannelMutedByDefault.js">
</script>
</body>
</html>

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

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test ActiveStateChangeOnChangingMutedOrVolume</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7" src="browserElement_ActiveStateChangeOnChangingMutedOrVolume.js">
</script>
</body>
</html>

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

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1235535 - Audio Channel Muted-By-Default.</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7" src="browserElement_AudioChannelMutedByDefault.js">
</script>
</body>
</html>

1
dom/cache/test/mochitest/mochitest.ini поставляемый
Просмотреть файл

@ -32,6 +32,7 @@ support-files =
[test_cache_overwrite.html] [test_cache_overwrite.html]
[test_cache_match_vary.html] [test_cache_match_vary.html]
[test_caches.html] [test_caches.html]
skip-if = e10s && debug && os == 'win'
[test_cache_keys.html] [test_cache_keys.html]
[test_cache_put.html] [test_cache_put.html]
[test_cache_requestCache.html] [test_cache_requestCache.html]

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

@ -599,6 +599,7 @@ WebGLProgram::GetProgramParameter(GLenum pname) const
if (mContext->IsWebGL2()) { if (mContext->IsWebGL2()) {
switch (pname) { switch (pname) {
case LOCAL_GL_ACTIVE_UNIFORM_BLOCKS: case LOCAL_GL_ACTIVE_UNIFORM_BLOCKS:
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
return JS::Int32Value(GetProgramiv(gl, mGLName, pname)); return JS::Int32Value(GetProgramiv(gl, mGLName, pname));
case LOCAL_GL_TRANSFORM_FEEDBACK_VARYINGS: case LOCAL_GL_TRANSFORM_FEEDBACK_VARYINGS:

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

@ -259,20 +259,28 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk')
[test_mozDashOffset.html] [test_mozDashOffset.html]
[test_mozGetAsFile.html] [test_mozGetAsFile.html]
[test_strokeText_throw.html] [test_strokeText_throw.html]
skip-if = (e10s && debug && os == 'win')
[test_toBlob.html] [test_toBlob.html]
skip-if = (e10s && debug && os == 'win') # bug 1236257
[test_toDataURL_alpha.html] [test_toDataURL_alpha.html]
skip-if = (e10s && debug && os == 'win')
[test_toDataURL_lowercase_ascii.html] [test_toDataURL_lowercase_ascii.html]
skip-if = (e10s && debug && os == 'win')
[test_toDataURL_parameters.html] [test_toDataURL_parameters.html]
skip-if = (e10s && debug && os == 'win')
[test_windingRuleUndefined.html] [test_windingRuleUndefined.html]
skip-if = (e10s && debug && os == 'win')
[test_2d.fillText.gradient.html] [test_2d.fillText.gradient.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # bug 1040965 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # bug 1040965
[test_2d_composite_canvaspattern_setTransform.html] [test_2d_composite_canvaspattern_setTransform.html]
[test_createPattern_broken.html] [test_createPattern_broken.html]
[test_setlinedash.html] [test_setlinedash.html]
skip-if = (e10s && debug && os == 'win')
[test_filter.html] [test_filter.html]
[test_offscreencanvas_toblob.html] [test_offscreencanvas_toblob.html]
tags = offscreencanvas tags = offscreencanvas
[test_offscreencanvas_toimagebitmap.html] [test_offscreencanvas_toimagebitmap.html]
skip-if = (e10s && debug && os == 'win')
tags = offscreencanvas tags = offscreencanvas
[test_offscreencanvas_basic_webgl.html] [test_offscreencanvas_basic_webgl.html]
tags = offscreencanvas tags = offscreencanvas

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

@ -87,7 +87,7 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' # b2g(1 failure out of 615,
[test_bug605242.html] [test_bug605242.html]
skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
[test_bug607464.html] [test_bug607464.html]
skip-if = buildapp == 'b2g' || toolkit == 'android' #CRASH_DUMP, RANDOM skip-if = buildapp == 'b2g' || toolkit == 'android' || (e10s && os == 'win') #CRASH_DUMP, RANDOM
[test_bug613634.html] [test_bug613634.html]
skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
[test_bug615597.html] [test_bug615597.html]

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

@ -170,7 +170,7 @@ addLoadEvent(doTest);
</script> </script>
</pre> </pre>
<div id="parent"> <div id="parent">
<span id="testTarget" style="padding: 5px; border: 1px solid black;">testTarget</span> <span id="testTarget" style="margin-left: 200px; padding: 5px; border: 1px solid black;">testTarget</span>
</div> </div>
</body> </body>
</html> </html>

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

@ -4842,20 +4842,8 @@ HTMLMediaElement::SetMediaKeys(mozilla::dom::MediaKeys* aMediaKeys,
if (aRv.Failed()) { if (aRv.Failed()) {
return nullptr; return nullptr;
} }
if (mMediaKeys == aMediaKeys) {
promise->MaybeResolve(JS::UndefinedHandleValue); // We only support EME for MSE content by default.
return promise.forget();
}
if (aMediaKeys && aMediaKeys->IsBoundToMediaElement()) {
promise->MaybeReject(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR,
NS_LITERAL_CSTRING("MediaKeys object is already bound to another HTMLMediaElement"));
return promise.forget();
}
if (mMediaKeys) {
// Existing MediaKeys object. Shut it down.
mMediaKeys->Shutdown();
mMediaKeys = nullptr;
}
if (mDecoder && if (mDecoder &&
!mMediaSource && !mMediaSource &&
Preferences::GetBool("media.eme.mse-only", true)) { Preferences::GetBool("media.eme.mse-only", true)) {
@ -4865,19 +4853,92 @@ HTMLMediaElement::SetMediaKeys(mozilla::dom::MediaKeys* aMediaKeys,
return promise.forget(); return promise.forget();
} }
mMediaKeys = aMediaKeys; // 1. If mediaKeys and the mediaKeys attribute are the same object,
// return a resolved promise.
if (mMediaKeys == aMediaKeys) {
promise->MaybeResolve(JS::UndefinedHandleValue);
return promise.forget();
}
// Note: Our attaching code is synchronous, so we can skip the following steps.
// 2. If this object's attaching media keys value is true, return a
// promise rejected with a new DOMException whose name is InvalidStateError.
// 3. Let this object's attaching media keys value be true.
// 4. Let promise be a new promise.
// 5. Run the following steps in parallel:
// 5.1 If mediaKeys is not null, CDM instance represented by mediaKeys is
// already in use by another media element, and the user agent is unable
// to use it with this element, let this object's attaching media keys
// value be false and reject promise with a new DOMException whose name
// is QuotaExceededError.
if (aMediaKeys && aMediaKeys->IsBoundToMediaElement()) {
promise->MaybeReject(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR,
NS_LITERAL_CSTRING("MediaKeys object is already bound to another HTMLMediaElement"));
return promise.forget();
}
// 5.2 If the mediaKeys attribute is not null, run the following steps:
if (mMediaKeys) { if (mMediaKeys) {
if (NS_FAILED(mMediaKeys->Bind(this))) { // 5.2.1 If the user agent or CDM do not support removing the association,
// let this object's attaching media keys value be false and reject promise
// with a new DOMException whose name is NotSupportedError.
// 5.2.2 If the association cannot currently be removed, let this object's
// attaching media keys value be false and reject promise with a new
// DOMException whose name is InvalidStateError.
if (mDecoder) {
// We don't support swapping out the MediaKeys once we've started to
// setup the playback pipeline. Note this also means we don't need to worry
// about handling disassociating the MediaKeys from the MediaDecoder.
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("Failed to bind MediaKeys object to HTMLMediaElement")); NS_LITERAL_CSTRING("Can't change MediaKeys on HTMLMediaElement after load has started"));
mMediaKeys = nullptr;
return promise.forget(); return promise.forget();
} }
// 5.2.3 Stop using the CDM instance represented by the mediaKeys attribute
// to decrypt media data and remove the association with the media element.
mMediaKeys->Unbind();
mMediaKeys = nullptr;
// 5.2.4 If the preceding step failed, let this object's attaching media
// keys value be false and reject promise with a new DOMException whose
// name is the appropriate error name.
}
// 5.3. If mediaKeys is not null, run the following steps:
if (aMediaKeys) {
// 5.3.1 Associate the CDM instance represented by mediaKeys with the
// media element for decrypting media data.
if (NS_FAILED(aMediaKeys->Bind(this))) {
// 5.3.2 If the preceding step failed, run the following steps:
// 5.3.2.1 Set the mediaKeys attribute to null.
mMediaKeys = nullptr;
// 5.3.2.2 Let this object's attaching media keys value be false.
// 5.3.2.3 Reject promise with a new DOMException whose name is
// the appropriate error name.
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("Failed to bind MediaKeys object to HTMLMediaElement"));
return promise.forget();
}
// 5.3.3 Queue a task to run the "Attempt to Resume Playback If Necessary"
// algorithm on the media element.
// Note: Setting the CDMProxy on the MediaDecoder will unblock playback.
if (mDecoder) { if (mDecoder) {
mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy()); mDecoder->SetCDMProxy(aMediaKeys->GetCDMProxy());
} }
} }
// 5.4 Set the mediaKeys attribute to mediaKeys.
mMediaKeys = aMediaKeys;
// 5.5 Let this object's attaching media keys value be false.
// 5.6 Resolve promise.
promise->MaybeResolve(JS::UndefinedHandleValue); promise->MaybeResolve(JS::UndefinedHandleValue);
// 6. Return promise.
return promise.forget(); return promise.forget();
} }

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

@ -269,7 +269,7 @@ nsHTMLDocument::CreateShell(nsPresContext* aContext,
nsViewManager* aViewManager, nsViewManager* aViewManager,
nsStyleSet* aStyleSet) nsStyleSet* aStyleSet)
{ {
return doCreateShell(aContext, aViewManager, aStyleSet, mCompatMode); return doCreateShell(aContext, aViewManager, aStyleSet);
} }
void void

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

@ -593,13 +593,14 @@ support-files = file_bug871161-1.html file_bug871161-2.html
[test_hash_encoded.html] [test_hash_encoded.html]
[test_bug1081037.html] [test_bug1081037.html]
[test_window_open_close.html] [test_window_open_close.html]
skip-if = buildapp == 'b2g' # bug 1129014 skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # bug 1129014
[test_img_complete.html] [test_img_complete.html]
[test_viewport_resize.html] [test_viewport_resize.html]
[test_extapp.html] [test_extapp.html]
[test_image_clone_load.html] [test_image_clone_load.html]
[test_bug1203668.html] [test_bug1203668.html]
[test_bug1166138.html] [test_bug1166138.html]
[test_bug1230665.html]
[test_filepicker_default_directory.html] [test_filepicker_default_directory.html]
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android'
[test_bug1233598.html] [test_bug1233598.html]

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

@ -0,0 +1,46 @@
<html>
<head>
<title>Test for Bug 1230665</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<script>
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(function() {
document.getElementById("flexbutton1").focus();
synthesizeKey("VK_TAB", { });
var e = document.getElementById("flexbutton2");
is(document.activeElement, e, "focus in flexbutton2 after TAB");
document.getElementById("gridbutton1").focus();
synthesizeKey("VK_TAB", { });
e = document.getElementById("gridbutton2");
is(document.activeElement, e, "focus in gridbutton2 after TAB");
SimpleTest.finish();
});
</script>
<div tabindex="0" style="display:flex">
<button id="flexbutton1"></button>
text <!-- this text will force a :-moz-anonymous-flex-item frame -->
<div style="">
<button id="flexbutton2"></button>
</div>
</div>
<div tabindex="0" style="display:grid">
<button id="gridbutton1"></button>
text <!-- this text will force a :-moz-anonymous-grid-item frame -->
<div style="">
<button id="gridbutton2"></button>
</div>
</div>
</body>
</html>

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

@ -172,6 +172,6 @@ PEExpectedVariableName=Expected identifier for variable name but found '%1$S'.
PEExpectedVariableFallback=Expected variable reference fallback after ','. PEExpectedVariableFallback=Expected variable reference fallback after ','.
PEExpectedVariableCommaOrCloseParen=Expected ',' or ')' after variable name in variable reference but found '%1$S'. PEExpectedVariableCommaOrCloseParen=Expected ',' or ')' after variable name in variable reference but found '%1$S'.
PESubgridNotSupported=Support for the 'subgrid' keyword of CSS Grid is not enabled. PESubgridNotSupported=Support for the 'subgrid' keyword of CSS Grid is not enabled.
PEMoreThanOneGridRepeatAutoFillInNameList=Only one repeat(auto-fill, ...) is allowed in a name list for a subgrid. PEMoreThanOneGridRepeatAutoFillInNameList=Only one repeat(auto-fill, ) is allowed in a name list for a subgrid.
PEMoreThanOneGridRepeatAutoFillFitInTrackList=Only one repeat(auto-fill, ...) or repeat(auto-fit, ...) is allowed in a track list. PEMoreThanOneGridRepeatAutoFillFitInTrackList=Only one repeat(auto-fill, …) or repeat(auto-fit, …) is allowed in a track list.
PEMoreThanOneGridRepeatTrackSize=Only one track size is allowed inside repeat(auto-fit/auto-fill, ...). PEMoreThanOneGridRepeatTrackSize=Only one track size is allowed inside repeat(auto-fit/auto-fill, ).

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

@ -504,5 +504,12 @@ MediaKeys::Bind(HTMLMediaElement* aElement)
return NS_OK; return NS_OK;
} }
void
MediaKeys::Unbind()
{
MOZ_ASSERT(NS_IsMainThread());
mElement = nullptr;
}
} // namespace dom } // namespace dom
} // namespace mozilla } // namespace mozilla

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

@ -55,6 +55,7 @@ public:
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
nsresult Bind(HTMLMediaElement* aElement); nsresult Bind(HTMLMediaElement* aElement);
void Unbind();
// Javascript: readonly attribute DOMString keySystem; // Javascript: readonly attribute DOMString keySystem;
void GetKeySystem(nsString& retval) const; void GetKeySystem(nsString& retval) const;

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

@ -10,10 +10,13 @@
using namespace mozilla; using namespace mozilla;
// "test.webm" contains 8 SimpleBlocks in a single Cluster with the following attributes // "test.webm" contains 8 SimpleBlocks in a single Cluster. The blocks with
static const uint64_t gTimecodes[] = { 66000000, 160000000, 100000000, 133000000, // timecodes 100000000 and are 133000000 skipped by WebMBufferedParser
166000000, 200000000, 233000000, 320000000 }; // because they occur after a block with timecode 160000000 and the parser
static const int64_t gEndOffsets[] = { 501, 772, 930, 1085, 1244, 1380, 1543, 2015 }; // expects in-order timecodes per the WebM spec. The remaining 6
// SimpleBlocks have the following attributes:
static const uint64_t gTimecodes[] = { 66000000, 160000000, 166000000, 200000000, 233000000, 320000000 };
static const int64_t gEndOffsets[] = { 501, 772, 1244, 1380, 1543, 2015 };
TEST(WebMBuffered, BasicTests) TEST(WebMBuffered, BasicTests)
{ {
@ -66,7 +69,7 @@ TEST(WebMBuffered, RealData)
nsTArray<WebMTimeDataOffset> mapping; nsTArray<WebMTimeDataOffset> mapping;
parser.Append(webmData.Elements(), webmData.Length(), mapping, dummy); parser.Append(webmData.Elements(), webmData.Length(), mapping, dummy);
EXPECT_EQ(mapping.Length(), 8u); EXPECT_EQ(mapping.Length(), 6u);
EXPECT_EQ(parser.mStartOffset, 0); EXPECT_EQ(parser.mStartOffset, 0);
EXPECT_EQ(parser.mCurrentOffset, int64_t(webmData.Length())); EXPECT_EQ(parser.mCurrentOffset, int64_t(webmData.Length()));
EXPECT_EQ(parser.GetTimecodeScale(), 500000u); EXPECT_EQ(parser.GetTimecodeScale(), 500000u);
@ -95,7 +98,7 @@ TEST(WebMBuffered, RealDataAppend)
EXPECT_EQ(parser.mCurrentOffset, int64_t(offset)); EXPECT_EQ(parser.mCurrentOffset, int64_t(offset));
if (mapping.Length() != arrayEntries) { if (mapping.Length() != arrayEntries) {
arrayEntries = mapping.Length(); arrayEntries = mapping.Length();
ASSERT_LE(arrayEntries, 8u); ASSERT_LE(arrayEntries, 6u);
uint32_t i = arrayEntries - 1; uint32_t i = arrayEntries - 1;
EXPECT_EQ(mapping[i].mEndOffset, gEndOffsets[i]); EXPECT_EQ(mapping[i].mEndOffset, gEndOffsets[i]);
EXPECT_EQ(mapping[i].mSyncOffset, 361); EXPECT_EQ(mapping[i].mSyncOffset, 361);
@ -103,7 +106,7 @@ TEST(WebMBuffered, RealDataAppend)
EXPECT_EQ(parser.GetTimecodeScale(), 500000u); EXPECT_EQ(parser.GetTimecodeScale(), 500000u);
} }
} }
EXPECT_EQ(mapping.Length(), 8u); EXPECT_EQ(mapping.Length(), 6u);
EXPECT_EQ(parser.mStartOffset, 0); EXPECT_EQ(parser.mStartOffset, 0);
EXPECT_EQ(parser.mCurrentOffset, int64_t(webmData.Length())); EXPECT_EQ(parser.mCurrentOffset, int64_t(webmData.Length()));
EXPECT_EQ(parser.GetTimecodeScale(), 500000u); EXPECT_EQ(parser.GetTimecodeScale(), 500000u);

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

@ -623,6 +623,8 @@ skip-if = (os == 'win' && os_version == '5.1') || (os != 'win' && toolkit != 'go
[test_eme_session_callable_value.html] [test_eme_session_callable_value.html]
[test_eme_canvas_blocked.html] [test_eme_canvas_blocked.html]
skip-if = toolkit == 'android' # bug 1149374 skip-if = toolkit == 'android' # bug 1149374
[test_eme_detach_media_keys.html]
skip-if = toolkit == 'android' # bug 1149374
[test_eme_initDataTypes.html] [test_eme_initDataTypes.html]
skip-if = toolkit == 'android' # bug 1149374 skip-if = toolkit == 'android' # bug 1149374
[test_eme_non_mse_fails.html] [test_eme_non_mse_fails.html]
@ -846,7 +848,9 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
[test_VideoPlaybackQuality_disabled.html] [test_VideoPlaybackQuality_disabled.html]
[test_volume.html] [test_volume.html]
[test_vttparser.html] [test_vttparser.html]
skip-if = e10s && debug && os == 'win'
[test_webvtt_disabled.html] [test_webvtt_disabled.html]
skip-if = e10s && debug && os == 'win'
# The tests below contain backend-specific tests. Write backend independent # The tests below contain backend-specific tests. Write backend independent
# tests rather than adding to this list. # tests rather than adding to this list.

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

@ -0,0 +1,63 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test Encrypted Media Extensions</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">
<video id="v" controls></video>
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
const keysystem = 'org.w3.clearkey';
function createAndSet() {
return new Promise(function(resolve, reject) {
var m;
navigator.requestMediaKeySystemAccess(keysystem, [{initDataType: 'cenc'}])
.then(function (access) {
return access.createMediaKeys();
}).then(function (mediaKeys) {
m = mediaKeys;
return document.getElementById("v").setMediaKeys(mediaKeys);
}).then(function() {
resolve(m);
});
}
)}
var m1,m2;
// Test that if we create and set two MediaKeys on one video element,
// that if the first MediaKeys we set on the media elemnt is still usable
// after the second MediaKeys has been set on the media element.
SetupEMEPref(() => {
createAndSet().then((m) => {
m1 = m; // Stash MediaKeys.
return createAndSet();
})
.then((m) => {
m2 = m;
is(document.getElementById("v").mediaKeys, m2, "Should have set MediaKeys on media element");
ok(document.getElementById("v").mediaKeys != m1, "First MediaKeys should no longer be set on media element");
var s = m1.createSession("temporary");
return s.generateRequest("webm", StringToArrayBuffer(atob('YAYeAX5Hfod+V9ANHtANHg==')));
})
.then(() => {
ok(true, "Was able to generateRequest using second CDM");
SimpleTest.finish();
}, () => {
ok(false, "Was *NOT* able to generateRequest using second CDM");
SimpleTest.finish();
});
});
</script>
</pre>
</body>
</html>

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

@ -9,8 +9,12 @@
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include <algorithm> #include <algorithm>
#define WEBM_DEBUG(arg, ...) MOZ_LOG(gWebMDemuxerLog, mozilla::LogLevel::Debug, ("WebMBufferedParser(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
namespace mozilla { namespace mozilla {
extern LazyLogModule gWebMDemuxerLog;
static uint32_t static uint32_t
VIntLength(unsigned char aFirstByte, uint32_t* aMask) VIntLength(unsigned char aFirstByte, uint32_t* aMask)
{ {
@ -183,9 +187,20 @@ void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
MOZ_ASSERT(mGotTimecodeScale); MOZ_ASSERT(mGotTimecodeScale);
uint64_t absTimecode = mClusterTimecode + mBlockTimecode; uint64_t absTimecode = mClusterTimecode + mBlockTimecode;
absTimecode *= mTimecodeScale; absTimecode *= mTimecodeScale;
WebMTimeDataOffset entry(endOffset, absTimecode, mLastInitStartOffset, // Avoid creating an entry if the timecode is out of order
mClusterOffset, mClusterEndOffset); // (invalid according to the WebM specification) so that
aMapping.InsertElementAt(idx, entry); // ordering invariants of aMapping are not violated.
if (idx == 0 ||
aMapping[idx - 1].mTimecode <= absTimecode ||
(idx + 1 < aMapping.Length() &&
aMapping[idx + 1].mTimecode >= absTimecode)) {
WebMTimeDataOffset entry(endOffset, absTimecode, mLastInitStartOffset,
mClusterOffset, mClusterEndOffset);
aMapping.InsertElementAt(idx, entry);
} else {
WEBM_DEBUG("Out of order timecode %llu in Cluster at %lld ignored",
absTimecode, mClusterOffset);
}
} }
} }
} }
@ -302,6 +317,7 @@ bool WebMBufferedState::CalculateBufferedForRange(int64_t aStartOffset, int64_t
"Must have found greatest WebMTimeDataOffset for end"); "Must have found greatest WebMTimeDataOffset for end");
} }
MOZ_ASSERT(mTimeMapping[end].mTimecode >= mTimeMapping[end - 1].mTimecode);
uint64_t frameDuration = mTimeMapping[end].mTimecode - mTimeMapping[end - 1].mTimecode; uint64_t frameDuration = mTimeMapping[end].mTimecode - mTimeMapping[end - 1].mTimecode;
*aStartTime = mTimeMapping[start].mTimecode; *aStartTime = mTimeMapping[start].mTimecode;
*aEndTime = mTimeMapping[end].mTimecode + frameDuration; *aEndTime = mTimeMapping[end].mTimecode + frameDuration;
@ -478,3 +494,6 @@ WebMBufferedState::GetNextKeyframeTime(uint64_t aTime, uint64_t* aKeyframeTime)
return true; return true;
} }
} // namespace mozilla } // namespace mozilla
#undef WEBM_DEBUG

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

@ -4,6 +4,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 "nsISupportsPrimitives.h"
#include "nsSpeechTask.h" #include "nsSpeechTask.h"
#include "mozilla/Logging.h" #include "mozilla/Logging.h"
@ -55,7 +56,9 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechSynthesis) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechSynthesis)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_END NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechSynthesis) NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechSynthesis)
@ -64,8 +67,16 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechSynthesis)
SpeechSynthesis::SpeechSynthesis(nsPIDOMWindow* aParent) SpeechSynthesis::SpeechSynthesis(nsPIDOMWindow* aParent)
: mParent(aParent) : mParent(aParent)
, mHoldQueue(false) , mHoldQueue(false)
, mInnerID(aParent->WindowID())
{ {
MOZ_ASSERT(aParent->IsInnerWindow()); MOZ_ASSERT(aParent->IsInnerWindow());
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->AddObserver(this, "inner-window-destroyed", true);
}
} }
SpeechSynthesis::~SpeechSynthesis() SpeechSynthesis::~SpeechSynthesis()
@ -118,6 +129,12 @@ SpeechSynthesis::Paused() const
(!mSpeechQueue.IsEmpty() && mSpeechQueue.ElementAt(0)->IsPaused()); (!mSpeechQueue.IsEmpty() && mSpeechQueue.ElementAt(0)->IsPaused());
} }
bool
SpeechSynthesis::HasEmptyQueue() const
{
return mSpeechQueue.Length() == 0;
}
void void
SpeechSynthesis::Speak(SpeechSynthesisUtterance& aUtterance) SpeechSynthesis::Speak(SpeechSynthesisUtterance& aUtterance)
{ {
@ -239,6 +256,8 @@ SpeechSynthesis::GetVoices(nsTArray< RefPtr<SpeechSynthesisVoice> >& aResult)
return; return;
} }
nsISupports* voiceParent = NS_ISUPPORTS_CAST(nsIObserver*, this);
for (uint32_t i = 0; i < voiceCount; i++) { for (uint32_t i = 0; i < voiceCount; i++) {
nsAutoString uri; nsAutoString uri;
rv = nsSynthVoiceRegistry::GetInstance()->GetVoice(i, uri); rv = nsSynthVoiceRegistry::GetInstance()->GetVoice(i, uri);
@ -251,7 +270,7 @@ SpeechSynthesis::GetVoices(nsTArray< RefPtr<SpeechSynthesisVoice> >& aResult)
SpeechSynthesisVoice* voice = mVoiceCache.GetWeak(uri); SpeechSynthesisVoice* voice = mVoiceCache.GetWeak(uri);
if (!voice) { if (!voice) {
voice = new SpeechSynthesisVoice(this, uri); voice = new SpeechSynthesisVoice(voiceParent, uri);
} }
aResult.AppendElement(voice); aResult.AppendElement(voice);
@ -275,5 +294,36 @@ SpeechSynthesis::ForceEnd()
} }
} }
NS_IMETHODIMP
SpeechSynthesis::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData)
{
MOZ_ASSERT(NS_IsMainThread());
if (strcmp(aTopic, "inner-window-destroyed")) {
return NS_OK;
}
nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
uint64_t innerID;
nsresult rv = wrapper->GetData(&innerID);
NS_ENSURE_SUCCESS(rv, rv);
if (innerID == mInnerID) {
if (mCurrentTask) {
mCurrentTask->Cancel();
}
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->RemoveObserver(this, "inner-window-destroyed");
}
}
return NS_OK;
}
} // namespace dom } // namespace dom
} // namespace mozilla } // namespace mozilla

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

@ -8,9 +8,11 @@
#define mozilla_dom_SpeechSynthesis_h #define mozilla_dom_SpeechSynthesis_h
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsString.h" #include "nsIObserver.h"
#include "nsWrapperCache.h"
#include "nsRefPtrHashtable.h" #include "nsRefPtrHashtable.h"
#include "nsString.h"
#include "nsWeakReference.h"
#include "nsWrapperCache.h"
#include "js/TypeDecls.h" #include "js/TypeDecls.h"
#include "SpeechSynthesisUtterance.h" #include "SpeechSynthesisUtterance.h"
@ -23,14 +25,17 @@ namespace dom {
class nsSpeechTask; class nsSpeechTask;
class SpeechSynthesis final : public nsISupports, class SpeechSynthesis final : public nsIObserver
public nsWrapperCache , public nsWrapperCache
, public nsSupportsWeakReference
{ {
public: public:
explicit SpeechSynthesis(nsPIDOMWindow* aParent); explicit SpeechSynthesis(nsPIDOMWindow* aParent);
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(SpeechSynthesis) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(SpeechSynthesis,
nsIObserver)
NS_DECL_NSIOBSERVER
nsIDOMWindow* GetParentObject() const; nsIDOMWindow* GetParentObject() const;
@ -42,6 +47,8 @@ public:
bool Paused() const; bool Paused() const;
bool HasEmptyQueue() const;
void Speak(SpeechSynthesisUtterance& aUtterance); void Speak(SpeechSynthesisUtterance& aUtterance);
void Cancel(); void Cancel();
@ -70,6 +77,8 @@ private:
nsRefPtrHashtable<nsStringHashKey, SpeechSynthesisVoice> mVoiceCache; nsRefPtrHashtable<nsStringHashKey, SpeechSynthesisVoice> mVoiceCache;
bool mHoldQueue; bool mHoldQueue;
uint64_t mInnerID;
}; };
} // namespace dom } // namespace dom

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

@ -82,7 +82,11 @@ SpeechSynthesisRequestParent::SpeechSynthesisRequestParent(SpeechTaskParent* aTa
SpeechSynthesisRequestParent::~SpeechSynthesisRequestParent() SpeechSynthesisRequestParent::~SpeechSynthesisRequestParent()
{ {
if (mTask) {
mTask->mActor = nullptr;
// If we still have a task, cancel it.
mTask->Cancel();
}
MOZ_COUNT_DTOR(SpeechSynthesisRequestParent); MOZ_COUNT_DTOR(SpeechSynthesisRequestParent);
} }
@ -157,7 +161,11 @@ SpeechTaskParent::DispatchStartImpl(const nsAString& aUri)
nsresult nsresult
SpeechTaskParent::DispatchEndImpl(float aElapsedTime, uint32_t aCharIndex) SpeechTaskParent::DispatchEndImpl(float aElapsedTime, uint32_t aCharIndex)
{ {
MOZ_ASSERT(mActor); if (!mActor) {
// Child is already gone.
return NS_OK;
}
if(NS_WARN_IF(!(mActor->SendOnEnd(false, aElapsedTime, aCharIndex)))) { if(NS_WARN_IF(!(mActor->SendOnEnd(false, aElapsedTime, aCharIndex)))) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }

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

@ -498,11 +498,17 @@ nsSpeechTask::DispatchResumeImpl(float aElapsedTime, uint32_t aCharIndex)
NS_IMETHODIMP NS_IMETHODIMP
nsSpeechTask::DispatchError(float aElapsedTime, uint32_t aCharIndex) nsSpeechTask::DispatchError(float aElapsedTime, uint32_t aCharIndex)
{ {
LOG(LogLevel::Debug, ("nsSpeechTask::DispatchError"));
if (!mIndirectAudio) { if (!mIndirectAudio) {
NS_WARNING("Can't call DispatchError() from a direct audio speech service"); NS_WARNING("Can't call DispatchError() from a direct audio speech service");
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
if (!mPreCanceled) {
nsSynthVoiceRegistry::GetInstance()->SpeakNext();
}
return DispatchErrorImpl(aElapsedTime, aCharIndex); return DispatchErrorImpl(aElapsedTime, aCharIndex);
} }
@ -514,6 +520,10 @@ nsSpeechTask::DispatchErrorImpl(float aElapsedTime, uint32_t aCharIndex)
return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_AVAILABLE;
} }
if (mSpeechSynthesis) {
mSpeechSynthesis->OnEnd(this);
}
mUtterance->mState = SpeechSynthesisUtterance::STATE_ENDED; mUtterance->mState = SpeechSynthesisUtterance::STATE_ENDED;
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("error"), mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("error"),
aCharIndex, aElapsedTime, aCharIndex, aElapsedTime,

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

@ -14,8 +14,6 @@ function synthTestQueue(aTestArgs, aEndFunc) {
is(e.target, utterances.shift(), "Target matches utterances"); is(e.target, utterances.shift(), "Target matches utterances");
ok(!speechSynthesis.speaking, "speechSynthesis is not speaking."); ok(!speechSynthesis.speaking, "speechSynthesis is not speaking.");
isnot(e.eventType, 'error', "Error in utterance");
if (utterances.length) { if (utterances.length) {
ok(speechSynthesis.pending, "other utterances queued"); ok(speechSynthesis.pending, "other utterances queued");
} else { } else {
@ -38,10 +36,12 @@ function synthTestQueue(aTestArgs, aEndFunc) {
u.addEventListener('end', onend_handler); u.addEventListener('end', onend_handler);
u.addEventListener('error', onend_handler); u.addEventListener('error', onend_handler);
u.addEventListener( u.addEventListener('error',
'error', function onerror_handler(e) { (function (expectedError) {
ok(false, "Error in speech utterance '" + e.target.text + "'"); return function onerror_handler(e) {
}); ok(expectedError, "Error in speech utterance '" + e.target.text + "'");
};
})(aTestArgs[i][1] ? aTestArgs[i][1].err : false));
utterances.push(u); utterances.push(u);
win.speechSynthesis.speak(u); win.speechSynthesis.speak(u);

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

@ -0,0 +1,28 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<script type="application/javascript">
var frameUnloaded = function() {
var u = new SpeechSynthesisUtterance('hi');
u.addEventListener('end', function () {
parent.ok(true, 'Successfully spoke utterance from new frame.');
parent.onDone();
});
speechSynthesis.speak(u);
}
addEventListener('pageshow', function onshow(evt) {
var u = new SpeechSynthesisUtterance('hello');
u.lang = 'it-IT-noend';
u.addEventListener('start', function() {
location =
'data:text/html,<html><body onpageshow="' +
frameUnloaded.toSource() + '()"></body></html>';
});
speechSynthesis.speak(u);
});
</script>
</head>
<body>
</body>
</html>

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

@ -28,7 +28,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1226015
function testFunc(done_cb) { function testFunc(done_cb) {
var utterance = new SpeechSynthesisUtterance(); var utterance = new SpeechSynthesisUtterance();
utterance.lang = 'it-IT-error'; utterance.lang = 'it-IT-failatstart';
speechSynthesis.speak(utterance); speechSynthesis.speak(utterance);
speechSynthesis.cancel(); speechSynthesis.cancel();

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

@ -30,9 +30,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=525444
var langUriMap = {}; var langUriMap = {};
for (var voice of speechSynthesis.getVoices()) { for (var voice of speechSynthesis.getVoices()) {
if (voice.voiceURI.indexOf('urn:moz-tts:fake-direct') < 0) {
continue;
}
langUriMap[voice.lang] = voice.voiceURI; langUriMap[voice.lang] = voice.voiceURI;
ok(true, voice.lang + ' ' + voice.voiceURI + ' ' + voice.default); ok(true, voice.lang + ' ' + voice.voiceURI + ' ' + voice.default);
is(voice.default, voice.lang == 'en-JM', 'Only Jamaican voice should be default'); is(voice.default, voice.lang == 'en-JM', 'Only Jamaican voice should be default');
@ -43,6 +40,7 @@ ok(langUriMap['en-GB'], 'No English-British voice');
ok(langUriMap['en-CA'], 'No English-Canadian voice'); ok(langUriMap['en-CA'], 'No English-Canadian voice');
ok(langUriMap['fr-CA'], 'No French-Canadian voice'); ok(langUriMap['fr-CA'], 'No French-Canadian voice');
ok(langUriMap['es-MX'], 'No Spanish-Mexican voice'); ok(langUriMap['es-MX'], 'No Spanish-Mexican voice');
ok(langUriMap['it-IT-fail'], 'No Failing Italian voice');
function testFunc(done_cb) { function testFunc(done_cb) {
synthTestQueue( synthTestQueue(
@ -53,6 +51,8 @@ function testFunc(done_cb) {
{ uri: langUriMap['fr-CA'], rate: 0.5, pitch: 0.75}], { uri: langUriMap['fr-CA'], rate: 0.5, pitch: 0.75}],
[{text: "How are you doing?", args: { lang: "en-GB" } }, [{text: "How are you doing?", args: { lang: "en-GB" } },
{ rate: 1, pitch: 1, uri: langUriMap['en-GB']}], { rate: 1, pitch: 1, uri: langUriMap['en-GB']}],
[{text: "Come stai?", args: { lang: "it-IT-fail" } },
{ rate: 1, pitch: 1, uri: langUriMap['it-IT-fail'], err: true }],
[{text: "¡hasta mañana!", args: { lang: "es-MX" } }, [{text: "¡hasta mañana!", args: { lang: "es-MX" } },
{ uri: langUriMap['es-MX'] }]], { uri: langUriMap['es-MX'] }]],
function () { function () {

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

@ -2,6 +2,7 @@
tags=msg tags=msg
support-files = support-files =
common.js common.js
file_bfcache_frame.html
file_setup.html file_setup.html
file_speech_queue.html file_speech_queue.html
file_speech_simple.html file_speech_simple.html
@ -21,3 +22,4 @@ support-files =
[test_global_queue.html] [test_global_queue.html]
[test_global_queue_cancel.html] [test_global_queue_cancel.html]
[test_global_queue_pause.html] [test_global_queue_pause.html]
[test_bfcache.html]

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

@ -31,7 +31,8 @@ enum VoiceFlags
{ {
eSuppressEvents = 1, eSuppressEvents = 1,
eSuppressEnd = 2, eSuppressEnd = 2,
eFailAtStart = 4 eFailAtStart = 4,
eFail = 8
}; };
struct VoiceDetails struct VoiceDetails
@ -55,7 +56,8 @@ static const VoiceDetails sIndirectVoices[] = {
{"urn:moz-tts:fake-indirect:zanetta", "Zanetta Farussi", "it-IT", false, 0}, {"urn:moz-tts:fake-indirect:zanetta", "Zanetta Farussi", "it-IT", false, 0},
{"urn:moz-tts:fake-indirect:margherita", "Margherita Durastanti", "it-IT-noevents-noend", false, eSuppressEvents | eSuppressEnd}, {"urn:moz-tts:fake-indirect:margherita", "Margherita Durastanti", "it-IT-noevents-noend", false, eSuppressEvents | eSuppressEnd},
{"urn:moz-tts:fake-indirect:teresa", "Teresa Cornelys", "it-IT-noend", false, eSuppressEnd}, {"urn:moz-tts:fake-indirect:teresa", "Teresa Cornelys", "it-IT-noend", false, eSuppressEnd},
{"urn:moz-tts:fake-indirect:cecilia", "Cecilia Bartoli", "it-IT-error", false, eFailAtStart}, {"urn:moz-tts:fake-indirect:cecilia", "Cecilia Bartoli", "it-IT-failatstart", false, eFailAtStart},
{"urn:moz-tts:fake-indirect:gottardo", "Gottardo Aldighieri", "it-IT-fail", false, eFail},
}; };
// FakeSynthCallback // FakeSynthCallback
@ -238,6 +240,26 @@ FakeIndirectAudioSynth::Speak(const nsAString& aText, const nsAString& aUri,
nsString mText; nsString mText;
}; };
class DispatchError final : public nsRunnable
{
public:
DispatchError(nsISpeechTask* aTask, const nsAString& aText) :
mTask(aTask), mText(aText)
{
}
NS_IMETHOD Run() override
{
mTask->DispatchError(mText.Length()/2, mText.Length());
return NS_OK;
}
private:
nsCOMPtr<nsISpeechTask> mTask;
nsString mText;
};
uint32_t flags = 0; uint32_t flags = 0;
for (uint32_t i = 0; i < ArrayLength(sIndirectVoices); i++) { for (uint32_t i = 0; i < ArrayLength(sIndirectVoices); i++) {
if (aUri.EqualsASCII(sIndirectVoices[i].uri)) { if (aUri.EqualsASCII(sIndirectVoices[i].uri)) {
@ -258,7 +280,10 @@ FakeIndirectAudioSynth::Speak(const nsAString& aText, const nsAString& aUri,
nsCOMPtr<nsIRunnable> runnable = new DispatchStart(aTask); nsCOMPtr<nsIRunnable> runnable = new DispatchStart(aTask);
NS_DispatchToMainThread(runnable); NS_DispatchToMainThread(runnable);
if ((flags & eSuppressEnd) == 0) { if (flags & eFail) {
runnable = new DispatchError(aTask, aText);
NS_DispatchToMainThread(runnable);
} else if ((flags & eSuppressEnd) == 0) {
runnable = new DispatchEnd(aTask, aText); runnable = new DispatchEnd(aTask, aText);
NS_DispatchToMainThread(runnable); NS_DispatchToMainThread(runnable);
} }

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

@ -0,0 +1,47 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1230533
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1230533: Test speech is stopped from a window when unloaded</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1230533">Mozilla Bug 1230533</a>
<p id="display"></p>
<iframe id="testFrame"></iframe>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 525444 **/
SimpleTest.waitForExplicitFinish();
var iframe;
function onDone() {
SimpleTest.finish();
}
function doTest() {
iframe = document.getElementById("testFrame");
iframe.src = "file_bfcache_frame.html";
}
SpecialPowers.pushPrefEnv({ set: [
['media.webspeech.synth.enabled', true],
['media.webspeech.synth.force_global_queue', true],
['browser.sessionhistory.cache_subframes', true],
['browser.sessionhistory.max_total_viewers', 10]] }, doTest());
</script>
</pre>
</body>
</html>

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

@ -304,19 +304,18 @@ PluginPRLibrary::SetBackgroundUnknown(NPP instance)
} }
nsresult nsresult
PluginPRLibrary::BeginUpdateBackground(NPP instance, PluginPRLibrary::BeginUpdateBackground(NPP instance, const nsIntRect&,
const nsIntRect&, gfxContext** aCtx) DrawTarget** aDrawTarget)
{ {
nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)instance->ndata; nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)instance->ndata;
NS_ENSURE_TRUE(inst, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(inst, NS_ERROR_NULL_POINTER);
NS_ERROR("Unexpected use of async APIs for in-process plugin."); NS_ERROR("Unexpected use of async APIs for in-process plugin.");
*aCtx = nullptr; *aDrawTarget = nullptr;
return NS_OK; return NS_OK;
} }
nsresult nsresult
PluginPRLibrary::EndUpdateBackground(NPP instance, PluginPRLibrary::EndUpdateBackground(NPP instance, const nsIntRect&)
gfxContext*, const nsIntRect&)
{ {
NS_RUNTIMEABORT("This should never be called"); NS_RUNTIMEABORT("This should never be called");
return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_AVAILABLE;

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

@ -117,10 +117,10 @@ public:
virtual nsresult ContentsScaleFactorChanged(NPP aInstance, double aContentsScaleFactor) override; virtual nsresult ContentsScaleFactorChanged(NPP aInstance, double aContentsScaleFactor) override;
#endif #endif
virtual nsresult SetBackgroundUnknown(NPP instance) override; virtual nsresult SetBackgroundUnknown(NPP instance) override;
virtual nsresult BeginUpdateBackground(NPP instance, virtual nsresult BeginUpdateBackground(NPP instance, const nsIntRect&,
const nsIntRect&, gfxContext** aCtx) override; DrawTarget** aDrawTarget) override;
virtual nsresult EndUpdateBackground(NPP instance, virtual nsresult EndUpdateBackground(NPP instance,
gfxContext* aCtx, const nsIntRect&) override; const nsIntRect&) override;
virtual void DidComposite(NPP aInstance) override { } virtual void DidComposite(NPP aInstance) override { }
virtual void GetLibraryPath(nsACString& aPath) { aPath.Assign(mFilePath); } virtual void GetLibraryPath(nsACString& aPath) { aPath.Assign(mFilePath); }
virtual nsresult GetRunID(uint32_t* aRunID) override { return NS_ERROR_NOT_IMPLEMENTED; } virtual nsresult GetRunID(uint32_t* aRunID) override { return NS_ERROR_NOT_IMPLEMENTED; }

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

@ -1250,7 +1250,7 @@ nsNPAPIPluginInstance::SetBackgroundUnknown()
nsresult nsresult
nsNPAPIPluginInstance::BeginUpdateBackground(nsIntRect* aRect, nsNPAPIPluginInstance::BeginUpdateBackground(nsIntRect* aRect,
gfxContext** aContext) DrawTarget** aDrawTarget)
{ {
if (RUNNING != mRunning) if (RUNNING != mRunning)
return NS_OK; return NS_OK;
@ -1259,12 +1259,11 @@ nsNPAPIPluginInstance::BeginUpdateBackground(nsIntRect* aRect,
if (!library) if (!library)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
return library->BeginUpdateBackground(&mNPP, *aRect, aContext); return library->BeginUpdateBackground(&mNPP, *aRect, aDrawTarget);
} }
nsresult nsresult
nsNPAPIPluginInstance::EndUpdateBackground(gfxContext* aContext, nsNPAPIPluginInstance::EndUpdateBackground(nsIntRect* aRect)
nsIntRect* aRect)
{ {
if (RUNNING != mRunning) if (RUNNING != mRunning)
return NS_OK; return NS_OK;
@ -1273,7 +1272,7 @@ nsNPAPIPluginInstance::EndUpdateBackground(gfxContext* aContext,
if (!library) if (!library)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
return library->EndUpdateBackground(&mNPP, aContext, *aRect); return library->EndUpdateBackground(&mNPP, *aRect);
} }
nsresult nsresult

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

@ -83,6 +83,8 @@ private:
typedef mozilla::PluginLibrary PluginLibrary; typedef mozilla::PluginLibrary PluginLibrary;
public: public:
typedef mozilla::gfx::DrawTarget DrawTarget;
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(nsNPAPIPluginInstance) MOZ_DECLARE_WEAKREFERENCE_TYPENAME(nsNPAPIPluginInstance)
NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIAUDIOCHANNELAGENTCALLBACK NS_DECL_NSIAUDIOCHANNELAGENTCALLBACK
@ -108,8 +110,8 @@ public:
nsresult NotifyPainted(void); nsresult NotifyPainted(void);
nsresult GetIsOOP(bool* aIsOOP); nsresult GetIsOOP(bool* aIsOOP);
nsresult SetBackgroundUnknown(); nsresult SetBackgroundUnknown();
nsresult BeginUpdateBackground(nsIntRect* aRect, gfxContext** aContext); nsresult BeginUpdateBackground(nsIntRect* aRect, DrawTarget** aContext);
nsresult EndUpdateBackground(gfxContext* aContext, nsIntRect* aRect); nsresult EndUpdateBackground(nsIntRect* aRect);
nsresult IsTransparent(bool* isTransparent); nsresult IsTransparent(bool* isTransparent);
nsresult GetFormValue(nsAString& aValue); nsresult GetFormValue(nsAString& aValue);
nsresult PushPopupsEnabledState(bool aEnabled); nsresult PushPopupsEnabledState(bool aEnabled);

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

@ -268,25 +268,24 @@ nsPluginInstanceOwner::SetBackgroundUnknown()
} }
} }
already_AddRefed<gfxContext> already_AddRefed<mozilla::gfx::DrawTarget>
nsPluginInstanceOwner::BeginUpdateBackground(const nsIntRect& aRect) nsPluginInstanceOwner::BeginUpdateBackground(const nsIntRect& aRect)
{ {
nsIntRect rect = aRect; nsIntRect rect = aRect;
RefPtr<gfxContext> ctx; RefPtr<DrawTarget> dt;
if (mInstance && if (mInstance &&
NS_SUCCEEDED(mInstance->BeginUpdateBackground(&rect, getter_AddRefs(ctx)))) { NS_SUCCEEDED(mInstance->BeginUpdateBackground(&rect, getter_AddRefs(dt)))) {
return ctx.forget(); return dt.forget();
} }
return nullptr; return nullptr;
} }
void void
nsPluginInstanceOwner::EndUpdateBackground(gfxContext* aContext, nsPluginInstanceOwner::EndUpdateBackground(const nsIntRect& aRect)
const nsIntRect& aRect)
{ {
nsIntRect rect = aRect; nsIntRect rect = aRect;
if (mInstance) { if (mInstance) {
mInstance->EndUpdateBackground(aContext, &rect); mInstance->EndUpdateBackground(&rect);
} }
} }

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

@ -28,6 +28,10 @@ class nsPluginDOMContextMenuListener;
class nsPluginFrame; class nsPluginFrame;
class nsDisplayListBuilder; class nsDisplayListBuilder;
#if defined(MOZ_X11) || defined(ANDROID)
class gfxContext;
#endif
namespace mozilla { namespace mozilla {
class TextComposition; class TextComposition;
namespace dom { namespace dom {
@ -54,6 +58,8 @@ class nsPluginInstanceOwner final : public nsIPluginInstanceOwner,
public nsSupportsWeakReference public nsSupportsWeakReference
{ {
public: public:
typedef mozilla::gfx::DrawTarget DrawTarget;
nsPluginInstanceOwner(); nsPluginInstanceOwner();
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
@ -236,9 +242,9 @@ public:
// The eventual target of these operations is PluginInstanceParent, // The eventual target of these operations is PluginInstanceParent,
// but it takes several hops to get there. // but it takes several hops to get there.
void SetBackgroundUnknown(); void SetBackgroundUnknown();
already_AddRefed<gfxContext> BeginUpdateBackground(const nsIntRect& aRect); already_AddRefed<DrawTarget> BeginUpdateBackground(const nsIntRect& aRect);
void EndUpdateBackground(gfxContext* aContext, const nsIntRect& aRect); void EndUpdateBackground(const nsIntRect& aRect);
bool UseAsyncRendering(); bool UseAsyncRendering();
already_AddRefed<nsIURI> GetBaseURI() const; already_AddRefed<nsIURI> GetBaseURI() const;

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

@ -1130,7 +1130,7 @@ PluginInstanceParent::SetBackgroundUnknown()
nsresult nsresult
PluginInstanceParent::BeginUpdateBackground(const nsIntRect& aRect, PluginInstanceParent::BeginUpdateBackground(const nsIntRect& aRect,
gfxContext** aCtx) DrawTarget** aDrawTarget)
{ {
PLUGIN_LOG_DEBUG( PLUGIN_LOG_DEBUG(
("[InstanceParent][%p] BeginUpdateBackground for <x=%d,y=%d, w=%d,h=%d>", ("[InstanceParent][%p] BeginUpdateBackground for <x=%d,y=%d, w=%d,h=%d>",
@ -1144,7 +1144,7 @@ PluginInstanceParent::BeginUpdateBackground(const nsIntRect& aRect,
MOZ_ASSERT(aRect.TopLeft() == nsIntPoint(0, 0), MOZ_ASSERT(aRect.TopLeft() == nsIntPoint(0, 0),
"Expecting rect for whole frame"); "Expecting rect for whole frame");
if (!CreateBackground(aRect.Size())) { if (!CreateBackground(aRect.Size())) {
*aCtx = nullptr; *aDrawTarget = nullptr;
return NS_OK; return NS_OK;
} }
} }
@ -1157,15 +1157,13 @@ PluginInstanceParent::BeginUpdateBackground(const nsIntRect& aRect,
RefPtr<gfx::DrawTarget> dt = gfxPlatform::GetPlatform()-> RefPtr<gfx::DrawTarget> dt = gfxPlatform::GetPlatform()->
CreateDrawTargetForSurface(mBackground, gfx::IntSize(sz.width, sz.height)); CreateDrawTargetForSurface(mBackground, gfx::IntSize(sz.width, sz.height));
RefPtr<gfxContext> ctx = new gfxContext(dt); dt.forget(aDrawTarget);
ctx.forget(aCtx);
return NS_OK; return NS_OK;
} }
nsresult nsresult
PluginInstanceParent::EndUpdateBackground(gfxContext* aCtx, PluginInstanceParent::EndUpdateBackground(const nsIntRect& aRect)
const nsIntRect& aRect)
{ {
PLUGIN_LOG_DEBUG( PLUGIN_LOG_DEBUG(
("[InstanceParent][%p] EndUpdateBackground for <x=%d,y=%d, w=%d,h=%d>", ("[InstanceParent][%p] EndUpdateBackground for <x=%d,y=%d, w=%d,h=%d>",

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

@ -60,6 +60,8 @@ public:
#endif // defined(XP_WIN) #endif // defined(XP_WIN)
public: public:
typedef mozilla::gfx::DrawTarget DrawTarget;
PluginInstanceParent(PluginModuleParent* parent, PluginInstanceParent(PluginModuleParent* parent,
NPP npp, NPP npp,
const nsCString& mimeType, const nsCString& mimeType,
@ -338,9 +340,8 @@ public:
#endif #endif
nsresult SetBackgroundUnknown(); nsresult SetBackgroundUnknown();
nsresult BeginUpdateBackground(const nsIntRect& aRect, nsresult BeginUpdateBackground(const nsIntRect& aRect,
gfxContext** aCtx); DrawTarget** aDrawTarget);
nsresult EndUpdateBackground(gfxContext* aCtx, nsresult EndUpdateBackground(const nsIntRect& aRect);
const nsIntRect& aRect);
void DidComposite(); void DidComposite();
bool IsUsingDirectDrawing(); bool IsUsingDirectDrawing();

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

@ -17,11 +17,13 @@
#include "nsSize.h" #include "nsSize.h"
#include "nsRect.h" #include "nsRect.h"
class gfxContext;
class nsCString; class nsCString;
class nsNPAPIPlugin; class nsNPAPIPlugin;
namespace mozilla { namespace mozilla {
namespace gfx {
class DrawTarget;
}
namespace layers { namespace layers {
class Image; class Image;
class ImageContainer; class ImageContainer;
@ -43,6 +45,8 @@ namespace mozilla {
class PluginLibrary class PluginLibrary
{ {
public: public:
typedef mozilla::gfx::DrawTarget DrawTarget;
virtual ~PluginLibrary() { } virtual ~PluginLibrary() { }
/** /**
@ -91,14 +95,12 @@ public:
*/ */
virtual nsresult SetBackgroundUnknown(NPP instance) = 0; virtual nsresult SetBackgroundUnknown(NPP instance) = 0;
virtual nsresult BeginUpdateBackground(NPP instance, virtual nsresult BeginUpdateBackground(NPP instance,
const nsIntRect&, gfxContext**) = 0; const nsIntRect&, DrawTarget**) = 0;
virtual nsresult EndUpdateBackground(NPP instance, virtual nsresult EndUpdateBackground(NPP instance, const nsIntRect&) = 0;
gfxContext*, const nsIntRect&) = 0;
virtual nsresult GetRunID(uint32_t* aRunID) = 0; virtual nsresult GetRunID(uint32_t* aRunID) = 0;
virtual void SetHasLocalInstance() = 0; virtual void SetHasLocalInstance() = 0;
}; };
} // namespace mozilla } // namespace mozilla
#endif // ifndef mozilla_PluginLibrary_h #endif // ifndef mozilla_PluginLibrary_h

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