Merge mozilla-inbound to m-c. a=merge

CLOSED TREE
This commit is contained in:
Ryan VanderMeulen 2015-03-26 14:43:39 -04:00
Родитель 9854d397ba 9064fad3d2
Коммит be425949b5
321 изменённых файлов: 7995 добавлений и 2888 удалений

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

@ -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)
if (accWrap) {
HyperTextAccessible* hyperText = accWrap->AsHyperText();
NS_ENSURE_TRUE(hyperText, nullptr);
Accessible* hyperLink = hyperText->LinkAt(aLinkIndex);
if (!hyperLink) {
return nullptr;
}
AtkObject* hyperLinkAtkObj = AccessibleWrap::GetAtkObject(hyperLink);
AccessibleWrap* accChild = GetAccessibleWrap(hyperLinkAtkObj);
NS_ENSURE_TRUE(accChild, nullptr);
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;
}
HyperTextAccessible* hyperText = accWrap->AsHyperText();
NS_ENSURE_TRUE(hyperText, nullptr);
Accessible* hyperLink = hyperText->LinkAt(aLinkIndex);
if (!hyperLink)
return nullptr;
AtkObject* hyperLinkAtkObj = AccessibleWrap::GetAtkObject(hyperLink);
AccessibleWrap* accChild = GetAccessibleWrap(hyperLinkAtkObj);
NS_ENSURE_TRUE(accChild, nullptr);
MaiHyperlink *maiHyperlink = accChild->GetMaiHyperlink();
NS_ENSURE_TRUE(maiHyperlink, nullptr);
return maiHyperlink->GetAtkHyperlink();
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();
}
HyperTextAccessible* hyperText = accWrap->AsHyperText();
NS_ENSURE_TRUE(hyperText, -1);
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
return proxy->LinkCount();
}
return hyperText->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);
HyperTextAccessible* hyperText = accWrap->AsHyperText();
NS_ENSURE_TRUE(hyperText, -1);
return hyperText->LinkIndexAtOffset(aCharIndex);
}
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);
}
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();
}
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) {
return nullptr;
}
Accessible* selectedItem = accWrap->GetSelectedItem(i);
if (!selectedItem)
return nullptr;
atkObj = AccessibleWrap::GetAtkObject(selectedItem);
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
ProxyAccessible* selectedItem = proxy->GetSelectedItem(i);
if (selectedItem) {
atkObj = GetWrapperFor(selectedItem);
}
}
AtkObject* atkObj = AccessibleWrap::GetAtkObject(selectedItem);
if (atkObj)
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();
}
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);
}
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);
}
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();
}
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;
}
}
// 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;
// No elements in siblings what means the table has one column only. Therefore
// it should be column header.
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,
"Wrong row header cell at index " + idx + " for the cell " +
prettyName(rowHeaderCells[idx]));
isObject(actualRowHeaderCell, rowHeaderCell,
"Wrong row header cell at index " + idx + " for the cell " +
dataCellIdentifier);
}
}
@ -735,9 +735,9 @@ function testHeaderCells(aHeaderInfoMap)
var colHeaderCell = getAccessible(colHeaderCells[idx]);
var actualColHeaderCell =
actualColHeaderCells.queryElementAt(idx, nsIAccessible);
ok(actualColHeaderCell, colHeaderCell,
"Wrong column header cell at index " + idx + " for the cell " +
prettyName(colHeaderCells[idx]));
isObject(actualColHeaderCell, colHeaderCell,
"Wrong column header cell at index " + idx + " for the cell " +
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();

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

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

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

@ -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 поставляемый
Просмотреть файл

@ -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 поставляемый
Просмотреть файл

@ -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 поставляемый
Просмотреть файл

@ -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';
}
static get displayModes() {
return displayModes;
}
static get orientationTypes() {
return orientationTypes;
}
// process method: processes json text into a clean manifest
// that conforms with the W3C specification. Takes an object
// expecting the following dictionary items:
// * jsonText: the JSON string to be processd.
// * manifestURL: the URL of the manifest, to resolve URLs.
// * docURL: the URL of the owner doc, for security checks.
process({
jsonText, manifestURL, docURL
}) {
const console = new ConsoleAPI({
prefix: 'Web Manifest: '
});
let rawManifest = {};
try {
rawManifest = JSON.parse(jsonText);
} catch (e) {}
if (typeof rawManifest !== 'object' || rawManifest === null) {
let msg = 'Manifest needs to be an object.';
console.warn(msg);
rawManifest = {};
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;
}
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),
return value;
}
function issueDeveloperWarning(msg) {
//https://bugzilla.mozilla.org/show_bug.cgi?id=1086997
}
function processNameMember(manifest) {
const obj = {
objectName: 'manifest',
object: manifest,
property: 'name',
expectedType: 'string'
};
processedManifest.scope = processScopeMember(rawManifest, manifestURL,
docURL, processedManifest.start_url);
return processedManifest;
let value = extractValue(obj);
return (value) ? value.trim() : value;
}
function processNameMember(aManifest) {
const spec = {
objectName: 'manifest',
object: aManifest,
property: 'name',
expectedType: 'string',
trim: true
};
return extractValue(spec, console);
}
function processShortNameMember(manifest) {
const obj = {
objectName: 'manifest',
object: manifest,
property: 'short_name',
expectedType: 'string'
};
let value = extractValue(obj);
return (value) ? value.trim() : value;
}
function processShortNameMember(aManifest) {
const spec = {
objectName: 'manifest',
object: aManifest,
property: 'short_name',
expectedType: 'string',
trim: true
};
return extractValue(spec, console);
}
function processOrientationMember(manifest) {
const obj = {
objectName: 'manifest',
object: manifest,
property: 'orientation',
expectedType: 'string'
};
let value = extractValue(obj);
value = (value) ? value.trim() : undefined;
//The spec special-cases orientation to return the empty string
return (orientationTypes.has(value)) ? value : '';
}
function processOrientationMember(aManifest) {
const spec = {
objectName: 'manifest',
object: aManifest,
property: 'orientation',
expectedType: 'string',
trim: true
};
const value = extractValue(spec, console);
if (ManifestProcessor.orientationTypes.has(value)) {
return value;
}
// The spec special-cases orientation to return the empty string.
return '';
}
function processDisplayMember(manifest) {
const obj = {
objectName: 'manifest',
object: manifest,
property: 'display',
expectedType: 'string'
};
function processDisplayMember(aManifest) {
const spec = {
objectName: 'manifest',
object: aManifest,
property: 'display',
expectedType: 'string',
trim: true
};
const value = extractValue(spec, console);
if (ManifestProcessor.displayModes.has(value)) {
return value;
}
return ManifestProcessor.defaultDisplayMode;
}
let value = extractValue(obj);
value = (value) ? value.trim() : value;
return (displayModes.has(value)) ? value : defaultDisplayMode;
}
function processScopeMember(aManifest, aManifestURL, aDocURL, aStartURL) {
const spec = {
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);
let scopeURL;
try {
scopeURL = new URL(value, aManifestURL);
} catch (e) {
let msg = 'The URL of scope is invalid.';
console.warn(msg);
return undefined;
}
if (scopeURL.origin !== aDocURL.origin) {
let msg = 'Scope needs to be same-origin as Document.';
console.warn(msg);
return undefined;
}
// If start URL is not within scope of scope URL:
let isSameOrigin = aStartURL && aStartURL.origin !== scopeURL.origin;
if (isSameOrigin || !aStartURL.pathname.startsWith(scopeURL.pathname)) {
let msg =
'The start URL is outside the scope, so scope is invalid.';
console.warn(msg);
return undefined;
}
return scopeURL;
dontTrim: true
},
value = extractValue(spec);
let scopeURL;
try {
scopeURL = new URL(value, manifestURL);
} catch (e) {
let msg = 'The URL of scope is invalid.';
issueDeveloperWarning(msg);
return undefined;
}
function processStartURLMember(aManifest, aManifestURL, aDocURL) {
const spec = {
objectName: 'manifest',
object: aManifest,
property: 'start_url',
expectedType: 'string',
trim: false
};
let result = new URL(aDocURL);
const value = extractValue(spec, console);
if (value === undefined || value === '') {
return result;
}
let potentialResult;
try {
potentialResult = new URL(value, aManifestURL);
} catch (e) {
console.warn('Invalid URL.');
return result;
}
if (potentialResult.origin !== aDocURL.origin) {
let msg = 'start_url must be same origin as document.';
console.warn(msg);
} else {
result = potentialResult;
}
if (scopeURL.origin !== docURL.origin) {
let msg = 'Scope needs to be same-origin as Document.';
issueDeveloperWarning(msg);
return undefined;
}
//If start URL is not within scope of scope URL:
if (startURL && startURL.origin !== scopeURL.origin || !startURL.pathname.startsWith(scopeURL.pathname)) {
let msg = 'The start URL is outside the scope, so scope is invalid.';
issueDeveloperWarning(msg);
return undefined;
}
return scopeURL;
}
function processStartURLMember(manifest, manifestURL, docURL) {
const obj = {
objectName: 'manifest',
object: manifest,
property: 'start_url',
expectedType: 'string'
};
let value = extractValue(obj),
result = new URL(docURL),
targetURI = makeURI(result),
sameOrigin = false,
potentialResult,
referrerURI;
if (value === undefined || value === '') {
return result;
}
}
}
this.ManifestProcessor = ManifestProcessor;
class IconsProcessor {
try {
potentialResult = new URL(value, manifestURL);
} catch (e) {
issueDeveloperWarning('Invalid URL.');
return result;
}
referrerURI = makeURI(potentialResult);
try {
securityManager.checkSameOriginURI(referrerURI, targetURI, false);
sameOrigin = true;
} catch (e) {}
if (!sameOrigin) {
let msg = 'start_url must be same origin as document.';
issueDeveloperWarning(msg);
} else {
result = potentialResult;
}
return result;
constructor() {
throw new Error('Static use only.');
//Converts a URL to a Gecko URI
function makeURI(webURL) {
return imports.Services.io.newURI(webURL.toString(), null, null);
}
}
static get onlyDecimals() {
return /^\d+$/;
}
//Constants used by IconsProcessor
const onlyDecimals = /^\d+$/,
anyRegEx = new RegExp('any', 'i');
static get anyRegEx() {
return new RegExp('any', 'i');
}
function IconsProcessor() {}
IconsProcessor.prototype.processIcons = function(manifest, baseURL) {
const obj = {
objectName: 'manifest',
object: manifest,
property: 'icons',
expectedType: 'array'
},
icons = [];
let value = extractValue(obj);
static process(aManifest, aBaseURL, console) {
const spec = {
objectName: 'manifest',
object: aManifest,
property: 'icons',
expectedType: 'array',
trim: false
};
const icons = [];
const value = extractValue(spec, console);
if (Array.isArray(value)) {
// Filter out icons whose "src" is not useful.
value.filter(item => !!processSrcMember(item, aBaseURL))
.map(toIconObject)
.forEach(icon => icons.push(icon));
//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(icon) {
const charset = {},
hadCharset = {},
obj = {
objectName: 'icon',
object: icon,
property: 'type',
expectedType: 'string'
};
let value = extractValue(obj),
isParsable = (typeof value === 'string' && value.length > 0);
value = (isParsable) ? netutil.parseContentType(value.trim(), charset, hadCharset) : undefined;
return (value === '') ? undefined : value;
}
function processTypeMember(aIcon) {
const charset = {};
const hadCharset = {};
const spec = {
objectName: 'icon',
object: aIcon,
property: 'type',
expectedType: 'string',
trim: true
};
let value = extractValue(spec, console);
if (value) {
value = imports.netutil.parseContentType(value, charset, hadCharset);
}
return value || undefined;
function 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 processDensityMember(aIcon) {
const value = parseFloat(aIcon.density);
const validNum = Number.isNaN(value) || value === +Infinity || value <=
0;
return (validNum) ? 1.0 : value;
}
function processSrcMember(aIcon, aBaseURL) {
const spec = {
objectName: 'icon',
object: aIcon,
property: 'src',
expectedType: 'string',
trim: false
};
const value = extractValue(spec, console);
function processSrcMember(icon, baseURL) {
const obj = {
objectName: 'icon',
object: icon,
property: 'src',
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));
session->SetSessionId(aSessionId);
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,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR),
NS_LITERAL_CSTRING("aac"))) &&
(!hasH264 || !HaveGMPFor(aGMPS,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR),
NS_LITERAL_CSTRING("h264")));
return (!hasAAC ||
!(HaveGMPFor(aGMPS,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR),
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")) ||
// 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);
}

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

@ -43,7 +43,7 @@ CopyArrayBufferViewOrArrayBufferData(const ArrayBufferViewOrArrayBuffer& aBuffer
// This class is used on the main thread only.
// Note: it's addref/release is not (and can't be) thread safe!
class MediaKeys final : public nsISupports,
public nsWrapperCache
public nsWrapperCache
{
~MediaKeys();
@ -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);
}

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

@ -20,7 +20,7 @@ namespace gmp {
class GMPParent;
class GMPDecryptorParent final : public GMPDecryptorProxy
, public PGMPDecryptorParent
, public PGMPDecryptorParent
{
public:
NS_INLINE_DECL_REFCOUNTING(GMPDecryptorParent)
@ -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()
{

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

@ -55,7 +55,7 @@ enum GMPState {
};
class GMPParent final : public PGMPParent,
public GMPSharedMem
public GMPSharedMem
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(GMPParent)
@ -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;
}

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

@ -31,7 +31,7 @@ class GMPParent;
#define GMP_DEFAULT_ASYNC_SHUTDONW_TIMEOUT 3000
class GeckoMediaPluginService final : public mozIGeckoMediaPluginService
, public nsIObserver
, public nsIObserver
{
public:
static already_AddRefed<GeckoMediaPluginService> GetGeckoMediaPluginService();
@ -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,12 +97,14 @@ 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 |
nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT |
nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT));
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 |
nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT));
eventSink->OnSecurityChange(mContext,
(nsIWebProgressListener::STATE_IS_BROKEN |
nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT));
}
}
@ -118,9 +120,10 @@ 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 |
nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT |
nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT));
eventSink->OnSecurityChange(mContext,
(nsIWebProgressListener::STATE_IS_BROKEN |
nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT |
nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT));
} else {
eventSink->OnSecurityChange(mContext, (nsIWebProgressListener::STATE_IS_BROKEN |
nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT));
@ -656,10 +659,31 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
if (allowMixedContent) {
LogMixedContentMessage(classification, aContentLocation, rootDoc, eUserOverride);
*aDecision = nsIContentPolicy::ACCEPT;
rootDoc->SetHasMixedActiveContentLoaded(true);
if (!rootDoc->GetHasMixedDisplayContentLoaded() && NS_SUCCEEDED(stateRV)) {
rootDoc->SetHasMixedDisplayContentLoaded(true);
eventSink->OnSecurityChange(aRequestingContext, (State | nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT));
// 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;
@ -675,50 +699,52 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
// If the content is active content, and the pref says active content should be blocked, block it
// unless the user has choosen to override the pref
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.
if (rootDoc->GetHasMixedActiveContentLoaded()) {
return NS_OK;
}
rootDoc->SetHasMixedActiveContentLoaded(true);
LogMixedContentMessage(classification, aContentLocation, rootDoc, eUserOverride);
*aDecision = nsIContentPolicy::ACCEPT;
// 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;
}
rootDoc->SetHasMixedActiveContentLoaded(true);
if (rootHasSecureConnection) {
// 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 |
nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT |
nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT));
} else {
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.
if (NS_SUCCEEDED(stateRV)) {
eventSink->OnSecurityChange(aRequestingContext, (State | nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT));
}
return NS_OK;
}
if (rootHasSecureConnection) {
// 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 |
nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT |
nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT));
} else {
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 active content was allowed on an https subframe.
if (NS_SUCCEEDED(stateRV)) {
eventSink->OnSecurityChange(aRequestingContext, (State | nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT));
}
return NS_OK;
}
} else {
//User has not overriden the pref by Disabling protection. Reject the request and update the security state.
*aDecision = nsIContentPolicy::REJECT_REQUEST;
LogMixedContentMessage(classification, aContentLocation, rootDoc, eBlocked);
// See if the pref will change here. If it will, only then do we need to call OnSecurityChange() to update the UI.
if (rootDoc->GetHasMixedActiveContentBlocked()) {
return NS_OK;
}
rootDoc->SetHasMixedActiveContentBlocked(true);
//User has not overriden the pref by Disabling protection. Reject the request and update the security state.
*aDecision = nsIContentPolicy::REJECT_REQUEST;
LogMixedContentMessage(classification, aContentLocation, rootDoc, eBlocked);
// See if the pref will change here. If it will, only then do we need to call OnSecurityChange() to update the UI.
if (rootDoc->GetHasMixedActiveContentBlocked()) {
return NS_OK;
}
rootDoc->SetHasMixedActiveContentBlocked(true);
// The user has not overriden the pref, so make sure they still have an option by calling eventSink
// which will invoke the doorhanger
if (NS_SUCCEEDED(stateRV)) {
eventSink->OnSecurityChange(aRequestingContext, (State | nsIWebProgressListener::STATE_BLOCKED_MIXED_ACTIVE_CONTENT));
}
return NS_OK;
// The user has not overriden the pref, so make sure they still have an option by calling eventSink
// which will invoke the doorhanger
if (NS_SUCCEEDED(stateRV)) {
eventSink->OnSecurityChange(aRequestingContext, (State | nsIWebProgressListener::STATE_BLOCKED_MIXED_ACTIVE_CONTENT));
}
return NS_OK;
}
} else {

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

@ -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,13 +47,16 @@ 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 &&
!httpProxy && !sslProxy && !httpProxyPort && !sslProxyPort)) {
(!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());
}
});

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

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

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

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

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

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

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

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

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