mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 19:35:51 +00:00
Merge mozilla-inbound to m-c. a=merge
CLOSED TREE
This commit is contained in:
commit
be425949b5
@ -10,8 +10,10 @@
|
||||
#include "HyperTextAccessible.h"
|
||||
#include "nsMai.h"
|
||||
#include "nsMaiHyperlink.h"
|
||||
#include "ProxyAccessible.h"
|
||||
#include "mozilla/Likely.h"
|
||||
|
||||
|
||||
using namespace mozilla::a11y;
|
||||
|
||||
extern "C" {
|
||||
@ -20,49 +22,69 @@ static AtkHyperlink*
|
||||
getLinkCB(AtkHypertext *aText, gint aLinkIndex)
|
||||
{
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||
if (!accWrap)
|
||||
return nullptr;
|
||||
|
||||
if (accWrap) {
|
||||
HyperTextAccessible* hyperText = accWrap->AsHyperText();
|
||||
NS_ENSURE_TRUE(hyperText, nullptr);
|
||||
|
||||
Accessible* hyperLink = hyperText->LinkAt(aLinkIndex);
|
||||
if (!hyperLink)
|
||||
if (!hyperLink) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AtkObject* hyperLinkAtkObj = AccessibleWrap::GetAtkObject(hyperLink);
|
||||
AccessibleWrap* accChild = GetAccessibleWrap(hyperLinkAtkObj);
|
||||
NS_ENSURE_TRUE(accChild, nullptr);
|
||||
|
||||
MaiHyperlink *maiHyperlink = accChild->GetMaiHyperlink();
|
||||
MaiHyperlink* maiHyperlink = accChild->GetMaiHyperlink();
|
||||
NS_ENSURE_TRUE(maiHyperlink, nullptr);
|
||||
return maiHyperlink->GetAtkHyperlink();
|
||||
}
|
||||
|
||||
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||
ProxyAccessible* proxyLink = proxy->LinkAt(aLinkIndex);
|
||||
if (proxyLink) {
|
||||
NS_WARNING("IMPLEMENT ME! See bug 1146518.");
|
||||
// We should somehow get from ProxyAccessible* to AtkHyperlink*.
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static gint
|
||||
getLinkCountCB(AtkHypertext *aText)
|
||||
{
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||
if (!accWrap)
|
||||
return -1;
|
||||
|
||||
if (accWrap) {
|
||||
HyperTextAccessible* hyperText = accWrap->AsHyperText();
|
||||
NS_ENSURE_TRUE(hyperText, -1);
|
||||
|
||||
return hyperText->LinkCount();
|
||||
}
|
||||
|
||||
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||
return proxy->LinkCount();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static gint
|
||||
getLinkIndexCB(AtkHypertext *aText, gint aCharIndex)
|
||||
{
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
|
||||
if (!accWrap)
|
||||
return -1;
|
||||
|
||||
if (accWrap) {
|
||||
HyperTextAccessible* hyperText = accWrap->AsHyperText();
|
||||
NS_ENSURE_TRUE(hyperText, -1);
|
||||
|
||||
return hyperText->LinkIndexAtOffset(aCharIndex);
|
||||
}
|
||||
|
||||
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||
return proxy->LinkIndexAtOffset(aCharIndex);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "Accessible-inl.h"
|
||||
#include "AccessibleWrap.h"
|
||||
#include "nsMai.h"
|
||||
#include "ProxyAccessible.h"
|
||||
#include "mozilla/Likely.h"
|
||||
|
||||
#include <atk/atk.h>
|
||||
@ -21,36 +22,54 @@ static gboolean
|
||||
addSelectionCB(AtkSelection *aSelection, gint i)
|
||||
{
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
|
||||
if (!accWrap || !accWrap->IsSelect())
|
||||
return FALSE;
|
||||
|
||||
if (accWrap && accWrap->IsSelect()) {
|
||||
return accWrap->AddItemToSelection(i);
|
||||
}
|
||||
|
||||
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
|
||||
return proxy->AddItemToSelection(i);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clearSelectionCB(AtkSelection *aSelection)
|
||||
{
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
|
||||
if (!accWrap || !accWrap->IsSelect())
|
||||
return FALSE;
|
||||
|
||||
if (accWrap && accWrap->IsSelect()) {
|
||||
return accWrap->UnselectAll();
|
||||
}
|
||||
|
||||
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
|
||||
return proxy->UnselectAll();
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static AtkObject*
|
||||
refSelectionCB(AtkSelection *aSelection, gint i)
|
||||
{
|
||||
AtkObject* atkObj = nullptr;
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
|
||||
if (!accWrap || !accWrap->IsSelect())
|
||||
return nullptr;
|
||||
|
||||
if (accWrap && accWrap->IsSelect()) {
|
||||
Accessible* selectedItem = accWrap->GetSelectedItem(i);
|
||||
if (!selectedItem)
|
||||
if (!selectedItem) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AtkObject* atkObj = AccessibleWrap::GetAtkObject(selectedItem);
|
||||
if (atkObj)
|
||||
atkObj = AccessibleWrap::GetAtkObject(selectedItem);
|
||||
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
|
||||
ProxyAccessible* selectedItem = proxy->GetSelectedItem(i);
|
||||
if (selectedItem) {
|
||||
atkObj = GetWrapperFor(selectedItem);
|
||||
}
|
||||
}
|
||||
|
||||
if (atkObj) {
|
||||
g_object_ref(atkObj);
|
||||
}
|
||||
|
||||
return atkObj;
|
||||
}
|
||||
@ -59,40 +78,60 @@ static gint
|
||||
getSelectionCountCB(AtkSelection *aSelection)
|
||||
{
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
|
||||
if (!accWrap || !accWrap->IsSelect())
|
||||
return -1;
|
||||
|
||||
if (accWrap && accWrap->IsSelect()) {
|
||||
return accWrap->SelectedItemCount();
|
||||
}
|
||||
|
||||
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
|
||||
return proxy->SelectedItemCount();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
isChildSelectedCB(AtkSelection *aSelection, gint i)
|
||||
{
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
|
||||
if (!accWrap || !accWrap->IsSelect())
|
||||
return FALSE;
|
||||
|
||||
if (accWrap && accWrap->IsSelect()) {
|
||||
return accWrap->IsItemSelected(i);
|
||||
}
|
||||
|
||||
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
|
||||
return proxy->IsItemSelected(i);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
removeSelectionCB(AtkSelection *aSelection, gint i)
|
||||
{
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
|
||||
if (!accWrap || !accWrap->IsSelect())
|
||||
return FALSE;
|
||||
|
||||
if (accWrap && accWrap->IsSelect()) {
|
||||
return accWrap->RemoveItemFromSelection(i);
|
||||
}
|
||||
|
||||
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
|
||||
return proxy->RemoveItemFromSelection(i);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
selectAllSelectionCB(AtkSelection *aSelection)
|
||||
{
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
|
||||
if (!accWrap || !accWrap->IsSelect())
|
||||
return FALSE;
|
||||
|
||||
if (accWrap && accWrap->IsSelect()) {
|
||||
return accWrap->SelectAll();
|
||||
}
|
||||
|
||||
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
|
||||
return proxy->SelectAll();
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,34 +314,28 @@ HTMLTableHeaderCellAccessible::NativeRole()
|
||||
return roles::ROWHEADER;
|
||||
}
|
||||
|
||||
// Assume it's columnheader if there are headers in siblings, otherwise
|
||||
// rowheader.
|
||||
// This should iterate the flattened tree
|
||||
nsIContent* parentContent = mContent->GetParent();
|
||||
if (!parentContent) {
|
||||
NS_ERROR("Deattached content on alive accessible?");
|
||||
TableAccessible* table = Table();
|
||||
if (!table)
|
||||
return roles::NOTHING;
|
||||
}
|
||||
|
||||
for (nsIContent* siblingContent = mContent->GetPreviousSibling(); siblingContent;
|
||||
siblingContent = siblingContent->GetPreviousSibling()) {
|
||||
if (siblingContent->IsElement()) {
|
||||
return nsCoreUtils::IsHTMLTableHeader(siblingContent) ?
|
||||
roles::COLUMNHEADER : roles::ROWHEADER;
|
||||
}
|
||||
}
|
||||
// If the cell next to this one is not a header cell then assume this cell is
|
||||
// a row header for it.
|
||||
uint32_t rowIdx = RowIdx(), colIdx = ColIdx();
|
||||
Accessible* cell = table->CellAt(rowIdx, colIdx + ColExtent());
|
||||
if (cell && !nsCoreUtils::IsHTMLTableHeader(cell->GetContent()))
|
||||
return roles::ROWHEADER;
|
||||
|
||||
for (nsIContent* siblingContent = mContent->GetNextSibling(); siblingContent;
|
||||
siblingContent = siblingContent->GetNextSibling()) {
|
||||
if (siblingContent->IsElement()) {
|
||||
return nsCoreUtils::IsHTMLTableHeader(siblingContent) ?
|
||||
roles::COLUMNHEADER : roles::ROWHEADER;
|
||||
}
|
||||
}
|
||||
|
||||
// No elements in siblings what means the table has one column only. Therefore
|
||||
// it should be column header.
|
||||
// If the cell below this one is not a header cell then assume this cell is
|
||||
// a column header for it.
|
||||
uint32_t rowExtent = RowExtent();
|
||||
cell = table->CellAt(rowIdx + rowExtent, colIdx);
|
||||
if (cell && !nsCoreUtils::IsHTMLTableHeader(cell->GetContent()))
|
||||
return roles::COLUMNHEADER;
|
||||
|
||||
// Otherwise if this cell is surrounded by header cells only then make a guess
|
||||
// based on its cell spanning. In other words if it is row spanned then assume
|
||||
// it's a row header, otherwise it's a column header.
|
||||
return rowExtent > 1 ? roles::ROWHEADER : roles::COLUMNHEADER;
|
||||
}
|
||||
|
||||
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "Relation.h"
|
||||
#include "HyperTextAccessible-inl.h"
|
||||
#include "ImageAccessible.h"
|
||||
#include "TableAccessible.h"
|
||||
#include "TableCellAccessible.h"
|
||||
#include "nsIPersistentProperties2.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
|
||||
@ -52,12 +54,25 @@ DocAccessibleChild::IdToAccessible(const uint64_t& aID) const
|
||||
return mDoc->GetAccessibleByUniqueID(reinterpret_cast<void*>(aID));
|
||||
}
|
||||
|
||||
Accessible*
|
||||
DocAccessibleChild::IdToAccessibleLink(const uint64_t& aID) const
|
||||
{
|
||||
Accessible* acc = IdToAccessible(aID);
|
||||
return acc && acc->IsLink() ? acc : nullptr;
|
||||
}
|
||||
|
||||
Accessible*
|
||||
DocAccessibleChild::IdToAccessibleSelect(const uint64_t& aID) const
|
||||
{
|
||||
Accessible* acc = IdToAccessible(aID);
|
||||
return acc && acc->IsSelect() ? acc : nullptr;
|
||||
}
|
||||
|
||||
HyperTextAccessible*
|
||||
DocAccessibleChild::IdToHyperTextAccessible(const uint64_t& aID) const
|
||||
{
|
||||
Accessible* acc = IdToAccessible(aID);
|
||||
MOZ_ASSERT(!acc || acc->IsHyperText());
|
||||
return acc ? acc->AsHyperText() : nullptr;
|
||||
return acc && acc->IsHyperText() ? acc->AsHyperText() : nullptr;
|
||||
}
|
||||
|
||||
ImageAccessible*
|
||||
@ -67,6 +82,20 @@ DocAccessibleChild::IdToImageAccessible(const uint64_t& aID) const
|
||||
return (acc && acc->IsImage()) ? acc->AsImage() : nullptr;
|
||||
}
|
||||
|
||||
TableCellAccessible*
|
||||
DocAccessibleChild::IdToTableCellAccessible(const uint64_t& aID) const
|
||||
{
|
||||
Accessible* acc = IdToAccessible(aID);
|
||||
return (acc && acc->IsTableCell()) ? acc->AsTableCell() : nullptr;
|
||||
}
|
||||
|
||||
TableAccessible*
|
||||
DocAccessibleChild::IdToTableAccessible(const uint64_t& aID) const
|
||||
{
|
||||
Accessible* acc = IdToAccessible(aID);
|
||||
return (acc && acc->IsTable()) ? acc->AsTable() : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
DocAccessibleChild::ShowEvent(AccShowEvent* aShowEvent)
|
||||
{
|
||||
@ -618,5 +647,788 @@ DocAccessibleChild::RecvImageSize(const uint64_t& aID,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvStartOffset(const uint64_t& aID,
|
||||
uint32_t* aRetVal,
|
||||
bool* aOk)
|
||||
{
|
||||
Accessible* acc = IdToAccessibleLink(aID);
|
||||
if (acc) {
|
||||
*aRetVal = acc->StartOffset();
|
||||
*aOk = true;
|
||||
} else {
|
||||
*aRetVal = 0;
|
||||
*aOk = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvEndOffset(const uint64_t& aID,
|
||||
uint32_t* aRetVal,
|
||||
bool* aOk)
|
||||
{
|
||||
Accessible* acc = IdToAccessibleLink(aID);
|
||||
if (acc) {
|
||||
*aRetVal = acc->EndOffset();
|
||||
*aOk = true;
|
||||
} else {
|
||||
*aRetVal = 0;
|
||||
*aOk = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvIsLinkValid(const uint64_t& aID,
|
||||
bool* aRetVal)
|
||||
{
|
||||
Accessible* acc = IdToAccessibleLink(aID);
|
||||
if (acc) {
|
||||
*aRetVal = acc->IsLinkValid();
|
||||
} else {
|
||||
*aRetVal = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvAnchorCount(const uint64_t& aID,
|
||||
uint32_t* aRetVal,
|
||||
bool* aOk)
|
||||
{
|
||||
Accessible* acc = IdToAccessibleLink(aID);
|
||||
if (acc) {
|
||||
*aRetVal = acc->AnchorCount();
|
||||
*aOk = true;
|
||||
} else {
|
||||
*aRetVal = 0;
|
||||
*aOk = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvAnchorURIAt(const uint64_t& aID,
|
||||
const uint32_t& aIndex,
|
||||
nsCString* aURI,
|
||||
bool* aOk)
|
||||
{
|
||||
Accessible* acc = IdToAccessibleLink(aID);
|
||||
*aOk = false;
|
||||
if (acc) {
|
||||
nsCOMPtr<nsIURI> uri = acc->AnchorURIAt(aIndex);
|
||||
if (uri) {
|
||||
uri->GetSpec(*aURI);
|
||||
*aOk = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvAnchorAt(const uint64_t& aID,
|
||||
const uint32_t& aIndex,
|
||||
uint64_t* aIDOfAnchor,
|
||||
bool* aOk)
|
||||
{
|
||||
*aIDOfAnchor = 0;
|
||||
*aOk = false;
|
||||
Accessible* acc = IdToAccessibleLink(aID);
|
||||
if (acc) {
|
||||
Accessible* anchor = acc->AnchorAt(aIndex);
|
||||
if (anchor) {
|
||||
*aIDOfAnchor = reinterpret_cast<uint64_t>(anchor->UniqueID());
|
||||
*aOk = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvLinkCount(const uint64_t& aID,
|
||||
uint32_t* aCount)
|
||||
{
|
||||
HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
|
||||
*aCount = acc ? acc->LinkCount() : 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvLinkAt(const uint64_t& aID,
|
||||
const uint32_t& aIndex,
|
||||
uint64_t* aIDOfLink,
|
||||
bool* aOk)
|
||||
{
|
||||
*aIDOfLink = 0;
|
||||
*aOk = false;
|
||||
HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
|
||||
if (acc) {
|
||||
Accessible* link = acc->LinkAt(aIndex);
|
||||
if (link) {
|
||||
*aIDOfLink = reinterpret_cast<uint64_t>(link->UniqueID());
|
||||
*aOk = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvLinkIndexOf(const uint64_t& aID,
|
||||
const uint64_t& aLinkID,
|
||||
int32_t* aIndex)
|
||||
{
|
||||
HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
|
||||
Accessible* link = IdToAccessible(aLinkID);
|
||||
*aIndex = -1;
|
||||
if (acc && link) {
|
||||
*aIndex = acc->LinkIndexOf(link);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvLinkIndexAtOffset(const uint64_t& aID,
|
||||
const uint32_t& aOffset,
|
||||
int32_t* aIndex)
|
||||
{
|
||||
HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
|
||||
*aIndex = acc ? acc->LinkIndexAtOffset(aOffset) : -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableOfACell(const uint64_t& aID,
|
||||
uint64_t* aTableID,
|
||||
bool* aOk)
|
||||
{
|
||||
*aTableID = 0;
|
||||
*aOk = false;
|
||||
TableCellAccessible* acc = IdToTableCellAccessible(aID);
|
||||
if (acc) {
|
||||
TableAccessible* table = acc->Table();
|
||||
if (table) {
|
||||
*aTableID = reinterpret_cast<uint64_t>(table->AsAccessible()->UniqueID());
|
||||
*aOk = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvColIdx(const uint64_t& aID,
|
||||
uint32_t* aIndex)
|
||||
{
|
||||
*aIndex = 0;
|
||||
TableCellAccessible* acc = IdToTableCellAccessible(aID);
|
||||
if (acc) {
|
||||
*aIndex = acc->ColIdx();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvRowIdx(const uint64_t& aID,
|
||||
uint32_t* aIndex)
|
||||
{
|
||||
*aIndex = 0;
|
||||
TableCellAccessible* acc = IdToTableCellAccessible(aID);
|
||||
if (acc) {
|
||||
*aIndex = acc->RowIdx();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvColExtent(const uint64_t& aID,
|
||||
uint32_t* aExtent)
|
||||
{
|
||||
*aExtent = 0;
|
||||
TableCellAccessible* acc = IdToTableCellAccessible(aID);
|
||||
if (acc) {
|
||||
*aExtent = acc->ColExtent();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvRowExtent(const uint64_t& aID,
|
||||
uint32_t* aExtent)
|
||||
{
|
||||
*aExtent = 0;
|
||||
TableCellAccessible* acc = IdToTableCellAccessible(aID);
|
||||
if (acc) {
|
||||
*aExtent = acc->RowExtent();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvColHeaderCells(const uint64_t& aID,
|
||||
nsTArray<uint64_t>* aCells)
|
||||
{
|
||||
TableCellAccessible* acc = IdToTableCellAccessible(aID);
|
||||
if (acc) {
|
||||
nsAutoTArray<Accessible*, 10> headerCells;
|
||||
acc->ColHeaderCells(&headerCells);
|
||||
aCells->SetCapacity(headerCells.Length());
|
||||
for (uint32_t i = 0; i < headerCells.Length(); ++i) {
|
||||
aCells->AppendElement(
|
||||
reinterpret_cast<uint64_t>(headerCells[i]->UniqueID()));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvRowHeaderCells(const uint64_t& aID,
|
||||
nsTArray<uint64_t>* aCells)
|
||||
{
|
||||
TableCellAccessible* acc = IdToTableCellAccessible(aID);
|
||||
if (acc) {
|
||||
nsAutoTArray<Accessible*, 10> headerCells;
|
||||
acc->RowHeaderCells(&headerCells);
|
||||
aCells->SetCapacity(headerCells.Length());
|
||||
for (uint32_t i = 0; i < headerCells.Length(); ++i) {
|
||||
aCells->AppendElement(
|
||||
reinterpret_cast<uint64_t>(headerCells[i]->UniqueID()));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvIsCellSelected(const uint64_t& aID,
|
||||
bool* aSelected)
|
||||
{
|
||||
TableCellAccessible* acc = IdToTableCellAccessible(aID);
|
||||
*aSelected = acc && acc->Selected();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableCaption(const uint64_t& aID,
|
||||
uint64_t* aCaptionID,
|
||||
bool* aOk)
|
||||
{
|
||||
*aCaptionID = 0;
|
||||
*aOk = false;
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
Accessible* caption = acc->Caption();
|
||||
if (caption) {
|
||||
*aCaptionID = reinterpret_cast<uint64_t>(caption->UniqueID());
|
||||
*aOk = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableSummary(const uint64_t& aID,
|
||||
nsString* aSummary)
|
||||
{
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
acc->Summary(*aSummary);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableColumnCount(const uint64_t& aID,
|
||||
uint32_t* aColCount)
|
||||
{
|
||||
*aColCount = 0;
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
*aColCount = acc->ColCount();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableRowCount(const uint64_t& aID,
|
||||
uint32_t* aRowCount)
|
||||
{
|
||||
*aRowCount = 0;
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
*aRowCount = acc->RowCount();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableCellAt(const uint64_t& aID,
|
||||
const uint32_t& aRow,
|
||||
const uint32_t& aCol,
|
||||
uint64_t* aCellID,
|
||||
bool* aOk)
|
||||
{
|
||||
*aCellID = 0;
|
||||
*aOk = false;
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
Accessible* cell = acc->CellAt(aRow, aCol);
|
||||
if (cell) {
|
||||
*aCellID = reinterpret_cast<uint64_t>(cell->UniqueID());
|
||||
*aOk = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableCellIndexAt(const uint64_t& aID,
|
||||
const uint32_t& aRow,
|
||||
const uint32_t& aCol,
|
||||
int32_t* aIndex)
|
||||
{
|
||||
*aIndex = -1;
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
*aIndex = acc->CellIndexAt(aRow, aCol);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableColumnIndexAt(const uint64_t& aID,
|
||||
const uint32_t& aCellIndex,
|
||||
int32_t* aCol)
|
||||
{
|
||||
*aCol = -1;
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
*aCol = acc->ColIndexAt(aCellIndex);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableRowIndexAt(const uint64_t& aID,
|
||||
const uint32_t& aCellIndex,
|
||||
int32_t* aRow)
|
||||
{
|
||||
*aRow = -1;
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
*aRow = acc->RowIndexAt(aCellIndex);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableRowAndColumnIndicesAt(const uint64_t& aID,
|
||||
const uint32_t& aCellIndex,
|
||||
int32_t* aRow,
|
||||
int32_t* aCol)
|
||||
{
|
||||
*aRow = -1;
|
||||
*aCol = -1;
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
acc->RowAndColIndicesAt(aCellIndex, aRow, aCol);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableColumnExtentAt(const uint64_t& aID,
|
||||
const uint32_t& aRow,
|
||||
const uint32_t& aCol,
|
||||
uint32_t* aExtent)
|
||||
{
|
||||
*aExtent = 0;
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
*aExtent = acc->ColExtentAt(aRow, aCol);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableRowExtentAt(const uint64_t& aID,
|
||||
const uint32_t& aRow,
|
||||
const uint32_t& aCol,
|
||||
uint32_t* aExtent)
|
||||
{
|
||||
*aExtent = 0;
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
*aExtent = acc->RowExtentAt(aRow, aCol);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableColumnDescription(const uint64_t& aID,
|
||||
const uint32_t& aCol,
|
||||
nsString* aDescription)
|
||||
{
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
acc->ColDescription(aCol, *aDescription);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableRowDescription(const uint64_t& aID,
|
||||
const uint32_t& aRow,
|
||||
nsString* aDescription)
|
||||
{
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
acc->RowDescription(aRow, *aDescription);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableColumnSelected(const uint64_t& aID,
|
||||
const uint32_t& aCol,
|
||||
bool* aSelected)
|
||||
{
|
||||
*aSelected = false;
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
*aSelected = acc->IsColSelected(aCol);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableRowSelected(const uint64_t& aID,
|
||||
const uint32_t& aRow,
|
||||
bool* aSelected)
|
||||
{
|
||||
*aSelected = false;
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
*aSelected = acc->IsRowSelected(aRow);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableCellSelected(const uint64_t& aID,
|
||||
const uint32_t& aRow,
|
||||
const uint32_t& aCol,
|
||||
bool* aSelected)
|
||||
{
|
||||
*aSelected = false;
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
*aSelected = acc->IsCellSelected(aRow, aCol);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableSelectedCellCount(const uint64_t& aID,
|
||||
uint32_t* aSelectedCells)
|
||||
{
|
||||
*aSelectedCells = 0;
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
*aSelectedCells = acc->SelectedCellCount();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableSelectedColumnCount(const uint64_t& aID,
|
||||
uint32_t* aSelectedColumns)
|
||||
{
|
||||
*aSelectedColumns = 0;
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
*aSelectedColumns = acc->SelectedColCount();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableSelectedRowCount(const uint64_t& aID,
|
||||
uint32_t* aSelectedRows)
|
||||
{
|
||||
*aSelectedRows = 0;
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
*aSelectedRows = acc->SelectedRowCount();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableSelectedCells(const uint64_t& aID,
|
||||
nsTArray<uint64_t>* aCellIDs)
|
||||
{
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
nsAutoTArray<Accessible*, 30> cells;
|
||||
acc->SelectedCells(&cells);
|
||||
aCellIDs->SetCapacity(cells.Length());
|
||||
for (uint32_t i = 0; i < cells.Length(); ++i) {
|
||||
aCellIDs->AppendElement(
|
||||
reinterpret_cast<uint64_t>(cells[i]->UniqueID()));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableSelectedCellIndices(const uint64_t& aID,
|
||||
nsTArray<uint32_t>* aCellIndices)
|
||||
{
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
acc->SelectedCellIndices(aCellIndices);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableSelectedColumnIndices(const uint64_t& aID,
|
||||
nsTArray<uint32_t>* aColumnIndices)
|
||||
{
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
acc->SelectedColIndices(aColumnIndices);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableSelectedRowIndices(const uint64_t& aID,
|
||||
nsTArray<uint32_t>* aRowIndices)
|
||||
{
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
acc->SelectedRowIndices(aRowIndices);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableSelectColumn(const uint64_t& aID,
|
||||
const uint32_t& aCol)
|
||||
{
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
acc->SelectCol(aCol);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableSelectRow(const uint64_t& aID,
|
||||
const uint32_t& aRow)
|
||||
{
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
acc->SelectRow(aRow);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableUnselectColumn(const uint64_t& aID,
|
||||
const uint32_t& aCol)
|
||||
{
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
acc->UnselectCol(aCol);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableUnselectRow(const uint64_t& aID,
|
||||
const uint32_t& aRow)
|
||||
{
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
acc->UnselectRow(aRow);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTableIsProbablyForLayout(const uint64_t& aID,
|
||||
bool* aForLayout)
|
||||
{
|
||||
*aForLayout = false;
|
||||
TableAccessible* acc = IdToTableAccessible(aID);
|
||||
if (acc) {
|
||||
*aForLayout = acc->IsProbablyLayoutTable();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvSelectedItems(const uint64_t& aID,
|
||||
nsTArray<uint64_t>* aSelectedItemIDs)
|
||||
{
|
||||
Accessible* acc = IdToAccessibleSelect(aID);
|
||||
if (acc) {
|
||||
nsAutoTArray<Accessible*, 10> selectedItems;
|
||||
acc->SelectedItems(&selectedItems);
|
||||
aSelectedItemIDs->SetCapacity(selectedItems.Length());
|
||||
for (size_t i = 0; i < selectedItems.Length(); ++i) {
|
||||
aSelectedItemIDs->AppendElement(
|
||||
reinterpret_cast<uint64_t>(selectedItems[i]->UniqueID()));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvSelectedItemCount(const uint64_t& aID,
|
||||
uint32_t* aCount)
|
||||
{
|
||||
*aCount = 0;
|
||||
Accessible* acc = IdToAccessibleSelect(aID);
|
||||
if (acc) {
|
||||
*aCount = acc->SelectedItemCount();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvGetSelectedItem(const uint64_t& aID,
|
||||
const uint32_t& aIndex,
|
||||
uint64_t* aSelected,
|
||||
bool* aOk)
|
||||
{
|
||||
*aSelected = 0;
|
||||
*aOk = false;
|
||||
Accessible* acc = IdToAccessibleSelect(aID);
|
||||
if (acc) {
|
||||
Accessible* item = acc->GetSelectedItem(aIndex);
|
||||
if (item) {
|
||||
*aSelected = reinterpret_cast<uint64_t>(item->UniqueID());
|
||||
*aOk = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvIsItemSelected(const uint64_t& aID,
|
||||
const uint32_t& aIndex,
|
||||
bool* aSelected)
|
||||
{
|
||||
*aSelected = false;
|
||||
Accessible* acc = IdToAccessibleSelect(aID);
|
||||
if (acc) {
|
||||
*aSelected = acc->IsItemSelected(aIndex);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvAddItemToSelection(const uint64_t& aID,
|
||||
const uint32_t& aIndex,
|
||||
bool* aSuccess)
|
||||
{
|
||||
*aSuccess = false;
|
||||
Accessible* acc = IdToAccessibleSelect(aID);
|
||||
if (acc) {
|
||||
*aSuccess = acc->AddItemToSelection(aIndex);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvRemoveItemFromSelection(const uint64_t& aID,
|
||||
const uint32_t& aIndex,
|
||||
bool* aSuccess)
|
||||
{
|
||||
*aSuccess = false;
|
||||
Accessible* acc = IdToAccessibleSelect(aID);
|
||||
if (acc) {
|
||||
*aSuccess = acc->RemoveItemFromSelection(aIndex);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvSelectAll(const uint64_t& aID,
|
||||
bool* aSuccess)
|
||||
{
|
||||
*aSuccess = false;
|
||||
Accessible* acc = IdToAccessibleSelect(aID);
|
||||
if (acc) {
|
||||
*aSuccess = acc->SelectAll();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvUnselectAll(const uint64_t& aID,
|
||||
bool* aSuccess)
|
||||
{
|
||||
*aSuccess = false;
|
||||
Accessible* acc = IdToAccessibleSelect(aID);
|
||||
if (acc) {
|
||||
*aSuccess = acc->UnselectAll();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,8 @@ namespace a11y {
|
||||
class Accessible;
|
||||
class HyperTextAccessible;
|
||||
class ImageAccessible;
|
||||
|
||||
class TableAccessible;
|
||||
class TableCellAccessible;
|
||||
class AccShowEvent;
|
||||
|
||||
/*
|
||||
@ -189,11 +190,176 @@ public:
|
||||
virtual bool RecvImageSize(const uint64_t& aID,
|
||||
nsIntSize* aRetVal) override;
|
||||
|
||||
virtual bool RecvStartOffset(const uint64_t& aID,
|
||||
uint32_t* aRetVal,
|
||||
bool* aOk) override;
|
||||
virtual bool RecvEndOffset(const uint64_t& aID,
|
||||
uint32_t* aRetVal,
|
||||
bool* aOk) override;
|
||||
virtual bool RecvIsLinkValid(const uint64_t& aID,
|
||||
bool* aRetVal) override;
|
||||
virtual bool RecvAnchorCount(const uint64_t& aID,
|
||||
uint32_t* aRetVal, bool* aOk) override;
|
||||
virtual bool RecvAnchorURIAt(const uint64_t& aID,
|
||||
const uint32_t& aIndex,
|
||||
nsCString* aURI,
|
||||
bool* aOk) override;
|
||||
virtual bool RecvAnchorAt(const uint64_t& aID,
|
||||
const uint32_t& aIndex,
|
||||
uint64_t* aIDOfAnchor,
|
||||
bool* aOk) override;
|
||||
|
||||
virtual bool RecvLinkCount(const uint64_t& aID,
|
||||
uint32_t* aCount) override;
|
||||
|
||||
virtual bool RecvLinkAt(const uint64_t& aID,
|
||||
const uint32_t& aIndex,
|
||||
uint64_t* aIDOfLink,
|
||||
bool* aOk) override;
|
||||
|
||||
virtual bool RecvLinkIndexOf(const uint64_t& aID,
|
||||
const uint64_t& aLinkID,
|
||||
int32_t* aIndex) override;
|
||||
|
||||
virtual bool RecvLinkIndexAtOffset(const uint64_t& aID,
|
||||
const uint32_t& aOffset,
|
||||
int32_t* aIndex) override;
|
||||
|
||||
virtual bool RecvTableOfACell(const uint64_t& aID,
|
||||
uint64_t* aTableID,
|
||||
bool* aOk) override;
|
||||
|
||||
virtual bool RecvColIdx(const uint64_t& aID, uint32_t* aIndex) override;
|
||||
|
||||
virtual bool RecvRowIdx(const uint64_t& aID, uint32_t* aIndex) override;
|
||||
|
||||
virtual bool RecvColExtent(const uint64_t& aID, uint32_t* aExtent) override;
|
||||
|
||||
virtual bool RecvRowExtent(const uint64_t& aID, uint32_t* aExtent) override;
|
||||
|
||||
virtual bool RecvColHeaderCells(const uint64_t& aID,
|
||||
nsTArray<uint64_t>* aCells) override;
|
||||
|
||||
virtual bool RecvRowHeaderCells(const uint64_t& aID,
|
||||
nsTArray<uint64_t>* aCells) override;
|
||||
|
||||
virtual bool RecvIsCellSelected(const uint64_t& aID,
|
||||
bool* aSelected) override;
|
||||
|
||||
virtual bool RecvTableCaption(const uint64_t& aID,
|
||||
uint64_t* aCaptionID,
|
||||
bool* aOk) override;
|
||||
virtual bool RecvTableSummary(const uint64_t& aID,
|
||||
nsString* aSummary) override;
|
||||
virtual bool RecvTableColumnCount(const uint64_t& aID,
|
||||
uint32_t* aColCount) override;
|
||||
virtual bool RecvTableRowCount(const uint64_t& aID,
|
||||
uint32_t* aRowCount) override;
|
||||
virtual bool RecvTableCellAt(const uint64_t& aID,
|
||||
const uint32_t& aRow,
|
||||
const uint32_t& aCol,
|
||||
uint64_t* aCellID,
|
||||
bool* aOk) override;
|
||||
virtual bool RecvTableCellIndexAt(const uint64_t& aID,
|
||||
const uint32_t& aRow,
|
||||
const uint32_t& aCol,
|
||||
int32_t* aIndex) override;
|
||||
virtual bool RecvTableColumnIndexAt(const uint64_t& aID,
|
||||
const uint32_t& aCellIndex,
|
||||
int32_t* aCol) override;
|
||||
virtual bool RecvTableRowIndexAt(const uint64_t& aID,
|
||||
const uint32_t& aCellIndex,
|
||||
int32_t* aRow) override;
|
||||
virtual bool RecvTableRowAndColumnIndicesAt(const uint64_t& aID,
|
||||
const uint32_t& aCellIndex,
|
||||
int32_t* aRow,
|
||||
int32_t* aCol) override;
|
||||
virtual bool RecvTableColumnExtentAt(const uint64_t& aID,
|
||||
const uint32_t& aRow,
|
||||
const uint32_t& aCol,
|
||||
uint32_t* aExtent) override;
|
||||
virtual bool RecvTableRowExtentAt(const uint64_t& aID,
|
||||
const uint32_t& aRow,
|
||||
const uint32_t& aCol,
|
||||
uint32_t* aExtent) override;
|
||||
virtual bool RecvTableColumnDescription(const uint64_t& aID,
|
||||
const uint32_t& aCol,
|
||||
nsString* aDescription) override;
|
||||
virtual bool RecvTableRowDescription(const uint64_t& aID,
|
||||
const uint32_t& aRow,
|
||||
nsString* aDescription) override;
|
||||
virtual bool RecvTableColumnSelected(const uint64_t& aID,
|
||||
const uint32_t& aCol,
|
||||
bool* aSelected) override;
|
||||
virtual bool RecvTableRowSelected(const uint64_t& aID,
|
||||
const uint32_t& aRow,
|
||||
bool* aSelected) override;
|
||||
virtual bool RecvTableCellSelected(const uint64_t& aID,
|
||||
const uint32_t& aRow,
|
||||
const uint32_t& aCol,
|
||||
bool* aSelected) override;
|
||||
virtual bool RecvTableSelectedCellCount(const uint64_t& aID,
|
||||
uint32_t* aSelectedCells) override;
|
||||
virtual bool RecvTableSelectedColumnCount(const uint64_t& aID,
|
||||
uint32_t* aSelectedColumns) override;
|
||||
virtual bool RecvTableSelectedRowCount(const uint64_t& aID,
|
||||
uint32_t* aSelectedRows) override;
|
||||
virtual bool RecvTableSelectedCells(const uint64_t& aID,
|
||||
nsTArray<uint64_t>* aCellIDs) override;
|
||||
virtual bool RecvTableSelectedCellIndices(const uint64_t& aID,
|
||||
nsTArray<uint32_t>* aCellIndices) override;
|
||||
virtual bool RecvTableSelectedColumnIndices(const uint64_t& aID,
|
||||
nsTArray<uint32_t>* aColumnIndices) override;
|
||||
virtual bool RecvTableSelectedRowIndices(const uint64_t& aID,
|
||||
nsTArray<uint32_t>* aRowIndices) override;
|
||||
virtual bool RecvTableSelectColumn(const uint64_t& aID,
|
||||
const uint32_t& aCol) override;
|
||||
virtual bool RecvTableSelectRow(const uint64_t& aID,
|
||||
const uint32_t& aRow) override;
|
||||
virtual bool RecvTableUnselectColumn(const uint64_t& aID,
|
||||
const uint32_t& aCol) override;
|
||||
virtual bool RecvTableUnselectRow(const uint64_t& aID,
|
||||
const uint32_t& aRow) override;
|
||||
virtual bool RecvTableIsProbablyForLayout(const uint64_t& aID,
|
||||
bool* aForLayout) override;
|
||||
|
||||
virtual bool RecvSelectedItems(const uint64_t& aID,
|
||||
nsTArray<uint64_t>* aSelectedItemIDs) override;
|
||||
|
||||
virtual bool RecvSelectedItemCount(const uint64_t& aID,
|
||||
uint32_t* aCount) override;
|
||||
|
||||
virtual bool RecvGetSelectedItem(const uint64_t& aID,
|
||||
const uint32_t& aIndex,
|
||||
uint64_t* aSelected,
|
||||
bool* aOk) override;
|
||||
|
||||
virtual bool RecvIsItemSelected(const uint64_t& aID,
|
||||
const uint32_t& aIndex,
|
||||
bool* aSelected) override;
|
||||
|
||||
virtual bool RecvAddItemToSelection(const uint64_t& aID,
|
||||
const uint32_t& aIndex,
|
||||
bool* aSuccess) override;
|
||||
|
||||
virtual bool RecvRemoveItemFromSelection(const uint64_t& aID,
|
||||
const uint32_t& aIndex,
|
||||
bool* aSuccess) override;
|
||||
|
||||
virtual bool RecvSelectAll(const uint64_t& aID,
|
||||
bool* aSuccess) override;
|
||||
|
||||
virtual bool RecvUnselectAll(const uint64_t& aID,
|
||||
bool* aSuccess) override;
|
||||
private:
|
||||
|
||||
Accessible* IdToAccessible(const uint64_t& aID) const;
|
||||
Accessible* IdToAccessibleLink(const uint64_t& aID) const;
|
||||
Accessible* IdToAccessibleSelect(const uint64_t& aID) const;
|
||||
HyperTextAccessible* IdToHyperTextAccessible(const uint64_t& aID) const;
|
||||
ImageAccessible* IdToImageAccessible(const uint64_t& aID) const;
|
||||
TableCellAccessible* IdToTableCellAccessible(const uint64_t& aID) const;
|
||||
TableAccessible* IdToTableAccessible(const uint64_t& aID) const;
|
||||
|
||||
bool PersistentPropertiesToArray(nsIPersistentProperties* aProps,
|
||||
nsTArray<Attribute>* aAttributes);
|
||||
|
@ -132,6 +132,66 @@ child:
|
||||
|
||||
prio(high) sync ImagePosition(uint64_t aID, uint32_t aCoordType) returns(nsIntPoint aRetVal);
|
||||
prio(high) sync ImageSize(uint64_t aID) returns(nsIntSize aRetVal);
|
||||
|
||||
prio(high) sync StartOffset(uint64_t aID) returns(uint32_t aRetVal, bool aOk);
|
||||
prio(high) sync EndOffset(uint64_t aID) returns(uint32_t aRetVal, bool aOk);
|
||||
prio(high) sync IsLinkValid(uint64_t aID) returns(bool aRetVal);
|
||||
prio(high) sync AnchorCount(uint64_t aID) returns(uint32_t aRetVal, bool aOk);
|
||||
prio(high) sync AnchorURIAt(uint64_t aID, uint32_t aIndex) returns(nsCString aURI, bool aOk);
|
||||
prio(high) sync AnchorAt(uint64_t aID, uint32_t aIndex) returns(uint64_t aIDOfAnchor, bool aOk);
|
||||
|
||||
prio(high) sync LinkCount(uint64_t aID) returns(uint32_t aCount);
|
||||
prio(high) sync LinkAt(uint64_t aID, uint32_t aIndex) returns(uint64_t aIDOfLink, bool aOk);
|
||||
prio(high) sync LinkIndexOf(uint64_t aID, uint64_t aLinkID) returns(int32_t aIndex);
|
||||
prio(high) sync LinkIndexAtOffset(uint64_t aID, uint32_t aOffset) returns(int32_t aIndex);
|
||||
|
||||
prio(high) sync TableOfACell(uint64_t aID) returns(uint64_t aTableID, bool aOk);
|
||||
prio(high) sync ColIdx(uint64_t aID) returns(uint32_t aIndex);
|
||||
prio(high) sync RowIdx(uint64_t aID) returns(uint32_t aIndex);
|
||||
prio(high) sync ColExtent(uint64_t aID) returns(uint32_t aExtent);
|
||||
prio(high) sync RowExtent(uint64_t aID) returns(uint32_t aExtent);
|
||||
prio(high) sync ColHeaderCells(uint64_t aID) returns(uint64_t[] aCells);
|
||||
prio(high) sync RowHeaderCells(uint64_t aID) returns(uint64_t[] aCells);
|
||||
prio(high) sync IsCellSelected(uint64_t aID) returns(bool aSelected);
|
||||
|
||||
prio(high) sync TableCaption(uint64_t aID) returns(uint64_t aCaptionID, bool aOk);
|
||||
prio(high) sync TableSummary(uint64_t aID) returns(nsString aSummary);
|
||||
prio(high) sync TableColumnCount(uint64_t aID) returns(uint32_t aColCount);
|
||||
prio(high) sync TableRowCount(uint64_t aID) returns(uint32_t aRowCount);
|
||||
prio(high) sync TableCellAt(uint64_t aID, uint32_t aRow, uint32_t aCol) returns(uint64_t aCellID, bool aOk);
|
||||
prio(high) sync TableCellIndexAt(uint64_t aID, uint32_t aRow, uint32_t aCol) returns(int32_t aIndex);
|
||||
prio(high) sync TableColumnIndexAt(uint64_t aID, uint32_t aCellIndex) returns(int32_t aCol);
|
||||
prio(high) sync TableRowIndexAt(uint64_t aID, uint32_t aCellIndex) returns(int32_t aRow);
|
||||
prio(high) sync TableRowAndColumnIndicesAt(uint64_t aID, uint32_t aCellIndex) returns(int32_t aRow, int32_t aCol);
|
||||
prio(high) sync TableColumnExtentAt(uint64_t aID, uint32_t aRow, uint32_t aCol) returns(uint32_t aExtent);
|
||||
prio(high) sync TableRowExtentAt(uint64_t aID, uint32_t aRow, uint32_t aCol) returns(uint32_t aExtent);
|
||||
prio(high) sync TableColumnDescription(uint64_t aID, uint32_t aCol) returns(nsString aDescription);
|
||||
prio(high) sync TableRowDescription(uint64_t aID, uint32_t aRow) returns(nsString aDescription);
|
||||
prio(high) sync TableColumnSelected(uint64_t aID, uint32_t aCol) returns(bool aSelected);
|
||||
prio(high) sync TableRowSelected(uint64_t aID, uint32_t aRow) returns(bool aSelected);
|
||||
prio(high) sync TableCellSelected(uint64_t aID, uint32_t aRow, uint32_t aCol) returns(bool aSelected);
|
||||
prio(high) sync TableSelectedCellCount(uint64_t aID) returns(uint32_t aSelectedCells);
|
||||
prio(high) sync TableSelectedColumnCount(uint64_t aID) returns(uint32_t aSelectedColumns);
|
||||
prio(high) sync TableSelectedRowCount(uint64_t aID) returns(uint32_t aSelectedRows);
|
||||
prio(high) sync TableSelectedCells(uint64_t aID) returns(uint64_t[] aCellIDs);
|
||||
prio(high) sync TableSelectedCellIndices(uint64_t aID) returns(uint32_t[] aCellIndeces);
|
||||
prio(high) sync TableSelectedColumnIndices(uint64_t aID) returns(uint32_t[] aColumnIndeces);
|
||||
prio(high) sync TableSelectedRowIndices(uint64_t aID) returns(uint32_t[] aRowIndeces);
|
||||
prio(high) sync TableSelectColumn(uint64_t aID, uint32_t aCol);
|
||||
prio(high) sync TableSelectRow(uint64_t aID, uint32_t aRow);
|
||||
prio(high) sync TableUnselectColumn(uint64_t aID, uint32_t aCol);
|
||||
prio(high) sync TableUnselectRow(uint64_t aID, uint32_t aRow);
|
||||
prio(high) sync TableIsProbablyForLayout(uint64_t aID) returns(bool aForLayout);
|
||||
|
||||
prio(high) sync SelectedItems(uint64_t aID) returns(uint64_t[] aSelectedItemIDs);
|
||||
prio(high) sync SelectedItemCount(uint64_t aID) returns(uint32_t aCount);
|
||||
prio(high) sync GetSelectedItem(uint64_t aID, uint32_t aIndex) returns(uint64_t aSelected, bool aOk);
|
||||
prio(high) sync IsItemSelected(uint64_t aID, uint32_t aIndex) returns(bool aSelected);
|
||||
prio(high) sync AddItemToSelection(uint64_t aID, uint32_t aIndex) returns(bool aSuccess);
|
||||
prio(high) sync RemoveItemFromSelection(uint64_t aID, uint32_t aIndex) returns(bool aSuccess);
|
||||
prio(high) sync SelectAll(uint64_t aID) returns(bool aSuccess);
|
||||
prio(high) sync UnselectAll(uint64_t aID) returns(bool aSuccess);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -379,5 +379,425 @@ ProxyAccessible::ImageSize()
|
||||
return retVal;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ProxyAccessible::StartOffset(bool* aOk)
|
||||
{
|
||||
uint32_t retVal = 0;
|
||||
unused << mDoc->SendStartOffset(mID, &retVal, aOk);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ProxyAccessible::EndOffset(bool* aOk)
|
||||
{
|
||||
uint32_t retVal = 0;
|
||||
unused << mDoc->SendEndOffset(mID, &retVal, aOk);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyAccessible::IsLinkValid()
|
||||
{
|
||||
bool retVal = false;
|
||||
unused << mDoc->SendIsLinkValid(mID, &retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ProxyAccessible::AnchorCount(bool* aOk)
|
||||
{
|
||||
uint32_t retVal = 0;
|
||||
unused << mDoc->SendAnchorCount(mID, &retVal, aOk);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::AnchorURIAt(uint32_t aIndex, nsCString& aURI, bool* aOk)
|
||||
{
|
||||
unused << mDoc->SendAnchorURIAt(mID, aIndex, &aURI, aOk);
|
||||
}
|
||||
|
||||
ProxyAccessible*
|
||||
ProxyAccessible::AnchorAt(uint32_t aIndex)
|
||||
{
|
||||
uint64_t id = 0;
|
||||
bool ok = false;
|
||||
unused << mDoc->SendAnchorAt(mID, aIndex, &id, &ok);
|
||||
return ok ? mDoc->GetAccessible(id) : nullptr;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ProxyAccessible::LinkCount()
|
||||
{
|
||||
uint32_t retVal = 0;
|
||||
unused << mDoc->SendLinkCount(mID, &retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
ProxyAccessible*
|
||||
ProxyAccessible::LinkAt(const uint32_t& aIndex)
|
||||
{
|
||||
uint64_t linkID = 0;
|
||||
bool ok = false;
|
||||
unused << mDoc->SendLinkAt(mID, aIndex, &linkID, &ok);
|
||||
return ok ? mDoc->GetAccessible(linkID) : nullptr;
|
||||
}
|
||||
|
||||
int32_t
|
||||
ProxyAccessible::LinkIndexOf(ProxyAccessible* aLink)
|
||||
{
|
||||
int32_t retVal = -1;
|
||||
if (aLink) {
|
||||
unused << mDoc->SendLinkIndexOf(mID, aLink->ID(), &retVal);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
int32_t
|
||||
ProxyAccessible::LinkIndexAtOffset(uint32_t aOffset)
|
||||
{
|
||||
int32_t retVal = -1;
|
||||
unused << mDoc->SendLinkIndexAtOffset(mID, aOffset, &retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
ProxyAccessible*
|
||||
ProxyAccessible::TableOfACell()
|
||||
{
|
||||
uint64_t tableID = 0;
|
||||
bool ok = false;
|
||||
unused << mDoc->SendTableOfACell(mID, &tableID, &ok);
|
||||
return ok ? mDoc->GetAccessible(tableID) : nullptr;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ProxyAccessible::ColIdx()
|
||||
{
|
||||
uint32_t index = 0;
|
||||
unused << mDoc->SendColIdx(mID, &index);
|
||||
return index;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ProxyAccessible::RowIdx()
|
||||
{
|
||||
uint32_t index = 0;
|
||||
unused << mDoc->SendRowIdx(mID, &index);
|
||||
return index;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ProxyAccessible::ColExtent()
|
||||
{
|
||||
uint32_t extent = 0;
|
||||
unused << mDoc->SendColExtent(mID, &extent);
|
||||
return extent;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ProxyAccessible::RowExtent()
|
||||
{
|
||||
uint32_t extent = 0;
|
||||
unused << mDoc->SendRowExtent(mID, &extent);
|
||||
return extent;
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::ColHeaderCells(nsTArray<uint64_t>* aCells)
|
||||
{
|
||||
unused << mDoc->SendColHeaderCells(mID, aCells);
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::RowHeaderCells(nsTArray<uint64_t>* aCells)
|
||||
{
|
||||
unused << mDoc->SendRowHeaderCells(mID, aCells);
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyAccessible::IsCellSelected()
|
||||
{
|
||||
bool selected = false;
|
||||
unused << mDoc->SendIsCellSelected(mID, &selected);
|
||||
return selected;
|
||||
}
|
||||
|
||||
ProxyAccessible*
|
||||
ProxyAccessible::TableCaption()
|
||||
{
|
||||
uint64_t captionID = 0;
|
||||
bool ok = false;
|
||||
unused << mDoc->SendTableCaption(mID, &captionID, &ok);
|
||||
return ok ? mDoc->GetAccessible(captionID) : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::TableSummary(nsString& aSummary)
|
||||
{
|
||||
unused << mDoc->SendTableSummary(mID, &aSummary);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ProxyAccessible::TableColumnCount()
|
||||
{
|
||||
uint32_t count = 0;
|
||||
unused << mDoc->SendTableColumnCount(mID, &count);
|
||||
return count;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ProxyAccessible::TableRowCount()
|
||||
{
|
||||
uint32_t count = 0;
|
||||
unused << mDoc->SendTableRowCount(mID, &count);
|
||||
return count;
|
||||
}
|
||||
|
||||
ProxyAccessible*
|
||||
ProxyAccessible::TableCellAt(uint32_t aRow, uint32_t aCol)
|
||||
{
|
||||
uint64_t cellID = 0;
|
||||
bool ok = false;
|
||||
unused << mDoc->SendTableCellAt(mID, aRow, aCol, &cellID, &ok);
|
||||
return ok ? mDoc->GetAccessible(cellID) : nullptr;
|
||||
}
|
||||
|
||||
int32_t
|
||||
ProxyAccessible::TableCellIndexAt(uint32_t aRow, uint32_t aCol)
|
||||
{
|
||||
int32_t index = 0;
|
||||
unused << mDoc->SendTableCellIndexAt(mID, aRow, aCol, &index);
|
||||
return index;
|
||||
}
|
||||
|
||||
int32_t
|
||||
ProxyAccessible::TableColumnIndexAt(uint32_t aCellIndex)
|
||||
{
|
||||
int32_t index = 0;
|
||||
unused << mDoc->SendTableColumnIndexAt(mID, aCellIndex, &index);
|
||||
return index;
|
||||
}
|
||||
|
||||
int32_t
|
||||
ProxyAccessible::TableRowIndexAt(uint32_t aCellIndex)
|
||||
{
|
||||
int32_t index = 0;
|
||||
unused << mDoc->SendTableRowIndexAt(mID, aCellIndex, &index);
|
||||
return index;
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::TableRowAndColumnIndicesAt(uint32_t aCellIndex,
|
||||
int32_t* aRow, int32_t* aCol)
|
||||
{
|
||||
unused << mDoc->SendTableRowAndColumnIndicesAt(mID, aCellIndex, aRow, aCol);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ProxyAccessible::TableColumnExtentAt(uint32_t aRow, uint32_t aCol)
|
||||
{
|
||||
uint32_t extent = 0;
|
||||
unused << mDoc->SendTableColumnExtentAt(mID, aRow, aCol, &extent);
|
||||
return extent;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ProxyAccessible::TableRowExtentAt(uint32_t aRow, uint32_t aCol)
|
||||
{
|
||||
uint32_t extent = 0;
|
||||
unused << mDoc->SendTableRowExtentAt(mID, aRow, aCol, &extent);
|
||||
return extent;
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::TableColumnDescription(uint32_t aCol, nsString& aDescription)
|
||||
{
|
||||
unused << mDoc->SendTableColumnDescription(mID, aCol, &aDescription);
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::TableRowDescription(uint32_t aRow, nsString& aDescription)
|
||||
{
|
||||
unused << mDoc->SendTableRowDescription(mID, aRow, &aDescription);
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyAccessible::TableColumnSelected(uint32_t aCol)
|
||||
{
|
||||
bool selected = false;
|
||||
unused << mDoc->SendTableColumnSelected(mID, aCol, &selected);
|
||||
return selected;
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyAccessible::TableRowSelected(uint32_t aRow)
|
||||
{
|
||||
bool selected = false;
|
||||
unused << mDoc->SendTableRowSelected(mID, aRow, &selected);
|
||||
return selected;
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyAccessible::TableCellSelected(uint32_t aRow, uint32_t aCol)
|
||||
{
|
||||
bool selected = false;
|
||||
unused << mDoc->SendTableCellSelected(mID, aRow, aCol, &selected);
|
||||
return selected;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ProxyAccessible::TableSelectedCellCount()
|
||||
{
|
||||
uint32_t count = 0;
|
||||
unused << mDoc->SendTableSelectedCellCount(mID, &count);
|
||||
return count;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ProxyAccessible::TableSelectedColumnCount()
|
||||
{
|
||||
uint32_t count = 0;
|
||||
unused << mDoc->SendTableSelectedColumnCount(mID, &count);
|
||||
return count;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ProxyAccessible::TableSelectedRowCount()
|
||||
{
|
||||
uint32_t count = 0;
|
||||
unused << mDoc->SendTableSelectedRowCount(mID, &count);
|
||||
return count;
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::TableSelectedCells(nsTArray<ProxyAccessible*>* aCellIDs)
|
||||
{
|
||||
nsAutoTArray<uint64_t, 30> cellIDs;
|
||||
unused << mDoc->SendTableSelectedCells(mID, &cellIDs);
|
||||
aCellIDs->SetCapacity(cellIDs.Length());
|
||||
for (uint32_t i = 0; i < cellIDs.Length(); ++i) {
|
||||
aCellIDs->AppendElement(mDoc->GetAccessible(cellIDs[i]));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::TableSelectedCellIndices(nsTArray<uint32_t>* aCellIndices)
|
||||
{
|
||||
unused << mDoc->SendTableSelectedCellIndices(mID, aCellIndices);
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::TableSelectedColumnIndices(nsTArray<uint32_t>* aColumnIndices)
|
||||
{
|
||||
unused << mDoc->SendTableSelectedColumnIndices(mID, aColumnIndices);
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::TableSelectedRowIndices(nsTArray<uint32_t>* aRowIndices)
|
||||
{
|
||||
unused << mDoc->SendTableSelectedRowIndices(mID, aRowIndices);
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::TableSelectColumn(uint32_t aCol)
|
||||
{
|
||||
unused << mDoc->SendTableSelectColumn(mID, aCol);
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::TableSelectRow(uint32_t aRow)
|
||||
{
|
||||
unused << mDoc->SendTableSelectRow(mID, aRow);
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::TableUnselectColumn(uint32_t aCol)
|
||||
{
|
||||
unused << mDoc->SendTableUnselectColumn(mID, aCol);
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::TableUnselectRow(uint32_t aRow)
|
||||
{
|
||||
unused << mDoc->SendTableUnselectRow(mID, aRow);
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyAccessible::TableIsProbablyForLayout()
|
||||
{
|
||||
bool forLayout = false;
|
||||
unused << mDoc->SendTableIsProbablyForLayout(mID, &forLayout);
|
||||
return forLayout;
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::SelectedItems(nsTArray<ProxyAccessible*>* aSelectedItems)
|
||||
{
|
||||
nsAutoTArray<uint64_t, 10> itemIDs;
|
||||
unused << mDoc->SendSelectedItems(mID, &itemIDs);
|
||||
aSelectedItems->SetCapacity(itemIDs.Length());
|
||||
for (size_t i = 0; i < itemIDs.Length(); ++i) {
|
||||
aSelectedItems->AppendElement(mDoc->GetAccessible(itemIDs[i]));
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ProxyAccessible::SelectedItemCount()
|
||||
{
|
||||
uint32_t count = 0;
|
||||
unused << mDoc->SendSelectedItemCount(mID, &count);
|
||||
return count;
|
||||
}
|
||||
|
||||
ProxyAccessible*
|
||||
ProxyAccessible::GetSelectedItem(uint32_t aIndex)
|
||||
{
|
||||
uint64_t selectedItemID = 0;
|
||||
bool ok = false;
|
||||
unused << mDoc->SendGetSelectedItem(mID, aIndex, &selectedItemID, &ok);
|
||||
return ok ? mDoc->GetAccessible(selectedItemID) : nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyAccessible::IsItemSelected(uint32_t aIndex)
|
||||
{
|
||||
bool selected = false;
|
||||
unused << mDoc->SendIsItemSelected(mID, aIndex, &selected);
|
||||
return selected;
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyAccessible::AddItemToSelection(uint32_t aIndex)
|
||||
{
|
||||
bool success = false;
|
||||
unused << mDoc->SendAddItemToSelection(mID, aIndex, &success);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyAccessible::RemoveItemFromSelection(uint32_t aIndex)
|
||||
{
|
||||
bool success = false;
|
||||
unused << mDoc->SendRemoveItemFromSelection(mID, aIndex, &success);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyAccessible::SelectAll()
|
||||
{
|
||||
bool success = false;
|
||||
unused << mDoc->SendSelectAll(mID, &success);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyAccessible::UnselectAll()
|
||||
{
|
||||
bool success = false;
|
||||
unused << mDoc->SendUnselectAll(mID, &success);
|
||||
return success;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -181,6 +181,81 @@ public:
|
||||
|
||||
nsIntSize ImageSize();
|
||||
|
||||
uint32_t StartOffset(bool* aOk);
|
||||
|
||||
uint32_t EndOffset(bool* aOk);
|
||||
|
||||
bool IsLinkValid();
|
||||
|
||||
uint32_t AnchorCount(bool* aOk);
|
||||
|
||||
void AnchorURIAt(uint32_t aIndex, nsCString& aURI, bool* aOk);
|
||||
|
||||
ProxyAccessible* AnchorAt(uint32_t aIndex);
|
||||
|
||||
uint32_t LinkCount();
|
||||
|
||||
ProxyAccessible* LinkAt(const uint32_t& aIndex);
|
||||
|
||||
int32_t LinkIndexOf(ProxyAccessible* aLink);
|
||||
|
||||
int32_t LinkIndexAtOffset(uint32_t aOffset);
|
||||
|
||||
ProxyAccessible* TableOfACell();
|
||||
|
||||
uint32_t ColIdx();
|
||||
|
||||
uint32_t RowIdx();
|
||||
|
||||
uint32_t ColExtent();
|
||||
|
||||
uint32_t RowExtent();
|
||||
|
||||
void ColHeaderCells(nsTArray<uint64_t>* aCells);
|
||||
|
||||
void RowHeaderCells(nsTArray<uint64_t>* aCells);
|
||||
|
||||
bool IsCellSelected();
|
||||
|
||||
ProxyAccessible* TableCaption();
|
||||
void TableSummary(nsString& aSummary);
|
||||
uint32_t TableColumnCount();
|
||||
uint32_t TableRowCount();
|
||||
ProxyAccessible* TableCellAt(uint32_t aRow, uint32_t aCol);
|
||||
int32_t TableCellIndexAt(uint32_t aRow, uint32_t aCol);
|
||||
int32_t TableColumnIndexAt(uint32_t aCellIndex);
|
||||
int32_t TableRowIndexAt(uint32_t aCellIndex);
|
||||
void TableRowAndColumnIndicesAt(uint32_t aCellIndex,
|
||||
int32_t* aRow, int32_t* aCol);
|
||||
uint32_t TableColumnExtentAt(uint32_t aRow, uint32_t aCol);
|
||||
uint32_t TableRowExtentAt(uint32_t aRow, uint32_t aCol);
|
||||
void TableColumnDescription(uint32_t aCol, nsString& aDescription);
|
||||
void TableRowDescription(uint32_t aRow, nsString& aDescription);
|
||||
bool TableColumnSelected(uint32_t aCol);
|
||||
bool TableRowSelected(uint32_t aRow);
|
||||
bool TableCellSelected(uint32_t aRow, uint32_t aCol);
|
||||
uint32_t TableSelectedCellCount();
|
||||
uint32_t TableSelectedColumnCount();
|
||||
uint32_t TableSelectedRowCount();
|
||||
void TableSelectedCells(nsTArray<ProxyAccessible*>* aCellIDs);
|
||||
void TableSelectedCellIndices(nsTArray<uint32_t>* aCellIndices);
|
||||
void TableSelectedColumnIndices(nsTArray<uint32_t>* aColumnIndices);
|
||||
void TableSelectedRowIndices(nsTArray<uint32_t>* aRowIndices);
|
||||
void TableSelectColumn(uint32_t aCol);
|
||||
void TableSelectRow(uint32_t aRow);
|
||||
void TableUnselectColumn(uint32_t aCol);
|
||||
void TableUnselectRow(uint32_t aRow);
|
||||
bool TableIsProbablyForLayout();
|
||||
|
||||
void SelectedItems(nsTArray<ProxyAccessible*>* aSelectedItems);
|
||||
uint32_t SelectedItemCount();
|
||||
ProxyAccessible* GetSelectedItem(uint32_t aIndex);
|
||||
bool IsItemSelected(uint32_t aIndex);
|
||||
bool AddItemToSelection(uint32_t aIndex);
|
||||
bool RemoveItemFromSelection(uint32_t aIndex);
|
||||
bool SelectAll();
|
||||
bool UnselectAll();
|
||||
|
||||
/**
|
||||
* Allow the platform to store a pointers worth of data on us.
|
||||
*/
|
||||
|
@ -714,9 +714,9 @@ function testHeaderCells(aHeaderInfoMap)
|
||||
var rowHeaderCell = getAccessible(rowHeaderCells[idx]);
|
||||
var actualRowHeaderCell =
|
||||
actualRowHeaderCells.queryElementAt(idx, nsIAccessible);
|
||||
ok(actualRowHeaderCell, rowHeaderCell,
|
||||
isObject(actualRowHeaderCell, rowHeaderCell,
|
||||
"Wrong row header cell at index " + idx + " for the cell " +
|
||||
prettyName(rowHeaderCells[idx]));
|
||||
dataCellIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
@ -735,9 +735,9 @@ function testHeaderCells(aHeaderInfoMap)
|
||||
var colHeaderCell = getAccessible(colHeaderCells[idx]);
|
||||
var actualColHeaderCell =
|
||||
actualColHeaderCells.queryElementAt(idx, nsIAccessible);
|
||||
ok(actualColHeaderCell, colHeaderCell,
|
||||
isObject(actualColHeaderCell, colHeaderCell,
|
||||
"Wrong column header cell at index " + idx + " for the cell " +
|
||||
prettyName(colHeaderCells[idx]));
|
||||
dataCellIdentifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -162,62 +162,62 @@
|
||||
headerInfoMap = [
|
||||
{
|
||||
cell: "t7_r1c1",
|
||||
rowHeaderCells: [ "t7_Females", "t7_Mary" ],
|
||||
rowHeaderCells: [ "t7_Mary", "t7_Females" ],
|
||||
columnHeaderCells: [ "t7_1km" ]
|
||||
},
|
||||
{
|
||||
cell: "t7_r1c2",
|
||||
rowHeaderCells: [ "t7_Females", "t7_Mary" ],
|
||||
rowHeaderCells: [ "t7_Mary", "t7_Females" ],
|
||||
columnHeaderCells: [ "t7_5km" ]
|
||||
},
|
||||
{
|
||||
cell: "t7_r1c3",
|
||||
rowHeaderCells: [ "t7_Females", "t7_Mary" ],
|
||||
rowHeaderCells: [ "t7_Mary", "t7_Females" ],
|
||||
columnHeaderCells: [ "t7_10km" ]
|
||||
},
|
||||
{
|
||||
cell: "t7_r2c1",
|
||||
rowHeaderCells: [ "t7_Females", "t7_Betsy" ],
|
||||
rowHeaderCells: [ "t7_Betsy", "t7_Females" ],
|
||||
columnHeaderCells: [ "t7_1km" ]
|
||||
},
|
||||
{
|
||||
cell: "t7_r2c2",
|
||||
rowHeaderCells: [ "t7_Females", "t7_Betsy" ],
|
||||
rowHeaderCells: [ "t7_Betsy", "t7_Females" ],
|
||||
columnHeaderCells: [ "t7_5km" ]
|
||||
},
|
||||
{
|
||||
cell: "t7_r2c3",
|
||||
rowHeaderCells: [ "t7_Females", "t7_Betsy" ],
|
||||
rowHeaderCells: [ "t7_Betsy", "t7_Females" ],
|
||||
columnHeaderCells: [ "t7_10km" ]
|
||||
},
|
||||
{
|
||||
cell: "t7_r3c1",
|
||||
rowHeaderCells: [ "t7_Males", "t7_Matt" ],
|
||||
rowHeaderCells: [ "t7_Matt", "t7_Males" ],
|
||||
columnHeaderCells: [ "t7_1km" ]
|
||||
},
|
||||
{
|
||||
cell: "t7_r3c2",
|
||||
rowHeaderCells: [ "t7_Males", "t7_Matt" ],
|
||||
rowHeaderCells: [ "t7_Matt", "t7_Males" ],
|
||||
columnHeaderCells: [ "t7_5km" ]
|
||||
},
|
||||
{
|
||||
cell: "t7_r3c3",
|
||||
rowHeaderCells: [ "t7_Males", "t7_Matt" ],
|
||||
rowHeaderCells: [ "t7_Matt", "t7_Males" ],
|
||||
columnHeaderCells: [ "t7_10km" ]
|
||||
},
|
||||
{
|
||||
cell: "t7_r4c1",
|
||||
rowHeaderCells: [ "t7_Males", "t7_Todd" ],
|
||||
rowHeaderCells: [ "t7_Todd", "t7_Males" ],
|
||||
columnHeaderCells: [ "t7_1km" ]
|
||||
},
|
||||
{
|
||||
cell: "t7_r4c2",
|
||||
rowHeaderCells: [ "t7_Males", "t7_Todd" ],
|
||||
rowHeaderCells: [ "t7_Todd", "t7_Males" ],
|
||||
columnHeaderCells: [ "t7_5km" ]
|
||||
},
|
||||
{
|
||||
cell: "t7_r4c3",
|
||||
rowHeaderCells: [ "t7_Males", "t7_Todd" ],
|
||||
rowHeaderCells: [ "t7_Todd", "t7_Males" ],
|
||||
columnHeaderCells: [ "t7_10km" ]
|
||||
}
|
||||
];
|
||||
@ -231,62 +231,198 @@
|
||||
{
|
||||
cell: "t8_r1c1",
|
||||
rowHeaderCells: [ "t8_1km" ],
|
||||
columnHeaderCells: [ "t7_Females", "t7_Mary" ]
|
||||
columnHeaderCells: [ "t8_Mary", "t8_Females" ]
|
||||
},
|
||||
{
|
||||
cell: "t8_r1c2",
|
||||
rowHeaderCells: [ "t8_5km" ],
|
||||
columnHeaderCells: [ "t8_Females", "t8_Mary" ]
|
||||
rowHeaderCells: [ "t8_1km" ],
|
||||
columnHeaderCells: [ "t8_Betsy", "t8_Females" ]
|
||||
},
|
||||
{
|
||||
cell: "t8_r1c3",
|
||||
rowHeaderCells: [ "t8_10km" ],
|
||||
columnHeaderCells: [ "t8_Females", "t8_Mary" ]
|
||||
rowHeaderCells: [ "t8_1km" ],
|
||||
columnHeaderCells: [ "t8_Matt", "t8_Males" ]
|
||||
},
|
||||
{
|
||||
cell: "t8_r1c4",
|
||||
rowHeaderCells: [ "t8_1km" ],
|
||||
columnHeaderCells: [ "t8_Females", "t8_Betsy" ]
|
||||
columnHeaderCells: [ "t8_Todd", "t8_Males" ]
|
||||
},
|
||||
{
|
||||
cell: "t8_r2c1",
|
||||
rowHeaderCells: [ "t8_5km" ],
|
||||
columnHeaderCells: [ "t8_Females", "t8_Betsy" ]
|
||||
columnHeaderCells: [ "t8_Mary", "t8_Females" ]
|
||||
},
|
||||
{
|
||||
cell: "t8_r2c2",
|
||||
rowHeaderCells: [ "t8_10km" ],
|
||||
columnHeaderCells: [ "t8_Females", "t8_Betsy" ]
|
||||
rowHeaderCells: [ "t8_5km" ],
|
||||
columnHeaderCells: [ "t8_Betsy", "t8_Females" ]
|
||||
},
|
||||
{
|
||||
cell: "t8_r2c3",
|
||||
rowHeaderCells: [ "t8_1km" ],
|
||||
columnHeaderCells: [ "t8_Males", "t8_Matt" ]
|
||||
rowHeaderCells: [ "t8_5km" ],
|
||||
columnHeaderCells: [ "t8_Matt", "t8_Males" ]
|
||||
},
|
||||
{
|
||||
cell: "t8_r2c4",
|
||||
rowHeaderCells: [ "t8_5km" ],
|
||||
columnHeaderCells: [ "t8_Males", "t8_Matt" ]
|
||||
columnHeaderCells: [ "t8_Todd", "t8_Males" ]
|
||||
},
|
||||
{
|
||||
cell: "t8_r3c1",
|
||||
rowHeaderCells: [ "t8_10km" ],
|
||||
columnHeaderCells: [ "t8_Males", "t8_Matt" ]
|
||||
columnHeaderCells: [ "t8_Mary", "t8_Females" ]
|
||||
},
|
||||
{
|
||||
cell: "t8_r3c2",
|
||||
rowHeaderCells: [ "t8_1km" ],
|
||||
columnHeaderCells: [ "t8_Males", "t8_Todd" ]
|
||||
rowHeaderCells: [ "t8_10km" ],
|
||||
columnHeaderCells: [ "t8_Betsy", "t8_Females" ]
|
||||
},
|
||||
{
|
||||
cell: "t8_r3c3",
|
||||
rowHeaderCells: [ "t8_5km" ],
|
||||
columnHeaderCells: [ "t8_Males", "t8_Todd" ]
|
||||
rowHeaderCells: [ "t8_10km" ],
|
||||
columnHeaderCells: [ "t8_Matt", "t8_Males" ]
|
||||
},
|
||||
{
|
||||
cell: "t8_r3c4",
|
||||
rowHeaderCells: [ "t8_10km" ],
|
||||
columnHeaderCells: [ "t8_Males", "t8_Todd" ]
|
||||
columnHeaderCells: [ "t8_Todd", "t8_Males" ]
|
||||
}
|
||||
];
|
||||
|
||||
testHeaderCells(headerInfoMap);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// spanned table header cells (v1), @headers define header order
|
||||
|
||||
headerInfoMap = [
|
||||
{
|
||||
cell: "t9_r1c1",
|
||||
rowHeaderCells: [ "t9_females", "t9_mary" ],
|
||||
columnHeaderCells: [ "t9_1km" ]
|
||||
},
|
||||
{
|
||||
cell: "t9_r1c2",
|
||||
rowHeaderCells: [ "t9_females", "t9_mary" ],
|
||||
columnHeaderCells: [ "t9_5km" ]
|
||||
},
|
||||
{
|
||||
cell: "t9_r1c3",
|
||||
rowHeaderCells: [ "t9_females", "t9_mary" ],
|
||||
columnHeaderCells: [ "t9_10km" ]
|
||||
},
|
||||
{
|
||||
cell: "t9_r2c1",
|
||||
rowHeaderCells: [ "t9_females", "t9_betsy" ],
|
||||
columnHeaderCells: [ "t9_1km" ]
|
||||
},
|
||||
{
|
||||
cell: "t9_r2c2",
|
||||
rowHeaderCells: [ "t9_females", "t9_betsy" ],
|
||||
columnHeaderCells: [ "t9_5km" ]
|
||||
},
|
||||
{
|
||||
cell: "t9_r2c3",
|
||||
rowHeaderCells: [ "t9_females", "t9_betsy" ],
|
||||
columnHeaderCells: [ "t9_10km" ]
|
||||
},
|
||||
{
|
||||
cell: "t9_r3c1",
|
||||
rowHeaderCells: [ "t9_males", "t9_matt" ],
|
||||
columnHeaderCells: [ "t9_1km" ]
|
||||
},
|
||||
{
|
||||
cell: "t9_r3c2",
|
||||
rowHeaderCells: [ "t9_males", "t9_matt" ],
|
||||
columnHeaderCells: [ "t9_5km" ]
|
||||
},
|
||||
{
|
||||
cell: "t9_r3c3",
|
||||
rowHeaderCells: [ "t9_males", "t9_matt" ],
|
||||
columnHeaderCells: [ "t9_10km" ]
|
||||
},
|
||||
{
|
||||
cell: "t9_r4c1",
|
||||
rowHeaderCells: [ "t9_males", "t9_todd" ],
|
||||
columnHeaderCells: [ "t9_1km" ]
|
||||
},
|
||||
{
|
||||
cell: "t9_r4c2",
|
||||
rowHeaderCells: [ "t9_males", "t9_todd" ],
|
||||
columnHeaderCells: [ "t9_5km" ]
|
||||
},
|
||||
{
|
||||
cell: "t9_r4c3",
|
||||
rowHeaderCells: [ "t9_males", "t9_todd" ],
|
||||
columnHeaderCells: [ "t9_10km" ]
|
||||
}
|
||||
];
|
||||
|
||||
testHeaderCells(headerInfoMap);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// spanned table header cells (v2), @headers define header order
|
||||
|
||||
headerInfoMap = [
|
||||
{
|
||||
cell: "t10_r1c1",
|
||||
rowHeaderCells: [ "t10_1km" ],
|
||||
columnHeaderCells: [ "t10_females", "t10_mary" ]
|
||||
},
|
||||
{
|
||||
cell: "t10_r1c2",
|
||||
rowHeaderCells: [ "t10_1km" ],
|
||||
columnHeaderCells: [ "t10_females", "t10_betsy" ]
|
||||
},
|
||||
{
|
||||
cell: "t10_r1c3",
|
||||
rowHeaderCells: [ "t10_1km" ],
|
||||
columnHeaderCells: [ "t10_males", "t10_matt" ]
|
||||
},
|
||||
{
|
||||
cell: "t10_r1c4",
|
||||
rowHeaderCells: [ "t10_1km" ],
|
||||
columnHeaderCells: [ "t10_males", "t10_todd" ]
|
||||
},
|
||||
{
|
||||
cell: "t10_r2c1",
|
||||
rowHeaderCells: [ "t10_5km" ],
|
||||
columnHeaderCells: [ "t10_females", "t10_mary" ]
|
||||
},
|
||||
{
|
||||
cell: "t10_r2c2",
|
||||
rowHeaderCells: [ "t10_5km" ],
|
||||
columnHeaderCells: [ "t10_females", "t10_betsy" ]
|
||||
},
|
||||
{
|
||||
cell: "t10_r2c3",
|
||||
rowHeaderCells: [ "t10_5km" ],
|
||||
columnHeaderCells: [ "t10_males", "t10_matt" ]
|
||||
},
|
||||
{
|
||||
cell: "t10_r2c4",
|
||||
rowHeaderCells: [ "t10_5km" ],
|
||||
columnHeaderCells: [ "t10_males", "t10_todd" ]
|
||||
},
|
||||
{
|
||||
cell: "t10_r3c1",
|
||||
rowHeaderCells: [ "t10_10km" ],
|
||||
columnHeaderCells: [ "t10_females", "t10_mary" ]
|
||||
},
|
||||
{
|
||||
cell: "t10_r3c2",
|
||||
rowHeaderCells: [ "t10_10km" ],
|
||||
columnHeaderCells: [ "t10_females", "t10_betsy" ]
|
||||
},
|
||||
{
|
||||
cell: "t10_r3c3",
|
||||
rowHeaderCells: [ "t10_10km" ],
|
||||
columnHeaderCells: [ "t10_males", "t10_matt" ]
|
||||
},
|
||||
{
|
||||
cell: "t10_r3c4",
|
||||
rowHeaderCells: [ "t10_10km" ],
|
||||
columnHeaderCells: [ "t10_males", "t10_todd" ]
|
||||
}
|
||||
];
|
||||
|
||||
@ -498,5 +634,80 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table id="table9" border="1">
|
||||
<caption>
|
||||
Example 1 (row group headers):
|
||||
</caption>
|
||||
<tr>
|
||||
<td colspan="2"><span class="offscreen">empty</span></td>
|
||||
<th id="t9_1km" width="40">1 km</th>
|
||||
<th id="t9_5km" width="35">5 km</th>
|
||||
<th id="t9_10km" width="42">10 km</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th id="t9_females" width="56" rowspan="2">Females</th>
|
||||
<th id="t9_mary" width="39">Mary</th>
|
||||
<td id="t9_r1c1" headers="t9_females t9_mary t9_1km">8:32</td>
|
||||
<td id="t9_r1c2" headers="t9_females t9_mary t9_5km">28:04</td>
|
||||
<td id="t9_r1c3" headers="t9_females t9_mary t9_10km">1:01:16</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th id="t9_betsy">Betsy</th>
|
||||
<td id="t9_r2c1" headers="t9_females t9_betsy t9_1km">7:43</td>
|
||||
<td id="t9_r2c2" headers="t9_females t9_betsy t9_5km">26:47</td>
|
||||
<td id="t9_r2c3" headers="t9_females t9_betsy t9_10km">55:38</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th id="t9_males" rowspan="2">Males</th>
|
||||
<th id="t9_matt">Matt</th>
|
||||
<td id="t9_r3c1" headers="t9_males t9_matt t9_1km">7:55</td>
|
||||
<td id="t9_r3c2" headers="t9_males t9_matt t9_5km">27:29</td>
|
||||
<td id="t9_r3c3" headers="t9_males t9_matt t9_10km">57:04</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th id="t9_todd">Todd</th>
|
||||
<td id="t9_r4c1" headers="t9_males t9_todd t9_1km">7:01</td>
|
||||
<td id="t9_r4c2" headers="t9_males t9_todd t9_5km">24:21</td>
|
||||
<td id="t9_r4c3" headers="t9_males t9_todd t9_10km">50:35</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table id="table10" border="1">
|
||||
<caption>
|
||||
Example 2 (column group headers):
|
||||
</caption>
|
||||
<tr>
|
||||
<td rowspan="2"><span class="offscreen">empty</span></td>
|
||||
<th colspan="2" id="t10_females">Females</th>
|
||||
<th colspan="2" id="t10_males">Males</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th width="40" id="t10_mary">Mary</th>
|
||||
<th width="35" id="t10_betsy">Betsy</th>
|
||||
<th width="42" id="t10_matt">Matt</th>
|
||||
<th width="42" id="t10_todd">Todd</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th width="39" id="t10_1km">1 km</th>
|
||||
<td headers="t10_females t10_mary t10_1km" id="t10_r1c1">8:32</td>
|
||||
<td headers="t10_females t10_betsy t10_1km" id="t10_r1c2">7:43</td>
|
||||
<td headers="t10_males t10_matt t10_1km" id="t10_r1c3">7:55</td>
|
||||
<td headers="t10_males t10_todd t10_1km" id="t10_r1c4">7:01</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th id="t10_5km">5 km</th>
|
||||
<td headers="t10_females t10_mary t10_5km" id="t10_r2c1">28:04</td>
|
||||
<td headers="t10_females t10_betsy t10_5km" id="t10_r2c2">26:47</td>
|
||||
<td headers="t10_males t10_matt t10_5km" id="t10_r2c3">27:29</td>
|
||||
<td headers="t10_males t10_todd t10_5km" id="t10_r2c4">24:21</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th id="t10_10km">10 km</th>
|
||||
<td headers="t10_females t10_mary t10_10km" id="t10_r3c1">1:01:16</td>
|
||||
<td headers="t10_females t10_betsy t10_10km" id="t10_r3c2">55:38</td>
|
||||
<td headers="t10_males t10_matt t10_10km" id="t10_r3c3">57:04</td>
|
||||
<td headers="t10_males t10_todd t10_10km" id="t10_r3c4">50:35</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -996,6 +996,13 @@ pref("b2g.theme.origin", "app://theme.gaiamobile.org");
|
||||
pref("dom.mozApps.themable", true);
|
||||
pref("dom.mozApps.selected_theme", "default_theme.gaiamobile.org");
|
||||
|
||||
// Enable PAC generator for B2G.
|
||||
pref("network.proxy.pac_generator", true);
|
||||
|
||||
// List of app origins to apply browsing traffic proxy setting, separated by
|
||||
// comma. Specify '*' in the list to apply to all apps.
|
||||
pref("network.proxy.browsing.app_origins", "app://system.gaiamobile.org");
|
||||
|
||||
// Enable Web Speech synthesis API
|
||||
pref("media.webspeech.synth.enabled", true);
|
||||
|
||||
|
@ -30,6 +30,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
|
||||
"@mozilla.org/uuid-generator;1",
|
||||
"nsIUUIDGenerator");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gPACGenerator",
|
||||
"@mozilla.org/pac-generator;1",
|
||||
"nsIPACGenerator");
|
||||
|
||||
// Once Bug 731746 - Allow chrome JS object to implement nsIDOMEventTarget
|
||||
// is resolved this helper could be removed.
|
||||
var SettingsListener = {
|
||||
@ -482,6 +486,40 @@ SettingsListener.observe("theme.selected",
|
||||
}
|
||||
});
|
||||
|
||||
// =================== Proxy server ======================
|
||||
(function setupBrowsingProxySettings() {
|
||||
function setPAC() {
|
||||
let usePAC;
|
||||
try {
|
||||
usePAC = Services.prefs.getBoolPref('network.proxy.pac_generator');
|
||||
} catch (ex) {}
|
||||
|
||||
if (usePAC) {
|
||||
Services.prefs.setCharPref('network.proxy.autoconfig_url',
|
||||
gPACGenerator.generate());
|
||||
Services.prefs.setIntPref('network.proxy.type',
|
||||
Ci.nsIProtocolProxyService.PROXYCONFIG_PAC);
|
||||
}
|
||||
}
|
||||
|
||||
SettingsListener.observe('browser.proxy.enabled', false, function(value) {
|
||||
Services.prefs.setBoolPref('network.proxy.browsing.enabled', value);
|
||||
setPAC();
|
||||
});
|
||||
|
||||
SettingsListener.observe('browser.proxy.host', '', function(value) {
|
||||
Services.prefs.setCharPref('network.proxy.browsing.host', value);
|
||||
setPAC();
|
||||
});
|
||||
|
||||
SettingsListener.observe('browser.proxy.port', 0, function(value) {
|
||||
Services.prefs.setIntPref('network.proxy.browsing.port', value);
|
||||
setPAC();
|
||||
});
|
||||
|
||||
setPAC();
|
||||
})();
|
||||
|
||||
// =================== Various simple mapping ======================
|
||||
let settingsToObserve = {
|
||||
'accessibility.screenreader_quicknav_modes': {
|
||||
|
@ -673,6 +673,9 @@
|
||||
@RESPATH@/components/TestInterfaceJS.manifest
|
||||
#endif
|
||||
|
||||
@RESPATH@/components/PACGenerator.js
|
||||
@RESPATH@/components/PACGenerator.manifest
|
||||
|
||||
; Modules
|
||||
@RESPATH@/modules/*
|
||||
|
||||
|
@ -409,6 +409,8 @@ support-files =
|
||||
skip-if = e10s # Bug 1137087 - browser_tabopen_reflows.js fails if this was previously run with e10s
|
||||
[browser_tabDrop.js]
|
||||
skip-if = buildapp == 'mulet' || e10s
|
||||
[browser_tabReorder.js]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[browser_tabMatchesInAwesomebar.js]
|
||||
[browser_tabMatchesInAwesomebar_perwindowpb.js]
|
||||
skip-if = e10s || os == 'linux' # Bug 1093373, bug 1104755
|
||||
|
@ -11,7 +11,7 @@
|
||||
detail: {
|
||||
id: "account_updates",
|
||||
message: {
|
||||
command: "profile:image:change",
|
||||
command: "profile:change",
|
||||
data: {
|
||||
uid: "abc123",
|
||||
},
|
||||
|
@ -34,7 +34,7 @@ let gTests = [
|
||||
content_uri: HTTP_PATH,
|
||||
});
|
||||
|
||||
makeObserver(FxAccountsCommon.ONPROFILE_IMAGE_CHANGE_NOTIFICATION, function (subject, topic, data) {
|
||||
makeObserver(FxAccountsCommon.ON_PROFILE_CHANGE_NOTIFICATION, function (subject, topic, data) {
|
||||
Assert.ok(tabOpened);
|
||||
Assert.equal(data, "abc123");
|
||||
resolve();
|
||||
|
82
browser/base/content/test/general/browser_tabReorder.js
Normal file
82
browser/base/content/test/general/browser_tabReorder.js
Normal file
@ -0,0 +1,82 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function test() {
|
||||
let initialTabsLength = gBrowser.tabs.length;
|
||||
|
||||
let newTab1 = gBrowser.selectedTab = gBrowser.addTab("about:robots", {skipAnimation: true});
|
||||
let newTab2 = gBrowser.selectedTab = gBrowser.addTab("about:about", {skipAnimation: true});
|
||||
let newTab3 = gBrowser.selectedTab = gBrowser.addTab("about:config", {skipAnimation: true});
|
||||
registerCleanupFunction(function () {
|
||||
while (gBrowser.tabs.length > initialTabsLength) {
|
||||
gBrowser.removeTab(gBrowser.tabs[initialTabsLength]);
|
||||
}
|
||||
});
|
||||
|
||||
is(gBrowser.tabs.length, initialTabsLength + 3, "new tabs are opened");
|
||||
is(gBrowser.tabs[initialTabsLength], newTab1, "newTab1 position is correct");
|
||||
is(gBrowser.tabs[initialTabsLength + 1], newTab2, "newTab2 position is correct");
|
||||
is(gBrowser.tabs[initialTabsLength + 2], newTab3, "newTab3 position is correct");
|
||||
|
||||
let dataTransfer;
|
||||
let trapDrag = function(event) {
|
||||
dataTransfer = event.dataTransfer;
|
||||
};
|
||||
window.addEventListener("dragstart", trapDrag, true);
|
||||
registerCleanupFunction(function () {
|
||||
window.removeEventListener("dragstart", trapDrag, true);
|
||||
});
|
||||
|
||||
let windowUtil = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
let ds = Components.classes["@mozilla.org/widget/dragservice;1"].
|
||||
getService(Components.interfaces.nsIDragService);
|
||||
|
||||
function dragAndDrop(tab1, tab2, copy) {
|
||||
let ctrlKey = copy;
|
||||
let altKey = copy;
|
||||
|
||||
let rect = tab1.getBoundingClientRect();
|
||||
let x = rect.width / 2;
|
||||
let y = rect.height / 2;
|
||||
let diffX = 10;
|
||||
|
||||
ds.startDragSession();
|
||||
try {
|
||||
EventUtils.synthesizeMouse(tab1, x, y, { type: "mousedown" }, window);
|
||||
EventUtils.synthesizeMouse(tab1, x + diffX, y, { type: "mousemove" }, window);
|
||||
|
||||
dataTransfer.dropEffect = copy ? "copy" : "move";
|
||||
|
||||
let event = window.document.createEvent("DragEvents");
|
||||
event.initDragEvent("dragover", true, true, window, 0,
|
||||
tab2.boxObject.screenX + x + diffX,
|
||||
tab2.boxObject.screenY + y,
|
||||
x + diffX, y, ctrlKey, altKey, false, false, 0, null, dataTransfer);
|
||||
windowUtil.dispatchDOMEventViaPresShell(tab2, event, true);
|
||||
|
||||
event = window.document.createEvent("DragEvents");
|
||||
event.initDragEvent("drop", true, true, window, 0,
|
||||
tab2.boxObject.screenX + x + diffX,
|
||||
tab2.boxObject.screenY + y,
|
||||
x + diffX, y, ctrlKey, altKey, false, false, 0, null, dataTransfer);
|
||||
windowUtil.dispatchDOMEventViaPresShell(tab2, event, true);
|
||||
|
||||
EventUtils.synthesizeMouse(tab2, x + diffX, y, { type: "mouseup" }, window);
|
||||
} finally {
|
||||
ds.endDragSession(true);
|
||||
}
|
||||
}
|
||||
|
||||
dragAndDrop(newTab1, newTab2, false);
|
||||
is(gBrowser.tabs.length, initialTabsLength + 3, "tabs are still there");
|
||||
is(gBrowser.tabs[initialTabsLength], newTab2, "newTab2 and newTab1 are swapped");
|
||||
is(gBrowser.tabs[initialTabsLength + 1], newTab1, "newTab1 and newTab2 are swapped");
|
||||
is(gBrowser.tabs[initialTabsLength + 2], newTab3, "newTab3 stays same place");
|
||||
|
||||
dragAndDrop(newTab2, newTab1, true);
|
||||
is(gBrowser.tabs.length, initialTabsLength + 4, "a tab is duplicated");
|
||||
is(gBrowser.tabs[initialTabsLength], newTab2, "newTab2 stays same place");
|
||||
is(gBrowser.tabs[initialTabsLength + 1], newTab1, "newTab1 stays same place");
|
||||
is(gBrowser.tabs[initialTabsLength + 3], newTab3, "a new tab is inserted before newTab3");
|
||||
}
|
@ -618,6 +618,9 @@
|
||||
@RESPATH@/components/TestInterfaceJS.manifest
|
||||
#endif
|
||||
|
||||
@RESPATH@/components/PACGenerator.js
|
||||
@RESPATH@/components/PACGenerator.manifest
|
||||
|
||||
; Modules
|
||||
@RESPATH@/browser/modules/*
|
||||
@RESPATH@/modules/*
|
||||
|
@ -3239,14 +3239,14 @@ nsDocShell::RemoveWeakScrollObserver(nsIScrollObserver* aObserver)
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShell::NotifyAsyncPanZoomStarted(const mozilla::CSSIntPoint aScrollPos)
|
||||
nsDocShell::NotifyAsyncPanZoomStarted()
|
||||
{
|
||||
nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
|
||||
while (iter.HasMore()) {
|
||||
nsWeakPtr ref = iter.GetNext();
|
||||
nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
|
||||
if (obs) {
|
||||
obs->AsyncPanZoomStarted(aScrollPos);
|
||||
obs->AsyncPanZoomStarted();
|
||||
} else {
|
||||
mScrollObservers.RemoveElement(ref);
|
||||
}
|
||||
@ -3257,20 +3257,20 @@ nsDocShell::NotifyAsyncPanZoomStarted(const mozilla::CSSIntPoint aScrollPos)
|
||||
nsCOMPtr<nsIDocShell> kid = do_QueryInterface(ChildAt(i));
|
||||
if (kid) {
|
||||
nsDocShell* docShell = static_cast<nsDocShell*>(kid.get());
|
||||
docShell->NotifyAsyncPanZoomStarted(aScrollPos);
|
||||
docShell->NotifyAsyncPanZoomStarted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShell::NotifyAsyncPanZoomStopped(const mozilla::CSSIntPoint aScrollPos)
|
||||
nsDocShell::NotifyAsyncPanZoomStopped()
|
||||
{
|
||||
nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
|
||||
while (iter.HasMore()) {
|
||||
nsWeakPtr ref = iter.GetNext();
|
||||
nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
|
||||
if (obs) {
|
||||
obs->AsyncPanZoomStopped(aScrollPos);
|
||||
obs->AsyncPanZoomStopped();
|
||||
} else {
|
||||
mScrollObservers.RemoveElement(ref);
|
||||
}
|
||||
@ -3281,7 +3281,7 @@ nsDocShell::NotifyAsyncPanZoomStopped(const mozilla::CSSIntPoint aScrollPos)
|
||||
nsCOMPtr<nsIDocShell> kid = do_QueryInterface(ChildAt(i));
|
||||
if (kid) {
|
||||
nsDocShell* docShell = static_cast<nsDocShell*>(kid.get());
|
||||
docShell->NotifyAsyncPanZoomStopped(aScrollPos);
|
||||
docShell->NotifyAsyncPanZoomStopped();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -262,10 +262,10 @@ public:
|
||||
|
||||
// Notify Scroll observers when an async panning/zooming transform
|
||||
// has started being applied
|
||||
void NotifyAsyncPanZoomStarted(const mozilla::CSSIntPoint aScrollPos);
|
||||
void NotifyAsyncPanZoomStarted();
|
||||
// Notify Scroll observers when an async panning/zooming transform
|
||||
// is no longer applied
|
||||
void NotifyAsyncPanZoomStopped(const mozilla::CSSIntPoint aScrollPos);
|
||||
void NotifyAsyncPanZoomStopped();
|
||||
|
||||
// Add new profile timeline markers to this docShell. This will only add
|
||||
// markers if the docShell is currently recording profile timeline markers.
|
||||
|
@ -11,8 +11,8 @@
|
||||
#include "Units.h"
|
||||
|
||||
#define NS_ISCROLLOBSERVER_IID \
|
||||
{ 0x00bc10e3, 0xaa59, 0x4aa3, \
|
||||
{ 0x88, 0xe9, 0x43, 0x0a, 0x01, 0xa3, 0x88, 0x04 } }
|
||||
{ 0xaa5026eb, 0x2f88, 0x4026, \
|
||||
{ 0xa4, 0x6b, 0xf4, 0x59, 0x6b, 0x4e, 0xdf, 0x00 } }
|
||||
|
||||
class nsIScrollObserver : public nsISupports
|
||||
{
|
||||
@ -28,13 +28,13 @@ public:
|
||||
* Called when an async panning/zooming transform has started being applied
|
||||
* and passed the scroll offset
|
||||
*/
|
||||
virtual void AsyncPanZoomStarted(const mozilla::CSSIntPoint aScrollPos) {};
|
||||
virtual void AsyncPanZoomStarted() {};
|
||||
|
||||
/**
|
||||
* Called when an async panning/zooming transform is no longer applied
|
||||
* and passed the scroll offset
|
||||
*/
|
||||
virtual void AsyncPanZoomStopped(const mozilla::CSSIntPoint aScrollPos) {};
|
||||
virtual void AsyncPanZoomStopped() {};
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIScrollObserver, NS_ISCROLLOBSERVER_IID)
|
||||
|
@ -159,7 +159,7 @@ bool
|
||||
WindowNamedPropertiesHandler::defineProperty(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aProxy,
|
||||
JS::Handle<jsid> aId,
|
||||
JS::MutableHandle<JSPropertyDescriptor> aDesc,
|
||||
JS::Handle<JSPropertyDescriptor> aDesc,
|
||||
JS::ObjectOpResult &result) const
|
||||
{
|
||||
ErrorResult rv;
|
||||
|
@ -28,7 +28,7 @@ public:
|
||||
virtual bool
|
||||
defineProperty(JSContext* aCx, JS::Handle<JSObject*> aProxy,
|
||||
JS::Handle<jsid> aId,
|
||||
JS::MutableHandle<JSPropertyDescriptor> aDesc,
|
||||
JS::Handle<JSPropertyDescriptor> aDesc,
|
||||
JS::ObjectOpResult &result) const override;
|
||||
virtual bool
|
||||
ownPropNames(JSContext* aCx, JS::Handle<JSObject*> aProxy, unsigned flags,
|
||||
|
@ -621,7 +621,7 @@ public:
|
||||
virtual bool defineProperty(JSContext* cx,
|
||||
JS::Handle<JSObject*> proxy,
|
||||
JS::Handle<jsid> id,
|
||||
JS::MutableHandle<JSPropertyDescriptor> desc,
|
||||
JS::Handle<JSPropertyDescriptor> desc,
|
||||
JS::ObjectOpResult &result) const override;
|
||||
virtual bool ownPropertyKeys(JSContext *cx,
|
||||
JS::Handle<JSObject*> proxy,
|
||||
@ -782,7 +782,7 @@ bool
|
||||
nsOuterWindowProxy::defineProperty(JSContext* cx,
|
||||
JS::Handle<JSObject*> proxy,
|
||||
JS::Handle<jsid> id,
|
||||
JS::MutableHandle<JSPropertyDescriptor> desc,
|
||||
JS::Handle<JSPropertyDescriptor> desc,
|
||||
JS::ObjectOpResult &result) const
|
||||
{
|
||||
int32_t index = GetArrayIndexFromId(cx, id);
|
||||
|
@ -1439,7 +1439,7 @@ XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
||||
bool
|
||||
XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
||||
JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
|
||||
JS::MutableHandle<JSPropertyDescriptor> desc,
|
||||
JS::Handle<JSPropertyDescriptor> desc,
|
||||
JS::ObjectOpResult &result, bool *defined)
|
||||
{
|
||||
if (!js::IsProxy(obj))
|
||||
|
@ -2466,7 +2466,7 @@ XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
||||
bool
|
||||
XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
||||
JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
|
||||
JS::MutableHandle<JSPropertyDescriptor> desc,
|
||||
JS::Handle<JSPropertyDescriptor> desc,
|
||||
JS::ObjectOpResult &result,
|
||||
bool *defined);
|
||||
|
||||
|
@ -10246,7 +10246,7 @@ class CGDOMJSProxyHandler_defineProperty(ClassMethod):
|
||||
args = [Argument('JSContext*', 'cx'),
|
||||
Argument('JS::Handle<JSObject*>', 'proxy'),
|
||||
Argument('JS::Handle<jsid>', 'id'),
|
||||
Argument('JS::MutableHandle<JSPropertyDescriptor>', 'desc'),
|
||||
Argument('JS::Handle<JSPropertyDescriptor>', 'desc'),
|
||||
Argument('JS::ObjectOpResult&', 'opresult'),
|
||||
Argument('bool*', 'defined')]
|
||||
ClassMethod.__init__(self, "defineProperty", "bool", args, virtual=True, override=True, const=True)
|
||||
|
@ -195,7 +195,7 @@ BaseDOMProxyHandler::getOwnPropertyDescriptor(JSContext* cx,
|
||||
|
||||
bool
|
||||
DOMProxyHandler::defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
|
||||
MutableHandle<JSPropertyDescriptor> desc,
|
||||
Handle<JSPropertyDescriptor> desc,
|
||||
JS::ObjectOpResult &result, bool *defined) const
|
||||
{
|
||||
if (desc.hasGetterObject() && desc.setter() == JS_StrictPropertyStub) {
|
||||
@ -252,7 +252,7 @@ DOMProxyHandler::set(JSContext *cx, Handle<JSObject*> proxy, Handle<JSObject*> r
|
||||
}
|
||||
}
|
||||
|
||||
return js::SetPropertyIgnoringNamedGetter(cx, proxy, id, vp, receiver, &desc, result);
|
||||
return js::SetPropertyIgnoringNamedGetter(cx, proxy, id, vp, receiver, desc, result);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -105,14 +105,14 @@ public:
|
||||
{}
|
||||
|
||||
bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
|
||||
JS::MutableHandle<JSPropertyDescriptor> desc,
|
||||
JS::Handle<JSPropertyDescriptor> desc,
|
||||
JS::ObjectOpResult &result) const override
|
||||
{
|
||||
bool unused;
|
||||
return defineProperty(cx, proxy, id, desc, result, &unused);
|
||||
}
|
||||
virtual bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
|
||||
JS::MutableHandle<JSPropertyDescriptor> desc,
|
||||
JS::Handle<JSPropertyDescriptor> desc,
|
||||
JS::ObjectOpResult &result, bool *defined) const;
|
||||
bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
|
||||
JS::ObjectOpResult &result) const override;
|
||||
|
@ -575,8 +575,6 @@ BrowserElementChild.prototype = {
|
||||
e.stopPropagation();
|
||||
let detail = {
|
||||
state: e.state,
|
||||
scrollX: e.scrollX,
|
||||
scrollY: e.scrollY,
|
||||
};
|
||||
sendAsyncMsg('scrollviewchange', detail);
|
||||
},
|
||||
|
@ -272,7 +272,8 @@ BrowserElementParent.prototype = {
|
||||
/* username and password */
|
||||
let detail = {
|
||||
host: authDetail.host,
|
||||
realm: authDetail.realm
|
||||
realm: authDetail.realm,
|
||||
isProxy: authDetail.isProxy
|
||||
};
|
||||
|
||||
evt = this._createEvent('usernameandpasswordrequired', detail,
|
||||
|
@ -383,17 +383,46 @@ BrowserElementAuthPrompt.prototype = {
|
||||
host: hostname,
|
||||
realm: httpRealm,
|
||||
username: authInfo.username,
|
||||
isProxy: !!(authInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY),
|
||||
isOnlyPassword: !!(authInfo.flags & Ci.nsIAuthInformation.ONLY_PASSWORD)
|
||||
};
|
||||
},
|
||||
|
||||
// The code is taken from nsLoginManagerPrompter.js, with slight
|
||||
// modification for parameter name consistency here.
|
||||
_getAuthTarget : function (channel, authInfo) {
|
||||
let hostname = this._getFormattedHostname(channel.URI);
|
||||
let hostname, realm;
|
||||
|
||||
// If our proxy is demanding authentication, don't use the
|
||||
// channel's actual destination.
|
||||
if (authInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY) {
|
||||
if (!(channel instanceof Ci.nsIProxiedChannel))
|
||||
throw new Error("proxy auth needs nsIProxiedChannel");
|
||||
|
||||
let info = channel.proxyInfo;
|
||||
if (!info)
|
||||
throw new Error("proxy auth needs nsIProxyInfo");
|
||||
|
||||
// Proxies don't have a scheme, but we'll use "moz-proxy://"
|
||||
// so that it's more obvious what the login is for.
|
||||
var idnService = Cc["@mozilla.org/network/idn-service;1"].
|
||||
getService(Ci.nsIIDNService);
|
||||
hostname = "moz-proxy://" +
|
||||
idnService.convertUTF8toACE(info.host) +
|
||||
":" + info.port;
|
||||
realm = authInfo.realm;
|
||||
if (!realm)
|
||||
realm = hostname;
|
||||
|
||||
return [hostname, realm];
|
||||
}
|
||||
|
||||
hostname = this._getFormattedHostname(channel.URI);
|
||||
|
||||
// If a HTTP WWW-Authenticate header specified a realm, that value
|
||||
// will be available here. If it wasn't set or wasn't HTTP, we'll use
|
||||
// the formatted hostname instead.
|
||||
let realm = authInfo.realm;
|
||||
realm = authInfo.realm;
|
||||
if (!realm)
|
||||
realm = hostname;
|
||||
|
||||
|
@ -66,11 +66,12 @@ function testHttpAuth(e) {
|
||||
iframe.removeEventListener("mozbrowsertitlechange", onTitleChange);
|
||||
iframe.removeEventListener("mozbrowserusernameandpasswordrequired", testFail);
|
||||
is(e.detail, 'http auth success', 'expect authentication to succeed');
|
||||
SimpleTest.executeSoon(testAuthJarNoInterfere);
|
||||
SimpleTest.executeSoon(testProxyAuth);
|
||||
});
|
||||
|
||||
is(e.detail.realm, 'http_realm', 'expected realm matches');
|
||||
is(e.detail.host, 'http://test', 'expected host matches');
|
||||
is(e.detail.isProxy, false, 'expected isProxy is false');
|
||||
e.preventDefault();
|
||||
|
||||
SimpleTest.executeSoon(function() {
|
||||
@ -78,6 +79,74 @@ function testHttpAuth(e) {
|
||||
});
|
||||
}
|
||||
|
||||
function testProxyAuth(e) {
|
||||
// The testingSJS simulates the 407 proxy authentication required response
|
||||
// for proxy server, which will trigger the browser element to send prompt
|
||||
// event with proxy infomation.
|
||||
var testingSJS = 'http://test/tests/dom/browser-element/mochitest/file_http_407_response.sjs';
|
||||
var mozproxy;
|
||||
|
||||
function onUserNameAndPasswordRequired(e) {
|
||||
iframe.removeEventListener("mozbrowserusernameandpasswordrequired",
|
||||
onUserNameAndPasswordRequired);
|
||||
iframe.addEventListener("mozbrowsertitlechange", function onTitleChange(e) {
|
||||
iframe.removeEventListener("mozbrowsertitlechange", onTitleChange);
|
||||
iframe.removeEventListener("mozbrowserusernameandpasswordrequired", testFail);
|
||||
is(e.detail, 'http auth success', 'expect authentication to succeed');
|
||||
SimpleTest.executeSoon(testAuthJarNoInterfere);
|
||||
});
|
||||
|
||||
is(e.detail.realm, 'http_realm', 'expected realm matches');
|
||||
is(e.detail.host, mozproxy, 'expected host matches');
|
||||
is(e.detail.isProxy, true, 'expected isProxy is true');
|
||||
e.preventDefault();
|
||||
|
||||
SimpleTest.executeSoon(function() {
|
||||
e.detail.authenticate("proxyuser", "proxypass");
|
||||
});
|
||||
}
|
||||
|
||||
// Resolve proxy information used by the test suite, we need it to validate
|
||||
// whether the proxy information delivered with the prompt event is correct.
|
||||
var resolveCallback = SpecialPowers.wrapCallbackObject({
|
||||
QueryInterface: function (iid) {
|
||||
const interfaces = [Ci.nsIProtocolProxyCallback, Ci.nsISupports];
|
||||
|
||||
if (!interfaces.some( function(v) { return iid.equals(v) } )) {
|
||||
throw SpecialPowers.Cr.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
onProxyAvailable: function (req, channel, pi, status) {
|
||||
isnot(pi, null, 'expected proxy information available');
|
||||
if (pi) {
|
||||
mozproxy = "moz-proxy://" + pi.host + ":" + pi.port;
|
||||
}
|
||||
iframe.addEventListener("mozbrowserusernameandpasswordrequired",
|
||||
onUserNameAndPasswordRequired);
|
||||
|
||||
iframe.src = testingSJS;
|
||||
}
|
||||
});
|
||||
|
||||
var ioService = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(SpecialPowers.Ci.nsIIOService);
|
||||
var pps = SpecialPowers.Cc["@mozilla.org/network/protocol-proxy-service;1"]
|
||||
.getService();
|
||||
var systemPrincipal = SpecialPowers.Services.scriptSecurityManager
|
||||
.getSystemPrincipal();
|
||||
var channel = ioService.newChannel2(testingSJS,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
systemPrincipal,
|
||||
null,
|
||||
SpecialPowers.Ci.nsILoadInfo.SEC_NORMAL,
|
||||
SpecialPowers.Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
pps.asyncResolve(channel, 0, resolveCallback);
|
||||
}
|
||||
|
||||
function testAuthJarNoInterfere(e) {
|
||||
var authMgr = SpecialPowers.Cc['@mozilla.org/network/http-auth-manager;1']
|
||||
.getService(SpecialPowers.Ci.nsIHttpAuthManager);
|
||||
|
16
dom/browser-element/mochitest/file_http_407_response.sjs
Normal file
16
dom/browser-element/mochitest/file_http_407_response.sjs
Normal file
@ -0,0 +1,16 @@
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
var auth = "";
|
||||
try {
|
||||
auth = request.getHeader("Proxy-Authorization");
|
||||
} catch(e) {}
|
||||
|
||||
if (auth == "Basic cHJveHl1c2VyOnByb3h5cGFzcw==") {
|
||||
response.setStatusLine("1.1", 200, "OK");
|
||||
response.write("<html><head><title>http auth success</title></head><html>");
|
||||
} else {
|
||||
response.setStatusLine("1.1", 407, "Proxy Authentication Required");
|
||||
response.setHeader("Proxy-Authenticate", "Basic realm=\"http_realm\"");
|
||||
response.write("<html><head><title>http auth failed</title></head><html>");
|
||||
}
|
||||
}
|
@ -111,6 +111,7 @@ support-files =
|
||||
file_empty_script.js
|
||||
file_focus.html
|
||||
file_http_401_response.sjs
|
||||
file_http_407_response.sjs
|
||||
file_inputmethod.html
|
||||
file_post_request.html
|
||||
file_wyciwyg.html
|
||||
|
57
dom/cache/Context.cpp
vendored
57
dom/cache/Context.cpp
vendored
@ -82,6 +82,7 @@ public:
|
||||
, mInitiatingThread(NS_GetCurrentThread())
|
||||
, mResult(NS_OK)
|
||||
, mState(STATE_INIT)
|
||||
, mCanceled(false)
|
||||
, mNeedsQuotaRelease(false)
|
||||
{
|
||||
MOZ_ASSERT(mContext);
|
||||
@ -91,7 +92,7 @@ public:
|
||||
|
||||
nsresult Dispatch()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(Action::Resolver);
|
||||
NS_ASSERT_OWNINGTHREAD(QuotaInitRunnable);
|
||||
MOZ_ASSERT(mState == STATE_INIT);
|
||||
|
||||
mState = STATE_CALL_WAIT_FOR_OPEN_ALLOWED;
|
||||
@ -103,6 +104,14 @@ public:
|
||||
return rv;
|
||||
}
|
||||
|
||||
void Cancel()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(QuotaInitRunnable);
|
||||
MOZ_ASSERT(!mCanceled);
|
||||
mCanceled = true;
|
||||
mQuotaIOThreadAction->CancelOnInitiatingThread();
|
||||
}
|
||||
|
||||
private:
|
||||
class SyncResolver final : public Action::Resolver
|
||||
{
|
||||
@ -152,7 +161,7 @@ private:
|
||||
|
||||
void Clear()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(Action::Resolver);
|
||||
NS_ASSERT_OWNINGTHREAD(QuotaInitRunnable);
|
||||
MOZ_ASSERT(mContext);
|
||||
mContext = nullptr;
|
||||
mManager = nullptr;
|
||||
@ -168,6 +177,7 @@ private:
|
||||
QuotaInfo mQuotaInfo;
|
||||
nsMainThreadPtrHandle<OfflineStorage> mOfflineStorage;
|
||||
State mState;
|
||||
Atomic<bool> mCanceled;
|
||||
bool mNeedsQuotaRelease;
|
||||
|
||||
public:
|
||||
@ -223,6 +233,12 @@ Context::QuotaInitRunnable::Run()
|
||||
case STATE_CALL_WAIT_FOR_OPEN_ALLOWED:
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mCanceled) {
|
||||
resolver->Resolve(NS_ERROR_ABORT);
|
||||
break;
|
||||
}
|
||||
|
||||
QuotaManager* qm = QuotaManager::GetOrCreate();
|
||||
if (!qm) {
|
||||
resolver->Resolve(NS_ERROR_FAILURE);
|
||||
@ -266,6 +282,11 @@ Context::QuotaInitRunnable::Run()
|
||||
|
||||
mNeedsQuotaRelease = true;
|
||||
|
||||
if (mCanceled) {
|
||||
resolver->Resolve(NS_ERROR_ABORT);
|
||||
break;
|
||||
}
|
||||
|
||||
QuotaManager* qm = QuotaManager::Get();
|
||||
MOZ_ASSERT(qm);
|
||||
|
||||
@ -289,6 +310,11 @@ Context::QuotaInitRunnable::Run()
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(_mOwningThread.GetThread() != PR_GetCurrentThread());
|
||||
|
||||
if (mCanceled) {
|
||||
resolver->Resolve(NS_ERROR_ABORT);
|
||||
break;
|
||||
}
|
||||
|
||||
QuotaManager* qm = QuotaManager::Get();
|
||||
MOZ_ASSERT(qm);
|
||||
nsresult rv = qm->EnsureOriginIsInitialized(PERSISTENCE_TYPE_DEFAULT,
|
||||
@ -318,7 +344,7 @@ Context::QuotaInitRunnable::Run()
|
||||
// -------------------
|
||||
case STATE_COMPLETING:
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(Action::Resolver);
|
||||
NS_ASSERT_OWNINGTHREAD(QuotaInitRunnable);
|
||||
if (mQuotaIOThreadAction) {
|
||||
mQuotaIOThreadAction->CompleteOnInitiatingThread(mResult);
|
||||
}
|
||||
@ -385,7 +411,7 @@ public:
|
||||
|
||||
nsresult Dispatch()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(Action::Resolver);
|
||||
NS_ASSERT_OWNINGTHREAD(ActionRunnable);
|
||||
MOZ_ASSERT(mState == STATE_INIT);
|
||||
|
||||
mState = STATE_RUN_ON_TARGET;
|
||||
@ -400,14 +426,14 @@ public:
|
||||
virtual bool
|
||||
MatchesCacheId(CacheId aCacheId) const override
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(Action::Resolver);
|
||||
NS_ASSERT_OWNINGTHREAD(ActionRunnable);
|
||||
return mAction->MatchesCacheId(aCacheId);
|
||||
}
|
||||
|
||||
virtual void
|
||||
Cancel() override
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(Action::Resolver);
|
||||
NS_ASSERT_OWNINGTHREAD(ActionRunnable);
|
||||
mAction->CancelOnInitiatingThread();
|
||||
}
|
||||
|
||||
@ -447,7 +473,7 @@ private:
|
||||
|
||||
void Clear()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(Action::Resolver);
|
||||
NS_ASSERT_OWNINGTHREAD(ActionRunnable);
|
||||
MOZ_ASSERT(mContext);
|
||||
MOZ_ASSERT(mAction);
|
||||
mContext->RemoveActivity(this);
|
||||
@ -562,7 +588,7 @@ Context::ActionRunnable::Run()
|
||||
// -------------------
|
||||
case STATE_COMPLETING:
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(Action::Resolver);
|
||||
NS_ASSERT_OWNINGTHREAD(ActionRunnable);
|
||||
mAction->CompleteOnInitiatingThread(mResult);
|
||||
mState = STATE_COMPLETE;
|
||||
// Explicitly cleanup here as the destructor could fire on any of
|
||||
@ -679,9 +705,9 @@ Context::Create(Manager* aManager, Action* aQuotaIOThreadAction)
|
||||
{
|
||||
nsRefPtr<Context> context = new Context(aManager);
|
||||
|
||||
nsRefPtr<QuotaInitRunnable> runnable =
|
||||
new QuotaInitRunnable(context, aManager, aQuotaIOThreadAction);
|
||||
nsresult rv = runnable->Dispatch();
|
||||
context->mInitRunnable = new QuotaInitRunnable(context, aManager,
|
||||
aQuotaIOThreadAction);
|
||||
nsresult rv = context->mInitRunnable->Dispatch();
|
||||
if (NS_FAILED(rv)) {
|
||||
// Shutdown must be delayed until all Contexts are destroyed. Shutdown
|
||||
// must also prevent any new Contexts from being constructed. Crash
|
||||
@ -723,6 +749,12 @@ void
|
||||
Context::CancelAll()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(Context);
|
||||
|
||||
if (mInitRunnable) {
|
||||
MOZ_ASSERT(mState == STATE_CONTEXT_INIT);
|
||||
mInitRunnable->Cancel();
|
||||
}
|
||||
|
||||
mState = STATE_CONTEXT_CANCELED;
|
||||
mPendingActions.Clear();
|
||||
{
|
||||
@ -807,6 +839,9 @@ Context::OnQuotaInit(nsresult aRv, const QuotaInfo& aQuotaInfo,
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(Context);
|
||||
|
||||
MOZ_ASSERT(mInitRunnable);
|
||||
mInitRunnable = nullptr;
|
||||
|
||||
mQuotaInfo = aQuotaInfo;
|
||||
|
||||
// Always save the offline storage to ensure QuotaManager does not shutdown
|
||||
|
1
dom/cache/Context.h
vendored
1
dom/cache/Context.h
vendored
@ -177,6 +177,7 @@ private:
|
||||
nsRefPtr<Manager> mManager;
|
||||
State mState;
|
||||
QuotaInfo mQuotaInfo;
|
||||
nsRefPtr<QuotaInitRunnable> mInitRunnable;
|
||||
nsTArray<PendingAction> mPendingActions;
|
||||
|
||||
// Weak refs since activites must remove themselves from this list before
|
||||
|
26
dom/cache/test/mochitest/test_cache_put.js
vendored
26
dom/cache/test/mochitest/test_cache_put.js
vendored
@ -15,10 +15,34 @@ Promise.all([fetch(url),
|
||||
return Promise.all([fetchResponse.text(),
|
||||
response.text()]);
|
||||
}).then(function(results) {
|
||||
// suppress large assert spam unless its relevent
|
||||
// suppress large assert spam unless it's relevent
|
||||
if (results[0] !== results[1]) {
|
||||
is(results[0], results[1], 'stored response body should match original');
|
||||
}
|
||||
|
||||
// Now, try to overwrite the request with a different response object.
|
||||
return cache.put(url, new Response("overwritten"));
|
||||
}).then(function() {
|
||||
return cache.matchAll(url);
|
||||
}).then(function(result) {
|
||||
is(result.length, 1, "Only one entry should exist");
|
||||
return result[0].text();
|
||||
}).then(function(body) {
|
||||
is(body, "overwritten", "The cache entry should be successfully overwritten");
|
||||
|
||||
// Now, try to write a URL with a fragment
|
||||
return cache.put(url + "#fragment", new Response("more overwritten"));
|
||||
}).then(function() {
|
||||
return cache.matchAll(url + "#differentFragment");
|
||||
}).then(function(result) {
|
||||
is(result.length, 1, "Only one entry should exist");
|
||||
return result[0].text();
|
||||
}).then(function(body) {
|
||||
is(body, "more overwritten", "The cache entry should be successfully overwritten");
|
||||
|
||||
// TODO: Verify that trying to store a response with an error raises a TypeError
|
||||
// when bug 1147178 is fixed.
|
||||
|
||||
return caches.delete('putter' + context);
|
||||
}).then(function(deleted) {
|
||||
ok(deleted, "The cache should be deleted successfully");
|
||||
|
@ -122,16 +122,32 @@ private:
|
||||
|
||||
public:
|
||||
void Uniform1uiv(WebGLUniformLocation* loc, const dom::Sequence<GLuint>& arr) {
|
||||
Uniform1uiv_base(loc,arr.Length(), arr.Elements());
|
||||
Uniform1uiv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform2uiv(WebGLUniformLocation* loc, const dom::Sequence<GLuint>& arr) {
|
||||
Uniform2uiv_base(loc,arr.Length(), arr.Elements());
|
||||
Uniform2uiv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform3uiv(WebGLUniformLocation* loc, const dom::Sequence<GLuint>& arr) {
|
||||
Uniform3uiv_base(loc,arr.Length(), arr.Elements());
|
||||
Uniform3uiv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform4uiv(WebGLUniformLocation* loc, const dom::Sequence<GLuint>& arr) {
|
||||
Uniform4uiv_base(loc,arr.Length(), arr.Elements());
|
||||
Uniform4uiv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform1uiv(WebGLUniformLocation* loc, const dom::Uint32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform1uiv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform2uiv(WebGLUniformLocation* loc, const dom::Uint32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform2uiv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform3uiv(WebGLUniformLocation* loc, const dom::Uint32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform3uiv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform4uiv(WebGLUniformLocation* loc, const dom::Uint32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform4uiv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -2431,7 +2431,7 @@ EventStateManager::DoScrollText(nsIScrollableFrame* aScrollableFrame,
|
||||
actualDevPixelScrollAmount.y = 0;
|
||||
}
|
||||
|
||||
nsIScrollableFrame::ScrollSnapMode snapMode = nsIScrollableFrame::DISABLE_SNAP;
|
||||
nsIScrollbarMediator::ScrollSnapMode snapMode = nsIScrollbarMediator::DISABLE_SNAP;
|
||||
nsIAtom* origin = nullptr;
|
||||
switch (aEvent->deltaMode) {
|
||||
case nsIDOMWheelEvent::DOM_DELTA_LINE:
|
||||
|
@ -2392,7 +2392,8 @@ TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent,
|
||||
return true;
|
||||
}
|
||||
|
||||
mAPZEventState->ProcessTouchEvent(localEvent, aGuid, aInputBlockId);
|
||||
mAPZEventState->ProcessTouchEvent(localEvent, aGuid, aInputBlockId,
|
||||
nsEventStatus_eIgnore);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
* ManifestProcessor
|
||||
* Implementation of processing algorithms from:
|
||||
* http://www.w3.org/2008/webapps/manifest/
|
||||
@ -10,351 +11,347 @@
|
||||
* or individual parts of a manifest object. A manifest is just a
|
||||
* standard JS object that has been cleaned up.
|
||||
*
|
||||
* .process({jsonText,manifestURL,docURL});
|
||||
* .process(jsonText, manifestURL, docURL);
|
||||
*
|
||||
* TODO: The constructor should accept the UA's supported orientations.
|
||||
* TODO: The constructor should accept the UA's supported display modes.
|
||||
* TODO: hook up developer tools to console. (1086997).
|
||||
* TODO: hook up developer tools to issueDeveloperWarning (1086997).
|
||||
*/
|
||||
/*globals Components*/
|
||||
/*exported EXPORTED_SYMBOLS */
|
||||
/*JSLint options in comment below: */
|
||||
/*globals Components, XPCOMUtils*/
|
||||
'use strict';
|
||||
|
||||
this.EXPORTED_SYMBOLS = ['ManifestProcessor'];
|
||||
const imports = {};
|
||||
const {
|
||||
utils: Cu,
|
||||
classes: Cc,
|
||||
interfaces: Ci
|
||||
} = Components;
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
const imports = {};
|
||||
Cu.import('resource://gre/modules/Services.jsm', imports);
|
||||
Cu.importGlobalProperties(['URL']);
|
||||
XPCOMUtils.defineLazyModuleGetter(imports, 'Services',
|
||||
'resource://gre/modules/Services.jsm');
|
||||
imports.netutil = Cc['@mozilla.org/network/util;1'].getService(Ci.nsINetUtil);
|
||||
// Helper function extracts values from manifest members
|
||||
// and reports conformance violations.
|
||||
function extractValue({
|
||||
objectName,
|
||||
object,
|
||||
property,
|
||||
expectedType,
|
||||
trim
|
||||
}, console) {
|
||||
const value = object[property];
|
||||
const isArray = Array.isArray(value);
|
||||
// We need to special-case "array", as it's not a JS primitive.
|
||||
const type = (isArray) ? 'array' : typeof value;
|
||||
if (type !== expectedType) {
|
||||
if (type !== 'undefined') {
|
||||
let msg = `Expected the ${objectName}'s ${property} `;
|
||||
msg += `member to a be a ${expectedType}.`;
|
||||
console.log(msg);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
// Trim string and returned undefined if the empty string.
|
||||
const shouldTrim = expectedType === 'string' && value && trim;
|
||||
if (shouldTrim) {
|
||||
return value.trim() || undefined;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
const displayModes = new Set(['fullscreen', 'standalone', 'minimal-ui',
|
||||
const securityManager = imports.Services.scriptSecurityManager;
|
||||
const netutil = Cc['@mozilla.org/network/util;1'].getService(Ci.nsINetUtil);
|
||||
const defaultDisplayMode = 'browser';
|
||||
const displayModes = new Set([
|
||||
'fullscreen',
|
||||
'standalone',
|
||||
'minimal-ui',
|
||||
'browser'
|
||||
]);
|
||||
const orientationTypes = new Set(['any', 'natural', 'landscape', 'portrait',
|
||||
'portrait-primary', 'portrait-secondary', 'landscape-primary',
|
||||
const orientationTypes = new Set([
|
||||
'any',
|
||||
'natural',
|
||||
'landscape',
|
||||
'portrait',
|
||||
'portrait-primary',
|
||||
'portrait-secondary',
|
||||
'landscape-primary',
|
||||
'landscape-secondary'
|
||||
]);
|
||||
const {
|
||||
ConsoleAPI
|
||||
} = Cu.import('resource://gre/modules/devtools/Console.jsm');
|
||||
|
||||
class ManifestProcessor {
|
||||
this.ManifestProcessor = function ManifestProcessor() {};
|
||||
/**
|
||||
* process method: processes json text into a clean manifest
|
||||
* that conforms with the W3C specification.
|
||||
* @param jsonText - the JSON string to be processd.
|
||||
* @param manifestURL - the URL of the manifest, to resolve URLs.
|
||||
* @param docURL - the URL of the owner doc, for security checks
|
||||
*/
|
||||
this.ManifestProcessor.prototype.process = function({
|
||||
jsonText: jsonText,
|
||||
manifestURL: manifestURL,
|
||||
docLocation: docURL
|
||||
}) {
|
||||
/*
|
||||
* This helper function is used to extract values from manifest members.
|
||||
* It also reports conformance violations.
|
||||
*/
|
||||
function extractValue(obj) {
|
||||
let value = obj.object[obj.property];
|
||||
//we need to special-case "array", as it's not a JS primitive
|
||||
const type = (Array.isArray(value)) ? 'array' : typeof value;
|
||||
|
||||
constructor() {}
|
||||
|
||||
static get defaultDisplayMode() {
|
||||
return 'browser';
|
||||
if (type !== obj.expectedType) {
|
||||
if (type !== 'undefined') {
|
||||
let msg = `Expected the ${obj.objectName}'s ${obj.property}`;
|
||||
msg += `member to a be a ${obj.expectedType}.`;
|
||||
issueDeveloperWarning(msg);
|
||||
}
|
||||
value = undefined;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static get displayModes() {
|
||||
return displayModes;
|
||||
function issueDeveloperWarning(msg) {
|
||||
//https://bugzilla.mozilla.org/show_bug.cgi?id=1086997
|
||||
}
|
||||
|
||||
static get orientationTypes() {
|
||||
return orientationTypes;
|
||||
}
|
||||
|
||||
// process method: processes json text into a clean manifest
|
||||
// that conforms with the W3C specification. Takes an object
|
||||
// expecting the following dictionary items:
|
||||
// * jsonText: the JSON string to be processd.
|
||||
// * manifestURL: the URL of the manifest, to resolve URLs.
|
||||
// * docURL: the URL of the owner doc, for security checks.
|
||||
process({
|
||||
jsonText, manifestURL, docURL
|
||||
}) {
|
||||
const console = new ConsoleAPI({
|
||||
prefix: 'Web Manifest: '
|
||||
});
|
||||
let rawManifest = {};
|
||||
try {
|
||||
rawManifest = JSON.parse(jsonText);
|
||||
} catch (e) {}
|
||||
if (typeof rawManifest !== 'object' || rawManifest === null) {
|
||||
let msg = 'Manifest needs to be an object.';
|
||||
console.warn(msg);
|
||||
rawManifest = {};
|
||||
}
|
||||
const processedManifest = {
|
||||
start_url: processStartURLMember(rawManifest, manifestURL, docURL),
|
||||
display: processDisplayMember(rawManifest),
|
||||
orientation: processOrientationMember(rawManifest),
|
||||
name: processNameMember(rawManifest),
|
||||
icons: IconsProcessor.process(rawManifest, manifestURL, console),
|
||||
short_name: processShortNameMember(rawManifest),
|
||||
};
|
||||
processedManifest.scope = processScopeMember(rawManifest, manifestURL,
|
||||
docURL, processedManifest.start_url);
|
||||
return processedManifest;
|
||||
|
||||
function processNameMember(aManifest) {
|
||||
const spec = {
|
||||
function processNameMember(manifest) {
|
||||
const obj = {
|
||||
objectName: 'manifest',
|
||||
object: aManifest,
|
||||
object: manifest,
|
||||
property: 'name',
|
||||
expectedType: 'string',
|
||||
trim: true
|
||||
expectedType: 'string'
|
||||
};
|
||||
return extractValue(spec, console);
|
||||
let value = extractValue(obj);
|
||||
return (value) ? value.trim() : value;
|
||||
}
|
||||
|
||||
function processShortNameMember(aManifest) {
|
||||
const spec = {
|
||||
function processShortNameMember(manifest) {
|
||||
const obj = {
|
||||
objectName: 'manifest',
|
||||
object: aManifest,
|
||||
object: manifest,
|
||||
property: 'short_name',
|
||||
expectedType: 'string',
|
||||
trim: true
|
||||
expectedType: 'string'
|
||||
};
|
||||
return extractValue(spec, console);
|
||||
let value = extractValue(obj);
|
||||
return (value) ? value.trim() : value;
|
||||
}
|
||||
|
||||
function processOrientationMember(aManifest) {
|
||||
const spec = {
|
||||
function processOrientationMember(manifest) {
|
||||
const obj = {
|
||||
objectName: 'manifest',
|
||||
object: aManifest,
|
||||
object: manifest,
|
||||
property: 'orientation',
|
||||
expectedType: 'string',
|
||||
trim: true
|
||||
expectedType: 'string'
|
||||
};
|
||||
const value = extractValue(spec, console);
|
||||
if (ManifestProcessor.orientationTypes.has(value)) {
|
||||
return value;
|
||||
}
|
||||
// The spec special-cases orientation to return the empty string.
|
||||
return '';
|
||||
let value = extractValue(obj);
|
||||
value = (value) ? value.trim() : undefined;
|
||||
//The spec special-cases orientation to return the empty string
|
||||
return (orientationTypes.has(value)) ? value : '';
|
||||
}
|
||||
|
||||
function processDisplayMember(aManifest) {
|
||||
const spec = {
|
||||
function processDisplayMember(manifest) {
|
||||
const obj = {
|
||||
objectName: 'manifest',
|
||||
object: aManifest,
|
||||
object: manifest,
|
||||
property: 'display',
|
||||
expectedType: 'string',
|
||||
trim: true
|
||||
expectedType: 'string'
|
||||
};
|
||||
const value = extractValue(spec, console);
|
||||
if (ManifestProcessor.displayModes.has(value)) {
|
||||
return value;
|
||||
}
|
||||
return ManifestProcessor.defaultDisplayMode;
|
||||
|
||||
let value = extractValue(obj);
|
||||
value = (value) ? value.trim() : value;
|
||||
return (displayModes.has(value)) ? value : defaultDisplayMode;
|
||||
}
|
||||
|
||||
function processScopeMember(aManifest, aManifestURL, aDocURL, aStartURL) {
|
||||
function processScopeMember(manifest, manifestURL, docURL, startURL) {
|
||||
const spec = {
|
||||
objectName: 'manifest',
|
||||
object: aManifest,
|
||||
object: manifest,
|
||||
property: 'scope',
|
||||
expectedType: 'string',
|
||||
trim: false
|
||||
};
|
||||
const value = extractValue(spec, console);
|
||||
dontTrim: true
|
||||
},
|
||||
value = extractValue(spec);
|
||||
let scopeURL;
|
||||
try {
|
||||
scopeURL = new URL(value, aManifestURL);
|
||||
scopeURL = new URL(value, manifestURL);
|
||||
} catch (e) {
|
||||
let msg = 'The URL of scope is invalid.';
|
||||
console.warn(msg);
|
||||
issueDeveloperWarning(msg);
|
||||
return undefined;
|
||||
}
|
||||
if (scopeURL.origin !== aDocURL.origin) {
|
||||
|
||||
if (scopeURL.origin !== docURL.origin) {
|
||||
let msg = 'Scope needs to be same-origin as Document.';
|
||||
console.warn(msg);
|
||||
issueDeveloperWarning(msg);
|
||||
return undefined;
|
||||
}
|
||||
// If start URL is not within scope of scope URL:
|
||||
let isSameOrigin = aStartURL && aStartURL.origin !== scopeURL.origin;
|
||||
if (isSameOrigin || !aStartURL.pathname.startsWith(scopeURL.pathname)) {
|
||||
let msg =
|
||||
'The start URL is outside the scope, so scope is invalid.';
|
||||
console.warn(msg);
|
||||
|
||||
//If start URL is not within scope of scope URL:
|
||||
if (startURL && startURL.origin !== scopeURL.origin || !startURL.pathname.startsWith(scopeURL.pathname)) {
|
||||
let msg = 'The start URL is outside the scope, so scope is invalid.';
|
||||
issueDeveloperWarning(msg);
|
||||
return undefined;
|
||||
}
|
||||
return scopeURL;
|
||||
}
|
||||
|
||||
function processStartURLMember(aManifest, aManifestURL, aDocURL) {
|
||||
const spec = {
|
||||
function processStartURLMember(manifest, manifestURL, docURL) {
|
||||
const obj = {
|
||||
objectName: 'manifest',
|
||||
object: aManifest,
|
||||
object: manifest,
|
||||
property: 'start_url',
|
||||
expectedType: 'string',
|
||||
trim: false
|
||||
expectedType: 'string'
|
||||
};
|
||||
let result = new URL(aDocURL);
|
||||
const value = extractValue(spec, console);
|
||||
|
||||
let value = extractValue(obj),
|
||||
result = new URL(docURL),
|
||||
targetURI = makeURI(result),
|
||||
sameOrigin = false,
|
||||
potentialResult,
|
||||
referrerURI;
|
||||
|
||||
if (value === undefined || value === '') {
|
||||
return result;
|
||||
}
|
||||
let potentialResult;
|
||||
|
||||
try {
|
||||
potentialResult = new URL(value, aManifestURL);
|
||||
potentialResult = new URL(value, manifestURL);
|
||||
} catch (e) {
|
||||
console.warn('Invalid URL.');
|
||||
issueDeveloperWarning('Invalid URL.');
|
||||
return result;
|
||||
}
|
||||
if (potentialResult.origin !== aDocURL.origin) {
|
||||
referrerURI = makeURI(potentialResult);
|
||||
try {
|
||||
securityManager.checkSameOriginURI(referrerURI, targetURI, false);
|
||||
sameOrigin = true;
|
||||
} catch (e) {}
|
||||
if (!sameOrigin) {
|
||||
let msg = 'start_url must be same origin as document.';
|
||||
console.warn(msg);
|
||||
issueDeveloperWarning(msg);
|
||||
} else {
|
||||
result = potentialResult;
|
||||
}
|
||||
return result;
|
||||
|
||||
//Converts a URL to a Gecko URI
|
||||
function makeURI(webURL) {
|
||||
return imports.Services.io.newURI(webURL.toString(), null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.ManifestProcessor = ManifestProcessor;
|
||||
|
||||
class IconsProcessor {
|
||||
//Constants used by IconsProcessor
|
||||
const onlyDecimals = /^\d+$/,
|
||||
anyRegEx = new RegExp('any', 'i');
|
||||
|
||||
constructor() {
|
||||
throw new Error('Static use only.');
|
||||
}
|
||||
|
||||
static get onlyDecimals() {
|
||||
return /^\d+$/;
|
||||
}
|
||||
|
||||
static get anyRegEx() {
|
||||
return new RegExp('any', 'i');
|
||||
}
|
||||
|
||||
static process(aManifest, aBaseURL, console) {
|
||||
const spec = {
|
||||
function IconsProcessor() {}
|
||||
IconsProcessor.prototype.processIcons = function(manifest, baseURL) {
|
||||
const obj = {
|
||||
objectName: 'manifest',
|
||||
object: aManifest,
|
||||
object: manifest,
|
||||
property: 'icons',
|
||||
expectedType: 'array',
|
||||
trim: false
|
||||
};
|
||||
const icons = [];
|
||||
const value = extractValue(spec, console);
|
||||
expectedType: 'array'
|
||||
},
|
||||
icons = [];
|
||||
let value = extractValue(obj);
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
// Filter out icons whose "src" is not useful.
|
||||
value.filter(item => !!processSrcMember(item, aBaseURL))
|
||||
.map(toIconObject)
|
||||
.forEach(icon => icons.push(icon));
|
||||
//filter out icons with no "src" or src is empty string
|
||||
let processableIcons = value.filter(
|
||||
icon => icon && Object.prototype.hasOwnProperty.call(icon, 'src') && icon.src !== ''
|
||||
);
|
||||
for (let potentialIcon of processableIcons) {
|
||||
let src = processSrcMember(potentialIcon, baseURL)
|
||||
if(src !== undefined){
|
||||
let icon = {
|
||||
src: src,
|
||||
type: processTypeMember(potentialIcon),
|
||||
sizes: processSizesMember(potentialIcon),
|
||||
density: processDensityMember(potentialIcon)
|
||||
};
|
||||
icons.push(icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
return icons;
|
||||
|
||||
function toIconObject(aIconData) {
|
||||
return {
|
||||
src: processSrcMember(aIconData, aBaseURL),
|
||||
type: processTypeMember(aIconData),
|
||||
sizes: processSizesMember(aIconData),
|
||||
density: processDensityMember(aIconData)
|
||||
};
|
||||
}
|
||||
|
||||
function processTypeMember(aIcon) {
|
||||
const charset = {};
|
||||
const hadCharset = {};
|
||||
const spec = {
|
||||
function processTypeMember(icon) {
|
||||
const charset = {},
|
||||
hadCharset = {},
|
||||
obj = {
|
||||
objectName: 'icon',
|
||||
object: aIcon,
|
||||
object: icon,
|
||||
property: 'type',
|
||||
expectedType: 'string',
|
||||
trim: true
|
||||
expectedType: 'string'
|
||||
};
|
||||
let value = extractValue(spec, console);
|
||||
if (value) {
|
||||
value = imports.netutil.parseContentType(value, charset, hadCharset);
|
||||
}
|
||||
return value || undefined;
|
||||
let value = extractValue(obj),
|
||||
isParsable = (typeof value === 'string' && value.length > 0);
|
||||
value = (isParsable) ? netutil.parseContentType(value.trim(), charset, hadCharset) : undefined;
|
||||
return (value === '') ? undefined : value;
|
||||
}
|
||||
|
||||
function processDensityMember(aIcon) {
|
||||
const value = parseFloat(aIcon.density);
|
||||
const validNum = Number.isNaN(value) || value === +Infinity || value <=
|
||||
0;
|
||||
return (validNum) ? 1.0 : value;
|
||||
function processDensityMember(icon) {
|
||||
const hasDensity = Object.prototype.hasOwnProperty.call(icon, 'density'),
|
||||
rawValue = (hasDensity) ? icon.density : undefined,
|
||||
value = parseFloat(rawValue),
|
||||
result = (Number.isNaN(value) || value === +Infinity || value <= 0) ? 1.0 : value;
|
||||
return result;
|
||||
}
|
||||
|
||||
function processSrcMember(aIcon, aBaseURL) {
|
||||
const spec = {
|
||||
function processSrcMember(icon, baseURL) {
|
||||
const obj = {
|
||||
objectName: 'icon',
|
||||
object: aIcon,
|
||||
object: icon,
|
||||
property: 'src',
|
||||
expectedType: 'string',
|
||||
trim: false
|
||||
};
|
||||
const value = extractValue(spec, console);
|
||||
expectedType: 'string'
|
||||
},
|
||||
value = extractValue(obj);
|
||||
let url;
|
||||
if (value && value.length) {
|
||||
if (typeof value === 'string' && value.trim() !== '') {
|
||||
try {
|
||||
url = new URL(value, aBaseURL);
|
||||
url = new URL(value, baseURL);
|
||||
} catch (e) {}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
function processSizesMember(aIcon) {
|
||||
function processSizesMember(icon) {
|
||||
const sizes = new Set(),
|
||||
spec = {
|
||||
obj = {
|
||||
objectName: 'icon',
|
||||
object: aIcon,
|
||||
object: icon,
|
||||
property: 'sizes',
|
||||
expectedType: 'string',
|
||||
trim: true
|
||||
},
|
||||
value = extractValue(spec, console);
|
||||
expectedType: 'string'
|
||||
};
|
||||
let value = extractValue(obj);
|
||||
value = (value) ? value.trim() : value;
|
||||
if (value) {
|
||||
// Split on whitespace and filter out invalid values.
|
||||
value.split(/\s+/)
|
||||
.filter(isValidSizeValue)
|
||||
.forEach(size => sizes.add(size));
|
||||
//split on whitespace and filter out invalid values
|
||||
let validSizes = value.split(/\s+/).filter(isValidSizeValue);
|
||||
validSizes.forEach((size) => sizes.add(size));
|
||||
}
|
||||
return sizes;
|
||||
// Implementation of HTML's link@size attribute checker.
|
||||
function isValidSizeValue(aSize) {
|
||||
const size = aSize.toLowerCase();
|
||||
if (IconsProcessor.anyRegEx.test(aSize)) {
|
||||
|
||||
/*
|
||||
* Implementation of HTML's link@size attribute checker
|
||||
*/
|
||||
function isValidSizeValue(size) {
|
||||
if (anyRegEx.test(size)) {
|
||||
return true;
|
||||
}
|
||||
size = size.toLowerCase();
|
||||
if (!size.contains('x') || size.indexOf('x') !== size.lastIndexOf('x')) {
|
||||
return false;
|
||||
}
|
||||
// Split left of x for width, after x for height.
|
||||
const widthAndHeight = size.split('x');
|
||||
const w = widthAndHeight.shift();
|
||||
const h = widthAndHeight.join('x');
|
||||
const validStarts = !w.startsWith('0') && !h.startsWith('0');
|
||||
const validDecimals = IconsProcessor.onlyDecimals.test(w + h);
|
||||
return (validStarts && validDecimals);
|
||||
|
||||
//split left of x for width, after x for height
|
||||
const width = size.substring(0, size.indexOf('x'));
|
||||
const height = size.substring(size.indexOf('x') + 1, size.length);
|
||||
const isValid = !(height.startsWith('0') || width.startsWith('0') || !onlyDecimals.test(width + height));
|
||||
return isValid;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function processIconsMember(manifest, manifestURL) {
|
||||
const iconsProcessor = new IconsProcessor();
|
||||
return iconsProcessor.processIcons(manifest, manifestURL);
|
||||
}
|
||||
}
|
||||
|
||||
//Processing starts here!
|
||||
let manifest = {};
|
||||
|
||||
try {
|
||||
manifest = JSON.parse(jsonText);
|
||||
if (typeof manifest !== 'object' || manifest === null) {
|
||||
let msg = 'Manifest needs to be an object.';
|
||||
issueDeveloperWarning(msg);
|
||||
manifest = {};
|
||||
}
|
||||
} catch (e) {
|
||||
issueDeveloperWarning(e);
|
||||
}
|
||||
|
||||
const processedManifest = {
|
||||
start_url: processStartURLMember(manifest, manifestURL, docURL),
|
||||
display: processDisplayMember(manifest),
|
||||
orientation: processOrientationMember(manifest),
|
||||
name: processNameMember(manifest),
|
||||
icons: processIconsMember(manifest, manifestURL),
|
||||
short_name: processShortNameMember(manifest)
|
||||
};
|
||||
processedManifest.scope = processScopeMember(manifest, manifestURL, docURL, processedManifest.start_url);
|
||||
return processedManifest;
|
||||
};
|
@ -16,5 +16,5 @@ const bsp = SpecialPowers.Cu.import('resource://gre/modules/ManifestProcessor.js
|
||||
data = {
|
||||
jsonText: '{}',
|
||||
manifestURL: manifestURL,
|
||||
docURL: docLocation
|
||||
docLocation: docLocation
|
||||
};
|
||||
|
@ -356,10 +356,9 @@ MediaDecoderReader::EnsureTaskQueue()
|
||||
{
|
||||
if (!mTaskQueue) {
|
||||
MOZ_ASSERT(!mTaskQueueIsBorrowed);
|
||||
RefPtr<SharedThreadPool> decodePool(GetMediaDecodeThreadPool());
|
||||
NS_ENSURE_TRUE(decodePool, nullptr);
|
||||
|
||||
mTaskQueue = new MediaTaskQueue(decodePool.forget());
|
||||
RefPtr<SharedThreadPool> pool(GetMediaThreadPool());
|
||||
MOZ_DIAGNOSTIC_ASSERT(pool);
|
||||
mTaskQueue = new MediaTaskQueue(pool.forget());
|
||||
}
|
||||
|
||||
return mTaskQueue;
|
||||
|
@ -249,9 +249,9 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
|
||||
// Set up our task queue.
|
||||
RefPtr<SharedThreadPool> threadPool(
|
||||
SharedThreadPool::Get(NS_LITERAL_CSTRING("Media State Machine"), 1));
|
||||
mTaskQueue = new MediaTaskQueue(threadPool.forget());
|
||||
RefPtr<SharedThreadPool> pool(GetMediaThreadPool());
|
||||
MOZ_DIAGNOSTIC_ASSERT(pool);
|
||||
mTaskQueue = new MediaTaskQueue(pool.forget());
|
||||
|
||||
static bool sPrefCacheInit = false;
|
||||
if (!sPrefCacheInit) {
|
||||
@ -1282,7 +1282,8 @@ static const char* const gMachineStateStr[] = {
|
||||
"SEEKING",
|
||||
"BUFFERING",
|
||||
"COMPLETED",
|
||||
"SHUTDOWN"
|
||||
"SHUTDOWN",
|
||||
"ERROR"
|
||||
};
|
||||
|
||||
void MediaDecoderStateMachine::SetState(State aState)
|
||||
|
@ -197,9 +197,9 @@ IsValidVideoRegion(const nsIntSize& aFrame, const nsIntRect& aPicture,
|
||||
aDisplay.width * aDisplay.height != 0;
|
||||
}
|
||||
|
||||
TemporaryRef<SharedThreadPool> GetMediaDecodeThreadPool()
|
||||
TemporaryRef<SharedThreadPool> GetMediaThreadPool()
|
||||
{
|
||||
return SharedThreadPool::Get(NS_LITERAL_CSTRING("Media Decode"),
|
||||
return SharedThreadPool::Get(NS_LITERAL_CSTRING("Media Playback"),
|
||||
Preferences::GetUint("media.num-decode-threads", 25));
|
||||
}
|
||||
|
||||
@ -301,7 +301,7 @@ class CreateTaskQueueTask : public nsRunnable {
|
||||
public:
|
||||
NS_IMETHOD Run() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool());
|
||||
mTaskQueue = new MediaTaskQueue(GetMediaThreadPool());
|
||||
return NS_OK;
|
||||
}
|
||||
nsRefPtr<MediaTaskQueue> mTaskQueue;
|
||||
@ -311,7 +311,7 @@ class CreateFlushableTaskQueueTask : public nsRunnable {
|
||||
public:
|
||||
NS_IMETHOD Run() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mTaskQueue = new FlushableMediaTaskQueue(GetMediaDecodeThreadPool());
|
||||
mTaskQueue = new FlushableMediaTaskQueue(GetMediaThreadPool());
|
||||
return NS_OK;
|
||||
}
|
||||
nsRefPtr<FlushableMediaTaskQueue> mTaskQueue;
|
||||
|
@ -219,7 +219,7 @@ class SharedThreadPool;
|
||||
|
||||
// Returns the thread pool that is shared amongst all decoder state machines
|
||||
// for decoding streams.
|
||||
TemporaryRef<SharedThreadPool> GetMediaDecodeThreadPool();
|
||||
TemporaryRef<SharedThreadPool> GetMediaThreadPool();
|
||||
|
||||
enum H264_PROFILE {
|
||||
H264_PROFILE_UNKNOWN = 0,
|
||||
|
@ -194,4 +194,15 @@ CDMCaps::AutoLock::GetKeyStatusesForSession(const nsAString& aSessionId,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CDMCaps::AutoLock::GetSessionIdsForKeyId(const CencKeyId& aKeyId,
|
||||
nsTArray<nsCString>& aOutSessionIds)
|
||||
{
|
||||
for (const auto& keyStatus : mData.mKeyStatuses) {
|
||||
if (keyStatus.mId == aKeyId) {
|
||||
aOutSessionIds.AppendElement(NS_ConvertUTF16toUTF8(keyStatus.mSessionId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -68,6 +68,9 @@ public:
|
||||
void GetKeyStatusesForSession(const nsAString& aSessionId,
|
||||
nsTArray<KeyStatus>& aOutKeyStatuses);
|
||||
|
||||
void GetSessionIdsForKeyId(const CencKeyId& aKeyId,
|
||||
nsTArray<nsCString>& aOutSessionIds);
|
||||
|
||||
// Sets the capabilities of the CDM. aCaps is the logical OR of the
|
||||
// GMP_EME_CAP_* flags from gmp-decryption.h.
|
||||
void SetCaps(uint64_t aCaps);
|
||||
|
@ -134,7 +134,12 @@ CDMProxy::OnCDMCreated(uint32_t aPromiseId)
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(!GetNodeId().IsEmpty());
|
||||
mKeys->OnCDMCreated(aPromiseId, GetNodeId());
|
||||
if (mCDM) {
|
||||
mKeys->OnCDMCreated(aPromiseId, GetNodeId(), mCDM->GetPluginId());
|
||||
} else {
|
||||
// No CDM? Just reject the promise.
|
||||
mKeys->RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -396,7 +401,9 @@ CDMProxy::OnSetSessionId(uint32_t aCreateSessionToken,
|
||||
}
|
||||
|
||||
nsRefPtr<dom::MediaKeySession> session(mKeys->GetPendingSession(aCreateSessionToken));
|
||||
if (session) {
|
||||
session->SetSessionId(aSessionId);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -584,6 +591,14 @@ CDMProxy::gmp_Decrypted(uint32_t aId,
|
||||
NS_WARNING("GMPDecryptorChild returned incorrect job ID");
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId,
|
||||
nsTArray<nsCString>& aSessionIds)
|
||||
{
|
||||
CDMCaps::AutoLock caps(Capabilites());
|
||||
caps.GetSessionIdsForKeyId(aKeyId, aSessionIds);
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::Terminated()
|
||||
{
|
||||
|
@ -166,6 +166,9 @@ public:
|
||||
// Main thread only.
|
||||
void OnKeyStatusesChange(const nsAString& aSessionId);
|
||||
|
||||
void GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId,
|
||||
nsTArray<nsCString>& aSessionIds);
|
||||
|
||||
#ifdef DEBUG
|
||||
bool IsOnGMPThread();
|
||||
#endif
|
||||
|
@ -66,7 +66,7 @@ MediaKeySession::MediaKeySession(JSContext* aCx,
|
||||
void MediaKeySession::SetSessionId(const nsAString& aSessionId)
|
||||
{
|
||||
EME_LOG("MediaKeySession[%p,'%s'] session Id set",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get());
|
||||
this, NS_ConvertUTF16toUTF8(aSessionId).get());
|
||||
|
||||
if (NS_WARN_IF(!mSessionId.IsEmpty())) {
|
||||
return;
|
||||
|
@ -103,6 +103,10 @@ EnsureMinCDMVersion(mozIGeckoMediaPluginService* aGMPService,
|
||||
tags.AppendElement(NS_ConvertUTF16toUTF8(aKeySystem));
|
||||
nsAutoCString versionStr;
|
||||
if (NS_FAILED(aGMPService->GetPluginVersionForAPI(NS_LITERAL_CSTRING(GMP_API_DECRYPTOR),
|
||||
&tags,
|
||||
versionStr)) &&
|
||||
// XXX to be removed later in bug 1147692
|
||||
NS_FAILED(aGMPService->GetPluginVersionForAPI(NS_LITERAL_CSTRING(GMP_API_DECRYPTOR_COMPAT),
|
||||
&tags,
|
||||
versionStr))) {
|
||||
return MediaKeySystemStatus::Error;
|
||||
@ -153,7 +157,11 @@ MediaKeySystemAccess::GetKeySystemStatus(const nsAString& aKeySystem,
|
||||
}
|
||||
if (!HaveGMPFor(mps,
|
||||
NS_ConvertUTF16toUTF8(aKeySystem),
|
||||
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR))) {
|
||||
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)) &&
|
||||
// XXX to be removed later in bug 1147692
|
||||
!HaveGMPFor(mps,
|
||||
NS_ConvertUTF16toUTF8(aKeySystem),
|
||||
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR_COMPAT))) {
|
||||
return MediaKeySystemStatus::Cdm_not_installed;
|
||||
}
|
||||
return EnsureMinCDMVersion(mps, aKeySystem, aMinCdmVersion);
|
||||
@ -197,14 +205,26 @@ IsPlayableWithGMP(mozIGeckoMediaPluginService* aGMPS,
|
||||
hasMP3) {
|
||||
return false;
|
||||
}
|
||||
return (!hasAAC || !HaveGMPFor(aGMPS,
|
||||
return (!hasAAC ||
|
||||
!(HaveGMPFor(aGMPS,
|
||||
NS_ConvertUTF16toUTF8(aKeySystem),
|
||||
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR),
|
||||
NS_LITERAL_CSTRING("aac"))) &&
|
||||
(!hasH264 || !HaveGMPFor(aGMPS,
|
||||
NS_LITERAL_CSTRING("aac")) ||
|
||||
// XXX remove later in bug 1147692
|
||||
HaveGMPFor(aGMPS,
|
||||
NS_ConvertUTF16toUTF8(aKeySystem),
|
||||
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR_COMPAT),
|
||||
NS_LITERAL_CSTRING("aac")))) &&
|
||||
(!hasH264 ||
|
||||
!(HaveGMPFor(aGMPS,
|
||||
NS_ConvertUTF16toUTF8(aKeySystem),
|
||||
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR),
|
||||
NS_LITERAL_CSTRING("h264")));
|
||||
NS_LITERAL_CSTRING("h264")) ||
|
||||
// XXX remove later in bug 1147692
|
||||
HaveGMPFor(aGMPS,
|
||||
NS_ConvertUTF16toUTF8(aKeySystem),
|
||||
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR_COMPAT),
|
||||
NS_LITERAL_CSTRING("h264"))));
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
@ -4,13 +4,16 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/HTMLMediaElement.h"
|
||||
#include "mozilla/dom/MediaKeys.h"
|
||||
#include "GMPService.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/dom/HTMLMediaElement.h"
|
||||
#include "mozilla/dom/MediaKeysBinding.h"
|
||||
#include "mozilla/dom/MediaKeyMessageEvent.h"
|
||||
#include "mozilla/dom/MediaKeyError.h"
|
||||
#include "mozilla/dom/MediaKeySession.h"
|
||||
#include "mozilla/dom/DOMException.h"
|
||||
#include "mozilla/dom/PluginCrashedEvent.h"
|
||||
#include "mozilla/dom/UnionTypes.h"
|
||||
#include "mozilla/CDMProxy.h"
|
||||
#include "mozilla/EMEUtils.h"
|
||||
@ -26,7 +29,6 @@
|
||||
#endif
|
||||
#include "nsContentCID.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "mozIGeckoMediaPluginService.h"
|
||||
#include "mozilla/dom/MediaKeySystemAccess.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
@ -180,7 +182,7 @@ MediaKeys::StorePromise(Promise* aPromise)
|
||||
MOZ_ASSERT(aPromise);
|
||||
uint32_t id = sEMEPromiseCount++;
|
||||
|
||||
EME_LOG("MediaKeys::StorePromise() id=%d", id);
|
||||
EME_LOG("MediaKeys[%p]::StorePromise() id=%d", this, id);
|
||||
|
||||
// Keep MediaKeys alive for the lifetime of its promises. Any still-pending
|
||||
// promises are rejected in Shutdown().
|
||||
@ -206,7 +208,7 @@ MediaKeys::RetrievePromise(PromiseId aId)
|
||||
void
|
||||
MediaKeys::RejectPromise(PromiseId aId, nsresult aExceptionCode)
|
||||
{
|
||||
EME_LOG("MediaKeys::RejectPromise(%d, 0x%x)", aId, aExceptionCode);
|
||||
EME_LOG("MediaKeys[%p]::RejectPromise(%d, 0x%x)", this, aId, aExceptionCode);
|
||||
|
||||
nsRefPtr<Promise> promise(RetrievePromise(aId));
|
||||
if (!promise) {
|
||||
@ -254,7 +256,7 @@ MediaKeys::OnSessionIdReady(MediaKeySession* aSession)
|
||||
void
|
||||
MediaKeys::ResolvePromise(PromiseId aId)
|
||||
{
|
||||
EME_LOG("MediaKeys::ResolvePromise(%d)", aId);
|
||||
EME_LOG("MediaKeys[%p]::ResolvePromise(%d)", this, aId);
|
||||
|
||||
nsRefPtr<Promise> promise(RetrievePromise(aId));
|
||||
if (!promise) {
|
||||
@ -341,7 +343,8 @@ MediaKeys::Init(ErrorResult& aRv)
|
||||
nsIDocument* doc = window->GetExtantDoc();
|
||||
const bool inPrivateBrowsing = nsContentUtils::IsInPrivateBrowsing(doc);
|
||||
|
||||
EME_LOG("MediaKeys::Create() (%s, %s), %s",
|
||||
EME_LOG("MediaKeys[%p]::Create() (%s, %s), %s",
|
||||
this,
|
||||
NS_ConvertUTF16toUTF8(origin).get(),
|
||||
NS_ConvertUTF16toUTF8(topLevelOrigin).get(),
|
||||
(inPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing"));
|
||||
@ -365,8 +368,83 @@ MediaKeys::Init(ErrorResult& aRv)
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
class CrashHandler : public gmp::GeckoMediaPluginService::PluginCrashCallback
|
||||
{
|
||||
public:
|
||||
CrashHandler(const nsACString& aPluginId,
|
||||
nsPIDOMWindow* aParentWindow,
|
||||
nsIDocument* aDocument)
|
||||
: gmp::GeckoMediaPluginService::PluginCrashCallback(aPluginId)
|
||||
, mParentWindowWeakPtr(do_GetWeakReference(aParentWindow))
|
||||
, mDocumentWeakPtr(do_GetWeakReference(aDocument))
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Run(const nsACString& aPluginName, const nsAString& aPluginDumpId) override
|
||||
{
|
||||
PluginCrashedEventInit init;
|
||||
init.mBubbles = true;
|
||||
init.mCancelable = true;
|
||||
init.mGmpPlugin = true;
|
||||
init.mPluginDumpID = aPluginDumpId;
|
||||
CopyUTF8toUTF16(aPluginName, init.mPluginName);
|
||||
init.mSubmittedCrashReport = false;
|
||||
|
||||
// The following PluginCrashedEvent fields stay empty:
|
||||
// init.mBrowserDumpID
|
||||
// init.mPluginFilename
|
||||
// TODO: Can/should we fill them?
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> parentWindow;
|
||||
nsCOMPtr<nsIDocument> document;
|
||||
if (!GetParentWindowAndDocumentIfValid(parentWindow, document)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<PluginCrashedEvent> event =
|
||||
PluginCrashedEvent::Constructor(document, NS_LITERAL_STRING("PluginCrashed"), init);
|
||||
event->SetTrusted(true);
|
||||
event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
|
||||
|
||||
EventDispatcher::DispatchDOMEvent(parentWindow, nullptr, event, nullptr, nullptr);
|
||||
}
|
||||
|
||||
virtual bool IsStillValid()
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> parentWindow;
|
||||
nsCOMPtr<nsIDocument> document;
|
||||
return GetParentWindowAndDocumentIfValid(parentWindow, document);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~CrashHandler()
|
||||
{ }
|
||||
|
||||
bool
|
||||
GetParentWindowAndDocumentIfValid(nsCOMPtr<nsPIDOMWindow>& parentWindow,
|
||||
nsCOMPtr<nsIDocument>& document)
|
||||
{
|
||||
parentWindow = do_QueryReferent(mParentWindowWeakPtr);
|
||||
if (!parentWindow) {
|
||||
return false;
|
||||
}
|
||||
document = do_QueryReferent(mDocumentWeakPtr);
|
||||
if (!document) {
|
||||
return false;
|
||||
}
|
||||
nsCOMPtr<nsIDocument> parentWindowDocument = parentWindow->GetExtantDoc();
|
||||
if (!parentWindowDocument || document.get() != parentWindowDocument.get()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
nsWeakPtr mParentWindowWeakPtr;
|
||||
nsWeakPtr mDocumentWeakPtr;
|
||||
};
|
||||
|
||||
void
|
||||
MediaKeys::OnCDMCreated(PromiseId aId, const nsACString& aNodeId)
|
||||
MediaKeys::OnCDMCreated(PromiseId aId, const nsACString& aNodeId, const nsACString& aPluginId)
|
||||
{
|
||||
nsRefPtr<Promise> promise(RetrievePromise(aId));
|
||||
if (!promise) {
|
||||
@ -374,7 +452,7 @@ MediaKeys::OnCDMCreated(PromiseId aId, const nsACString& aNodeId)
|
||||
}
|
||||
mNodeId = aNodeId;
|
||||
nsRefPtr<MediaKeys> keys(this);
|
||||
EME_LOG("MediaKeys::OnCDMCreated() resolve promise id=%d", aId);
|
||||
EME_LOG("MediaKeys[%p]::OnCDMCreated() resolve promise id=%d", this, aId);
|
||||
promise->MaybeResolve(keys);
|
||||
if (mCreatePromiseId == aId) {
|
||||
Release();
|
||||
@ -383,6 +461,25 @@ MediaKeys::OnCDMCreated(PromiseId aId, const nsACString& aNodeId)
|
||||
MediaKeySystemAccess::NotifyObservers(mParent,
|
||||
mKeySystem,
|
||||
MediaKeySystemStatus::Cdm_created);
|
||||
|
||||
if (!aPluginId.IsEmpty()) {
|
||||
// Prepare plugin crash reporter.
|
||||
nsRefPtr<gmp::GeckoMediaPluginService> service =
|
||||
gmp::GeckoMediaPluginService::GetGeckoMediaPluginService();
|
||||
if (NS_WARN_IF(!service)) {
|
||||
return;
|
||||
}
|
||||
if (NS_WARN_IF(!mParent)) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIDocument> doc = mParent->GetExtantDoc();
|
||||
if (NS_WARN_IF(!doc)) {
|
||||
return;
|
||||
}
|
||||
service->AddPluginCrashCallback(new CrashHandler(aPluginId, mParent, doc));
|
||||
EME_LOG("MediaKeys[%p]::OnCDMCreated() registered crash handler for pluginId '%s'",
|
||||
this, aPluginId.Data());
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<MediaKeySession>
|
||||
@ -416,7 +513,7 @@ MediaKeys::OnSessionLoaded(PromiseId aId, bool aSuccess)
|
||||
if (!promise) {
|
||||
return;
|
||||
}
|
||||
EME_LOG("MediaKeys::OnSessionLoaded() resolve promise id=%d", aId);
|
||||
EME_LOG("MediaKeys[%p]::OnSessionLoaded() resolve promise id=%d", this, aId);
|
||||
|
||||
promise->MaybeResolve(aSuccess);
|
||||
}
|
||||
|
@ -80,7 +80,8 @@ public:
|
||||
already_AddRefed<MediaKeySession> GetPendingSession(uint32_t aToken);
|
||||
|
||||
// Called once a Init() operation succeeds.
|
||||
void OnCDMCreated(PromiseId aId, const nsACString& aNodeId);
|
||||
void OnCDMCreated(PromiseId aId,
|
||||
const nsACString& aNodeId, const nsACString& aPluginId);
|
||||
|
||||
// Called once the CDM generates a sessionId while servicing a
|
||||
// MediaKeySession.generateRequest() or MediaKeySession.load() call,
|
||||
|
@ -248,10 +248,10 @@ MP4Reader::Init(MediaDecoderReader* aCloneDonor)
|
||||
|
||||
InitLayersBackendType();
|
||||
|
||||
mAudio.mTaskQueue = new FlushableMediaTaskQueue(GetMediaDecodeThreadPool());
|
||||
mAudio.mTaskQueue = new FlushableMediaTaskQueue(GetMediaThreadPool());
|
||||
NS_ENSURE_TRUE(mAudio.mTaskQueue, NS_ERROR_FAILURE);
|
||||
|
||||
mVideo.mTaskQueue = new FlushableMediaTaskQueue(GetMediaDecodeThreadPool());
|
||||
mVideo.mTaskQueue = new FlushableMediaTaskQueue(GetMediaThreadPool());
|
||||
NS_ENSURE_TRUE(mVideo.mTaskQueue, NS_ERROR_FAILURE);
|
||||
|
||||
static bool sSetupPrefCache = false;
|
||||
@ -749,6 +749,18 @@ MP4Reader::Update(TrackType aTrack)
|
||||
mFoundSPSForTelemetry = AccumulateSPSTelemetry(extradata);
|
||||
}
|
||||
|
||||
if (sample && sample->mMp4Sample && sample->mMp4Sample->crypto.valid) {
|
||||
CryptoSample& crypto = sample->mMp4Sample->crypto;
|
||||
MOZ_ASSERT(crypto.session_ids.IsEmpty());
|
||||
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
|
||||
nsRefPtr<CDMProxy> proxy = mDecoder->GetCDMProxy();
|
||||
MOZ_ASSERT(proxy);
|
||||
|
||||
proxy->GetSessionIdsForKeyId(crypto.key, crypto.session_ids);
|
||||
}
|
||||
|
||||
if (sample) {
|
||||
decoder.mDecoder->Input(sample->mMp4Sample.forget());
|
||||
if (aTrack == kVideo) {
|
||||
|
@ -58,7 +58,7 @@ public:
|
||||
};
|
||||
|
||||
SharedDecoderManager::SharedDecoderManager()
|
||||
: mTaskQueue(new FlushableMediaTaskQueue(GetMediaDecodeThreadPool()))
|
||||
: mTaskQueue(new FlushableMediaTaskQueue(GetMediaThreadPool()))
|
||||
, mActiveProxy(nullptr)
|
||||
, mActiveCallback(nullptr)
|
||||
, mWaitForInternalDrain(false)
|
||||
|
@ -1,5 +1,5 @@
|
||||
Name: fake
|
||||
Description: Fake GMP Plugin
|
||||
Version: 1.0
|
||||
APIs: encode-video[h264], decode-video[h264], eme-decrypt-v6[fake]
|
||||
APIs: encode-video[h264], decode-video[h264], eme-decrypt-v7[fake]
|
||||
Libraries: dxva2.dll
|
||||
|
@ -629,6 +629,12 @@ GMPChild::RecvPGMPDecryptorConstructor(PGMPDecryptorChild* aActor)
|
||||
|
||||
void* session = nullptr;
|
||||
GMPErr err = GetAPI(GMP_API_DECRYPTOR, host, &session);
|
||||
|
||||
if (err != GMPNoErr && !session) {
|
||||
// XXX to remove in bug 1147692
|
||||
err = GetAPI(GMP_API_DECRYPTOR_COMPAT, host, &session);
|
||||
}
|
||||
|
||||
if (err != GMPNoErr || !session) {
|
||||
return false;
|
||||
}
|
||||
|
@ -21,12 +21,19 @@ GMPDecryptorParent::GMPDecryptorParent(GMPParent* aPlugin)
|
||||
#endif
|
||||
{
|
||||
MOZ_ASSERT(mPlugin && mGMPThread);
|
||||
mPluginId = aPlugin->GetPluginId();
|
||||
}
|
||||
|
||||
GMPDecryptorParent::~GMPDecryptorParent()
|
||||
{
|
||||
}
|
||||
|
||||
const nsACString&
|
||||
GMPDecryptorParent::GetPluginId() const
|
||||
{
|
||||
return mPluginId;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GMPDecryptorParent::Init(GMPDecryptorProxyCallback* aCallback)
|
||||
{
|
||||
@ -140,7 +147,8 @@ GMPDecryptorParent::Decrypt(uint32_t aId,
|
||||
GMPDecryptionData data(aCrypto.key,
|
||||
aCrypto.iv,
|
||||
aCrypto.plain_sizes,
|
||||
aCrypto.encrypted_sizes);
|
||||
aCrypto.encrypted_sizes,
|
||||
aCrypto.session_ids);
|
||||
|
||||
unused << SendDecrypt(aId, aBuffer, data);
|
||||
}
|
||||
|
@ -28,6 +28,9 @@ public:
|
||||
explicit GMPDecryptorParent(GMPParent *aPlugin);
|
||||
|
||||
// GMPDecryptorProxy
|
||||
|
||||
virtual const nsACString& GetPluginId() const override;
|
||||
|
||||
virtual nsresult Init(GMPDecryptorProxyCallback* aCallback) override;
|
||||
|
||||
virtual void CreateSession(uint32_t aCreateSessionToken,
|
||||
@ -107,6 +110,7 @@ private:
|
||||
bool mIsOpen;
|
||||
bool mShuttingDown;
|
||||
nsRefPtr<GMPParent> mPlugin;
|
||||
nsCString mPluginId;
|
||||
GMPDecryptorProxyCallback* mCallback;
|
||||
#ifdef DEBUG
|
||||
nsIThread* const mGMPThread;
|
||||
|
@ -59,6 +59,8 @@ class GMPDecryptorProxy {
|
||||
public:
|
||||
~GMPDecryptorProxy() {}
|
||||
|
||||
virtual const nsACString& GetPluginId() const = 0;
|
||||
|
||||
virtual nsresult Init(GMPDecryptorProxyCallback* aCallback) = 0;
|
||||
|
||||
virtual void CreateSession(uint32_t aCreateSessionToken,
|
||||
|
@ -14,15 +14,17 @@ GMPEncryptedBufferDataImpl::GMPEncryptedBufferDataImpl(const CryptoSample& aCryp
|
||||
, mIV(aCrypto.iv)
|
||||
, mClearBytes(aCrypto.plain_sizes)
|
||||
, mCipherBytes(aCrypto.encrypted_sizes)
|
||||
, mSessionIdList(aCrypto.session_ids)
|
||||
{
|
||||
}
|
||||
|
||||
GMPEncryptedBufferDataImpl::GMPEncryptedBufferDataImpl(const GMPDecryptionData& aData)
|
||||
: mKeyId(aData.mKeyId())
|
||||
, mIV(aData.mIV())
|
||||
, mClearBytes(aData.mClearBytes())
|
||||
, mCipherBytes(aData.mCipherBytes())
|
||||
, mSessionIdList(aData.mSessionIds())
|
||||
{
|
||||
mKeyId = aData.mKeyId();
|
||||
mIV = aData.mIV();
|
||||
mClearBytes = aData.mClearBytes();
|
||||
mCipherBytes = aData.mCipherBytes();
|
||||
MOZ_ASSERT(mClearBytes.Length() == mCipherBytes.Length());
|
||||
}
|
||||
|
||||
@ -37,6 +39,7 @@ GMPEncryptedBufferDataImpl::RelinquishData(GMPDecryptionData& aData)
|
||||
aData.mIV() = Move(mIV);
|
||||
aData.mClearBytes() = Move(mClearBytes);
|
||||
aData.mCipherBytes() = Move(mCipherBytes);
|
||||
mSessionIdList.RelinquishData(aData.mSessionIds());
|
||||
}
|
||||
|
||||
const uint8_t*
|
||||
@ -75,6 +78,12 @@ GMPEncryptedBufferDataImpl::CipherBytes() const
|
||||
return mCipherBytes.Elements();
|
||||
}
|
||||
|
||||
const GMPStringList*
|
||||
GMPEncryptedBufferDataImpl::SessionIds() const
|
||||
{
|
||||
return &mSessionIdList;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GMPEncryptedBufferDataImpl::NumSubsamples() const
|
||||
{
|
||||
@ -84,5 +93,39 @@ GMPEncryptedBufferDataImpl::NumSubsamples() const
|
||||
return std::min<uint32_t>(mClearBytes.Length(), mCipherBytes.Length());
|
||||
}
|
||||
|
||||
GMPStringListImpl::GMPStringListImpl(const nsTArray<nsCString>& aStrings)
|
||||
: mStrings(aStrings)
|
||||
{
|
||||
}
|
||||
|
||||
const uint32_t
|
||||
GMPStringListImpl::Size() const
|
||||
{
|
||||
return mStrings.Length();
|
||||
}
|
||||
|
||||
void
|
||||
GMPStringListImpl::StringAt(uint32_t aIndex,
|
||||
const char** aOutString,
|
||||
uint32_t *aOutLength) const
|
||||
{
|
||||
if (NS_WARN_IF(aIndex >= Size())) {
|
||||
return;
|
||||
}
|
||||
|
||||
*aOutString = mStrings[aIndex].BeginReading();
|
||||
*aOutLength = mStrings[aIndex].Length();
|
||||
}
|
||||
|
||||
void
|
||||
GMPStringListImpl::RelinquishData(nsTArray<nsCString>& aStrings)
|
||||
{
|
||||
aStrings = Move(mStrings);
|
||||
}
|
||||
|
||||
GMPStringListImpl::~GMPStringListImpl()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
@ -14,6 +14,20 @@
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPStringListImpl : public GMPStringList
|
||||
{
|
||||
public:
|
||||
explicit GMPStringListImpl(const nsTArray<nsCString>& aStrings);
|
||||
virtual const uint32_t Size() const override;
|
||||
virtual void StringAt(uint32_t aIndex,
|
||||
const char** aOutString, uint32_t *aOutLength) const override;
|
||||
virtual ~GMPStringListImpl() override;
|
||||
void RelinquishData(nsTArray<nsCString>& aStrings);
|
||||
|
||||
private:
|
||||
nsTArray<nsCString> mStrings;
|
||||
};
|
||||
|
||||
class GMPEncryptedBufferDataImpl : public GMPEncryptedBufferMetadata {
|
||||
private:
|
||||
typedef mp4_demuxer::CryptoSample CryptoSample;
|
||||
@ -31,12 +45,15 @@ public:
|
||||
virtual uint32_t NumSubsamples() const override;
|
||||
virtual const uint16_t* ClearBytes() const override;
|
||||
virtual const uint32_t* CipherBytes() const override;
|
||||
virtual const GMPStringList* SessionIds() const override;
|
||||
|
||||
private:
|
||||
nsTArray<uint8_t> mKeyId;
|
||||
nsTArray<uint8_t> mIV;
|
||||
nsTArray<uint16_t> mClearBytes;
|
||||
nsTArray<uint32_t> mCipherBytes;
|
||||
|
||||
GMPStringListImpl mSessionIdList;
|
||||
};
|
||||
|
||||
class GMPBufferImpl : public GMPBuffer {
|
||||
|
@ -60,6 +60,9 @@ GMPParent::GMPParent()
|
||||
#endif
|
||||
{
|
||||
LOGD("GMPParent ctor");
|
||||
// Use the parent address to identify it.
|
||||
// We could use any unique-to-the-parent value.
|
||||
mPluginId.AppendInt(reinterpret_cast<uint64_t>(this));
|
||||
}
|
||||
|
||||
GMPParent::~GMPParent()
|
||||
@ -634,6 +637,9 @@ GMPParent::GetCrashID(nsString& aResult)
|
||||
TakeMinidump(getter_AddRefs(dumpFile), nullptr);
|
||||
if (!dumpFile) {
|
||||
NS_WARNING("GMP crash without crash report");
|
||||
aResult = mName;
|
||||
aResult += '-';
|
||||
AppendUTF8toUTF16(mVersion, aResult);
|
||||
return;
|
||||
}
|
||||
GetIDFromMinidump(dumpFile, aResult);
|
||||
@ -641,12 +647,23 @@ GMPParent::GetCrashID(nsString& aResult)
|
||||
}
|
||||
|
||||
static void
|
||||
GMPNotifyObservers(nsAString& aData)
|
||||
GMPNotifyObservers(const nsACString& aPluginId, const nsACString& aPluginName, const nsAString& aPluginDumpId)
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
nsString temp(aData);
|
||||
obs->NotifyObservers(nullptr, "gmp-plugin-crash", temp.get());
|
||||
nsString id;
|
||||
AppendUTF8toUTF16(aPluginId, id);
|
||||
id.Append(NS_LITERAL_STRING(" "));
|
||||
AppendUTF8toUTF16(aPluginName, id);
|
||||
id.Append(NS_LITERAL_STRING(" "));
|
||||
id.Append(aPluginDumpId);
|
||||
obs->NotifyObservers(nullptr, "gmp-plugin-crash", id.Data());
|
||||
}
|
||||
|
||||
nsRefPtr<gmp::GeckoMediaPluginService> service =
|
||||
gmp::GeckoMediaPluginService::GetGeckoMediaPluginService();
|
||||
if (service) {
|
||||
service->RunPluginCrashCallbacks(aPluginId, aPluginName, aPluginDumpId);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -660,17 +677,10 @@ GMPParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
NS_LITERAL_CSTRING("gmplugin"), 1);
|
||||
nsString dumpID;
|
||||
GetCrashID(dumpID);
|
||||
nsString id;
|
||||
// use the parent address to identify it
|
||||
// We could use any unique-to-the-parent value
|
||||
id.AppendInt(reinterpret_cast<uint64_t>(this));
|
||||
id.Append(NS_LITERAL_STRING(" "));
|
||||
AppendUTF8toUTF16(mDisplayName, id);
|
||||
id.Append(NS_LITERAL_STRING(" "));
|
||||
id.Append(dumpID);
|
||||
|
||||
// NotifyObservers is mainthread-only
|
||||
NS_DispatchToMainThread(WrapRunnableNM(&GMPNotifyObservers, id),
|
||||
NS_DispatchToMainThread(WrapRunnableNM(&GMPNotifyObservers,
|
||||
mPluginId, mDisplayName, dumpID),
|
||||
NS_DISPATCH_NORMAL);
|
||||
}
|
||||
#endif
|
||||
@ -1013,6 +1023,12 @@ GMPParent::GetVersion() const
|
||||
return mVersion;
|
||||
}
|
||||
|
||||
const nsACString&
|
||||
GMPParent::GetPluginId() const
|
||||
{
|
||||
return mPluginId;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPParent::RecvAsyncShutdownRequired()
|
||||
{
|
||||
|
@ -117,6 +117,7 @@ public:
|
||||
|
||||
const nsCString& GetDisplayName() const;
|
||||
const nsCString& GetVersion() const;
|
||||
const nsACString& GetPluginId() const;
|
||||
|
||||
// Returns true if a plugin can be or is being used across multiple NodeIds.
|
||||
bool CanBeSharedCrossNodeIds() const;
|
||||
@ -180,6 +181,7 @@ private:
|
||||
nsCString mDisplayName; // name of plugin displayed to users
|
||||
nsCString mDescription; // description of plugin for display to users
|
||||
nsCString mVersion;
|
||||
nsCString mPluginId;
|
||||
nsTArray<nsAutoPtr<GMPCapability>> mCapabilities;
|
||||
GMPProcessParent* mProcess;
|
||||
bool mDeleteProcessOnlyOnUnload;
|
||||
|
@ -170,6 +170,65 @@ GeckoMediaPluginService::AsyncShutdownTimeoutMs()
|
||||
return sMaxAsyncShutdownWaitMs;
|
||||
}
|
||||
|
||||
void
|
||||
GeckoMediaPluginService::RemoveObsoletePluginCrashCallbacks()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
for (size_t i = mPluginCrashCallbacks.Length(); i != 0; --i) {
|
||||
nsRefPtr<PluginCrashCallback>& callback = mPluginCrashCallbacks[i - 1];
|
||||
if (!callback->IsStillValid()) {
|
||||
LOGD(("%s::%s - Removing obsolete callback for pluginId %s",
|
||||
__CLASS__, __FUNCTION__,
|
||||
PromiseFlatCString(callback->PluginId()).get()));
|
||||
mPluginCrashCallbacks.RemoveElementAt(i - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GeckoMediaPluginService::AddPluginCrashCallback(
|
||||
nsRefPtr<PluginCrashCallback> aPluginCrashCallback)
|
||||
{
|
||||
RemoveObsoletePluginCrashCallbacks();
|
||||
mPluginCrashCallbacks.AppendElement(aPluginCrashCallback);
|
||||
}
|
||||
|
||||
void
|
||||
GeckoMediaPluginService::RemovePluginCrashCallbacks(const nsACString& aPluginId)
|
||||
{
|
||||
RemoveObsoletePluginCrashCallbacks();
|
||||
for (size_t i = mPluginCrashCallbacks.Length(); i != 0; --i) {
|
||||
nsRefPtr<PluginCrashCallback>& callback = mPluginCrashCallbacks[i - 1];
|
||||
if (callback->PluginId() == aPluginId) {
|
||||
mPluginCrashCallbacks.RemoveElementAt(i - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GeckoMediaPluginService::RunPluginCrashCallbacks(const nsACString& aPluginId,
|
||||
const nsACString& aPluginName,
|
||||
const nsAString& aPluginDumpId)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
LOGD(("%s::%s(%s)", __CLASS__, __FUNCTION__, aPluginId.Data()));
|
||||
for (size_t i = mPluginCrashCallbacks.Length(); i != 0; --i) {
|
||||
nsRefPtr<PluginCrashCallback>& callback = mPluginCrashCallbacks[i - 1];
|
||||
const nsACString& callbackPluginId = callback->PluginId();
|
||||
if (!callback->IsStillValid()) {
|
||||
LOGD(("%s::%s(%s) - Removing obsolete callback for pluginId %s",
|
||||
__CLASS__, __FUNCTION__, aPluginId.Data(),
|
||||
PromiseFlatCString(callback->PluginId()).get()));
|
||||
mPluginCrashCallbacks.RemoveElementAt(i - 1);
|
||||
} else if (callbackPluginId == aPluginId) {
|
||||
LOGD(("%s::%s(%s) - Running #%u",
|
||||
__CLASS__, __FUNCTION__, aPluginId.Data(), i - 1));
|
||||
callback->Run(aPluginName, aPluginDumpId);
|
||||
mPluginCrashCallbacks.RemoveElementAt(i - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
GeckoMediaPluginService::Init()
|
||||
{
|
||||
@ -543,6 +602,14 @@ GeckoMediaPluginService::GetGMPDecryptor(nsTArray<nsCString>* aTags,
|
||||
nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aNodeId,
|
||||
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR),
|
||||
*aTags);
|
||||
|
||||
if (!gmp) {
|
||||
// XXX to remove in bug 1147692
|
||||
gmp = SelectPluginForAPI(aNodeId,
|
||||
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR_COMPAT),
|
||||
*aTags);
|
||||
}
|
||||
|
||||
if (!gmp) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -49,6 +49,34 @@ public:
|
||||
|
||||
int32_t AsyncShutdownTimeoutMs();
|
||||
|
||||
class PluginCrashCallback
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(PluginCrashCallback)
|
||||
|
||||
PluginCrashCallback(const nsACString& aPluginId)
|
||||
: mPluginId(aPluginId)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
const nsACString& PluginId() const { return mPluginId; }
|
||||
virtual void Run(const nsACString& aPluginName, const nsAString& aPluginDumpId) = 0;
|
||||
virtual bool IsStillValid() = 0; // False if callback has become useless.
|
||||
protected:
|
||||
virtual ~PluginCrashCallback()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
private:
|
||||
const nsCString mPluginId;
|
||||
};
|
||||
void RemoveObsoletePluginCrashCallbacks(); // Called from add/remove/run.
|
||||
void AddPluginCrashCallback(nsRefPtr<PluginCrashCallback> aPluginCrashCallback);
|
||||
void RemovePluginCrashCallbacks(const nsACString& aPluginId);
|
||||
void RunPluginCrashCallbacks(const nsACString& aPluginId,
|
||||
const nsACString& aPluginName,
|
||||
const nsAString& aPluginDumpId);
|
||||
|
||||
private:
|
||||
~GeckoMediaPluginService();
|
||||
|
||||
@ -124,6 +152,8 @@ private:
|
||||
bool mShuttingDown;
|
||||
bool mShuttingDownOnGMPThread;
|
||||
|
||||
nsTArray<nsRefPtr<PluginCrashCallback>> mPluginCrashCallbacks;
|
||||
|
||||
// True if we've inspected MOZ_GMP_PATH on the GMP thread and loaded any
|
||||
// plugins found there into mPlugins.
|
||||
Atomic<bool> mScannedPluginOnDisk;
|
||||
|
@ -14,6 +14,7 @@ struct GMPDecryptionData {
|
||||
uint8_t[] mIV;
|
||||
uint16_t[] mClearBytes;
|
||||
uint32_t[] mCipherBytes;
|
||||
nsCString[] mSessionIds;
|
||||
};
|
||||
|
||||
struct GMPVideoEncodedFrameData
|
||||
|
@ -19,6 +19,16 @@
|
||||
|
||||
#include "gmp-platform.h"
|
||||
|
||||
class GMPStringList {
|
||||
public:
|
||||
virtual const uint32_t Size() const = 0;
|
||||
|
||||
virtual void StringAt(uint32_t aIndex,
|
||||
const char** aOutString, uint32_t* aOutLength) const = 0;
|
||||
|
||||
virtual ~GMPStringList() { }
|
||||
};
|
||||
|
||||
class GMPEncryptedBufferMetadata {
|
||||
public:
|
||||
// Key ID to identify the decryption key.
|
||||
@ -41,6 +51,10 @@ public:
|
||||
virtual const uint32_t* CipherBytes() const = 0;
|
||||
|
||||
virtual ~GMPEncryptedBufferMetadata() {}
|
||||
|
||||
// The set of MediaKeySession IDs associated with this decryption key in
|
||||
// the current stream.
|
||||
virtual const GMPStringList* SessionIds() const = 0;
|
||||
};
|
||||
|
||||
class GMPBuffer {
|
||||
@ -224,7 +238,10 @@ enum GMPSessionType {
|
||||
kGMPSessionInvalid = 2 // Must always be last.
|
||||
};
|
||||
|
||||
#define GMP_API_DECRYPTOR "eme-decrypt-v6"
|
||||
#define GMP_API_DECRYPTOR "eme-decrypt-v7"
|
||||
|
||||
// XXX remove in bug 1147692
|
||||
#define GMP_API_DECRYPTOR_COMPAT "eme-decrypt-v6"
|
||||
|
||||
// API exposed by plugin library to manage decryption sessions.
|
||||
// When the Host requests this by calling GMPGetAPIFunc().
|
||||
|
@ -338,11 +338,11 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
// Gaps of up to 20ms (marginally longer than a single frame at 60fps) are considered
|
||||
// Gaps of up to 35ms (marginally longer than a single frame at 30fps) are considered
|
||||
// to be sequential frames.
|
||||
int64_t GetRoundingError()
|
||||
{
|
||||
return 20000;
|
||||
return 35000;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -305,6 +305,18 @@ MediaSourceDecoder::SetCDMProxy(CDMProxy* aProxy)
|
||||
rv = mReader->SetCDMProxy(aProxy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
{
|
||||
// The sub readers can't decrypt EME content until they have a CDMProxy,
|
||||
// and the CDMProxy knows the capabilities of the CDM. The MediaSourceReader
|
||||
// remains in "waiting for resources" state until then. We need to kick the
|
||||
// reader out of waiting if the CDM gets added with known capabilities.
|
||||
CDMCaps::AutoLock caps(aProxy->Capabilites());
|
||||
if (!caps.AreCapsKnown()) {
|
||||
nsCOMPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethod(this, &MediaDecoder::NotifyWaitingForResourcesStatusChanged));
|
||||
caps.CallOnMainThreadWhenCapsAvailable(task);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
@ -97,13 +97,22 @@ MediaSourceReader::IsWaitingOnCDMResource()
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
MOZ_ASSERT(!IsWaitingMediaResources());
|
||||
|
||||
for (auto& trackBuffer : mTrackBuffers) {
|
||||
if (trackBuffer->IsWaitingOnCDMResource()) {
|
||||
return true;
|
||||
}
|
||||
if (!mInfo.IsEncrypted()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We'll need to wait on the CDMProxy being added, and it having received
|
||||
// notification from the child GMP of its capabilities; whether it can
|
||||
// decode, or whether we need to decode on our side.
|
||||
if (!mCDMProxy) {
|
||||
return true;
|
||||
}
|
||||
|
||||
{
|
||||
CDMCaps::AutoLock caps(mCDMProxy->Capabilites());
|
||||
return !caps.AreCapsKnown();
|
||||
}
|
||||
|
||||
return mInfo.IsEncrypted() && !mCDMProxy;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
@ -52,7 +52,7 @@ TrackBuffer::TrackBuffer(MediaSourceDecoder* aParentDecoder, const nsACString& a
|
||||
{
|
||||
MOZ_COUNT_CTOR(TrackBuffer);
|
||||
mParser = ContainerParser::CreateForMIMEType(aType);
|
||||
mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool());
|
||||
mTaskQueue = new MediaTaskQueue(GetMediaThreadPool());
|
||||
aParentDecoder->AddTrackBuffer(this);
|
||||
mDecoderPerSegment = Preferences::GetBool("media.mediasource.decoder-per-segment", false);
|
||||
MSE_DEBUG("TrackBuffer created for parent decoder %p", aParentDecoder);
|
||||
|
@ -78,4 +78,4 @@ load 1080986.html
|
||||
include ../../mediasource/test/crashtests/crashtests.list
|
||||
|
||||
# This needs to run at the end to avoid leaking busted state into other tests.
|
||||
skip-if(winWidget||OSX==1010&&isDebugBuild) load 691096-1.html
|
||||
skip-if(B2G||winWidget||OSX==1010&&isDebugBuild) load 691096-1.html
|
||||
|
@ -7,6 +7,7 @@ support-files =
|
||||
silence.ogg^headers^
|
||||
|
||||
[test_abort.html]
|
||||
skip-if = toolkit == 'android' || toolkit == 'gonk' # bug 1037287
|
||||
[test_audio_capture_error.html]
|
||||
[test_call_start_from_end_handler.html]
|
||||
[test_nested_eventloop.html]
|
||||
|
@ -274,6 +274,7 @@ function testOpenFailed() {
|
||||
|
||||
return socket.opened.then(function() {
|
||||
ok(false, 'should not resolve openedPromise while fail to bind socket');
|
||||
socket.close();
|
||||
}).catch(function(reason) {
|
||||
is(reason.name, 'NetworkError', 'expected openedPromise to be rejected while fail to bind socket');
|
||||
});
|
||||
@ -291,7 +292,9 @@ function testSendBeforeOpen() {
|
||||
ok(true, 'expected send fail before openedPromise is resolved');
|
||||
}
|
||||
|
||||
return socket.opened;
|
||||
return socket.opened.then(function() {
|
||||
socket.close();
|
||||
});
|
||||
}
|
||||
|
||||
function testCloseBeforeOpened() {
|
||||
|
@ -97,11 +97,13 @@ public:
|
||||
if (eventSink) {
|
||||
// If mixed display content is loaded, make sure to include that in the state.
|
||||
if (rootDoc->GetHasMixedDisplayContentLoaded()) {
|
||||
eventSink->OnSecurityChange(mContext, (nsIWebProgressListener::STATE_IS_BROKEN |
|
||||
eventSink->OnSecurityChange(mContext,
|
||||
(nsIWebProgressListener::STATE_IS_BROKEN |
|
||||
nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT |
|
||||
nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT));
|
||||
} else {
|
||||
eventSink->OnSecurityChange(mContext, (nsIWebProgressListener::STATE_IS_BROKEN |
|
||||
eventSink->OnSecurityChange(mContext,
|
||||
(nsIWebProgressListener::STATE_IS_BROKEN |
|
||||
nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT));
|
||||
}
|
||||
}
|
||||
@ -118,7 +120,8 @@ public:
|
||||
if (eventSink) {
|
||||
// If mixed active content is loaded, make sure to include that in the state.
|
||||
if (rootDoc->GetHasMixedActiveContentLoaded()) {
|
||||
eventSink->OnSecurityChange(mContext, (nsIWebProgressListener::STATE_IS_BROKEN |
|
||||
eventSink->OnSecurityChange(mContext,
|
||||
(nsIWebProgressListener::STATE_IS_BROKEN |
|
||||
nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT |
|
||||
nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT));
|
||||
} else {
|
||||
@ -656,11 +659,32 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
||||
if (allowMixedContent) {
|
||||
LogMixedContentMessage(classification, aContentLocation, rootDoc, eUserOverride);
|
||||
*aDecision = nsIContentPolicy::ACCEPT;
|
||||
rootDoc->SetHasMixedActiveContentLoaded(true);
|
||||
if (!rootDoc->GetHasMixedDisplayContentLoaded() && NS_SUCCEEDED(stateRV)) {
|
||||
// See if mixed display content has already loaded on the page or if the state needs to be updated here.
|
||||
// If mixed display hasn't loaded previously, then we need to call OnSecurityChange() to update the UI.
|
||||
if (rootDoc->GetHasMixedDisplayContentLoaded()) {
|
||||
return NS_OK;
|
||||
}
|
||||
rootDoc->SetHasMixedDisplayContentLoaded(true);
|
||||
|
||||
if (rootHasSecureConnection) {
|
||||
if (rootDoc->GetHasMixedActiveContentLoaded()) {
|
||||
// If mixed active content is loaded, make sure to include that in the state.
|
||||
eventSink->OnSecurityChange(aRequestingContext,
|
||||
(nsIWebProgressListener::STATE_IS_BROKEN |
|
||||
nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT |
|
||||
nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT));
|
||||
} else {
|
||||
eventSink->OnSecurityChange(aRequestingContext,
|
||||
(nsIWebProgressListener::STATE_IS_BROKEN |
|
||||
nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT));
|
||||
}
|
||||
} else {
|
||||
// User has overriden the pref and the root is not https;
|
||||
// mixed display content was allowed on an https subframe.
|
||||
if (NS_SUCCEEDED(stateRV)) {
|
||||
eventSink->OnSecurityChange(aRequestingContext, (State | nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*aDecision = nsIContentPolicy::REJECT_REQUEST;
|
||||
LogMixedContentMessage(classification, aContentLocation, rootDoc, eBlocked);
|
||||
@ -677,7 +701,7 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
||||
if (allowMixedContent) {
|
||||
LogMixedContentMessage(classification, aContentLocation, rootDoc, eUserOverride);
|
||||
*aDecision = nsIContentPolicy::ACCEPT;
|
||||
// See if the pref will change here. If it will, only then do we need to call OnSecurityChange() to update the UI.
|
||||
// See if the state will change here. If it will, only then do we need to call OnSecurityChange() to update the UI.
|
||||
if (rootDoc->GetHasMixedActiveContentLoaded()) {
|
||||
return NS_OK;
|
||||
}
|
||||
@ -687,17 +711,19 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
||||
// User has decided to override the pref and the root is https, so change the Security State.
|
||||
if (rootDoc->GetHasMixedDisplayContentLoaded()) {
|
||||
// If mixed display content is loaded, make sure to include that in the state.
|
||||
eventSink->OnSecurityChange(aRequestingContext, (nsIWebProgressListener::STATE_IS_BROKEN |
|
||||
eventSink->OnSecurityChange(aRequestingContext,
|
||||
(nsIWebProgressListener::STATE_IS_BROKEN |
|
||||
nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT |
|
||||
nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT));
|
||||
} else {
|
||||
eventSink->OnSecurityChange(aRequestingContext, (nsIWebProgressListener::STATE_IS_BROKEN |
|
||||
eventSink->OnSecurityChange(aRequestingContext,
|
||||
(nsIWebProgressListener::STATE_IS_BROKEN |
|
||||
nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT));
|
||||
}
|
||||
return NS_OK;
|
||||
} else {
|
||||
// User has already overriden the pref and the root is not https;
|
||||
// mixed content was allowed on an https subframe.
|
||||
// mixed active content was allowed on an https subframe.
|
||||
if (NS_SUCCEEDED(stateRV)) {
|
||||
eventSink->OnSecurityChange(aRequestingContext, (State | nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT));
|
||||
}
|
||||
|
@ -23,6 +23,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gNetworkWorker",
|
||||
"@mozilla.org/network/worker;1",
|
||||
"nsINetworkWorker");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gPACGenerator",
|
||||
"@mozilla.org/pac-generator;1",
|
||||
"nsIPACGenerator");
|
||||
|
||||
// 1xx - Requested action is proceeding
|
||||
const NETD_COMMAND_PROCEEDING = 100;
|
||||
// 2xx - Requested action has been successfully completed
|
||||
@ -37,7 +41,8 @@ const NETD_COMMAND_UNSOLICITED = 600;
|
||||
|
||||
const WIFI_CTRL_INTERFACE = "wl0.1";
|
||||
|
||||
const MANUAL_PROXY_CONFIGURATION = 1;
|
||||
const PROXY_TYPE_MANUAL = Ci.nsIProtocolProxyService.PROXYCONFIG_MANUAL;
|
||||
const PROXY_TYPE_PAC = Ci.nsIProtocolProxyService.PROXYCONFIG_PAC;
|
||||
|
||||
let debug;
|
||||
function updateDebug() {
|
||||
@ -523,8 +528,7 @@ NetworkService.prototype = {
|
||||
}
|
||||
|
||||
debug("Going to set proxy settings for " + network.name + " network interface.");
|
||||
// Sets manual proxy configuration.
|
||||
Services.prefs.setIntPref("network.proxy.type", MANUAL_PROXY_CONFIGURATION);
|
||||
|
||||
// Do not use this proxy server for all protocols.
|
||||
Services.prefs.setBoolPref("network.proxy.share_proxy_settings", false);
|
||||
Services.prefs.setCharPref("network.proxy.http", network.httpProxyHost);
|
||||
@ -532,6 +536,19 @@ NetworkService.prototype = {
|
||||
let port = network.httpProxyPort === 0 ? 8080 : network.httpProxyPort;
|
||||
Services.prefs.setIntPref("network.proxy.http_port", port);
|
||||
Services.prefs.setIntPref("network.proxy.ssl_port", port);
|
||||
|
||||
let usePAC;
|
||||
try {
|
||||
usePAC = Services.prefs.getBoolPref("network.proxy.pac_generator");
|
||||
} catch (ex) {}
|
||||
|
||||
if (usePAC) {
|
||||
Services.prefs.setCharPref("network.proxy.autoconfig_url",
|
||||
gPACGenerator.generate());
|
||||
Services.prefs.setIntPref("network.proxy.type", PROXY_TYPE_PAC);
|
||||
} else {
|
||||
Services.prefs.setIntPref("network.proxy.type", PROXY_TYPE_MANUAL);
|
||||
}
|
||||
} catch(ex) {
|
||||
debug("Exception " + ex + ". Unable to set proxy setting for " +
|
||||
network.name + " network interface.");
|
||||
@ -541,12 +558,24 @@ NetworkService.prototype = {
|
||||
clearNetworkProxy: function() {
|
||||
debug("Going to clear all network proxy.");
|
||||
|
||||
Services.prefs.clearUserPref("network.proxy.type");
|
||||
Services.prefs.clearUserPref("network.proxy.share_proxy_settings");
|
||||
Services.prefs.clearUserPref("network.proxy.http");
|
||||
Services.prefs.clearUserPref("network.proxy.http_port");
|
||||
Services.prefs.clearUserPref("network.proxy.ssl");
|
||||
Services.prefs.clearUserPref("network.proxy.ssl_port");
|
||||
|
||||
let usePAC;
|
||||
try {
|
||||
usePAC = Services.prefs.getBoolPref("network.proxy.pac_generator");
|
||||
} catch (ex) {}
|
||||
|
||||
if (usePAC) {
|
||||
Services.prefs.setCharPref("network.proxy.autoconfig_url",
|
||||
gPACGenerator.generate());
|
||||
Services.prefs.setIntPref("network.proxy.type", PROXY_TYPE_PAC);
|
||||
} else {
|
||||
Services.prefs.clearUserPref("network.proxy.type");
|
||||
}
|
||||
},
|
||||
|
||||
// Enable/Disable DHCP server.
|
||||
|
@ -6,7 +6,8 @@ MARIONETTE_HEAD_JS = "head.js";
|
||||
|
||||
const HTTP_PROXY = "10.0.2.200";
|
||||
const HTTP_PROXY_PORT = "8080";
|
||||
const MANUAL_PROXY_CONFIGURATION = 1;
|
||||
const PROXY_TYPE_MANUAL = Ci.nsIProtocolProxyService.PROXYCONFIG_MANUAL;
|
||||
const PROXY_TYPE_PAC = Ci.nsIProtocolProxyService.PROXYCONFIG_PAC;
|
||||
|
||||
// Test initial State
|
||||
function verifyInitialState() {
|
||||
@ -38,6 +39,7 @@ function waitForHttpProxyVerified(aShouldBeSet) {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
try {
|
||||
waitFor(aResolve, () => {
|
||||
let usePAC = SpecialPowers.getBoolPref("network.proxy.pac_generator");
|
||||
let proxyType = SpecialPowers.getIntPref("network.proxy.type");
|
||||
let httpProxy = SpecialPowers.getCharPref("network.proxy.http");
|
||||
let sslProxy = SpecialPowers.getCharPref("network.proxy.ssl");
|
||||
@ -45,12 +47,15 @@ function waitForHttpProxyVerified(aShouldBeSet) {
|
||||
let sslProxyPort = SpecialPowers.getIntPref("network.proxy.ssl_port");
|
||||
|
||||
if ((aShouldBeSet &&
|
||||
proxyType == MANUAL_PROXY_CONFIGURATION &&
|
||||
(usePAC ? proxyType == PROXY_TYPE_PAC :
|
||||
proxyType == PROXY_TYPE_MANUAL) &&
|
||||
httpProxy == HTTP_PROXY &&
|
||||
sslProxy == HTTP_PROXY &&
|
||||
httpProxyPort == HTTP_PROXY_PORT &&
|
||||
sslProxyPort == HTTP_PROXY_PORT) ||
|
||||
(!aShouldBeSet && proxyType != MANUAL_PROXY_CONFIGURATION &&
|
||||
(!aShouldBeSet &&
|
||||
(usePAC ? proxyType == PROXY_TYPE_PAC :
|
||||
proxyType != PROXY_TYPE_MANUAL) &&
|
||||
!httpProxy && !sslProxy && !httpProxyPort && !sslProxyPort)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -8,14 +8,10 @@ enum ScrollState {"started", "stopped"};
|
||||
|
||||
dictionary ScrollViewChangeEventInit : EventInit {
|
||||
ScrollState state = "started";
|
||||
float scrollX = 0;
|
||||
float scrollY = 0;
|
||||
};
|
||||
|
||||
[Constructor(DOMString type, optional ScrollViewChangeEventInit eventInit),
|
||||
ChromeOnly]
|
||||
interface ScrollViewChangeEvent : Event {
|
||||
readonly attribute ScrollState state;
|
||||
readonly attribute float scrollX;
|
||||
readonly attribute float scrollY;
|
||||
};
|
||||
|
@ -375,9 +375,13 @@ interface WebGL2RenderingContext : WebGLRenderingContext
|
||||
void uniform2ui(WebGLUniformLocation? location, GLuint v0, GLuint v1);
|
||||
void uniform3ui(WebGLUniformLocation? location, GLuint v0, GLuint v1, GLuint v2);
|
||||
void uniform4ui(WebGLUniformLocation? location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
|
||||
void uniform1uiv(WebGLUniformLocation? location, Uint32Array value);
|
||||
void uniform1uiv(WebGLUniformLocation? location, sequence<GLuint> value);
|
||||
void uniform2uiv(WebGLUniformLocation? location, Uint32Array value);
|
||||
void uniform2uiv(WebGLUniformLocation? location, sequence<GLuint> value);
|
||||
void uniform3uiv(WebGLUniformLocation? location, Uint32Array value);
|
||||
void uniform3uiv(WebGLUniformLocation? location, sequence<GLuint> value);
|
||||
void uniform4uiv(WebGLUniformLocation? location, Uint32Array value);
|
||||
void uniform4uiv(WebGLUniformLocation? location, sequence<GLuint> value);
|
||||
void uniformMatrix2x3fv(WebGLUniformLocation? location, GLboolean transpose, Float32Array value);
|
||||
void uniformMatrix2x3fv(WebGLUniformLocation? location, GLboolean transpose, sequence<GLfloat> value);
|
||||
|
@ -970,10 +970,10 @@ Proxy::Teardown()
|
||||
}
|
||||
}
|
||||
|
||||
mWorkerPrivate = nullptr;
|
||||
mOutstandingSendCount = 0;
|
||||
}
|
||||
|
||||
mWorkerPrivate = nullptr;
|
||||
mXHRUpload = nullptr;
|
||||
mXHR = nullptr;
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
self.addEventListener("fetch", function(event) {
|
||||
if (event.request.url.indexOf("index.html") >= 0 ||
|
||||
event.request.url.indexOf("register.html") >= 0 ||
|
||||
event.request.url.indexOf("unregister.html") >= 0) {
|
||||
// Handle pass-through requests
|
||||
event.respondWith(fetch(event.request));
|
||||
} else if (event.request.url.indexOf("fetch.txt") >= 0) {
|
||||
var body = event.request.context == "fetch" ?
|
||||
"so fetch" : "so unfetch";
|
||||
event.respondWith(new Response(body));
|
||||
} else {
|
||||
// Fail any request that we don't know about.
|
||||
event.respondWith(Promise.reject());
|
||||
}
|
||||
});
|
27
dom/workers/test/serviceworkers/fetch/context/index.html
Normal file
27
dom/workers/test/serviceworkers/fetch/context/index.html
Normal file
@ -0,0 +1,27 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
function ok(v, msg) {
|
||||
window.parent.postMessage({status: "ok", result: !!v, message: msg}, "*");
|
||||
}
|
||||
|
||||
function is(a, b, msg) {
|
||||
ok(a === b, msg + ", expected '" + b + "', got '" + a + "'");
|
||||
}
|
||||
|
||||
function finish() {
|
||||
window.parent.postMessage({status: "done"}, "*");
|
||||
}
|
||||
|
||||
function testFetch() {
|
||||
return fetch("fetch.txt").then(function(r) {
|
||||
return r.text();
|
||||
}).then(function(body) {
|
||||
is(body, "so fetch", "A fetch() Request should have the 'fetch' context");
|
||||
});
|
||||
}
|
||||
|
||||
testFetch()
|
||||
.then(function() {
|
||||
finish();
|
||||
});
|
||||
</script>
|
26
dom/workers/test/serviceworkers/fetch/context/register.html
Normal file
26
dom/workers/test/serviceworkers/fetch/context/register.html
Normal file
@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
function ok(v, msg) {
|
||||
window.parent.postMessage({status: "ok", result: !!v, message: msg}, "*");
|
||||
}
|
||||
|
||||
var isDone = false;
|
||||
function done(reg) {
|
||||
if (!isDone) {
|
||||
ok(reg.waiting || reg.active, "Either active or waiting worker should be available.");
|
||||
window.parent.postMessage({status: "registrationdone"}, "*");
|
||||
isDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
navigator.serviceWorker.register("context_test.js", {scope: "."})
|
||||
.then(function(registration) {
|
||||
if (registration.installing) {
|
||||
registration.installing.onstatechange = function(e) {
|
||||
done(registration);
|
||||
};
|
||||
} else {
|
||||
done(registration);
|
||||
}
|
||||
});
|
||||
</script>
|
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
navigator.serviceWorker.getRegistration(".").then(function(registration) {
|
||||
registration.unregister().then(function(success) {
|
||||
if (success) {
|
||||
window.parent.postMessage({status: "unregistrationdone"}, "*");
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
@ -26,6 +26,10 @@ support-files =
|
||||
fetch/fetch_worker_script.js
|
||||
fetch/fetch_tests.js
|
||||
fetch/deliver-gzip.sjs
|
||||
fetch/context/index.html
|
||||
fetch/context/register.html
|
||||
fetch/context/unregister.html
|
||||
fetch/context/context_test.js
|
||||
fetch/https/index.html
|
||||
fetch/https/register.html
|
||||
fetch/https/unregister.html
|
||||
@ -74,3 +78,4 @@ support-files =
|
||||
[test_serviceworker_not_sharedworker.html]
|
||||
[test_match_all_client_id.html]
|
||||
[test_sandbox_intercept.html]
|
||||
[test_request_context.html]
|
||||
|
50
dom/workers/test/serviceworkers/test_request_context.html
Normal file
50
dom/workers/test/serviceworkers/test_request_context.html
Normal file
@ -0,0 +1,50 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1121157 - Test that Request objects passed to FetchEvent have the correct context</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
<iframe></iframe>
|
||||
</div>
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var iframe;
|
||||
function runTest() {
|
||||
iframe = document.querySelector("iframe");
|
||||
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/context/register.html";
|
||||
window.onmessage = function(e) {
|
||||
if (e.data.status == "ok") {
|
||||
ok(e.data.result, e.data.message);
|
||||
} else if (e.data.status == "registrationdone") {
|
||||
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/context/index.html";
|
||||
} else if (e.data.status == "done") {
|
||||
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/context/unregister.html";
|
||||
} else if (e.data.status == "unregistrationdone") {
|
||||
window.onmessage = null;
|
||||
ok(true, "Test finished successfully");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
onload = function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
]}, runTest);
|
||||
};
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
22
editor/libeditor/crashtests/1134545.html
Normal file
22
editor/libeditor/crashtests/1134545.html
Normal file
@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- saved from url=(0065)https://bug1134545.bugzilla.mozilla.org/attachment.cgi?id=8566418 -->
|
||||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<script>
|
||||
|
||||
function boom()
|
||||
{
|
||||
textNode = document.createTextNode(" ");
|
||||
x.appendChild(textNode);
|
||||
x.setAttribute('contenteditable', "true");
|
||||
textNode.remove();
|
||||
window.getSelection().selectAllChildren(textNode);
|
||||
document.execCommand("increasefontsize", false, null);
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="boom();">
|
||||
<div id="x" contenteditable="true"></div>
|
||||
|
||||
|
||||
</body></html>
|
@ -59,3 +59,4 @@ load 772282.html
|
||||
load 776323.html
|
||||
needs-focus load 793866.html
|
||||
load 1057677.html
|
||||
load 1134545.html
|
||||
|
@ -1527,10 +1527,10 @@ nsHTMLEditor::RelativeFontChange( int32_t aSizeChange)
|
||||
int32_t offset;
|
||||
nsCOMPtr<nsINode> selectedNode;
|
||||
GetStartNodeAndOffset(selection, getter_AddRefs(selectedNode), &offset);
|
||||
NS_ENSURE_TRUE(selectedNode, NS_OK);
|
||||
if (IsTextNode(selectedNode)) {
|
||||
if (selectedNode && IsTextNode(selectedNode)) {
|
||||
selectedNode = selectedNode->GetParentNode();
|
||||
}
|
||||
NS_ENSURE_TRUE(selectedNode, NS_OK);
|
||||
if (!CanContainTag(*selectedNode, *atom)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -33,6 +33,18 @@ BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type, unsigned int arraySi
|
||||
return memberInfo;
|
||||
}
|
||||
|
||||
// static
|
||||
size_t BlockLayoutEncoder::getBlockRegister(const BlockMemberInfo &info)
|
||||
{
|
||||
return (info.offset / BytesPerComponent) / ComponentsPerRegister;
|
||||
}
|
||||
|
||||
// static
|
||||
size_t BlockLayoutEncoder::getBlockRegisterElement(const BlockMemberInfo &info)
|
||||
{
|
||||
return (info.offset / BytesPerComponent) % ComponentsPerRegister;
|
||||
}
|
||||
|
||||
void BlockLayoutEncoder::nextRegister()
|
||||
{
|
||||
mCurrentOffset = rx::roundUp<size_t>(mCurrentOffset, ComponentsPerRegister);
|
||||
|
@ -61,6 +61,9 @@ class BlockLayoutEncoder
|
||||
static const size_t BytesPerComponent = 4u;
|
||||
static const unsigned int ComponentsPerRegister = 4u;
|
||||
|
||||
static size_t getBlockRegister(const BlockMemberInfo &info);
|
||||
static size_t getBlockRegisterElement(const BlockMemberInfo &info);
|
||||
|
||||
protected:
|
||||
size_t mCurrentOffset;
|
||||
|
||||
|
@ -1394,30 +1394,28 @@ void ProgramD3D::defineUniform(GLenum shader, const sh::ShaderVariable &uniform,
|
||||
|
||||
gl::LinkedUniform *linkedUniform = getUniformByName(fullName);
|
||||
|
||||
// Advance the uniform offset, to track registers allocation for structs
|
||||
sh::BlockMemberInfo blockInfo = encoder->encodeType(uniform.type, uniform.arraySize, false);
|
||||
|
||||
if (!linkedUniform)
|
||||
{
|
||||
linkedUniform = new gl::LinkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize,
|
||||
-1, sh::BlockMemberInfo::getDefaultBlockInfo());
|
||||
ASSERT(linkedUniform);
|
||||
linkedUniform->registerElement = encoder->getCurrentElement();
|
||||
linkedUniform->registerElement = sh::HLSLBlockEncoder::getBlockRegisterElement(blockInfo);
|
||||
mUniforms.push_back(linkedUniform);
|
||||
}
|
||||
|
||||
ASSERT(linkedUniform->registerElement == encoder->getCurrentElement());
|
||||
|
||||
if (shader == GL_FRAGMENT_SHADER)
|
||||
{
|
||||
linkedUniform->psRegisterIndex = encoder->getCurrentRegister();
|
||||
linkedUniform->psRegisterIndex = sh::HLSLBlockEncoder::getBlockRegister(blockInfo);
|
||||
}
|
||||
else if (shader == GL_VERTEX_SHADER)
|
||||
{
|
||||
linkedUniform->vsRegisterIndex = encoder->getCurrentRegister();
|
||||
linkedUniform->vsRegisterIndex = sh::HLSLBlockEncoder::getBlockRegister(blockInfo);
|
||||
}
|
||||
else UNREACHABLE();
|
||||
|
||||
// Advance the uniform offset, to track registers allocation for structs
|
||||
encoder->encodeType(uniform.type, uniform.arraySize, false);
|
||||
|
||||
// Arrays are treated as aggregate types
|
||||
if (uniform.isArray())
|
||||
{
|
||||
|
@ -681,6 +681,16 @@ private:
|
||||
|
||||
// Whether or not the frame can be vertically scrolled with a mouse wheel.
|
||||
bool mAllowVerticalScrollWithWheel;
|
||||
|
||||
// WARNING!!!!
|
||||
//
|
||||
// When adding new fields to FrameMetrics, the following places should be
|
||||
// updated to include them (as needed):
|
||||
// FrameMetrics::operator ==
|
||||
// AsyncPanZoomController::NotifyLayersUpdated
|
||||
// The ParamTraits specialization in GfxMessageUtils.h
|
||||
//
|
||||
// Please add new fields above this comment.
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -903,7 +903,6 @@ APZCTreeManager::WillHandleWheelEvent(WidgetWheelEvent* aEvent)
|
||||
{
|
||||
return EventStateManager::WheelEventIsScrollAction(aEvent) &&
|
||||
aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE &&
|
||||
!gfxPrefs::MouseWheelHasScrollDeltaOverride() &&
|
||||
!EventStateManager::WheelEventNeedsDeltaMultipliers(aEvent);
|
||||
}
|
||||
|
||||
|
@ -1442,6 +1442,18 @@ AsyncPanZoomController::GetScrollWheelDelta(const ScrollWheelInput& aEvent,
|
||||
MOZ_ASSERT_UNREACHABLE("unexpected scroll delta type");
|
||||
}
|
||||
|
||||
if (gfxPrefs::MouseWheelHasRootScrollDeltaOverride()) {
|
||||
// Only apply delta multipliers if we're increasing the delta.
|
||||
double hfactor = double(gfxPrefs::MouseWheelRootHScrollDeltaFactor()) / 100;
|
||||
double vfactor = double(gfxPrefs::MouseWheelRootVScrollDeltaFactor()) / 100;
|
||||
if (vfactor > 1.0) {
|
||||
aOutDeltaX *= hfactor;
|
||||
}
|
||||
if (hfactor > 1.0) {
|
||||
aOutDeltaY *= vfactor;
|
||||
}
|
||||
}
|
||||
|
||||
LayoutDeviceIntSize pageScrollSize = mFrameMetrics.GetPageScrollAmount();
|
||||
if (Abs(aOutDeltaX) > pageScrollSize.width) {
|
||||
aOutDeltaX = (aOutDeltaX >= 0)
|
||||
@ -2855,6 +2867,8 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
|
||||
mFrameMetrics.SetPresShellResolution(aLayerMetrics.GetPresShellResolution());
|
||||
mFrameMetrics.SetCumulativeResolution(aLayerMetrics.GetCumulativeResolution());
|
||||
mFrameMetrics.SetHasScrollgrab(aLayerMetrics.GetHasScrollgrab());
|
||||
mFrameMetrics.SetLineScrollAmount(aLayerMetrics.GetLineScrollAmount());
|
||||
mFrameMetrics.SetPageScrollAmount(aLayerMetrics.GetPageScrollAmount());
|
||||
|
||||
if (scrollOffsetUpdated) {
|
||||
APZC_LOG("%p updating scroll offset from %s to %s\n", this,
|
||||
|
@ -236,7 +236,8 @@ APZEventState::ProcessLongTap(const nsCOMPtr<nsIDOMWindowUtils>& aUtils,
|
||||
void
|
||||
APZEventState::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
|
||||
const ScrollableLayerGuid& aGuid,
|
||||
uint64_t aInputBlockId)
|
||||
uint64_t aInputBlockId,
|
||||
nsEventStatus aApzResponse)
|
||||
{
|
||||
if (aEvent.message == NS_TOUCH_START && aEvent.touches.Length() > 0) {
|
||||
mActiveElementManager->SetTargetElement(aEvent.touches[0]->GetTarget());
|
||||
@ -244,6 +245,7 @@ APZEventState::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
|
||||
|
||||
bool isTouchPrevented = TouchManager::gPreventMouseEvents ||
|
||||
aEvent.mFlags.mMultipleActionsPrevented;
|
||||
bool sentContentResponse = false;
|
||||
switch (aEvent.message) {
|
||||
case NS_TOUCH_START: {
|
||||
mTouchEndCancelled = false;
|
||||
@ -252,10 +254,12 @@ APZEventState::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
|
||||
// respond to the first one. Respond to it now.
|
||||
mContentReceivedInputBlockCallback->Run(mPendingTouchPreventedGuid,
|
||||
mPendingTouchPreventedBlockId, false);
|
||||
sentContentResponse = true;
|
||||
mPendingTouchPreventedResponse = false;
|
||||
}
|
||||
if (isTouchPrevented) {
|
||||
mContentReceivedInputBlockCallback->Run(aGuid, aInputBlockId, isTouchPrevented);
|
||||
sentContentResponse = true;
|
||||
} else {
|
||||
mPendingTouchPreventedResponse = true;
|
||||
mPendingTouchPreventedGuid = aGuid;
|
||||
@ -274,13 +278,28 @@ APZEventState::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
|
||||
mActiveElementManager->HandleTouchEndEvent(mEndTouchIsClick);
|
||||
// fall through
|
||||
case NS_TOUCH_MOVE: {
|
||||
SendPendingTouchPreventedResponse(isTouchPrevented, aGuid);
|
||||
sentContentResponse = SendPendingTouchPreventedResponse(isTouchPrevented, aGuid);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
NS_WARNING("Unknown touch event type");
|
||||
}
|
||||
|
||||
if (sentContentResponse &&
|
||||
aApzResponse == nsEventStatus_eConsumeDoDefault &&
|
||||
gfxPrefs::PointerEventsEnabled()) {
|
||||
WidgetTouchEvent cancelEvent(aEvent);
|
||||
cancelEvent.message = NS_TOUCH_CANCEL;
|
||||
cancelEvent.mFlags.mCancelable = false; // message != NS_TOUCH_CANCEL;
|
||||
for (uint32_t i = 0; i < cancelEvent.touches.Length(); ++i) {
|
||||
if (mozilla::dom::Touch* touch = cancelEvent.touches[i]) {
|
||||
touch->convertToPointer = true;
|
||||
}
|
||||
}
|
||||
nsEventStatus status;
|
||||
cancelEvent.widget->DispatchEvent(&cancelEvent, status);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -314,7 +333,7 @@ APZEventState::ProcessAPZStateChange(const nsCOMPtr<nsIDocument>& aDocument,
|
||||
nsCOMPtr<nsIDocShell> docshell(aDocument->GetDocShell());
|
||||
if (docshell && sf) {
|
||||
nsDocShell* nsdocshell = static_cast<nsDocShell*>(docshell.get());
|
||||
nsdocshell->NotifyAsyncPanZoomStarted(sf->GetScrollPositionCSSPixels());
|
||||
nsdocshell->NotifyAsyncPanZoomStarted();
|
||||
}
|
||||
}
|
||||
mActiveAPZTransforms++;
|
||||
@ -336,7 +355,7 @@ APZEventState::ProcessAPZStateChange(const nsCOMPtr<nsIDocument>& aDocument,
|
||||
nsCOMPtr<nsIDocShell> docshell(aDocument->GetDocShell());
|
||||
if (docshell && sf) {
|
||||
nsDocShell* nsdocshell = static_cast<nsDocShell*>(docshell.get());
|
||||
nsdocshell->NotifyAsyncPanZoomStopped(sf->GetScrollPositionCSSPixels());
|
||||
nsdocshell->NotifyAsyncPanZoomStopped();
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -364,7 +383,7 @@ APZEventState::ProcessAPZStateChange(const nsCOMPtr<nsIDocument>& aDocument,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
APZEventState::SendPendingTouchPreventedResponse(bool aPreventDefault,
|
||||
const ScrollableLayerGuid& aGuid)
|
||||
{
|
||||
@ -373,7 +392,9 @@ APZEventState::SendPendingTouchPreventedResponse(bool aPreventDefault,
|
||||
mContentReceivedInputBlockCallback->Run(mPendingTouchPreventedGuid,
|
||||
mPendingTouchPreventedBlockId, aPreventDefault);
|
||||
mPendingTouchPreventedResponse = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIWidget>
|
||||
|
@ -61,7 +61,8 @@ public:
|
||||
float aPresShellResolution);
|
||||
void ProcessTouchEvent(const WidgetTouchEvent& aEvent,
|
||||
const ScrollableLayerGuid& aGuid,
|
||||
uint64_t aInputBlockId);
|
||||
uint64_t aInputBlockId,
|
||||
nsEventStatus aApzResponse);
|
||||
void ProcessWheelEvent(const WidgetWheelEvent& aEvent,
|
||||
const ScrollableLayerGuid& aGuid,
|
||||
uint64_t aInputBlockId);
|
||||
@ -71,7 +72,7 @@ public:
|
||||
int aArg);
|
||||
private:
|
||||
~APZEventState();
|
||||
void SendPendingTouchPreventedResponse(bool aPreventDefault,
|
||||
bool SendPendingTouchPreventedResponse(bool aPreventDefault,
|
||||
const ScrollableLayerGuid& aGuid);
|
||||
already_AddRefed<nsIWidget> GetWidget() const;
|
||||
private:
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user