Merge autoland to mozilla-central. a=merge

This commit is contained in:
Narcis Beleuzu 2022-04-02 12:40:22 +03:00
Родитель 9c3532a723 71ead80661
Коммит 1f263e9a1f
1101 изменённых файлов: 15571 добавлений и 6030 удалений

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

@ -183,7 +183,6 @@ module.exports = {
// These are suitable as good first bugs, take one or two related lines
// per bug.
"caps/tests/unit/test_origin.js",
"caps/tests/unit/test_site_origin.js",
"chrome/test/unit/test_no_remote_registration.js",
"extensions/permissions/**",
"image/test/unit/**",
@ -538,24 +537,6 @@ module.exports = {
"mozilla/prefer-boolean-length-check": "off",
},
},
{
// TODO: Bug 1609271 Fix all violations for ChromeUtils.import(..., null)
files: [
"toolkit/mozapps/extensions/internal/AddonTestUtils.jsm",
"toolkit/mozapps/extensions/test/browser/browser_gmpProvider.js",
"toolkit/mozapps/extensions/test/xpcshell/head_addons.js",
"toolkit/mozapps/extensions/test/xpcshell/test_gmpProvider.js",
"toolkit/mozapps/extensions/test/xpcshell/test_no_addons.js",
"toolkit/mozapps/extensions/test/xpcshell/test_permissions_prefs.js",
"toolkit/mozapps/extensions/test/xpcshell/test_signed_updatepref.js",
"toolkit/mozapps/extensions/test/xpcshell/test_signed_verify.js",
"toolkit/mozapps/extensions/test/xpcshell/test_webextension_events.js",
"toolkit/mozapps/extensions/test/xpcshell/test_XPIStates.js",
],
rules: {
"mozilla/reject-chromeutils-import-params": "warn",
},
},
{
// Rules of Hooks broadly checks for camelCase "use" identifiers, so
// enable only for paths actually using React to avoid false positives.

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

@ -16,8 +16,8 @@
#include "RemoteAccessible.h"
#include "DocAccessibleParent.h"
#include "RootAccessible.h"
#include "TableAccessible.h"
#include "TableCellAccessible.h"
#include "mozilla/a11y/TableAccessibleBase.h"
#include "mozilla/a11y/TableCellAccessibleBase.h"
#include "nsMai.h"
#include "nsMaiHyperlink.h"
#include "nsString.h"
@ -1525,13 +1525,13 @@ void AccessibleWrap::GetKeyBinding(LocalAccessible* aAccessible,
}
// static
LocalAccessible* AccessibleWrap::GetColumnHeader(TableAccessible* aAccessible,
int32_t aColIdx) {
Accessible* AccessibleWrap::GetColumnHeader(TableAccessibleBase* aAccessible,
int32_t aColIdx) {
if (!aAccessible) {
return nullptr;
}
LocalAccessible* cell = aAccessible->CellAt(0, aColIdx);
Accessible* cell = aAccessible->CellAt(0, aColIdx);
if (!cell) {
return nullptr;
}
@ -1543,12 +1543,12 @@ LocalAccessible* AccessibleWrap::GetColumnHeader(TableAccessible* aAccessible,
}
// otherwise get column header for the data cell at the first row.
TableCellAccessible* tableCell = cell->AsTableCell();
TableCellAccessibleBase* tableCell = cell->AsTableCellBase();
if (!tableCell) {
return nullptr;
}
AutoTArray<LocalAccessible*, 10> headerCells;
AutoTArray<Accessible*, 10> headerCells;
tableCell->ColHeaderCells(&headerCells);
if (headerCells.IsEmpty()) {
return nullptr;
@ -1558,13 +1558,13 @@ LocalAccessible* AccessibleWrap::GetColumnHeader(TableAccessible* aAccessible,
}
// static
LocalAccessible* AccessibleWrap::GetRowHeader(TableAccessible* aAccessible,
int32_t aRowIdx) {
Accessible* AccessibleWrap::GetRowHeader(TableAccessibleBase* aAccessible,
int32_t aRowIdx) {
if (!aAccessible) {
return nullptr;
}
LocalAccessible* cell = aAccessible->CellAt(aRowIdx, 0);
Accessible* cell = aAccessible->CellAt(aRowIdx, 0);
if (!cell) {
return nullptr;
}
@ -1576,12 +1576,12 @@ LocalAccessible* AccessibleWrap::GetRowHeader(TableAccessible* aAccessible,
}
// otherwise get row header for the data cell at the first column.
TableCellAccessible* tableCell = cell->AsTableCell();
TableCellAccessibleBase* tableCell = cell->AsTableCellBase();
if (!tableCell) {
return nullptr;
}
AutoTArray<LocalAccessible*, 10> headerCells;
AutoTArray<Accessible*, 10> headerCells;
tableCell->RowHeaderCells(&headerCells);
if (headerCells.IsEmpty()) {
return nullptr;

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

@ -70,10 +70,10 @@ class AccessibleWrap : public LocalAccessible {
static void GetKeyBinding(LocalAccessible* aAccessible, nsAString& aResult);
static LocalAccessible* GetColumnHeader(TableAccessible* aAccessible,
int32_t aColIdx);
static LocalAccessible* GetRowHeader(TableAccessible* aAccessible,
int32_t aRowIdx);
static Accessible* GetColumnHeader(TableAccessibleBase* aAccessible,
int32_t aColIdx);
static Accessible* GetRowHeader(TableAccessibleBase* aAccessible,
int32_t aRowIdx);
protected:
nsresult FireAtkStateChangeEvent(AccEvent* aEvent, AtkObject* aObject);

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

@ -6,17 +6,18 @@
#include "InterfaceInitFuncs.h"
#include "LocalAccessible-inl.h"
#include "AccessibleWrap.h"
#include "nsAccUtils.h"
#include "TableAccessible.h"
#include "TableCellAccessible.h"
#include "mozilla/a11y/TableAccessibleBase.h"
#include "mozilla/a11y/TableCellAccessibleBase.h"
#include "mozilla/StaticPrefs_accessibility.h"
#include "nsMai.h"
#include "RemoteAccessible.h"
#include "nsArrayUtils.h"
#include "mozilla/Likely.h"
using namespace mozilla;
using namespace mozilla::a11y;
extern "C" {
@ -26,15 +27,18 @@ static AtkObject* refAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx) {
}
AtkObject* cellAtkObj = nullptr;
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (accWrap) {
LocalAccessible* cell = accWrap->AsTable()->CellAt(aRowIdx, aColIdx);
Accessible* acc = GetInternalObj(ATK_OBJECT(aTable));
if (!acc) {
return nullptr;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
Accessible* cell = acc->AsTableBase()->CellAt(aRowIdx, aColIdx);
if (!cell) {
return nullptr;
}
cellAtkObj = AccessibleWrap::GetAtkObject(cell);
} else if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
cellAtkObj = GetWrapperFor(cell);
} else if (RemoteAccessible* proxy = acc->AsRemote()) {
RemoteAccessible* cell = proxy->TableCellAt(aRowIdx, aColIdx);
if (!cell) {
return nullptr;
@ -55,12 +59,15 @@ static gint getIndexAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx) {
return -1;
}
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (accWrap) {
return static_cast<gint>(accWrap->AsTable()->CellIndexAt(aRowIdx, aColIdx));
Accessible* acc = GetInternalObj(ATK_OBJECT(aTable));
if (!acc) {
return -1;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
return static_cast<gint>(acc->AsTableBase()->CellIndexAt(aRowIdx, aColIdx));
}
if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
if (RemoteAccessible* proxy = acc->AsRemote()) {
return static_cast<gint>(proxy->TableCellIndexAt(aRowIdx, aColIdx));
}
@ -72,12 +79,15 @@ static gint getColumnAtIndexCB(AtkTable* aTable, gint aIdx) {
return -1;
}
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (accWrap) {
return static_cast<gint>(accWrap->AsTable()->ColIndexAt(aIdx));
Accessible* acc = GetInternalObj(ATK_OBJECT(aTable));
if (!acc) {
return -1;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
return static_cast<gint>(acc->AsTableBase()->ColIndexAt(aIdx));
}
if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
if (RemoteAccessible* proxy = acc->AsRemote()) {
return static_cast<gint>(proxy->TableColumnIndexAt(aIdx));
}
@ -89,12 +99,15 @@ static gint getRowAtIndexCB(AtkTable* aTable, gint aIdx) {
return -1;
}
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (accWrap) {
return static_cast<gint>(accWrap->AsTable()->RowIndexAt(aIdx));
Accessible* acc = GetInternalObj(ATK_OBJECT(aTable));
if (!acc) {
return -1;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
return static_cast<gint>(acc->AsTableBase()->RowIndexAt(aIdx));
}
if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
if (RemoteAccessible* proxy = acc->AsRemote()) {
return static_cast<gint>(proxy->TableRowIndexAt(aIdx));
}
@ -102,12 +115,15 @@ static gint getRowAtIndexCB(AtkTable* aTable, gint aIdx) {
}
static gint getColumnCountCB(AtkTable* aTable) {
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (accWrap) {
return static_cast<gint>(accWrap->AsTable()->ColCount());
Accessible* acc = GetInternalObj(ATK_OBJECT(aTable));
if (!acc) {
return -1;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
return static_cast<gint>(acc->AsTableBase()->ColCount());
}
if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
if (RemoteAccessible* proxy = acc->AsRemote()) {
return static_cast<gint>(proxy->TableColumnCount());
}
@ -115,12 +131,15 @@ static gint getColumnCountCB(AtkTable* aTable) {
}
static gint getRowCountCB(AtkTable* aTable) {
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (accWrap) {
return static_cast<gint>(accWrap->AsTable()->RowCount());
Accessible* acc = GetInternalObj(ATK_OBJECT(aTable));
if (!acc) {
return -1;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
return static_cast<gint>(acc->AsTableBase()->RowCount());
}
if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
if (RemoteAccessible* proxy = acc->AsRemote()) {
return static_cast<gint>(proxy->TableRowCount());
}
@ -132,12 +151,15 @@ static gint getColumnExtentAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx) {
return -1;
}
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (accWrap) {
return static_cast<gint>(accWrap->AsTable()->ColExtentAt(aRowIdx, aColIdx));
Accessible* acc = GetInternalObj(ATK_OBJECT(aTable));
if (!acc) {
return -1;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
return static_cast<gint>(acc->AsTableBase()->ColExtentAt(aRowIdx, aColIdx));
}
if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
if (RemoteAccessible* proxy = acc->AsRemote()) {
return static_cast<gint>(proxy->TableColumnExtentAt(aRowIdx, aColIdx));
}
@ -145,12 +167,15 @@ static gint getColumnExtentAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx) {
}
static gint getRowExtentAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx) {
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (accWrap) {
return static_cast<gint>(accWrap->AsTable()->RowExtentAt(aRowIdx, aColIdx));
Accessible* acc = GetInternalObj(ATK_OBJECT(aTable));
if (!acc) {
return -1;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
return static_cast<gint>(acc->AsTableBase()->RowExtentAt(aRowIdx, aColIdx));
}
if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
if (RemoteAccessible* proxy = acc->AsRemote()) {
return static_cast<gint>(proxy->TableRowExtentAt(aRowIdx, aColIdx));
}
@ -158,13 +183,16 @@ static gint getRowExtentAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx) {
}
static AtkObject* getCaptionCB(AtkTable* aTable) {
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (accWrap) {
LocalAccessible* caption = accWrap->AsTable()->Caption();
return caption ? AccessibleWrap::GetAtkObject(caption) : nullptr;
Accessible* acc = GetInternalObj(ATK_OBJECT(aTable));
if (!acc) {
return nullptr;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
Accessible* caption = acc->AsTableBase()->Caption();
return caption ? GetWrapperFor(caption) : nullptr;
}
if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
if (RemoteAccessible* proxy = acc->AsRemote()) {
RemoteAccessible* caption = proxy->TableCaption();
return caption ? GetWrapperFor(caption) : nullptr;
}
@ -174,27 +202,31 @@ static AtkObject* getCaptionCB(AtkTable* aTable) {
static const gchar* getColumnDescriptionCB(AtkTable* aTable, gint aColumn) {
nsAutoString autoStr;
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (accWrap) {
accWrap->AsTable()->ColDescription(aColumn, autoStr);
} else if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
proxy->TableColumnDescription(aColumn, autoStr);
} else {
Accessible* acc = GetInternalObj(ATK_OBJECT(aTable));
if (!acc) {
return nullptr;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
acc->AsTableBase()->ColDescription(aColumn, autoStr);
} else if (RemoteAccessible* proxy = acc->AsRemote()) {
proxy->TableColumnDescription(aColumn, autoStr);
}
return AccessibleWrap::ReturnString(autoStr);
}
static AtkObject* getColumnHeaderCB(AtkTable* aTable, gint aColIdx) {
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (accWrap) {
LocalAccessible* header =
AccessibleWrap::GetColumnHeader(accWrap->AsTable(), aColIdx);
return header ? AccessibleWrap::GetAtkObject(header) : nullptr;
Accessible* acc = GetInternalObj(ATK_OBJECT(aTable));
if (!acc) {
return nullptr;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
Accessible* header =
AccessibleWrap::GetColumnHeader(acc->AsTableBase(), aColIdx);
return header ? GetWrapperFor(header) : nullptr;
}
if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
if (RemoteAccessible* proxy = acc->AsRemote()) {
RemoteAccessible* header = proxy->AtkTableColumnHeader(aColIdx);
return header ? GetWrapperFor(header) : nullptr;
}
@ -204,27 +236,31 @@ static AtkObject* getColumnHeaderCB(AtkTable* aTable, gint aColIdx) {
static const gchar* getRowDescriptionCB(AtkTable* aTable, gint aRow) {
nsAutoString autoStr;
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (accWrap) {
accWrap->AsTable()->RowDescription(aRow, autoStr);
} else if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
proxy->TableRowDescription(aRow, autoStr);
} else {
Accessible* acc = GetInternalObj(ATK_OBJECT(aTable));
if (!acc) {
return nullptr;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
acc->AsTableBase()->RowDescription(aRow, autoStr);
} else if (RemoteAccessible* proxy = acc->AsRemote()) {
proxy->TableRowDescription(aRow, autoStr);
}
return AccessibleWrap::ReturnString(autoStr);
}
static AtkObject* getRowHeaderCB(AtkTable* aTable, gint aRowIdx) {
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (accWrap) {
LocalAccessible* header =
AccessibleWrap::GetRowHeader(accWrap->AsTable(), aRowIdx);
return header ? AccessibleWrap::GetAtkObject(header) : nullptr;
Accessible* acc = GetInternalObj(ATK_OBJECT(aTable));
if (!acc) {
return nullptr;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
Accessible* header =
AccessibleWrap::GetRowHeader(acc->AsTableBase(), aRowIdx);
return header ? GetWrapperFor(header) : nullptr;
}
if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
if (RemoteAccessible* proxy = acc->AsRemote()) {
RemoteAccessible* header = proxy->AtkTableRowHeader(aRowIdx);
return header ? GetWrapperFor(header) : nullptr;
}
@ -244,14 +280,15 @@ static gint getSelectedColumnsCB(AtkTable* aTable, gint** aSelected) {
*aSelected = nullptr;
AutoTArray<uint32_t, 10> cols;
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (accWrap) {
accWrap->AsTable()->SelectedColIndices(&cols);
} else if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
proxy->TableSelectedColumnIndices(&cols);
} else {
Accessible* acc = GetInternalObj(ATK_OBJECT(aTable));
if (!acc) {
return 0;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
acc->AsTableBase()->SelectedColIndices(&cols);
} else if (RemoteAccessible* proxy = acc->AsRemote()) {
proxy->TableSelectedColumnIndices(&cols);
}
if (cols.IsEmpty()) return 0;
@ -268,14 +305,15 @@ static gint getSelectedColumnsCB(AtkTable* aTable, gint** aSelected) {
static gint getSelectedRowsCB(AtkTable* aTable, gint** aSelected) {
AutoTArray<uint32_t, 10> rows;
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (accWrap) {
accWrap->AsTable()->SelectedRowIndices(&rows);
} else if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
proxy->TableSelectedRowIndices(&rows);
} else {
Accessible* acc = GetInternalObj(ATK_OBJECT(aTable));
if (!acc) {
return 0;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
acc->AsTableBase()->SelectedRowIndices(&rows);
} else if (RemoteAccessible* proxy = acc->AsRemote()) {
proxy->TableSelectedRowIndices(&rows);
}
gint* atkRows = g_new(gint, rows.Length());
if (!atkRows) {
@ -289,11 +327,14 @@ static gint getSelectedRowsCB(AtkTable* aTable, gint** aSelected) {
}
static gboolean isColumnSelectedCB(AtkTable* aTable, gint aColIdx) {
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (accWrap) {
return static_cast<gboolean>(accWrap->AsTable()->IsColSelected(aColIdx));
Accessible* acc = GetInternalObj(ATK_OBJECT(aTable));
if (!acc) {
return FALSE;
}
if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
return static_cast<gboolean>(acc->AsTableBase()->IsColSelected(aColIdx));
}
if (RemoteAccessible* proxy = acc->AsRemote()) {
return static_cast<gboolean>(proxy->TableColumnSelected(aColIdx));
}
@ -301,11 +342,14 @@ static gboolean isColumnSelectedCB(AtkTable* aTable, gint aColIdx) {
}
static gboolean isRowSelectedCB(AtkTable* aTable, gint aRowIdx) {
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (accWrap) {
return static_cast<gboolean>(accWrap->AsTable()->IsRowSelected(aRowIdx));
Accessible* acc = GetInternalObj(ATK_OBJECT(aTable));
if (!acc) {
return FALSE;
}
if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
return static_cast<gboolean>(acc->AsTableBase()->IsRowSelected(aRowIdx));
}
if (RemoteAccessible* proxy = acc->AsRemote()) {
return static_cast<gboolean>(proxy->TableRowSelected(aRowIdx));
}
@ -313,12 +357,15 @@ static gboolean isRowSelectedCB(AtkTable* aTable, gint aRowIdx) {
}
static gboolean isCellSelectedCB(AtkTable* aTable, gint aRowIdx, gint aColIdx) {
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (accWrap) {
return static_cast<gboolean>(
accWrap->AsTable()->IsCellSelected(aRowIdx, aColIdx));
Accessible* acc = GetInternalObj(ATK_OBJECT(aTable));
if (!acc) {
return FALSE;
}
if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
return static_cast<gboolean>(
acc->AsTableBase()->IsCellSelected(aRowIdx, aColIdx));
}
if (RemoteAccessible* proxy = acc->AsRemote()) {
return static_cast<gboolean>(proxy->TableCellSelected(aRowIdx, aColIdx));
}

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

@ -6,40 +6,46 @@
#include "InterfaceInitFuncs.h"
#include "LocalAccessible-inl.h"
#include "AccessibleWrap.h"
#include "nsAccUtils.h"
#include "TableAccessible.h"
#include "TableCellAccessible.h"
#include "mozilla/a11y/TableAccessibleBase.h"
#include "mozilla/a11y/TableCellAccessibleBase.h"
#include "mozilla/StaticPrefs_accessibility.h"
#include "nsMai.h"
#include "RemoteAccessible.h"
#include "nsArrayUtils.h"
#include "mozilla/Likely.h"
using namespace mozilla;
using namespace mozilla::a11y;
extern "C" {
static gint GetColumnSpanCB(AtkTableCell* aCell) {
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell));
if (accWrap) {
return accWrap->AsTableCell()->ColExtent();
Accessible* acc = GetInternalObj(ATK_OBJECT(aCell));
if (!acc) {
return 0;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
return static_cast<gint>(acc->AsTableCellBase()->ColExtent());
}
if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
if (RemoteAccessible* proxy = acc->AsRemote()) {
return proxy->ColExtent();
}
return 0;
}
static gboolean GetRowSpanCB(AtkTableCell* aCell) {
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell));
if (accWrap) {
return accWrap->AsTableCell()->RowExtent();
static gint GetRowSpanCB(AtkTableCell* aCell) {
Accessible* acc = GetInternalObj(ATK_OBJECT(aCell));
if (!acc) {
return 0;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
return static_cast<gint>(acc->AsTableCellBase()->RowExtent());
}
if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
if (RemoteAccessible* proxy = acc->AsRemote()) {
return proxy->RowExtent();
}
@ -47,8 +53,12 @@ static gboolean GetRowSpanCB(AtkTableCell* aCell) {
}
static gboolean GetPositionCB(AtkTableCell* aCell, gint* aRow, gint* aCol) {
if (AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell))) {
TableCellAccessible* cell = accWrap->AsTableCell();
Accessible* acc = GetInternalObj(ATK_OBJECT(aCell));
if (!acc) {
return false;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
TableCellAccessibleBase* cell = acc->AsTableCellBase();
if (!cell) {
return false;
}
@ -57,7 +67,7 @@ static gboolean GetPositionCB(AtkTableCell* aCell, gint* aRow, gint* aCol) {
return true;
}
if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
if (RemoteAccessible* proxy = acc->AsRemote()) {
uint32_t rowIdx = 0, colIdx = 0;
proxy->GetPosition(&rowIdx, &colIdx);
*aCol = colIdx;
@ -70,8 +80,12 @@ static gboolean GetPositionCB(AtkTableCell* aCell, gint* aRow, gint* aCol) {
static gboolean GetColumnRowSpanCB(AtkTableCell* aCell, gint* aCol, gint* aRow,
gint* aColExtent, gint* aRowExtent) {
if (AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell))) {
TableCellAccessible* cellAcc = accWrap->AsTableCell();
Accessible* acc = GetInternalObj(ATK_OBJECT(aCell));
if (!acc) {
return false;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
TableCellAccessibleBase* cellAcc = acc->AsTableCellBase();
if (!cellAcc) {
return false;
}
@ -82,7 +96,7 @@ static gboolean GetColumnRowSpanCB(AtkTableCell* aCell, gint* aCol, gint* aRow,
return true;
}
if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
if (RemoteAccessible* proxy = acc->AsRemote()) {
uint32_t colIdx = 0, rowIdx = 0, colExtent = 0, rowExtent = 0;
proxy->GetColRowExtents(&colIdx, &rowIdx, &colExtent, &rowExtent);
*aCol = colIdx;
@ -96,15 +110,18 @@ static gboolean GetColumnRowSpanCB(AtkTableCell* aCell, gint* aCol, gint* aRow,
}
static AtkObject* GetTableCB(AtkTableCell* aTableCell) {
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTableCell));
if (accWrap) {
TableAccessible* table = accWrap->AsTableCell()->Table();
Accessible* acc = GetInternalObj(ATK_OBJECT(aTableCell));
if (!acc) {
return nullptr;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
TableAccessibleBase* table = acc->AsTableCellBase()->Table();
if (!table) {
return nullptr;
}
LocalAccessible* tableAcc = table->AsAccessible();
return tableAcc ? AccessibleWrap::GetAtkObject(tableAcc) : nullptr;
Accessible* tableAcc = table->AsAccessible();
return tableAcc ? GetWrapperFor(tableAcc) : nullptr;
}
if (RemoteAccessible* proxy = GetProxy(ATK_OBJECT(aTableCell))) {
@ -116,16 +133,20 @@ static AtkObject* GetTableCB(AtkTableCell* aTableCell) {
}
static GPtrArray* GetColumnHeaderCellsCB(AtkTableCell* aCell) {
if (AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell))) {
AutoTArray<LocalAccessible*, 10> headers;
accWrap->AsTableCell()->ColHeaderCells(&headers);
Accessible* acc = GetInternalObj(ATK_OBJECT(aCell));
if (!acc) {
return nullptr;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
AutoTArray<Accessible*, 10> headers;
acc->AsTableCellBase()->ColHeaderCells(&headers);
if (headers.IsEmpty()) {
return nullptr;
}
GPtrArray* atkHeaders = g_ptr_array_sized_new(headers.Length());
for (LocalAccessible* header : headers) {
AtkObject* atkHeader = AccessibleWrap::GetAtkObject(header);
for (Accessible* header : headers) {
AtkObject* atkHeader = AccessibleWrap::GetAtkObject(header->AsLocal());
g_object_ref(atkHeader);
g_ptr_array_add(atkHeaders, atkHeader);
}
@ -154,16 +175,20 @@ static GPtrArray* GetColumnHeaderCellsCB(AtkTableCell* aCell) {
}
static GPtrArray* GetRowHeaderCellsCB(AtkTableCell* aCell) {
if (AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell))) {
AutoTArray<LocalAccessible*, 10> headers;
accWrap->AsTableCell()->RowHeaderCells(&headers);
Accessible* acc = GetInternalObj(ATK_OBJECT(aCell));
if (!acc) {
return nullptr;
}
if (StaticPrefs::accessibility_cache_enabled_AtStartup() || acc->IsLocal()) {
AutoTArray<Accessible*, 10> headers;
acc->AsTableCellBase()->RowHeaderCells(&headers);
if (headers.IsEmpty()) {
return nullptr;
}
GPtrArray* atkHeaders = g_ptr_array_sized_new(headers.Length());
for (LocalAccessible* header : headers) {
AtkObject* atkHeader = AccessibleWrap::GetAtkObject(header);
for (Accessible* header : headers) {
AtkObject* atkHeader = AccessibleWrap::GetAtkObject(header->AsLocal());
g_object_ref(atkHeader);
g_ptr_array_add(atkHeaders, atkHeader);
}

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

@ -69,6 +69,13 @@ void AccAttributes::StringFromValueAndName(nsAtom* aAttrName,
},
[&aValueString](const UniquePtr<gfx::Matrix4x4>& val) {
aValueString.AppendPrintf("Matrix4x4=%s", ToString(*val).c_str());
},
[&aValueString](const nsTArray<uint64_t>& val) {
for (size_t i = 0; i < val.Length() - 1; i++) {
aValueString.AppendInt(val[i]);
aValueString.Append(u", ");
}
aValueString.AppendInt(val[val.Length() - 1]);
});
}
@ -165,6 +172,11 @@ void AccAttributes::CopyTo(AccAttributes* aDest) const {
[](const UniquePtr<gfx::Matrix4x4>& val) {
MOZ_ASSERT_UNREACHABLE(
"Trying to copy an AccAttributes containing a matrix");
},
[](const nsTArray<uint64_t>& val) {
// We don't copy arrays.
MOZ_ASSERT_UNREACHABLE(
"Trying to copy an AccAttributes containing an array");
});
}
}

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

@ -70,7 +70,7 @@ class AccAttributes {
Variant<bool, float, double, int32_t, RefPtr<nsAtom>, nsTArray<int32_t>,
CSSCoord, FontSize, Color, DeleteEntry, UniquePtr<nsString>,
RefPtr<AccAttributes>, uint64_t, UniquePtr<AccGroupInfo>,
UniquePtr<gfx::Matrix4x4>>;
UniquePtr<gfx::Matrix4x4>, nsTArray<uint64_t>>;
static_assert(sizeof(AttrValueType) <= 16);
using AtomVariantMap = nsTHashMap<nsRefPtrHashKey<nsAtom>, AttrValueType>;

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

@ -23,7 +23,7 @@ namespace a11y {
class AccIterable {
public:
virtual ~AccIterable() {}
virtual LocalAccessible* Next() = 0;
virtual Accessible* Next() = 0;
private:
friend class Relation;

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

@ -24,6 +24,7 @@ class CacheDomain {
static constexpr uint64_t Style = ((uint64_t)0x1) << 9;
static constexpr uint64_t TransformMatrix = ((uint64_t)0x1) << 10;
static constexpr uint64_t ScrollPosition = ((uint64_t)0x1) << 11;
static constexpr uint64_t Table = ((uint64_t)0x1) << 11;
static constexpr uint64_t All = ~((uint64_t)0x0);
};

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

@ -0,0 +1,474 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CachedTableAccessible.h"
#include "AccIterator.h"
#include "DocAccessibleParent.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/UniquePtr.h"
#include "nsAccUtils.h"
#include "nsIAccessiblePivot.h"
#include "Pivot.h"
#include "RemoteAccessible.h"
#include "TableAccessible.h"
#include "TableCellAccessible.h"
namespace mozilla::a11y {
// Used to search for table descendants relevant to table structure.
class TablePartRule : public PivotRule {
public:
virtual uint16_t Match(Accessible* aAcc) override {
role accRole = aAcc->Role();
if (accRole == roles::CAPTION || aAcc->IsTableCell()) {
return nsIAccessibleTraversalRule::FILTER_MATCH |
nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
}
if (aAcc->IsTableRow()) {
return nsIAccessibleTraversalRule::FILTER_MATCH;
}
if (aAcc->IsTable() ||
// Generic containers.
accRole == roles::TEXT || accRole == roles::TEXT_CONTAINER ||
accRole == roles::SECTION ||
// Row groups.
accRole == roles::GROUPING) {
// Walk inside these, but don't match them.
return nsIAccessibleTraversalRule::FILTER_IGNORE;
}
return nsIAccessibleTraversalRule::FILTER_IGNORE |
nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
}
};
// Iterates through headers explicitly associated with a remote table cell via
// the headers DOM attribute. These are cached as Accessible ids.
class RemoteExplicitHeadersIterator : public AccIterable {
public:
RemoteExplicitHeadersIterator(const nsTArray<uint64_t>& aHeaders,
Accessible* aDoc)
: mHeaders(aHeaders), mDoc(aDoc), mIndex(0) {}
virtual Accessible* Next() override {
while (mIndex < mHeaders.Length()) {
uint64_t id = mHeaders[mIndex++];
Accessible* acc = nsAccUtils::GetAccessibleByID(mDoc, id);
if (acc) {
return acc;
}
}
return nullptr;
}
private:
const nsTArray<uint64_t>& mHeaders;
Accessible* mDoc;
uint32_t mIndex;
};
// The Accessible* keys should only be used for lookup. They should not be
// dereferenced.
using CachedTablesMap = nsTHashMap<Accessible*, CachedTableAccessible>;
// We use a global map rather than a map in each document for three reasons:
// 1. We don't have a common base class for local and remote documents.
// 2. It avoids wasting memory in a document that doesn't have any tables.
// 3. It allows the cache management to be encapsulated here in
// CachedTableAccessible.
static StaticAutoPtr<CachedTablesMap> sCachedTables;
/* static */
CachedTableAccessible* CachedTableAccessible::GetFrom(Accessible* aAcc) {
if (!sCachedTables) {
sCachedTables = new CachedTablesMap();
ClearOnShutdown(&sCachedTables);
}
return &sCachedTables->LookupOrInsertWith(
aAcc, [&] { return CachedTableAccessible(aAcc); });
}
/* static */
void CachedTableAccessible::Invalidate(Accessible* aAcc) {
if (!sCachedTables) {
return;
}
Accessible* table = nullptr;
if (aAcc->IsTable()) {
table = aAcc;
} else if (aAcc->IsTableCell()) {
for (table = aAcc->Parent(); table; table = table->Parent()) {
if (table->IsTable()) {
break;
}
}
} else {
MOZ_ASSERT_UNREACHABLE("Should only be called on a table or a cell");
}
if (table) {
// Destroy the instance (if any). We'll create a new one the next time it
// is requested.
sCachedTables->Remove(table);
}
}
CachedTableAccessible::CachedTableAccessible(Accessible* aAcc) : mAcc(aAcc) {
MOZ_ASSERT(mAcc);
// Build the cache. The cache can only be built once per instance. When it's
// invalidated, we just throw away the instance and create a new one when
// the cache is next needed.
int32_t rowIdx = -1;
uint32_t colIdx = 0;
// Maps a column index to the cell index of its previous implicit column
// header.
nsTHashMap<uint32_t, uint32_t> prevColHeaders;
Pivot pivot(mAcc);
TablePartRule rule;
for (Accessible* part = pivot.Next(mAcc, rule); part;
part = pivot.Next(part, rule)) {
role partRole = part->Role();
if (partRole == roles::CAPTION) {
// If there are multiple captions, use the first.
if (!mCaptionAccID) {
mCaptionAccID = part->ID();
}
continue;
}
if (part->IsTableRow()) {
++rowIdx;
colIdx = 0;
// This might be an empty row, so ensure a row here, as our row count is
// based on the length of mRowColToCellIdx.
EnsureRow(rowIdx);
continue;
}
MOZ_ASSERT(part->IsTableCell());
if (rowIdx == -1) {
// We haven't created a row yet, so this cell must be outside a row.
continue;
}
// Check for a cell spanning multiple rows which already occupies this
// position. Keep incrementing until we find a vacant position.
for (;;) {
EnsureRowCol(rowIdx, colIdx);
if (mRowColToCellIdx[rowIdx][colIdx] == kNoCellIdx) {
// This position is not occupied.
break;
}
// This position is occupied.
++colIdx;
}
// Create the cell.
uint32_t cellIdx = mCells.Length();
auto prevColHeader = prevColHeaders.MaybeGet(colIdx);
auto cell = mCells.AppendElement(
CachedTableCellAccessible(part->ID(), part, rowIdx, colIdx,
prevColHeader ? *prevColHeader : kNoCellIdx));
mAccToCellIdx.InsertOrUpdate(part, cellIdx);
// Update our row/col map.
// This cell might span multiple rows and/or columns. In that case, we need
// to occupy multiple coordinates in the row/col map.
uint32_t lastRowForCell =
static_cast<uint32_t>(rowIdx) + cell->RowExtent() - 1;
MOZ_ASSERT(lastRowForCell >= static_cast<uint32_t>(rowIdx));
uint32_t lastColForCell = colIdx + cell->ColExtent() - 1;
MOZ_ASSERT(lastColForCell >= colIdx);
for (uint32_t spannedRow = static_cast<uint32_t>(rowIdx);
spannedRow <= lastRowForCell; ++spannedRow) {
for (uint32_t spannedCol = colIdx; spannedCol <= lastColForCell;
++spannedCol) {
EnsureRowCol(spannedRow, spannedCol);
MOZ_ASSERT(mRowColToCellIdx[spannedRow][spannedCol] == kNoCellIdx);
auto& rowCol = mRowColToCellIdx[spannedRow][spannedCol];
// If a cell already occupies this position, it overlaps with this one;
// e.g. r1..2c2 and r2c1..2. In that case, we want to prefer the first
// cell.
if (rowCol == kNoCellIdx) {
rowCol = cellIdx;
}
}
}
if (partRole == roles::COLUMNHEADER) {
for (uint32_t spannedCol = colIdx; spannedCol <= lastColForCell;
++spannedCol) {
prevColHeaders.InsertOrUpdate(spannedCol, cellIdx);
}
}
// Increment for the next cell.
colIdx = lastColForCell + 1;
}
}
void CachedTableAccessible::EnsureRow(uint32_t aRowIdx) {
for (uint32_t newRow = mRowColToCellIdx.Length(); newRow <= aRowIdx;
++newRow) {
// The next row doesn't exist yet. Create it.
mRowColToCellIdx.AppendElement();
}
MOZ_ASSERT(mRowColToCellIdx.Length() > aRowIdx);
}
void CachedTableAccessible::EnsureRowCol(uint32_t aRowIdx, uint32_t aColIdx) {
EnsureRow(aRowIdx);
auto& row = mRowColToCellIdx[aRowIdx];
for (uint32_t newCol = row.Length(); newCol <= aColIdx; ++newCol) {
// An entry doesn't yet exist for this column in this row.
row.AppendElement(kNoCellIdx);
}
MOZ_ASSERT(row.Length() > aColIdx);
if (mColCount <= aColIdx) {
++mColCount;
}
}
Accessible* CachedTableAccessible::Caption() const {
if (mCaptionAccID) {
Accessible* caption = nsAccUtils::GetAccessibleByID(
nsAccUtils::DocumentFor(mAcc), mCaptionAccID);
MOZ_ASSERT(caption, "Dead caption Accessible!");
MOZ_ASSERT(caption->Role() != roles::CAPTION, "Caption has wrong role");
return caption;
}
return nullptr;
}
void CachedTableAccessible::Summary(nsString& aSummary) {
if (Caption()) {
// If there's a caption, we map caption to Name and summary to Description.
mAcc->Description(aSummary);
} else {
// If there's no caption, we map summary to Name.
mAcc->Name(aSummary);
}
}
Accessible* CachedTableAccessible::CellAt(uint32_t aRowIdx, uint32_t aColIdx) {
int32_t cellIdx = CellIndexAt(aRowIdx, aColIdx);
if (cellIdx == -1) {
return nullptr;
}
return mCells[cellIdx].Acc(mAcc);
}
void CachedTableAccessible::SelectCol(uint32_t aColIdx) {
if (LocalAccessible* localAcc = mAcc->AsLocal()) {
TableAccessible* table = localAcc->AsTable();
table->SelectCol(aColIdx);
}
// XXX Implement support for RemoteAccessible.
}
void CachedTableAccessible::UnselectCol(uint32_t aColIdx) {
if (LocalAccessible* localAcc = mAcc->AsLocal()) {
TableAccessible* table = localAcc->AsTable();
table->UnselectCol(aColIdx);
}
// XXX Implement support for RemoteAccessible.
}
void CachedTableAccessible::SelectRow(uint32_t aRowIdx) {
if (LocalAccessible* localAcc = mAcc->AsLocal()) {
TableAccessible* table = localAcc->AsTable();
table->SelectRow(aRowIdx);
}
// XXX Implement support for RemoteAccessible.
}
void CachedTableAccessible::UnselectRow(uint32_t aRowIdx) {
if (LocalAccessible* localAcc = mAcc->AsLocal()) {
TableAccessible* table = localAcc->AsTable();
table->UnselectRow(aRowIdx);
}
// XXX Implement support for RemoteAccessible.
}
bool CachedTableAccessible::IsProbablyLayoutTable() {
if (RemoteAccessible* remoteAcc = mAcc->AsRemote()) {
return remoteAcc->TableIsProbablyForLayout();
}
TableAccessible* localTable = mAcc->AsLocal()->AsTable();
return localTable->IsProbablyLayoutTable();
}
/* static */
CachedTableCellAccessible* CachedTableCellAccessible::GetFrom(
Accessible* aAcc) {
MOZ_ASSERT(aAcc->IsTableCell());
for (Accessible* parent = aAcc; parent; parent = parent->Parent()) {
if (auto* table =
static_cast<CachedTableAccessible*>(parent->AsTableBase())) {
if (auto cellIdx = table->mAccToCellIdx.Lookup(aAcc)) {
return &table->mCells[*cellIdx];
}
}
}
return nullptr;
}
Accessible* CachedTableCellAccessible::Acc(Accessible* aTableAcc) const {
Accessible* acc =
nsAccUtils::GetAccessibleByID(nsAccUtils::DocumentFor(aTableAcc), mAccID);
MOZ_DIAGNOSTIC_ASSERT(acc == mAcc, "Cell's cached mAcc is dead!");
return acc;
}
TableAccessibleBase* CachedTableCellAccessible::Table() const {
for (const Accessible* acc = mAcc; acc; acc = acc->Parent()) {
// Since the caller has this cell, the table is already created, so it's
// okay to ignore the const restriction here.
if (TableAccessibleBase* table =
const_cast<Accessible*>(acc)->AsTableBase()) {
return table;
}
}
return nullptr;
}
uint32_t CachedTableCellAccessible::ColExtent() const {
if (RemoteAccessible* remoteAcc = mAcc->AsRemote()) {
if (remoteAcc->mCachedFields) {
if (auto colSpan = remoteAcc->mCachedFields->GetAttribute<int32_t>(
nsGkAtoms::colspan)) {
return *colSpan;
}
}
} else if (LocalAccessible* localAcc = mAcc->AsLocal()) {
// For HTML table cells, we must use the HTMLTableCellAccessible
// GetColExtent method rather than using the DOM attributes directly.
// This is because of things like rowspan="0" which depend on knowing
// about thead, tbody, etc., which is info we don't have in the a11y tree.
TableCellAccessible* cell = localAcc->AsTableCell();
MOZ_ASSERT(cell);
return cell->ColExtent();
}
return 1;
}
uint32_t CachedTableCellAccessible::RowExtent() const {
if (RemoteAccessible* remoteAcc = mAcc->AsRemote()) {
if (remoteAcc->mCachedFields) {
if (auto rowSpan = remoteAcc->mCachedFields->GetAttribute<int32_t>(
nsGkAtoms::rowspan)) {
return *rowSpan;
}
}
} else if (LocalAccessible* localAcc = mAcc->AsLocal()) {
// For HTML table cells, we must use the HTMLTableCellAccessible
// GetRowExtent method rather than using the DOM attributes directly.
// This is because of things like rowspan="0" which depend on knowing
// about thead, tbody, etc., which is info we don't have in the a11y tree.
TableCellAccessible* cell = localAcc->AsTableCell();
MOZ_ASSERT(cell);
return cell->RowExtent();
}
return 1;
}
UniquePtr<AccIterable> CachedTableCellAccessible::GetExplicitHeadersIterator() {
if (RemoteAccessible* remoteAcc = mAcc->AsRemote()) {
if (remoteAcc->mCachedFields) {
if (auto headers =
remoteAcc->mCachedFields->GetAttribute<nsTArray<uint64_t>>(
nsGkAtoms::headers)) {
return MakeUnique<RemoteExplicitHeadersIterator>(*headers,
remoteAcc->Document());
}
}
} else if (LocalAccessible* localAcc = mAcc->AsLocal()) {
return MakeUnique<IDRefsIterator>(
localAcc->Document(), localAcc->GetContent(), nsGkAtoms::headers);
}
return nullptr;
}
void CachedTableCellAccessible::ColHeaderCells(nsTArray<Accessible*>* aCells) {
auto* table = static_cast<CachedTableAccessible*>(Table());
if (!table) {
return;
}
if (auto iter = GetExplicitHeadersIterator()) {
while (Accessible* header = iter->Next()) {
role headerRole = header->Role();
if (headerRole == roles::COLUMNHEADER) {
aCells->AppendElement(header);
} else if (headerRole != roles::ROWHEADER) {
// Treat this cell as a column header only if it's in the same column.
if (auto cellIdx = table->mAccToCellIdx.Lookup(header)) {
CachedTableCellAccessible& cell = table->mCells[*cellIdx];
if (cell.ColIdx() == ColIdx()) {
aCells->AppendElement(header);
}
}
}
}
if (!aCells->IsEmpty()) {
return;
}
}
Accessible* doc = nsAccUtils::DocumentFor(table->AsAccessible());
// Each cell stores its previous implicit column header, effectively forming a
// linked list. We traverse that to get all the headers.
CachedTableCellAccessible* cell = this;
for (;;) {
if (cell->mPrevColHeaderCellIdx == kNoCellIdx) {
break; // No more headers.
}
cell = &table->mCells[cell->mPrevColHeaderCellIdx];
Accessible* cellAcc = nsAccUtils::GetAccessibleByID(doc, cell->mAccID);
aCells->AppendElement(cellAcc);
}
}
void CachedTableCellAccessible::RowHeaderCells(nsTArray<Accessible*>* aCells) {
auto* table = static_cast<CachedTableAccessible*>(Table());
if (!table) {
return;
}
if (auto iter = GetExplicitHeadersIterator()) {
while (Accessible* header = iter->Next()) {
role headerRole = header->Role();
if (headerRole == roles::ROWHEADER) {
aCells->AppendElement(header);
} else if (headerRole != roles::COLUMNHEADER) {
// Treat this cell as a row header only if it's in the same row.
if (auto cellIdx = table->mAccToCellIdx.Lookup(header)) {
CachedTableCellAccessible& cell = table->mCells[*cellIdx];
if (cell.RowIdx() == RowIdx()) {
aCells->AppendElement(header);
}
}
}
}
if (!aCells->IsEmpty()) {
return;
}
}
// We don't cache implicit row headers because there are usually not that many
// cells per row. Get all the row headers on the row before this cell.
uint32_t row = RowIdx();
uint32_t thisCol = ColIdx();
for (uint32_t col = thisCol - 1; col < thisCol; --col) {
Accessible* cellAcc = table->CellAt(row, col);
if (!cellAcc) {
continue;
}
TableCellAccessibleBase* cell = cellAcc->AsTableCellBase();
MOZ_ASSERT(cell);
// cell might span multiple columns. We don't want to visit it multiple
// times, so ensure col is set to cell's starting column.
col = cell->ColIdx();
if (cellAcc->Role() != roles::ROWHEADER) {
continue;
}
aCells->AppendElement(cellAcc);
}
}
bool CachedTableCellAccessible::Selected() {
return mAcc->State() & states::SELECTED;
}
} // namespace mozilla::a11y

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

@ -0,0 +1,299 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef CACHED_TABLE_ACCESSIBLE_H
#define CACHED_TABLE_ACCESSIBLE_H
#include "mozilla/a11y/TableAccessibleBase.h"
#include "mozilla/a11y/TableCellAccessibleBase.h"
#include "mozilla/UniquePtr.h"
#include "nsTHashMap.h"
namespace mozilla::a11y {
const uint32_t kNoCellIdx = UINT32_MAX;
class AccIterable;
class CachedTableAccessible;
class CachedTableCellAccessible final : public TableCellAccessibleBase {
public:
static CachedTableCellAccessible* GetFrom(Accessible* aAcc);
virtual TableAccessibleBase* Table() const override;
virtual uint32_t ColIdx() const override {
return static_cast<int32_t>(mColIdx);
}
virtual uint32_t RowIdx() const override {
return static_cast<int32_t>(mRowIdx);
}
virtual uint32_t ColExtent() const override;
virtual uint32_t RowExtent() const override;
virtual void ColHeaderCells(nsTArray<Accessible*>* aCells) override;
virtual void RowHeaderCells(nsTArray<Accessible*>* aCells) override;
virtual bool Selected() override;
private:
CachedTableCellAccessible(uint64_t aAccID, Accessible* aAcc, uint32_t aRowIdx,
uint32_t aColIdx, uint32_t aPrevColHeaderCellIdx)
: mAccID(aAccID),
mAcc(aAcc),
mRowIdx(aRowIdx),
mColIdx(aColIdx),
mPrevColHeaderCellIdx(aPrevColHeaderCellIdx) {}
// Get the Accessible for this table cell given its ancestor table Accessible,
// verifying that the Accessible is valid.
Accessible* Acc(Accessible* aTableAcc) const;
UniquePtr<AccIterable> GetExplicitHeadersIterator();
uint64_t mAccID;
// CachedTableAccessible methods which fetch a cell should retrieve the
// Accessible using Acc() rather than using mAcc. We need mAcc for some
// methods because we can't fetch a document by id. It's okay to use mAcc in
// these methods because the caller has to hold the Accessible in order to
// call them.
Accessible* mAcc;
uint32_t mRowIdx;
uint32_t mColIdx;
// The cell index of the previous implicit column header.
uint32_t mPrevColHeaderCellIdx;
friend class CachedTableAccessible;
};
/**
* TableAccessible implementation which builds and queries a cache.
*/
class CachedTableAccessible final : public TableAccessibleBase {
public:
static CachedTableAccessible* GetFrom(Accessible* aAcc);
/**
* This must be called whenever a table is destroyed or the structure of a
* table changes; e.g. cells wer added or removed. It can be called with
* either a table or a cell.
*/
static void Invalidate(Accessible* aAcc);
virtual Accessible* Caption() const override;
virtual void Summary(nsString& aSummary) override;
virtual uint32_t ColCount() const override { return mColCount; }
virtual uint32_t RowCount() override { return mRowColToCellIdx.Length(); }
virtual int32_t ColIndexAt(uint32_t aCellIdx) override {
if (aCellIdx < mCells.Length()) {
return static_cast<int32_t>(mCells[aCellIdx].mColIdx);
}
return -1;
}
virtual int32_t RowIndexAt(uint32_t aCellIdx) override {
if (aCellIdx < mCells.Length()) {
return static_cast<int32_t>(mCells[aCellIdx].mRowIdx);
}
return -1;
}
virtual void RowAndColIndicesAt(uint32_t aCellIdx, int32_t* aRowIdx,
int32_t* aColIdx) override {
if (aCellIdx < mCells.Length()) {
CachedTableCellAccessible& cell = mCells[aCellIdx];
*aRowIdx = static_cast<int32_t>(cell.mRowIdx);
*aColIdx = static_cast<int32_t>(cell.mColIdx);
return;
}
*aRowIdx = -1;
*aColIdx = -1;
}
virtual uint32_t ColExtentAt(uint32_t aRowIdx, uint32_t aColIdx) override {
int32_t cellIdx = CellIndexAt(aRowIdx, aColIdx);
if (cellIdx == -1) {
return 0;
}
// Verify that the cell's Accessible is valid.
mCells[cellIdx].Acc(mAcc);
return mCells[cellIdx].ColExtent();
}
virtual uint32_t RowExtentAt(uint32_t aRowIdx, uint32_t aColIdx) override {
int32_t cellIdx = CellIndexAt(aRowIdx, aColIdx);
if (cellIdx == -1) {
return 0;
}
// Verify that the cell's Accessible is valid.
mCells[cellIdx].Acc(mAcc);
return mCells[cellIdx].RowExtent();
}
virtual int32_t CellIndexAt(uint32_t aRowIdx, uint32_t aColIdx) override {
if (aRowIdx < mRowColToCellIdx.Length()) {
auto& row = mRowColToCellIdx[aRowIdx];
if (aColIdx < row.Length()) {
uint32_t cellIdx = row[aColIdx];
if (cellIdx != kNoCellIdx) {
return static_cast<int32_t>(cellIdx);
}
}
}
return -1;
}
virtual Accessible* CellAt(uint32_t aRowIdx, uint32_t aColIdx) override;
virtual bool IsColSelected(uint32_t aColIdx) override {
bool selected = false;
for (uint32_t row = 0; row < RowCount(); ++row) {
selected = IsCellSelected(row, aColIdx);
if (!selected) {
break;
}
}
return selected;
}
virtual bool IsRowSelected(uint32_t aRowIdx) override {
bool selected = false;
for (uint32_t col = 0; col < mColCount; ++col) {
selected = IsCellSelected(aRowIdx, col);
if (!selected) {
break;
}
}
return selected;
}
virtual bool IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx) override {
int32_t cellIdx = CellIndexAt(aRowIdx, aColIdx);
if (cellIdx == -1) {
return false;
}
// Verify that the cell's Accessible is valid.
mCells[cellIdx].Acc(mAcc);
return mCells[cellIdx].Selected();
}
virtual uint32_t SelectedCellCount() override {
uint32_t count = 0;
for (auto& cell : mCells) {
// Verify that the cell's Accessible is valid.
cell.Acc(mAcc);
if (cell.Selected()) {
++count;
}
}
return count;
}
virtual uint32_t SelectedColCount() override {
uint32_t count = 0;
for (uint32_t col = 0; col < mColCount; ++col) {
if (IsColSelected(col)) {
++count;
}
}
return count;
}
virtual uint32_t SelectedRowCount() override {
uint32_t count = 0;
for (uint32_t row = 0; row < RowCount(); ++row) {
if (IsRowSelected(row)) {
++count;
}
}
return count;
}
virtual void SelectedCells(nsTArray<Accessible*>* aCells) override {
for (auto& cell : mCells) {
// Verify that the cell's Accessible is valid.
Accessible* acc = cell.Acc(mAcc);
if (cell.Selected()) {
aCells->AppendElement(acc);
}
}
}
virtual void SelectedCellIndices(nsTArray<uint32_t>* aCells) override {
for (uint32_t idx = 0; idx < mCells.Length(); ++idx) {
CachedTableCellAccessible& cell = mCells[idx];
// Verify that the cell's Accessible is valid.
cell.Acc(mAcc);
if (cell.Selected()) {
aCells->AppendElement(idx);
}
}
}
virtual void SelectedColIndices(nsTArray<uint32_t>* aCols) override {
for (uint32_t col = 0; col < mColCount; ++col) {
if (IsColSelected(col)) {
aCols->AppendElement(col);
}
}
}
virtual void SelectedRowIndices(nsTArray<uint32_t>* aRows) override {
for (uint32_t row = 0; row < RowCount(); ++row) {
if (IsRowSelected(row)) {
aRows->AppendElement(row);
}
}
}
virtual void SelectCol(uint32_t aColIdx) override;
virtual void SelectRow(uint32_t aRowIdx) override;
virtual void UnselectCol(uint32_t aColIdx) override;
virtual void UnselectRow(uint32_t aRowIdx) override;
virtual Accessible* AsAccessible() override { return mAcc; }
virtual bool IsProbablyLayoutTable() override;
private:
explicit CachedTableAccessible(Accessible* aAcc);
// Ensure that the given row exists in our data structure, creating array
// elements as needed.
void EnsureRow(uint32_t aRowIdx);
// Ensure that the given row and column coordinate exists in our data
// structure, creating array elements as needed. A newly created coordinate
// will be set to kNoCellIdx.
void EnsureRowCol(uint32_t aRowIdx, uint32_t aColIdx);
Accessible* mAcc; // The table Accessible.
// We track the column count because it might not be uniform across rows in
// malformed tables.
uint32_t mColCount = 0;
// An array of cell instances. A cell index is an index into this array.
nsTArray<CachedTableCellAccessible> mCells;
// Maps row and column coordinates to cell indices.
nsTArray<nsTArray<uint32_t>> mRowColToCellIdx;
// Maps Accessibles to cell indexes to facilitate retrieval of a cell
// instance from a cell Accessible. The Accessible* keys should only be used
// for lookup. They should not be dereferenced.
nsTHashMap<Accessible*, uint32_t> mAccToCellIdx;
uint64_t mCaptionAccID = 0;
friend class CachedTableCellAccessible;
};
} // namespace mozilla::a11y
#endif

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

@ -75,7 +75,7 @@ class Relation {
* compute and return the next related accessible.
*/
inline LocalAccessible* Next() {
LocalAccessible* target = nullptr;
Accessible* target = nullptr;
while (mFirstIter && !(target = mFirstIter->Next())) {
mFirstIter = std::move(mFirstIter->mNextIter);
@ -83,7 +83,7 @@ class Relation {
if (!mFirstIter) mLastIter = nullptr;
return target;
return target ? target->AsLocal() : nullptr;
}
private:

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

@ -90,19 +90,6 @@ class LeafRule : public PivotRule {
}
};
/**
* Get the document Accessible which owns a given Accessible.
* This function is needed because there is no unified base class for local and
* remote documents and thus there is no unified way to retrieve the document
* from an Accessible.
*/
static Accessible* DocumentFor(Accessible* aAcc) {
if (LocalAccessible* localAcc = aAcc->AsLocal()) {
return localAcc->Document();
}
return aAcc->AsRemote()->Document();
}
static HyperTextAccessible* HyperTextFor(LocalAccessible* aAcc) {
for (LocalAccessible* acc = aAcc; acc; acc = acc->LocalParent()) {
if (HyperTextAccessible* ht = acc->AsHyperText()) {
@ -113,14 +100,16 @@ static HyperTextAccessible* HyperTextFor(LocalAccessible* aAcc) {
}
static Accessible* NextLeaf(Accessible* aOrigin) {
Accessible* doc = DocumentFor(aOrigin);
MOZ_ASSERT(aOrigin);
Accessible* doc = nsAccUtils::DocumentFor(aOrigin);
Pivot pivot(doc);
auto rule = LeafRule();
return pivot.Next(aOrigin, rule);
}
static Accessible* PrevLeaf(Accessible* aOrigin) {
Accessible* doc = DocumentFor(aOrigin);
MOZ_ASSERT(aOrigin);
Accessible* doc = nsAccUtils::DocumentFor(aOrigin);
Pivot pivot(doc);
auto rule = LeafRule();
return pivot.Prev(aOrigin, rule);
@ -957,7 +946,7 @@ TextLeafPoint TextLeafPoint::FindParagraphSameAcc(nsDirection aDirection,
}
Accessible* prevLeaf = PrevLeaf(mAcc);
BlockRule blockRule;
Pivot pivot(DocumentFor(mAcc));
Pivot pivot(nsAccUtils::DocumentFor(mAcc));
Accessible* prevBlock = pivot.Prev(mAcc, blockRule);
// Check if we're the first leaf after a block element.
if (prevBlock &&

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

@ -34,6 +34,7 @@ UNIFIED_SOURCES += [
"ARIAMap.cpp",
"ARIAStateMap.cpp",
"Asserts.cpp",
"CachedTableAccessible.cpp",
"DocManager.cpp",
"EmbeddedObjCollector.cpp",
"EventQueue.cpp",

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

@ -11,6 +11,7 @@
#include "nsAccessibilityService.h"
#include "nsCoreUtils.h"
#include "DocAccessible.h"
#include "DocAccessibleParent.h"
#include "HyperTextAccessible.h"
#include "nsIAccessibleTypes.h"
#include "Role.h"
@ -452,3 +453,28 @@ bool nsAccUtils::IsARIALive(const LocalAccessible* aAccessible) {
return false;
}
Accessible* nsAccUtils::DocumentFor(Accessible* aAcc) {
if (!aAcc) {
return nullptr;
}
if (LocalAccessible* localAcc = aAcc->AsLocal()) {
return localAcc->Document();
}
return aAcc->AsRemote()->Document();
}
Accessible* nsAccUtils::GetAccessibleByID(Accessible* aDoc, uint64_t aID) {
if (!aDoc) {
return nullptr;
}
if (LocalAccessible* localAcc = aDoc->AsLocal()) {
if (DocAccessible* doc = localAcc->AsDoc()) {
return doc->GetAccessibleByUniqueID(
reinterpret_cast<void*>(static_cast<uintptr_t>(aID)));
}
} else if (DocAccessibleParent* doc = aDoc->AsRemote()->AsDoc()) {
return doc->GetAccessible(aID);
}
return nullptr;
}

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

@ -225,6 +225,23 @@ class nsAccUtils {
* the container-live attribute would be something other than "off" or empty.
*/
static bool IsARIALive(const LocalAccessible* aAccessible);
/**
* Get the document Accessible which owns a given Accessible.
* This function is needed because there is no unified base class for local
* and remote documents.
* If aAcc is null, null will be returned.
*/
static Accessible* DocumentFor(Accessible* aAcc);
/**
* Get an Accessible in a given document by its unique id.
* An Accessible's id can be obtained using Accessible::ID.
* This function is needed because there is no unified base class for local
* and remote documents.
* If aDoc is nul, null will be returned.
*/
static Accessible* GetAccessibleByID(Accessible* aDoc, uint64_t aID);
};
} // namespace a11y

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

@ -24,6 +24,8 @@ class AccGroupInfo;
class HyperTextAccessibleBase;
class LocalAccessible;
class RemoteAccessible;
class TableAccessibleBase;
class TableCellAccessibleBase;
/**
* Name type flags.
@ -74,6 +76,13 @@ class Accessible {
uint8_t aRoleMapEntryIndex);
public:
/**
* Return an id for this Accessible which is unique within the document.
* Use nsAccUtils::GetAccessibleByID to retrieve an Accessible given an id
* returned from this method.
*/
virtual uint64_t ID() const = 0;
virtual Accessible* Parent() const = 0;
virtual role Role() const = 0;
@ -425,6 +434,9 @@ class Accessible {
virtual HyperTextAccessibleBase* AsHyperTextBase() { return nullptr; }
virtual TableAccessibleBase* AsTableBase() { return nullptr; }
virtual TableCellAccessibleBase* AsTableCellBase() { return nullptr; }
/**
* Return the localized string for the given key.
*/

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

@ -0,0 +1,192 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef TABLE_ACCESSIBLE_BASE_H
#define TABLE_ACCESSIBLE_BASE_H
#include "nsString.h"
#include "nsTArray.h"
namespace mozilla {
namespace a11y {
class Accessible;
/**
* Accessible table interface.
*/
class TableAccessibleBase {
public:
/**
* Return the caption accessible if any for this table.
*/
virtual Accessible* Caption() const { return nullptr; }
/**
* Get the summary for this table.
*/
virtual void Summary(nsString& aSummary) { aSummary.Truncate(); }
/**
* Return the number of columns in the table.
*/
virtual uint32_t ColCount() const { return 0; }
/**
* Return the number of rows in the table.
*/
virtual uint32_t RowCount() { return 0; }
/**
* Return the accessible for the cell at the given row and column indices.
*/
virtual Accessible* CellAt(uint32_t aRowIdx, uint32_t aColIdx) {
return nullptr;
}
/**
* Return the index of the cell at the given row and column.
*/
virtual int32_t CellIndexAt(uint32_t aRowIdx, uint32_t aColIdx) { return -1; }
/**
* Return the column index of the cell with the given index.
* This returns -1 if the column count is 0 or an invalid index is being
* passed in.
*/
virtual int32_t ColIndexAt(uint32_t aCellIdx) { return -1; }
/**
* Return the row index of the cell with the given index.
* This returns -1 if the column count is 0 or an invalid index is being
* passed in.
*/
virtual int32_t RowIndexAt(uint32_t aCellIdx) { return -1; }
/**
* Get the row and column indices for the cell at the given index.
* This returns -1 for both output parameters if the column count is 0 or an
* invalid index is being passed in.
*/
virtual void RowAndColIndicesAt(uint32_t aCellIdx, int32_t* aRowIdx,
int32_t* aColIdx) {
*aRowIdx = -1;
*aColIdx = -1;
}
/**
* Return the number of columns occupied by the cell at the given row and
* column indices.
*/
virtual uint32_t ColExtentAt(uint32_t aRowIdx, uint32_t aColIdx) { return 1; }
/**
* Return the number of rows occupied by the cell at the given row and column
* indices.
*/
virtual uint32_t RowExtentAt(uint32_t aRowIdx, uint32_t aColIdx) { return 1; }
/**
* Get the description of the given column.
*/
virtual void ColDescription(uint32_t aColIdx, nsString& aDescription) {
aDescription.Truncate();
}
/**
* Get the description for the given row.
*/
virtual void RowDescription(uint32_t aRowIdx, nsString& aDescription) {
aDescription.Truncate();
}
/**
* Return true if the given column is selected.
*/
virtual bool IsColSelected(uint32_t aColIdx) { return false; }
/**
* Return true if the given row is selected.
*/
virtual bool IsRowSelected(uint32_t aRowIdx) { return false; }
/**
* Return true if the given cell is selected.
*/
virtual bool IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx) {
return false;
}
/**
* Return the number of selected cells.
*/
virtual uint32_t SelectedCellCount() { return 0; }
/**
* Return the number of selected columns.
*/
virtual uint32_t SelectedColCount() { return 0; }
/**
* Return the number of selected rows.
*/
virtual uint32_t SelectedRowCount() { return 0; }
/**
* Get the set of selected cells.
*/
virtual void SelectedCells(nsTArray<Accessible*>* aCells) {}
/**
* Get the set of selected cell indices.
*/
virtual void SelectedCellIndices(nsTArray<uint32_t>* aCells) {}
/**
* Get the set of selected column indices.
*/
virtual void SelectedColIndices(nsTArray<uint32_t>* aCols) {}
/**
* Get the set of selected row indices.
*/
virtual void SelectedRowIndices(nsTArray<uint32_t>* aRows) {}
/**
* Select the given column unselecting any other selected columns.
*/
virtual void SelectCol(uint32_t aColIdx) {}
/**
* Select the given row unselecting all other previously selected rows.
*/
virtual void SelectRow(uint32_t aRowIdx) {}
/**
* Unselect the given column leaving other selected columns selected.
*/
virtual void UnselectCol(uint32_t aColIdx) {}
/**
* Unselect the given row leaving other selected rows selected.
*/
virtual void UnselectRow(uint32_t aRowIdx) {}
/**
* Return true if the table is probably for layout.
*/
virtual bool IsProbablyLayoutTable() { return false; }
/**
* Convert the table to an Accessible*.
*/
virtual Accessible* AsAccessible() = 0;
};
} // namespace a11y
} // namespace mozilla
#endif

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

@ -0,0 +1,68 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_a11y_TableCellAccessibleBase_h__
#define mozilla_a11y_TableCellAccessibleBase_h__
#include "nsTArray.h"
#include <stdint.h>
namespace mozilla {
namespace a11y {
class Accessible;
class TableAccessibleBase;
/**
* Abstract interface implemented by table cell accessibles.
*/
class TableCellAccessibleBase {
public:
/**
* Return the table this cell is in.
*/
virtual TableAccessibleBase* Table() const = 0;
/**
* Return the column of the table this cell is in.
*/
virtual uint32_t ColIdx() const = 0;
/**
* Return the row of the table this cell is in.
*/
virtual uint32_t RowIdx() const = 0;
/**
* Return the column extent of this cell.
*/
virtual uint32_t ColExtent() const { return 1; }
/**
* Return the row extent of this cell.
*/
virtual uint32_t RowExtent() const { return 1; }
/**
* Return the column header cells for this cell.
*/
virtual void ColHeaderCells(nsTArray<Accessible*>* aCells) = 0;
/**
* Return the row header cells for this cell.
*/
virtual void RowHeaderCells(nsTArray<Accessible*>* aCells) = 0;
/**
* Returns true if this cell is selected.
*/
virtual bool Selected() = 0;
};
} // namespace a11y
} // namespace mozilla
#endif // mozilla_a11y_TableCellAccessibleBase_h__

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

@ -7,6 +7,8 @@
EXPORTS.mozilla.a11y += [
"Accessible.h",
"HyperTextAccessibleBase.h",
"TableAccessibleBase.h",
"TableCellAccessibleBase.h",
]
UNIFIED_SOURCES += [

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

@ -219,7 +219,7 @@ uint32_t ARIAGridAccessible::SelectedRowCount() {
return count;
}
void ARIAGridAccessible::SelectedCells(nsTArray<LocalAccessible*>* aCells) {
void ARIAGridAccessible::SelectedCells(nsTArray<Accessible*>* aCells) {
if (IsARIARole(nsGkAtoms::table)) return;
AccIterator rowIter(this, filters::GetRow);

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

@ -40,7 +40,7 @@ class ARIAGridAccessible : public HyperTextAccessibleWrap,
virtual uint32_t SelectedCellCount() override;
virtual uint32_t SelectedColCount() override;
virtual uint32_t SelectedRowCount() override;
virtual void SelectedCells(nsTArray<LocalAccessible*>* aCells) override;
virtual void SelectedCells(nsTArray<Accessible*>* aCells) override;
virtual void SelectedCellIndices(nsTArray<uint32_t>* aCells) override;
virtual void SelectedColIndices(nsTArray<uint32_t>* aCols) override;
virtual void SelectedRowIndices(nsTArray<uint32_t>* aRows) override;

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

@ -7,6 +7,7 @@
#include "LocalAccessible-inl.h"
#include "AccIterator.h"
#include "AccAttributes.h"
#include "CachedTableAccessible.h"
#include "DocAccessible-inl.h"
#include "DocAccessibleChild.h"
#include "HTMLImageMapAccessible.h"
@ -1323,6 +1324,19 @@ bool DocAccessible::PruneOrInsertSubtree(nsIContent* aRoot) {
// cache, which listens for the following event.
if (acc->IsTable() || acc->IsTableRow() || acc->IsTableCell()) {
FireDelayedEvent(nsIAccessibleEvent::EVENT_TABLE_STYLING_CHANGED, acc);
LocalAccessible* table;
if (acc->IsTable()) {
table = acc;
} else {
for (table = acc->LocalParent(); table; table = table->LocalParent()) {
if (table->IsTable()) {
break;
}
}
}
if (table && table->IsTable()) {
QueueCacheUpdate(acc, CacheDomain::Table);
}
}
// The accessible can be reparented or reordered in its parent.
@ -2083,8 +2097,8 @@ void DocAccessible::ContentRemoved(LocalAccessible* aChild) {
}
}
MOZ_DIAGNOSTIC_ASSERT(aChild->LocalParent(), "Unparented #2");
parent->RemoveChild(aChild);
UncacheChildrenInSubtree(aChild);
parent->RemoveChild(aChild);
mt.Done();
}
@ -2481,6 +2495,14 @@ void DocAccessible::UncacheChildrenInSubtree(LocalAccessible* aRoot) {
aRoot->mStateFlags |= eIsNotInDocument;
RemoveDependentIDsFor(aRoot);
// The parent of the removed subtree is about to be cleared, so we must do
// this here rather than in LocalAccessible::UnbindFromParent because we need
// the ancestry for this to work.
if (StaticPrefs::accessibility_cache_enabled_AtStartup() &&
(aRoot->IsTable() || aRoot->IsTableCell())) {
CachedTableAccessible::Invalidate(aRoot);
}
nsTArray<RefPtr<LocalAccessible>>* owned = mARIAOwnsHash.Get(aRoot);
uint32_t count = aRoot->ContentChildCount();
for (uint32_t idx = 0; idx < count; idx++) {

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

@ -10,6 +10,7 @@
#include "AccGroupInfo.h"
#include "AccIterator.h"
#include "CacheConstants.h"
#include "CachedTableAccessible.h"
#include "DocAccessible-inl.h"
#include "nsAccUtils.h"
#include "nsAccessibilityService.h"
@ -2498,18 +2499,28 @@ void LocalAccessible::BindToParent(LocalAccessible* aParent,
static_cast<uint32_t>((mParent->IsAlert() || mParent->IsInsideAlert())) &
eInsideAlert;
// if a new column header is being added, invalidate the table's header cache.
TableCellAccessible* cell = AsTableCell();
if (cell && Role() == roles::COLUMNHEADER) {
TableAccessible* table = cell->Table();
if (table) {
table->GetHeaderCache().Clear();
if (TableCellAccessible* cell = AsTableCell()) {
if (StaticPrefs::accessibility_cache_enabled_AtStartup()) {
CachedTableAccessible::Invalidate(this);
} else if (Role() == roles::COLUMNHEADER) {
// A new column header is being added. Invalidate the table's header
// cache.
TableAccessible* table = cell->Table();
if (table) {
table->GetHeaderCache().Clear();
}
}
}
}
// LocalAccessible protected
void LocalAccessible::UnbindFromParent() {
// Usually, when a subtree is removed, we do this in
// DocAccessible::UncacheChildrenInSubtree. However, that won't get called
// when the document is shut down, so we handle that here.
if (StaticPrefs::accessibility_cache_enabled_AtStartup() && IsTable()) {
CachedTableAccessible::Invalidate(this);
}
mParent = nullptr;
mIndexInParent = -1;
mIndexOfEmbeddedChild = -1;
@ -3337,6 +3348,47 @@ already_AddRefed<AccAttributes> LocalAccessible::BundleFieldsForCache(
}
}
if (aCacheDomain & CacheDomain::Table) {
if (IsTable()) {
TableAccessible* table = AsTable();
if (table->IsProbablyLayoutTable()) {
fields->SetAttribute(nsGkAtoms::layout_guess, true);
} else if (aUpdateType == CacheUpdateType::Update) {
fields->SetAttribute(nsGkAtoms::layout_guess, DeleteEntry());
}
} else if (TableCellAccessible* cell = AsTableCell()) {
// For HTML table cells, we must use the HTMLTableCellAccessible
// GetRow/ColExtent methods rather than using the DOM attributes directly.
// This is because of things like rowspan="0" which depend on knowing
// about thead, tbody, etc., which is info we don't have in the a11y tree.
int32_t value = static_cast<int32_t>(cell->RowExtent());
if (value != 1) {
fields->SetAttribute(nsGkAtoms::rowspan, value);
} else if (aUpdateType == CacheUpdateType::Update) {
fields->SetAttribute(nsGkAtoms::rowspan, DeleteEntry());
}
value = static_cast<int32_t>(cell->ColExtent());
if (value != 1) {
fields->SetAttribute(nsGkAtoms::colspan, value);
} else if (aUpdateType == CacheUpdateType::Update) {
fields->SetAttribute(nsGkAtoms::colspan, DeleteEntry());
}
if (mContent->AsElement()->HasAttr(kNameSpaceID_None,
nsGkAtoms::headers)) {
nsTArray<uint64_t> headers;
IDRefsIterator iter(mDoc, mContent, nsGkAtoms::headers);
while (LocalAccessible* cell = iter.Next()) {
if (cell->IsTableCell()) {
headers.AppendElement(cell->ID());
}
}
fields->SetAttribute(nsGkAtoms::headers, std::move(headers));
} else {
fields->SetAttribute(nsGkAtoms::headers, DeleteEntry());
}
}
}
if (aUpdateType == CacheUpdateType::Initial) {
// Add fields which never change and thus only need to be included in the
// initial cache push.
@ -3552,3 +3604,25 @@ void KeyBinding::ToAtkFormat(nsAString& aValue) const {
aValue.Append(mKey);
}
TableAccessibleBase* LocalAccessible::AsTableBase() {
if (StaticPrefs::accessibility_cache_enabled_AtStartup() && IsTable() &&
!mContent->IsXULElement()) {
// This isn't strictly related to caching, but this new table implementation
// is being developed to make caching feasible. We put it behind this pref
// to make it easy to test while it's still under development.
return CachedTableAccessible::GetFrom(this);
}
return AsTable();
}
TableCellAccessibleBase* LocalAccessible::AsTableCellBase() {
if (StaticPrefs::accessibility_cache_enabled_AtStartup() && IsTableCell() &&
!mContent->IsXULElement()) {
// This isn't strictly related to caching, but this new table implementation
// is being developed to make caching feasible. We put it behind this pref
// to make it easy to test while it's still under development.
return CachedTableCellAccessible::GetFrom(this);
}
return AsTableCell();
}

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

@ -53,7 +53,9 @@ class RemoteAccessible;
class Relation;
class RootAccessible;
class TableAccessible;
class TableAccessibleBase;
class TableCellAccessible;
class TableCellAccessibleBase;
class TextLeafAccessible;
class XULLabelAccessible;
class XULTreeAccessible;
@ -124,9 +126,15 @@ class LocalAccessible : public nsISupports, public Accessible {
/**
* Return the unique identifier of the accessible.
* ID() should be preferred, but this method still exists because many
* LocalAccessible callers expect a void*.
*/
void* UniqueID() { return static_cast<void*>(this); }
virtual uint64_t ID() const override {
return reinterpret_cast<uintptr_t>(this);
}
/**
* Return language associated with the accessible.
*/
@ -494,6 +502,9 @@ class LocalAccessible : public nsISupports, public Accessible {
return const_cast<LocalAccessible*>(this)->AsTableCell();
}
virtual TableAccessibleBase* AsTableBase() override;
virtual TableCellAccessibleBase* AsTableCellBase() override;
TextLeafAccessible* AsTextLeaf();
XULLabelAccessible* AsXULLabel();

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

@ -7,189 +7,40 @@
#ifndef TABLE_ACCESSIBLE_H
#define TABLE_ACCESSIBLE_H
#include "TableCellAccessible.h"
#include "LocalAccessible.h"
#include "mozilla/a11y/TableAccessibleBase.h"
#include "mozilla/a11y/TableCellAccessibleBase.h"
#include "nsPointerHashKeys.h"
#include "nsRefPtrHashtable.h"
#include "nsString.h"
#include "nsTArray.h"
namespace mozilla {
namespace a11y {
class LocalAccessible;
/**
* Accessible table interface.
* Base class for LocalAccessible table implementations.
*/
class TableAccessible {
class TableAccessible : public TableAccessibleBase {
public:
/**
* Return the caption accessible if any for this table.
*/
virtual LocalAccessible* Caption() const { return nullptr; }
virtual LocalAccessible* Caption() const override { return nullptr; }
/**
* Get the summary for this table.
*/
virtual void Summary(nsString& aSummary) { aSummary.Truncate(); }
/**
* Return the number of columns in the table.
*/
virtual uint32_t ColCount() const { return 0; }
/**
* Return the number of rows in the table.
*/
virtual uint32_t RowCount() { return 0; }
/**
* Return the accessible for the cell at the given row and column indices.
*/
virtual LocalAccessible* CellAt(uint32_t aRowIdx, uint32_t aColIdx) {
virtual LocalAccessible* CellAt(uint32_t aRowIdx, uint32_t aColIdx) override {
return nullptr;
}
/**
* Return the index of the cell at the given row and column.
*/
virtual int32_t CellIndexAt(uint32_t aRowIdx, uint32_t aColIdx) {
virtual int32_t CellIndexAt(uint32_t aRowIdx, uint32_t aColIdx) override {
return ColCount() * aRowIdx + aColIdx;
}
/**
* Return the column index of the cell with the given index.
* This returns -1 if the column count is 0 or an invalid index is being
* passed in.
*/
virtual int32_t ColIndexAt(uint32_t aCellIdx);
/**
* Return the row index of the cell with the given index.
* This returns -1 if the column count is 0 or an invalid index is being
* passed in.
*/
virtual int32_t RowIndexAt(uint32_t aCellIdx);
/**
* Get the row and column indices for the cell at the given index.
* This returns -1 for both output parameters if the column count is 0 or an
* invalid index is being passed in.
*/
virtual int32_t ColIndexAt(uint32_t aCellIdx) override;
virtual int32_t RowIndexAt(uint32_t aCellIdx) override;
virtual void RowAndColIndicesAt(uint32_t aCellIdx, int32_t* aRowIdx,
int32_t* aColIdx);
int32_t* aColIdx) override;
virtual bool IsProbablyLayoutTable() override;
virtual LocalAccessible* AsAccessible() override = 0;
/**
* Return the number of columns occupied by the cell at the given row and
* column indices.
*/
virtual uint32_t ColExtentAt(uint32_t aRowIdx, uint32_t aColIdx) { return 1; }
/**
* Return the number of rows occupied by the cell at the given row and column
* indices.
*/
virtual uint32_t RowExtentAt(uint32_t aRowIdx, uint32_t aColIdx) { return 1; }
/**
* Get the description of the given column.
*/
virtual void ColDescription(uint32_t aColIdx, nsString& aDescription) {
aDescription.Truncate();
}
/**
* Get the description for the given row.
*/
virtual void RowDescription(uint32_t aRowIdx, nsString& aDescription) {
aDescription.Truncate();
}
/**
* Return true if the given column is selected.
*/
virtual bool IsColSelected(uint32_t aColIdx) { return false; }
/**
* Return true if the given row is selected.
*/
virtual bool IsRowSelected(uint32_t aRowIdx) { return false; }
/**
* Return true if the given cell is selected.
*/
virtual bool IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx) {
return false;
}
/**
* Return the number of selected cells.
*/
virtual uint32_t SelectedCellCount() { return 0; }
/**
* Return the number of selected columns.
*/
virtual uint32_t SelectedColCount() { return 0; }
/**
* Return the number of selected rows.
*/
virtual uint32_t SelectedRowCount() { return 0; }
/**
* Get the set of selected cells.
*/
virtual void SelectedCells(nsTArray<LocalAccessible*>* aCells) = 0;
/**
* Get the set of selected cell indices.
*/
virtual void SelectedCellIndices(nsTArray<uint32_t>* aCells) = 0;
/**
* Get the set of selected column indices.
*/
virtual void SelectedColIndices(nsTArray<uint32_t>* aCols) = 0;
/**
* Get the set of selected row indices.
*/
virtual void SelectedRowIndices(nsTArray<uint32_t>* aRows) = 0;
/**
* Select the given column unselecting any other selected columns.
*/
virtual void SelectCol(uint32_t aColIdx) {}
/**
* Select the given row unselecting all other previously selected rows.
*/
virtual void SelectRow(uint32_t aRowIdx) {}
/**
* Unselect the given column leaving other selected columns selected.
*/
virtual void UnselectCol(uint32_t aColIdx) {}
/**
* Unselect the given row leaving other selected rows selected.
*/
virtual void UnselectRow(uint32_t aRowIdx) {}
/**
* Return true if the table is probably for layout.
*/
virtual bool IsProbablyLayoutTable();
/**
* Convert the table to an Accessible*.
*/
virtual LocalAccessible* AsAccessible() = 0;
typedef nsRefPtrHashtable<nsPtrHashKey<const TableCellAccessible>,
LocalAccessible>
HeaderCache;
using HeaderCache =
nsRefPtrHashtable<nsPtrHashKey<const TableCellAccessibleBase>,
LocalAccessible>;
/**
* Get the header cache, which maps a TableCellAccessible to its previous

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

@ -12,7 +12,7 @@
using namespace mozilla;
using namespace mozilla::a11y;
void TableCellAccessible::RowHeaderCells(nsTArray<LocalAccessible*>* aCells) {
void TableCellAccessible::RowHeaderCells(nsTArray<Accessible*>* aCells) {
uint32_t rowIdx = RowIdx(), colIdx = ColIdx();
TableAccessible* table = Table();
if (!table) return;
@ -106,7 +106,7 @@ LocalAccessible* TableCellAccessible::PrevColHeader() {
return nullptr;
}
void TableCellAccessible::ColHeaderCells(nsTArray<LocalAccessible*>* aCells) {
void TableCellAccessible::ColHeaderCells(nsTArray<Accessible*>* aCells) {
for (LocalAccessible* cell = PrevColHeader(); cell;
cell = cell->AsTableCell()->PrevColHeader()) {
aCells->AppendElement(cell);

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

@ -7,59 +7,22 @@
#ifndef mozilla_a11y_TableCellAccessible_h__
#define mozilla_a11y_TableCellAccessible_h__
#include "nsTArray.h"
#include <stdint.h>
#include "mozilla/a11y/TableCellAccessibleBase.h"
#include "TableAccessible.h"
namespace mozilla {
namespace a11y {
class LocalAccessible;
class TableAccessible;
/**
* Abstract interface implemented by table cell accessibles.
* Base class for LocalAccessible table cell implementations.
*/
class TableCellAccessible {
class TableCellAccessible : public TableCellAccessibleBase {
public:
/**
* Return the table this cell is in.
*/
virtual TableAccessible* Table() const = 0;
/**
* Return the column of the table this cell is in.
*/
virtual uint32_t ColIdx() const = 0;
/**
* Return the row of the table this cell is in.
*/
virtual uint32_t RowIdx() const = 0;
/**
* Return the column extent of this cell.
*/
virtual uint32_t ColExtent() const { return 1; }
/**
* Return the row extent of this cell.
*/
virtual uint32_t RowExtent() const { return 1; }
/**
* Return the column header cells for this cell.
*/
virtual void ColHeaderCells(nsTArray<LocalAccessible*>* aCells);
/**
* Return the row header cells for this cell.
*/
virtual void RowHeaderCells(nsTArray<LocalAccessible*>* aCells);
/**
* Returns true if this cell is selected.
*/
virtual bool Selected() = 0;
virtual TableAccessible* Table() const override = 0;
virtual void ColHeaderCells(nsTArray<Accessible*>* aCells) override;
virtual void RowHeaderCells(nsTArray<Accessible*>* aCells) override;
private:
LocalAccessible* PrevColHeader();

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

@ -10,6 +10,7 @@
#include "nsAccessibilityService.h"
#include "nsAccUtils.h"
#include "AccAttributes.h"
#include "CacheConstants.h"
#include "DocAccessible.h"
#include "LocalAccessible-inl.h"
#include "nsTextEquivUtils.h"
@ -150,6 +151,10 @@ void HTMLTableCellAccessible::DOMAttributeChanged(int32_t aNameSpaceID,
aAttribute == nsGkAtoms::scope) {
mDoc->FireDelayedEvent(nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED,
this);
mDoc->QueueCacheUpdate(this, CacheDomain::Table);
} else if (aAttribute == nsGkAtoms::rowspan ||
aAttribute == nsGkAtoms::colspan) {
mDoc->QueueCacheUpdate(this, CacheDomain::Table);
}
}
@ -199,8 +204,7 @@ uint32_t HTMLTableCellAccessible::RowExtent() const {
return table->RowExtentAt(rowIdx, colIdx);
}
void HTMLTableCellAccessible::ColHeaderCells(
nsTArray<LocalAccessible*>* aCells) {
void HTMLTableCellAccessible::ColHeaderCells(nsTArray<Accessible*>* aCells) {
IDRefsIterator itr(mDoc, mContent, nsGkAtoms::headers);
while (LocalAccessible* cell = itr.Next()) {
a11y::role cellRole = cell->Role();
@ -219,8 +223,7 @@ void HTMLTableCellAccessible::ColHeaderCells(
if (aCells->IsEmpty()) TableCellAccessible::ColHeaderCells(aCells);
}
void HTMLTableCellAccessible::RowHeaderCells(
nsTArray<LocalAccessible*>* aCells) {
void HTMLTableCellAccessible::RowHeaderCells(nsTArray<Accessible*>* aCells) {
IDRefsIterator itr(mDoc, mContent, nsGkAtoms::headers);
while (LocalAccessible* cell = itr.Next()) {
a11y::role cellRole = cell->Role();
@ -525,7 +528,7 @@ uint32_t HTMLTableAccessible::SelectedRowCount() {
return count;
}
void HTMLTableAccessible::SelectedCells(nsTArray<LocalAccessible*>* aCells) {
void HTMLTableAccessible::SelectedCells(nsTArray<Accessible*>* aCells) {
nsTableWrapperFrame* tableFrame = GetTableWrapperFrame();
if (!tableFrame) return;

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

@ -52,8 +52,8 @@ class HTMLTableCellAccessible : public HyperTextAccessibleWrap,
virtual uint32_t RowIdx() const override;
virtual uint32_t ColExtent() const override;
virtual uint32_t RowExtent() const override;
virtual void ColHeaderCells(nsTArray<LocalAccessible*>* aCells) override;
virtual void RowHeaderCells(nsTArray<LocalAccessible*>* aCells) override;
virtual void ColHeaderCells(nsTArray<Accessible*>* aCells) override;
virtual void RowHeaderCells(nsTArray<Accessible*>* aCells) override;
virtual bool Selected() override;
protected:
@ -152,7 +152,7 @@ class HTMLTableAccessible : public HyperTextAccessibleWrap,
virtual uint32_t SelectedCellCount() override;
virtual uint32_t SelectedColCount() override;
virtual uint32_t SelectedRowCount() override;
virtual void SelectedCells(nsTArray<LocalAccessible*>* aCells) override;
virtual void SelectedCells(nsTArray<Accessible*>* aCells) override;
virtual void SelectedCellIndices(nsTArray<uint32_t>* aCells) override;
virtual void SelectedColIndices(nsTArray<uint32_t>* aCols) override;
virtual void SelectedRowIndices(nsTArray<uint32_t>* aRows) override;

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

@ -4,6 +4,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CachedTableAccessible.h"
#include "DocAccessibleParent.h"
#include "mozilla/a11y/Platform.h"
#include "mozilla/dom/BrowserBridgeParent.h"
@ -162,6 +163,10 @@ uint32_t DocAccessibleParent::AddSubtree(
});
}
if (newProxy->IsTableCell()) {
CachedTableAccessible::Invalidate(newProxy);
}
DebugOnly<bool> isOuterDoc = newProxy->ChildCount() == 1;
uint32_t accessibles = 1;
@ -188,6 +193,9 @@ void DocAccessibleParent::ShutdownOrPrepareForMove(RemoteAccessible* aAcc) {
// This is a move. Moves are sent as a hide and then a show, but for a move,
// we want to keep the Accessible alive for reuse later.
aAcc->SetParent(nullptr);
if (aAcc->IsTable() || aAcc->IsTableCell()) {
CachedTableAccessible::Invalidate(aAcc);
}
mMovingIDs.EnsureRemoved(id);
if (aAcc->IsOuterDoc()) {
// Leave child documents alone. They are added and removed differently to

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

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ARIAMap.h"
#include "CachedTableAccessible.h"
#include "DocAccessible.h"
#include "mozilla/a11y/DocAccessibleParent.h"
#include "mozilla/a11y/DocManager.h"
@ -17,6 +18,7 @@
#include "mozilla/dom/CanonicalBrowsingContext.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/gfx/Matrix.h"
#include "mozilla/StaticPrefs_accessibility.h"
#include "mozilla/Unused.h"
#include "nsAccUtils.h"
#include "nsTextEquivUtils.h"
@ -49,6 +51,10 @@ void RemoteAccessibleBase<Derived>::Shutdown() {
xpcDoc->NotifyOfShutdown(static_cast<Derived*>(this));
}
if (IsTable() || IsTableCell()) {
CachedTableAccessible::Invalidate(this);
}
// XXX Ideally this wouldn't be necessary, but it seems OuterDoc accessibles
// can be destroyed before the doc they own.
uint32_t childCount = mChildren.Length();
@ -619,6 +625,20 @@ already_AddRefed<AccAttributes> RemoteAccessibleBase<Derived>::Attributes() {
if (RefPtr<nsAtom> display = DisplayStyle()) {
attributes->SetAttribute(nsGkAtoms::display, display);
}
if (TableCellAccessibleBase* cell = AsTableCellBase()) {
TableAccessibleBase* table = cell->Table();
uint32_t row = cell->RowIdx();
uint32_t col = cell->ColIdx();
int32_t cellIdx = table->CellIndexAt(row, col);
if (cellIdx != -1) {
attributes->SetAttribute(nsGkAtoms::tableCellIndex, cellIdx);
}
}
if (bool layoutGuess = TableIsProbablyForLayout()) {
attributes->SetAttribute(nsGkAtoms::layout_guess, layoutGuess);
}
}
return attributes.forget();
@ -950,6 +970,36 @@ void RemoteAccessibleBase<Derived>::SetSelected(bool aSelect) {
Unused << mDoc->SendSetSelected(mID, aSelect);
}
template <class Derived>
TableAccessibleBase* RemoteAccessibleBase<Derived>::AsTableBase() {
MOZ_ASSERT(StaticPrefs::accessibility_cache_enabled_AtStartup());
if (IsTable()) {
return CachedTableAccessible::GetFrom(this);
}
return nullptr;
}
template <class Derived>
TableCellAccessibleBase* RemoteAccessibleBase<Derived>::AsTableCellBase() {
MOZ_ASSERT(StaticPrefs::accessibility_cache_enabled_AtStartup());
if (IsTableCell()) {
return CachedTableCellAccessible::GetFrom(this);
}
return nullptr;
}
template <class Derived>
bool RemoteAccessibleBase<Derived>::TableIsProbablyForLayout() {
MOZ_ASSERT(StaticPrefs::accessibility_cache_enabled_AtStartup());
if (mCachedFields) {
if (auto layoutGuess =
mCachedFields->GetAttribute<bool>(nsGkAtoms::layout_guess)) {
return *layoutGuess;
}
}
return false;
}
template class RemoteAccessibleBase<RemoteAccessible>;
} // namespace a11y

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

@ -220,10 +220,7 @@ class RemoteAccessibleBase : public Accessible, public HyperTextAccessibleBase {
uintptr_t GetWrapper() const { return mWrapper; }
void SetWrapper(uintptr_t aWrapper) { mWrapper = aWrapper; }
/*
* Return the ID of the accessible being proxied.
*/
uint64_t ID() const { return mID; }
virtual uint64_t ID() const override { return mID; }
/**
* Return the document containing this proxy, or the proxy itself if it is a
@ -274,6 +271,8 @@ class RemoteAccessibleBase : public Accessible, public HyperTextAccessibleBase {
virtual void AppendTextTo(nsAString& aText, uint32_t aStartOffset = 0,
uint32_t aLength = UINT32_MAX) override;
virtual bool TableIsProbablyForLayout();
uint32_t GetCachedTextLength();
Maybe<const nsTArray<int32_t>&> GetCachedTextLines();
RefPtr<const AccAttributes> GetCachedTextAttributes();
@ -283,6 +282,9 @@ class RemoteAccessibleBase : public Accessible, public HyperTextAccessibleBase {
: nullptr;
}
virtual TableAccessibleBase* AsTableBase() override;
virtual TableCellAccessibleBase* AsTableCellBase() override;
/**
* Return the id of the dom node this accessible represents. Note this
* should probably only be used for testing.
@ -339,6 +341,7 @@ class RemoteAccessibleBase : public Accessible, public HyperTextAccessibleBase {
friend Derived;
friend DocAccessibleParent;
friend class xpcAccessible;
friend class CachedTableCellAccessible;
nsTArray<Derived*> mChildren;
DocAccessibleParent* mDoc;

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

@ -193,7 +193,6 @@ void TableSelectColumn(uint32_t aCol);
void TableSelectRow(uint32_t aRow);
void TableUnselectColumn(uint32_t aCol);
void TableUnselectRow(uint32_t aRow);
bool TableIsProbablyForLayout();
RemoteAccessible* AtkTableColumnHeader(int32_t aCol);
RemoteAccessible* AtkTableRowHeader(int32_t aRow);

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

@ -844,12 +844,11 @@ mozilla::ipc::IPCResult DocAccessibleChild::RecvColHeaderCells(
const uint64_t& aID, nsTArray<uint64_t>* aCells) {
TableCellAccessible* acc = IdToTableCellAccessible(aID);
if (acc) {
AutoTArray<LocalAccessible*, 10> headerCells;
AutoTArray<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()));
for (Accessible* header : headerCells) {
aCells->AppendElement(header->ID());
}
}
@ -860,12 +859,11 @@ mozilla::ipc::IPCResult DocAccessibleChild::RecvRowHeaderCells(
const uint64_t& aID, nsTArray<uint64_t>* aCells) {
TableCellAccessible* acc = IdToTableCellAccessible(aID);
if (acc) {
AutoTArray<LocalAccessible*, 10> headerCells;
AutoTArray<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()));
for (Accessible* header : headerCells) {
aCells->AppendElement(header->ID());
}
}
@ -1106,11 +1104,11 @@ mozilla::ipc::IPCResult DocAccessibleChild::RecvTableSelectedCells(
const uint64_t& aID, nsTArray<uint64_t>* aCellIDs) {
TableAccessible* acc = IdToTableAccessible(aID);
if (acc) {
AutoTArray<LocalAccessible*, 30> cells;
AutoTArray<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()));
for (Accessible* cell : cells) {
aCellIDs->AppendElement(cell->ID());
}
}
@ -1206,9 +1204,9 @@ mozilla::ipc::IPCResult DocAccessibleChild::RecvAtkTableColumnHeader(
#ifdef MOZ_ACCESSIBILITY_ATK
TableAccessible* acc = IdToTableAccessible(aID);
if (acc) {
LocalAccessible* header = AccessibleWrap::GetColumnHeader(acc, aCol);
Accessible* header = AccessibleWrap::GetColumnHeader(acc, aCol);
if (header) {
*aHeader = reinterpret_cast<uint64_t>(header->UniqueID());
*aHeader = header->ID();
*aOk = true;
}
}
@ -1225,9 +1223,9 @@ mozilla::ipc::IPCResult DocAccessibleChild::RecvAtkTableRowHeader(
#ifdef MOZ_ACCESSIBILITY_ATK
TableAccessible* acc = IdToTableAccessible(aID);
if (acc) {
LocalAccessible* header = AccessibleWrap::GetRowHeader(acc, aRow);
Accessible* header = AccessibleWrap::GetRowHeader(acc, aRow);
if (header) {
*aHeader = reinterpret_cast<uint64_t>(header->UniqueID());
*aHeader = header->ID();
*aOk = true;
}
}

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

@ -67,6 +67,8 @@ class RemoteAccessible : public RemoteAccessibleBase<RemoteAccessible> {
bool SelectionBoundsAt(int32_t aSelectionNum, nsString& aData,
int32_t* aStartOffset, int32_t* aEndOffset);
virtual bool TableIsProbablyForLayout() override;
protected:
explicit RemoteAccessible(DocAccessibleParent* aThisAsDoc)
: RemoteAccessibleBase(aThisAsDoc) {

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

@ -18,11 +18,19 @@ namespace a11y {
namespace utils {
// convert an array of Gecko accessibles to an NSArray of native accessibles
NSArray<mozAccessible*>* ConvertToNSArray(nsTArray<LocalAccessible*>& aArray);
template <typename AccArray>
NSArray<mozAccessible*>* ConvertToNSArray(AccArray& aArray) {
NSMutableArray* nativeArray = [[[NSMutableArray alloc] init] autorelease];
// convert an array of Gecko proxy accessibles to an NSArray of native
// accessibles
NSArray<mozAccessible*>* ConvertToNSArray(nsTArray<RemoteAccessible*>& aArray);
// iterate through the list, and get each native accessible.
for (Accessible* curAccessible : aArray) {
mozAccessible* curNative = GetNativeFromGeckoAccessible(curAccessible);
if (curNative)
[nativeArray addObject:GetObjectOrRepresentedView(curNative)];
}
return nativeArray;
}
/**
* Get a localized string from the string bundle.

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

@ -15,39 +15,6 @@ namespace mozilla {
namespace a11y {
namespace utils {
// convert an array of Gecko accessibles to an NSArray of native accessibles
NSArray<mozAccessible*>* ConvertToNSArray(nsTArray<LocalAccessible*>& aArray) {
NSMutableArray* nativeArray = [[[NSMutableArray alloc] init] autorelease];
// iterate through the list, and get each native accessible.
size_t totalCount = aArray.Length();
for (size_t i = 0; i < totalCount; i++) {
LocalAccessible* curAccessible = aArray.ElementAt(i);
mozAccessible* curNative = GetNativeFromGeckoAccessible(curAccessible);
if (curNative)
[nativeArray addObject:GetObjectOrRepresentedView(curNative)];
}
return nativeArray;
}
// convert an array of Gecko proxy accessibles to an NSArray of native
// accessibles
NSArray<mozAccessible*>* ConvertToNSArray(nsTArray<RemoteAccessible*>& aArray) {
NSMutableArray* nativeArray = [[[NSMutableArray alloc] init] autorelease];
// iterate through the list, and get each native accessible.
size_t totalCount = aArray.Length();
for (size_t i = 0; i < totalCount; i++) {
RemoteAccessible* curAccessible = aArray.ElementAt(i);
mozAccessible* curNative = GetNativeFromGeckoAccessible(curAccessible);
if (curNative)
[nativeArray addObject:GetObjectOrRepresentedView(curNative)];
}
return nativeArray;
}
/**
* Get a localized string from the a11y string bundle.
* Return nil if not found.

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

@ -12,8 +12,9 @@
#include "AccIterator.h"
#include "LocalAccessible.h"
#include "TableAccessible.h"
#include "TableCellAccessible.h"
#include "mozilla/a11y/TableAccessibleBase.h"
#include "mozilla/a11y/TableCellAccessibleBase.h"
#include "mozilla/StaticPrefs_accessibility.h"
#include "XULTreeAccessible.h"
#include "Pivot.h"
#include "Relation.h"
@ -49,13 +50,14 @@ enum CachedBool { eCachedBoolMiss, eCachedTrue, eCachedFalse };
mChildren = [[NSMutableArray alloc] init];
if (LocalAccessible* acc = [mParent geckoAccessible]->AsLocal()) {
TableAccessible* table = acc->AsTable();
if (StaticPrefs::accessibility_cache_enabled_AtStartup() ||
[mParent geckoAccessible]->IsLocal()) {
TableAccessibleBase* table = [mParent geckoAccessible]->AsTableBase();
MOZ_ASSERT(table, "Got null table when fetching column children!");
uint32_t numRows = table->RowCount();
for (uint32_t j = 0; j < numRows; j++) {
LocalAccessible* cell = table->CellAt(j, mIndex);
Accessible* cell = table->CellAt(j, mIndex);
mozAccessible* nativeCell =
cell ? GetNativeFromGeckoAccessible(cell) : nil;
if ([nativeCell isAccessibilityElement]) {
@ -196,6 +198,11 @@ enum CachedBool { eCachedBoolMiss, eCachedTrue, eCachedFalse };
}
bool tableGuess;
// For LocalAccessible and cached RemoteAccessible, We could use
// AsTableBase()->IsProbablyLayoutTable(). However, if the cache is enabled,
// that would build the table cache, which is pointless for layout tables on
// Mac because layout tables are AXGroups and do not expose table properties
// like AXRows, AXColumns, etc.
if (LocalAccessible* acc = mGeckoAccessible->AsLocal()) {
tableGuess = acc->AsTable()->IsProbablyLayoutTable();
} else {
@ -235,16 +242,18 @@ enum CachedBool { eCachedBoolMiss, eCachedTrue, eCachedFalse };
- (NSNumber*)moxRowCount {
MOZ_ASSERT(mGeckoAccessible);
return mGeckoAccessible->IsLocal()
? @(mGeckoAccessible->AsLocal()->AsTable()->RowCount())
return (StaticPrefs::accessibility_cache_enabled_AtStartup() ||
mGeckoAccessible->IsLocal())
? @(mGeckoAccessible->AsTableBase()->RowCount())
: @(mGeckoAccessible->AsRemote()->TableRowCount());
}
- (NSNumber*)moxColumnCount {
MOZ_ASSERT(mGeckoAccessible);
return mGeckoAccessible->IsLocal()
? @(mGeckoAccessible->AsLocal()->AsTable()->ColCount())
return (StaticPrefs::accessibility_cache_enabled_AtStartup() ||
mGeckoAccessible->IsLocal())
? @(mGeckoAccessible->AsTableBase()->ColCount())
: @(mGeckoAccessible->AsRemote()->TableColumnCount());
}
@ -286,8 +295,9 @@ enum CachedBool { eCachedBoolMiss, eCachedTrue, eCachedFalse };
mColContainers = [[NSMutableArray alloc] init];
uint32_t numCols = 0;
if (LocalAccessible* acc = mGeckoAccessible->AsLocal()) {
numCols = acc->AsTable()->ColCount();
if (StaticPrefs::accessibility_cache_enabled_AtStartup() ||
mGeckoAccessible->IsLocal()) {
numCols = mGeckoAccessible->AsTableBase()->ColCount();
} else {
numCols = mGeckoAccessible->AsRemote()->TableColumnCount();
}
@ -314,10 +324,11 @@ enum CachedBool { eCachedBoolMiss, eCachedTrue, eCachedFalse };
MOZ_ASSERT(mGeckoAccessible);
uint32_t numCols = 0;
TableAccessible* table = nullptr;
TableAccessibleBase* table = nullptr;
if (LocalAccessible* acc = mGeckoAccessible->AsLocal()) {
table = mGeckoAccessible->AsLocal()->AsTable();
if (StaticPrefs::accessibility_cache_enabled_AtStartup() ||
mGeckoAccessible->IsLocal()) {
table = mGeckoAccessible->AsTableBase();
numCols = table->ColCount();
} else {
numCols = mGeckoAccessible->AsRemote()->TableColumnCount();
@ -354,8 +365,9 @@ enum CachedBool { eCachedBoolMiss, eCachedTrue, eCachedFalse };
MOZ_ASSERT(mGeckoAccessible);
Accessible* cell;
if (mGeckoAccessible->IsLocal()) {
cell = mGeckoAccessible->AsLocal()->AsTable()->CellAt(row, col);
if (StaticPrefs::accessibility_cache_enabled_AtStartup() ||
mGeckoAccessible->IsLocal()) {
cell = mGeckoAccessible->AsTableBase()->CellAt(row, col);
} else {
cell = mGeckoAccessible->AsRemote()->TableCellAt(row, col);
}
@ -416,8 +428,9 @@ enum CachedBool { eCachedBoolMiss, eCachedTrue, eCachedFalse };
- (NSValue*)moxRowIndexRange {
MOZ_ASSERT(mGeckoAccessible);
if (mGeckoAccessible->IsLocal()) {
TableCellAccessible* cell = mGeckoAccessible->AsLocal()->AsTableCell();
if (StaticPrefs::accessibility_cache_enabled_AtStartup() ||
mGeckoAccessible->IsLocal()) {
TableCellAccessibleBase* cell = mGeckoAccessible->AsTableCellBase();
return
[NSValue valueWithRange:NSMakeRange(cell->RowIdx(), cell->RowExtent())];
} else {
@ -430,8 +443,9 @@ enum CachedBool { eCachedBoolMiss, eCachedTrue, eCachedFalse };
- (NSValue*)moxColumnIndexRange {
MOZ_ASSERT(mGeckoAccessible);
if (mGeckoAccessible->IsLocal()) {
TableCellAccessible* cell = mGeckoAccessible->AsLocal()->AsTableCell();
if (StaticPrefs::accessibility_cache_enabled_AtStartup() ||
mGeckoAccessible->IsLocal()) {
TableCellAccessibleBase* cell = mGeckoAccessible->AsTableCellBase();
return
[NSValue valueWithRange:NSMakeRange(cell->ColIdx(), cell->ColExtent())];
} else {
@ -444,9 +458,10 @@ enum CachedBool { eCachedBoolMiss, eCachedTrue, eCachedFalse };
- (NSArray*)moxRowHeaderUIElements {
MOZ_ASSERT(mGeckoAccessible);
if (mGeckoAccessible->IsLocal()) {
TableCellAccessible* cell = mGeckoAccessible->AsLocal()->AsTableCell();
AutoTArray<LocalAccessible*, 10> headerCells;
if (StaticPrefs::accessibility_cache_enabled_AtStartup() ||
mGeckoAccessible->IsLocal()) {
TableCellAccessibleBase* cell = mGeckoAccessible->AsTableCellBase();
AutoTArray<Accessible*, 10> headerCells;
cell->RowHeaderCells(&headerCells);
return utils::ConvertToNSArray(headerCells);
} else {
@ -460,9 +475,10 @@ enum CachedBool { eCachedBoolMiss, eCachedTrue, eCachedFalse };
- (NSArray*)moxColumnHeaderUIElements {
MOZ_ASSERT(mGeckoAccessible);
if (mGeckoAccessible->IsLocal()) {
TableCellAccessible* cell = mGeckoAccessible->AsLocal()->AsTableCell();
AutoTArray<LocalAccessible*, 10> headerCells;
if (StaticPrefs::accessibility_cache_enabled_AtStartup() ||
mGeckoAccessible->IsLocal()) {
TableCellAccessibleBase* cell = mGeckoAccessible->AsTableCellBase();
AutoTArray<Accessible*, 10> headerCells;
cell->ColHeaderCells(&headerCells);
return utils::ConvertToNSArray(headerCells);
} else {

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

@ -22,6 +22,7 @@ support-files =
skip-if = (os == "linux" && bits == 64) || (debug && os == "mac") || (debug && os == "win") #Bug 1388256
[browser_caching_relations.js]
[browser_caching_states.js]
[browser_caching_table.js]
[browser_caching_text.js]
[browser_caching_value.js]
[browser_caching_uniqueid.js]

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

@ -0,0 +1,330 @@
/* 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/. */
/**
* Test tables for both local and remote Accessibles. There is more extensive
* coverage in ../../mochitest/table. These tests are primarily to ensure that
* the cache works as expected and that there is consistency between local and
* remote.
*/
"use strict";
/* import-globals-from ../../mochitest/table.js */
/* import-globals-from ../../mochitest/attributes.js */
loadScripts(
{ name: "table.js", dir: MOCHITESTS_DIR },
{ name: "attributes.js", dir: MOCHITESTS_DIR }
);
/**
* Test table counts, indexes, extents and implicit headers.
*/
addAccessibleTask(
`
<table id="table">
<thead>
<tr><th id="a">a</th><th id="bc" colspan="2">bc</th><th id="d">d</th></tr>
</thead>
<tbody>
<tr><th id="ei" rowspan="2">ei</th><td id="fj" rowspan="0">fj</td><td id="g">g</td><td id="h">h</td></tr>
<tr><td id="k">k</td></tr>
</tbody>
</table>
`,
async function(browser, docAcc) {
const table = findAccessibleChildByID(docAcc, "table", [
nsIAccessibleTable,
]);
is(table.rowCount, 3, "table rowCount correct");
is(table.columnCount, 4, "table columnCount correct");
testTableIndexes(table, [
[0, 1, 1, 2],
[3, 4, 5, 6],
[3, 4, 7, -1],
]);
const cells = {};
for (const id of ["a", "bc", "d", "ei", "fj", "g", "h", "k"]) {
cells[id] = findAccessibleChildByID(docAcc, id, [nsIAccessibleTableCell]);
}
is(cells.a.rowExtent, 1, "a rowExtent correct");
is(cells.a.columnExtent, 1, "a columnExtent correct");
is(cells.bc.rowExtent, 1, "bc rowExtent correct");
is(cells.bc.columnExtent, 2, "bc columnExtent correct");
is(cells.ei.rowExtent, 2, "ei rowExtent correct");
is(cells.fj.rowExtent, 2, "fj rowExtent correct");
testHeaderCells([
{
cell: cells.ei,
rowHeaderCells: [],
columnHeaderCells: [cells.a],
},
{
cell: cells.g,
rowHeaderCells: [cells.ei],
columnHeaderCells: [cells.bc],
},
{
cell: cells.k,
rowHeaderCells: [cells.ei],
columnHeaderCells: [cells.bc],
},
]);
},
{
chrome: true,
topLevel: isCacheEnabled,
iframe: isCacheEnabled,
remoteIframe: isCacheEnabled,
}
);
/**
* Test table explicit headers.
*/
addAccessibleTask(
`
<table id="table">
<tr><th id="a">a</th><th id="b">b</th></tr>
<tr><td id="c" headers="b d">c</td><th scope="row" id="d">d</th></tr>
<tr><td id="e" headers="c f">e</td><td id="f">f</td></tr>
</table>
`,
async function(browser, docAcc) {
const cells = {};
for (const id of ["a", "b", "c", "d", "e", "f"]) {
cells[id] = findAccessibleChildByID(docAcc, id, [nsIAccessibleTableCell]);
}
testHeaderCells([
{
cell: cells.c,
rowHeaderCells: [cells.d],
columnHeaderCells: [cells.b],
},
{
cell: cells.e,
rowHeaderCells: [cells.f],
columnHeaderCells: [cells.c],
},
]);
},
{
chrome: true,
topLevel: isCacheEnabled,
iframe: isCacheEnabled,
remoteIframe: isCacheEnabled,
}
);
/**
* Test that an inner table doesn't impact an outer table.
*/
addAccessibleTask(
`
<table id="outerTable">
<tr><th id="outerCell">outerCell<table id="innerTable">
<tr><th id="innerCell">a</th></tr></table>
</table></th></tr>
</table>
`,
async function(browser, docAcc) {
const outerTable = findAccessibleChildByID(docAcc, "outerTable", [
nsIAccessibleTable,
]);
is(outerTable.rowCount, 1, "outerTable rowCount correct");
is(outerTable.columnCount, 1, "outerTable columnCount correct");
const outerCell = findAccessibleChildByID(docAcc, "outerCell");
is(
outerTable.getCellAt(0, 0),
outerCell,
"outerTable returns correct cell"
);
const innerTable = findAccessibleChildByID(docAcc, "innerTable", [
nsIAccessibleTable,
]);
is(innerTable.rowCount, 1, "innerTable rowCount correct");
is(innerTable.columnCount, 1, "innerTable columnCount correct");
const innerCell = findAccessibleChildByID(docAcc, "innerCell");
is(
innerTable.getCellAt(0, 0),
innerCell,
"innerTable returns correct cell"
);
},
{
chrome: true,
topLevel: isCacheEnabled,
iframe: isCacheEnabled,
remoteIframe: isCacheEnabled,
}
);
/**
* Test table caption and summary.
*/
addAccessibleTask(
`
<table id="t1">
<caption id="c1">c1</caption>
<tr><th>a</th></tr>
</table>
<table id="t2" summary="s2">
<tr><th>a</th></tr>
</table>
<table id="t3" summary="s3">
<caption id="c3">c3</caption>
<tr><th>a</th></tr>
</table>
`,
async function(browser, docAcc) {
const t1 = findAccessibleChildByID(docAcc, "t1", [nsIAccessibleTable]);
const c1 = findAccessibleChildByID(docAcc, "c1");
is(t1.caption, c1, "t1 caption correct");
ok(!t1.summary, "t1 no summary");
const t2 = findAccessibleChildByID(docAcc, "t2", [nsIAccessibleTable]);
ok(!t2.caption, "t2 caption is null");
is(t2.summary, "s2", "t2 summary correct");
const t3 = findAccessibleChildByID(docAcc, "t3", [nsIAccessibleTable]);
const c3 = findAccessibleChildByID(docAcc, "c3");
is(t3.caption, c3, "t3 caption correct");
is(t3.summary, "s3", "t3 summary correct");
},
{
chrome: true,
topLevel: isCacheEnabled,
iframe: isCacheEnabled,
remoteIframe: isCacheEnabled,
}
);
/**
* Test table layout guess.
*/
addAccessibleTask(
`
<table id="layout"><tr><td>a</td></tr></table>
<table id="data"><tr><th>a</th></tr></table>
`,
async function(browser, docAcc) {
const layout = findAccessibleChildByID(docAcc, "layout", [
nsIAccessibleTable,
]);
testAttrs(layout, { "layout-guess": "true" }, true);
const data = findAccessibleChildByID(docAcc, "data", [nsIAccessibleTable]);
testAbsentAttrs(data, { "layout-guess": "true" });
},
{
chrome: true,
topLevel: isCacheEnabled,
iframe: isCacheEnabled,
remoteIframe: isCacheEnabled,
}
);
/**
* Test ARIA grid.
*/
addAccessibleTask(
`
<div id="grid" role="grid">
<div role="rowgroup">
<div role="row"><div id="a" role="columnheader">a</div><div id="b" role="columnheader">b</div></div>
</div>
<div tabindex="-1">
<div role="row"><div id="c" role="rowheader">c</div><div id="d" role="gridcell">d</div></div>
</div>
</div>
`,
async function(browser, docAcc) {
const grid = findAccessibleChildByID(docAcc, "grid", [nsIAccessibleTable]);
is(grid.rowCount, 2, "grid rowCount correct");
is(grid.columnCount, 2, "grid columnCount correct");
testTableIndexes(grid, [
[0, 1],
[2, 3],
]);
const cells = {};
for (const id of ["a", "b", "c", "d"]) {
cells[id] = findAccessibleChildByID(docAcc, id, [nsIAccessibleTableCell]);
}
is(cells.a.rowExtent, 1, "a rowExtent correct");
is(cells.a.columnExtent, 1, "a columnExtent correct");
testHeaderCells([
{
cell: cells.c,
rowHeaderCells: [],
columnHeaderCells: [cells.a],
},
{
cell: cells.d,
rowHeaderCells: [cells.c],
columnHeaderCells: [cells.b],
},
]);
},
{
chrome: true,
topLevel: isCacheEnabled,
iframe: isCacheEnabled,
remoteIframe: isCacheEnabled,
}
);
function setNodeHidden(browser, id, hidden) {
return invokeContentTask(browser, [id, hidden], (cId, cHidden) => {
content.document.getElementById(cId).hidden = cHidden;
});
}
/**
* Test that the table is updated correctly when it is mutated.
*/
addAccessibleTask(
`
<table id="table">
<tr id="r1"><td>a</td><td id="b">b</td></tr>
<tr id="r2" hidden><td>c</td><td>d</td></tr>
</table>
`,
async function(browser, docAcc) {
const table = findAccessibleChildByID(docAcc, "table", [
nsIAccessibleTable,
]);
is(table.rowCount, 1, "table rowCount correct");
is(table.columnCount, 2, "table columnCount correct");
testTableIndexes(table, [[0, 1]]);
info("Showing r2");
let reordered = waitForEvent(EVENT_REORDER, table);
setNodeHidden(browser, "r2", false);
await reordered;
is(table.rowCount, 2, "table rowCount correct");
testTableIndexes(table, [
[0, 1],
[2, 3],
]);
info("Hiding r2");
reordered = waitForEvent(EVENT_REORDER, table);
setNodeHidden(browser, "r2", true);
await reordered;
is(table.rowCount, 1, "table rowCount correct");
testTableIndexes(table, [[0, 1]]);
info("Hiding b");
reordered = waitForEvent(EVENT_REORDER, "r1");
setNodeHidden(browser, "b", true);
await reordered;
is(table.columnCount, 1, "table columnCount correct");
testTableIndexes(table, [[0]]);
info("Showing b");
reordered = waitForEvent(EVENT_REORDER, "r1");
setNodeHidden(browser, "b", false);
await reordered;
is(table.columnCount, 2, "table columnCount correct");
},
{
chrome: true,
topLevel: isCacheEnabled,
iframe: isCacheEnabled,
remoteIframe: isCacheEnabled,
}
);

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

@ -368,7 +368,8 @@ function wrapWithIFrame(doc, options = {}) {
} else {
srcURL.searchParams.append(
"html",
`<html>
`<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Accessibility Fission Test</title>
@ -387,7 +388,8 @@ function wrapWithIFrame(doc, options = {}) {
`<body ${attrsToString(iframeDocBodyAttrs)}>`
);
} else {
doc = `<body ${attrsToString(iframeDocBodyAttrs)}>${doc}</body>`;
doc = `<!doctype html>
<body ${attrsToString(iframeDocBodyAttrs)}>${doc}</body>`;
}
src = `data:${mimeType};charset=utf-8,${encodeURIComponent(doc)}`;
@ -424,7 +426,8 @@ function snippetToURL(doc, options = {}) {
}
const encodedDoc = encodeURIComponent(
`<html>
`<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Accessibility Test</title>

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

@ -11,19 +11,18 @@
#include "AccessibleTable_i.c"
#include "AccessibleTable2_i.c"
#include "AccessibleWrap.h"
#include "IUnknownImpl.h"
#include "Statistics.h"
#include "TableAccessible.h"
#include "mozilla/a11y/Accessible.h"
#include "mozilla/a11y/TableAccessibleBase.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include "Statistics.h"
using namespace mozilla::a11y;
TableAccessible* ia2AccessibleTable::TableAcc() {
AccessibleWrap* acc = LocalAcc();
return acc ? acc->AsTable() : nullptr;
TableAccessibleBase* ia2AccessibleTable::TableAcc() {
Accessible* acc = Acc();
return acc ? acc->AsTableBase() : nullptr;
}
// IUnknown
@ -64,14 +63,13 @@ ia2AccessibleTable::get_caption(IUnknown** aAccessible) {
if (!aAccessible) return E_INVALIDARG;
*aAccessible = nullptr;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
AccessibleWrap* caption = static_cast<AccessibleWrap*>(table->Caption());
Accessible* caption = table->Caption();
if (!caption) return S_FALSE;
RefPtr<IAccessible> result;
caption->GetNativeInterface(getter_AddRefs(result));
RefPtr<IAccessible> result = MsaaAccessible::GetFrom(caption);
result.forget(aAccessible);
return S_OK;
}
@ -82,7 +80,7 @@ ia2AccessibleTable::get_childIndex(long aRowIdx, long aColIdx,
if (!aChildIdx) return E_INVALIDARG;
*aChildIdx = 0;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
if (aRowIdx < 0 || aColIdx < 0 ||
@ -99,7 +97,7 @@ ia2AccessibleTable::get_columnDescription(long aColIdx, BSTR* aDescription) {
if (!aDescription) return E_INVALIDARG;
*aDescription = nullptr;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= table->ColCount())
@ -119,7 +117,7 @@ ia2AccessibleTable::get_columnExtentAt(long aRowIdx, long aColIdx,
if (!aSpan) return E_INVALIDARG;
*aSpan = 0;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
if (aRowIdx < 0 || aColIdx < 0 ||
@ -146,7 +144,7 @@ ia2AccessibleTable::get_columnIndex(long aCellIdx, long* aColIdx) {
if (!aColIdx) return E_INVALIDARG;
*aColIdx = 0;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
if (aCellIdx < 0) {
@ -167,7 +165,7 @@ ia2AccessibleTable::get_nColumns(long* aColCount) {
if (!aColCount) return E_INVALIDARG;
*aColCount = 0;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
*aColCount = table->ColCount();
@ -179,7 +177,7 @@ ia2AccessibleTable::get_nRows(long* aRowCount) {
if (!aRowCount) return E_INVALIDARG;
*aRowCount = 0;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
*aRowCount = table->RowCount();
@ -196,7 +194,7 @@ ia2AccessibleTable::get_nSelectedColumns(long* aColCount) {
if (!aColCount) return E_INVALIDARG;
*aColCount = 0;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
*aColCount = table->SelectedColCount();
@ -208,7 +206,7 @@ ia2AccessibleTable::get_nSelectedRows(long* aRowCount) {
if (!aRowCount) return E_INVALIDARG;
*aRowCount = 0;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
*aRowCount = table->SelectedRowCount();
@ -221,7 +219,7 @@ ia2AccessibleTable::get_rowDescription(long aRowIdx, BSTR* aDescription) {
if (!aDescription) return E_INVALIDARG;
*aDescription = nullptr;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= table->RowCount())
@ -240,7 +238,7 @@ ia2AccessibleTable::get_rowExtentAt(long aRowIdx, long aColIdx, long* aSpan) {
if (!aSpan) return E_INVALIDARG;
*aSpan = 0;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
if (aRowIdx < 0 || aColIdx < 0 ||
@ -267,7 +265,7 @@ ia2AccessibleTable::get_rowIndex(long aCellIdx, long* aRowIdx) {
if (!aRowIdx) return E_INVALIDARG;
*aRowIdx = 0;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
if (aCellIdx < 0) {
@ -290,7 +288,7 @@ ia2AccessibleTable::get_selectedChildren(long aMaxChildren, long** aChildren,
*aChildren = nullptr;
*aNChildren = 0;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
AutoTArray<uint32_t, 30> cellIndices;
@ -336,7 +334,7 @@ ia2AccessibleTable::get_isColumnSelected(long aColIdx, boolean* aIsSelected) {
if (!aIsSelected) return E_INVALIDARG;
*aIsSelected = false;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= table->ColCount())
@ -351,7 +349,7 @@ ia2AccessibleTable::get_isRowSelected(long aRowIdx, boolean* aIsSelected) {
if (!aIsSelected) return E_INVALIDARG;
*aIsSelected = false;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= table->RowCount())
@ -367,7 +365,7 @@ ia2AccessibleTable::get_isSelected(long aRowIdx, long aColIdx,
if (!aIsSelected) return E_INVALIDARG;
*aIsSelected = false;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
if (aRowIdx < 0 || aColIdx < 0 ||
@ -381,7 +379,7 @@ ia2AccessibleTable::get_isSelected(long aRowIdx, long aColIdx,
STDMETHODIMP
ia2AccessibleTable::selectRow(long aRowIdx) {
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= table->RowCount())
@ -393,7 +391,7 @@ ia2AccessibleTable::selectRow(long aRowIdx) {
STDMETHODIMP
ia2AccessibleTable::selectColumn(long aColIdx) {
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= table->ColCount())
@ -405,7 +403,7 @@ ia2AccessibleTable::selectColumn(long aColIdx) {
STDMETHODIMP
ia2AccessibleTable::unselectRow(long aRowIdx) {
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= table->RowCount())
@ -417,7 +415,7 @@ ia2AccessibleTable::unselectRow(long aRowIdx) {
STDMETHODIMP
ia2AccessibleTable::unselectColumn(long aColIdx) {
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= table->ColCount())
@ -441,7 +439,7 @@ ia2AccessibleTable::get_rowColumnExtentsAtIndex(long aCellIdx, long* aRowIdx,
*aRowExtents = 0;
*aColExtents = 0;
*aIsSelected = false;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
if (aCellIdx < 0) {
@ -477,15 +475,13 @@ ia2AccessibleTable::get_cellAt(long aRowIdx, long aColIdx, IUnknown** aCell) {
*aCell = nullptr;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
AccessibleWrap* cell =
static_cast<AccessibleWrap*>(table->CellAt(aRowIdx, aColIdx));
Accessible* cell = table->CellAt(aRowIdx, aColIdx);
if (!cell) return E_INVALIDARG;
RefPtr<IAccessible> result;
cell->GetNativeInterface(getter_AddRefs(result));
RefPtr<IAccessible> result = MsaaAccessible::GetFrom(cell);
result.forget(aCell);
return S_OK;
}
@ -495,7 +491,7 @@ ia2AccessibleTable::get_nSelectedCells(long* aCellCount) {
if (!aCellCount) return E_INVALIDARG;
*aCellCount = 0;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
*aCellCount = table->SelectedCellCount();
@ -509,10 +505,10 @@ ia2AccessibleTable::get_selectedCells(IUnknown*** aCells,
*aCells = nullptr;
*aNSelectedCells = 0;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
AutoTArray<LocalAccessible*, 30> cells;
AutoTArray<Accessible*, 30> cells;
table->SelectedCells(&cells);
if (cells.IsEmpty()) return S_FALSE;
@ -521,8 +517,7 @@ ia2AccessibleTable::get_selectedCells(IUnknown*** aCells,
if (!*aCells) return E_OUTOFMEMORY;
for (uint32_t i = 0; i < cells.Length(); i++) {
RefPtr<IAccessible> cell;
cells[i]->GetNativeInterface(getter_AddRefs(cell));
RefPtr<IAccessible> cell = MsaaAccessible::GetFrom(cells[i]);
cell.forget(&(*aCells)[i]);
}
@ -536,7 +531,7 @@ ia2AccessibleTable::get_selectedColumns(long** aColumns, long* aNColumns) {
*aColumns = nullptr;
*aNColumns = 0;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
AutoTArray<uint32_t, 30> colIndices;
@ -558,7 +553,7 @@ ia2AccessibleTable::get_selectedRows(long** aRows, long* aNRows) {
*aRows = nullptr;
*aNRows = 0;
TableAccessible* table = TableAcc();
TableAccessibleBase* table = TableAcc();
if (!table) return CO_E_OBJNOTCONNECTED;
AutoTArray<uint32_t, 30> rowIndices;

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

@ -16,7 +16,7 @@
namespace mozilla {
namespace a11y {
class TableAccessible;
class TableAccessibleBase;
class ia2AccessibleTable : public IAccessibleTable,
public IAccessibleTable2,
@ -169,7 +169,7 @@ class ia2AccessibleTable : public IAccessibleTable,
using ia2AccessibleHypertext::ia2AccessibleHypertext;
private:
TableAccessible* TableAcc();
TableAccessibleBase* TableAcc();
};
} // namespace a11y

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

@ -10,19 +10,18 @@
#include "AccessibleTable2_i.c"
#include "AccessibleTableCell_i.c"
#include "AccessibleWrap.h"
#include "TableAccessible.h"
#include "TableCellAccessible.h"
#include "IUnknownImpl.h"
#include "mozilla/a11y/Accessible.h"
#include "mozilla/a11y/TableAccessibleBase.h"
#include "mozilla/a11y/TableCellAccessibleBase.h"
#include "nsCOMPtr.h"
#include "nsString.h"
using namespace mozilla::a11y;
TableCellAccessible* ia2AccessibleTableCell::CellAcc() {
AccessibleWrap* acc = LocalAcc();
return acc ? acc->AsTableCell() : nullptr;
TableCellAccessibleBase* ia2AccessibleTableCell::CellAcc() {
Accessible* acc = Acc();
return acc ? acc->AsTableCellBase() : nullptr;
}
// IUnknown
@ -38,15 +37,14 @@ ia2AccessibleTableCell::get_table(IUnknown** aTable) {
if (!aTable) return E_INVALIDARG;
*aTable = nullptr;
TableCellAccessible* tableCell = CellAcc();
TableCellAccessibleBase* tableCell = CellAcc();
if (!tableCell) return CO_E_OBJNOTCONNECTED;
TableAccessible* table = tableCell->Table();
TableAccessibleBase* table = tableCell->Table();
if (!table) return E_FAIL;
AccessibleWrap* wrap = static_cast<AccessibleWrap*>(table->AsAccessible());
RefPtr<IAccessibleTable> result;
wrap->GetNativeInterface(getter_AddRefs(result));
Accessible* tableAcc = table->AsAccessible();
RefPtr<IAccessible> result = MsaaAccessible::GetFrom(tableAcc);
result.forget(aTable);
return S_OK;
}
@ -56,7 +54,7 @@ ia2AccessibleTableCell::get_columnExtent(long* aSpan) {
if (!aSpan) return E_INVALIDARG;
*aSpan = 0;
TableCellAccessible* tableCell = CellAcc();
TableCellAccessibleBase* tableCell = CellAcc();
if (!tableCell) return CO_E_OBJNOTCONNECTED;
*aSpan = tableCell->ColExtent();
@ -71,10 +69,10 @@ ia2AccessibleTableCell::get_columnHeaderCells(IUnknown*** aCellAccessibles,
*aCellAccessibles = nullptr;
*aNColumnHeaderCells = 0;
TableCellAccessible* tableCell = CellAcc();
TableCellAccessibleBase* tableCell = CellAcc();
if (!tableCell) return CO_E_OBJNOTCONNECTED;
AutoTArray<LocalAccessible*, 10> cells;
AutoTArray<Accessible*, 10> cells;
tableCell->ColHeaderCells(&cells);
*aNColumnHeaderCells = cells.Length();
@ -84,9 +82,7 @@ ia2AccessibleTableCell::get_columnHeaderCells(IUnknown*** aCellAccessibles,
if (!*aCellAccessibles) return E_OUTOFMEMORY;
for (uint32_t i = 0; i < cells.Length(); i++) {
AccessibleWrap* cell = static_cast<AccessibleWrap*>(cells[i]);
RefPtr<IAccessible> iaCell;
cell->GetNativeInterface(getter_AddRefs(iaCell));
RefPtr<IAccessible> iaCell = MsaaAccessible::GetFrom(cells[i]);
iaCell.forget(&(*aCellAccessibles)[i]);
}
@ -98,7 +94,7 @@ ia2AccessibleTableCell::get_columnIndex(long* aColIdx) {
if (!aColIdx) return E_INVALIDARG;
*aColIdx = -1;
TableCellAccessible* tableCell = CellAcc();
TableCellAccessibleBase* tableCell = CellAcc();
if (!tableCell) return CO_E_OBJNOTCONNECTED;
*aColIdx = tableCell->ColIdx();
@ -110,7 +106,7 @@ ia2AccessibleTableCell::get_rowExtent(long* aSpan) {
if (!aSpan) return E_INVALIDARG;
*aSpan = 0;
TableCellAccessible* tableCell = CellAcc();
TableCellAccessibleBase* tableCell = CellAcc();
if (!tableCell) return CO_E_OBJNOTCONNECTED;
*aSpan = tableCell->RowExtent();
@ -124,10 +120,10 @@ ia2AccessibleTableCell::get_rowHeaderCells(IUnknown*** aCellAccessibles,
*aCellAccessibles = nullptr;
*aNRowHeaderCells = 0;
TableCellAccessible* tableCell = CellAcc();
TableCellAccessibleBase* tableCell = CellAcc();
if (!tableCell) return CO_E_OBJNOTCONNECTED;
AutoTArray<LocalAccessible*, 10> cells;
AutoTArray<Accessible*, 10> cells;
tableCell->RowHeaderCells(&cells);
*aNRowHeaderCells = cells.Length();
@ -136,9 +132,7 @@ ia2AccessibleTableCell::get_rowHeaderCells(IUnknown*** aCellAccessibles,
if (!*aCellAccessibles) return E_OUTOFMEMORY;
for (uint32_t i = 0; i < cells.Length(); i++) {
AccessibleWrap* cell = static_cast<AccessibleWrap*>(cells[i]);
RefPtr<IAccessible> iaCell;
cell->GetNativeInterface(getter_AddRefs(iaCell));
RefPtr<IAccessible> iaCell = MsaaAccessible::GetFrom(cells[i]);
iaCell.forget(&(*aCellAccessibles)[i]);
}
@ -150,7 +144,7 @@ ia2AccessibleTableCell::get_rowIndex(long* aRowIdx) {
if (!aRowIdx) return E_INVALIDARG;
*aRowIdx = -1;
TableCellAccessible* tableCell = CellAcc();
TableCellAccessibleBase* tableCell = CellAcc();
if (!tableCell) return CO_E_OBJNOTCONNECTED;
*aRowIdx = tableCell->RowIdx();
@ -167,7 +161,7 @@ ia2AccessibleTableCell::get_rowColumnExtents(long* aRowIdx, long* aColIdx,
*aRowIdx = *aColIdx = *aRowExtents = *aColExtents = 0;
*aIsSelected = false;
TableCellAccessible* tableCell = CellAcc();
TableCellAccessibleBase* tableCell = CellAcc();
if (!tableCell) return CO_E_OBJNOTCONNECTED;
*aRowIdx = tableCell->RowIdx();
@ -184,7 +178,7 @@ ia2AccessibleTableCell::get_isSelected(boolean* aIsSelected) {
if (!aIsSelected) return E_INVALIDARG;
*aIsSelected = false;
TableCellAccessible* tableCell = CellAcc();
TableCellAccessibleBase* tableCell = CellAcc();
if (!tableCell) return CO_E_OBJNOTCONNECTED;
*aIsSelected = tableCell->Selected();

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

@ -14,7 +14,7 @@
namespace mozilla {
namespace a11y {
class TableCellAccessible;
class TableCellAccessibleBase;
class ia2AccessibleTableCell : public IAccessibleTableCell,
public ia2AccessibleHypertext {
@ -62,7 +62,7 @@ class ia2AccessibleTableCell : public IAccessibleTableCell,
using ia2AccessibleHypertext::ia2AccessibleHypertext;
private:
TableCellAccessible* CellAcc();
TableCellAccessibleBase* CellAcc();
};
} // namespace a11y

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

@ -59,14 +59,14 @@ MsaaAccessible* MsaaAccessible::Create(Accessible* aAcc) {
if (aAcc->IsDoc()) {
return new MsaaDocAccessible(aAcc);
}
if (aAcc->IsTable()) {
return new ia2AccessibleTable(aAcc);
}
if (aAcc->IsTableCell()) {
return new ia2AccessibleTableCell(aAcc);
}
if (localAcc) {
// XXX These classes don't support RemoteAccessible yet.
if (aAcc->IsTable()) {
return new ia2AccessibleTable(aAcc);
}
if (aAcc->IsTableCell()) {
return new ia2AccessibleTableCell(aAcc);
}
if (aAcc->IsApplication()) {
return new ia2AccessibleApplication(aAcc);
}

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

@ -6,8 +6,8 @@
#include "xpcAccessibleTable.h"
#include "LocalAccessible.h"
#include "TableAccessible.h"
#include "mozilla/a11y/Accessible.h"
#include "mozilla/a11y/TableAccessibleBase.h"
#include "nsIMutableArray.h"
#include "nsComponentManagerUtils.h"
@ -250,12 +250,12 @@ xpcAccessibleTable::GetSelectedCells(nsIArray** aSelectedCells) {
do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
AutoTArray<LocalAccessible*, XPC_TABLE_DEFAULT_SIZE> cellsArray;
AutoTArray<Accessible*, XPC_TABLE_DEFAULT_SIZE> cellsArray;
Intl()->SelectedCells(&cellsArray);
uint32_t totalCount = cellsArray.Length();
for (uint32_t idx = 0; idx < totalCount; idx++) {
LocalAccessible* cell = cellsArray.ElementAt(idx);
Accessible* cell = cellsArray.ElementAt(idx);
selCells->AppendElement(static_cast<nsIAccessible*>(ToXPC(cell)));
}

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

@ -12,6 +12,7 @@
namespace mozilla {
namespace a11y {
class TableAccessibleBase;
/**
* XPCOM wrapper around TableAccessible class.
@ -65,9 +66,7 @@ class xpcAccessibleTable : public xpcAccessibleHyperText,
virtual ~xpcAccessibleTable() {}
private:
TableAccessible* Intl() {
return mIntl->IsLocal() ? mIntl->AsLocal()->AsTable() : nullptr;
}
TableAccessibleBase* Intl() { return mIntl->AsTableBase(); }
xpcAccessibleTable(const xpcAccessibleTable&) = delete;
xpcAccessibleTable& operator=(const xpcAccessibleTable&) = delete;

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

@ -6,10 +6,10 @@
#include "xpcAccessibleTableCell.h"
#include "LocalAccessible.h"
#include "mozilla/a11y/Accessible.h"
#include "mozilla/a11y/TableAccessibleBase.h"
#include "mozilla/a11y/TableCellAccessibleBase.h"
#include "nsIAccessibleTable.h"
#include "TableAccessible.h"
#include "TableCellAccessible.h"
#include "nsComponentManagerUtils.h"
#include "nsIMutableArray.h"
@ -34,7 +34,7 @@ xpcAccessibleTableCell::GetTable(nsIAccessibleTable** aTable) {
if (!Intl()) return NS_ERROR_FAILURE;
TableAccessible* table = Intl()->Table();
TableAccessibleBase* table = Intl()->Table();
if (!table) return NS_ERROR_FAILURE;
nsCOMPtr<nsIAccessibleTable> xpcTable = do_QueryInterface(
@ -94,7 +94,7 @@ xpcAccessibleTableCell::GetColumnHeaderCells(nsIArray** aHeaderCells) {
if (!Intl()) return NS_ERROR_FAILURE;
AutoTArray<LocalAccessible*, 10> headerCells;
AutoTArray<Accessible*, 10> headerCells;
Intl()->ColHeaderCells(&headerCells);
nsCOMPtr<nsIMutableArray> cells = do_CreateInstance(NS_ARRAY_CONTRACTID);
@ -115,7 +115,7 @@ xpcAccessibleTableCell::GetRowHeaderCells(nsIArray** aHeaderCells) {
if (!Intl()) return NS_ERROR_FAILURE;
AutoTArray<LocalAccessible*, 10> headerCells;
AutoTArray<Accessible*, 10> headerCells;
Intl()->RowHeaderCells(&headerCells);
nsCOMPtr<nsIMutableArray> cells = do_CreateInstance(NS_ARRAY_CONTRACTID);

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

@ -13,6 +13,7 @@
namespace mozilla {
namespace a11y {
class TableCellAccessibleBase;
/**
* XPCOM wrapper around TableAccessibleCell class.
@ -39,13 +40,7 @@ class xpcAccessibleTableCell : public xpcAccessibleHyperText,
virtual ~xpcAccessibleTableCell() {}
private:
TableCellAccessible* Intl() {
if (LocalAccessible* acc = mIntl->AsLocal()) {
return acc->AsTableCell();
}
return nullptr;
}
TableCellAccessibleBase* Intl() { return mIntl->AsTableCellBase(); }
xpcAccessibleTableCell(const xpcAccessibleTableCell&) = delete;
xpcAccessibleTableCell& operator=(const xpcAccessibleTableCell&) = delete;

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

@ -210,7 +210,7 @@ uint32_t XULListboxAccessible::SelectedRowCount() {
return selectedRowCount >= 0 ? selectedRowCount : 0;
}
void XULListboxAccessible::SelectedCells(nsTArray<LocalAccessible*>* aCells) {
void XULListboxAccessible::SelectedCells(nsTArray<Accessible*>* aCells) {
nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
Elm()->AsXULMultiSelectControl();
NS_ASSERTION(control,

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

@ -66,7 +66,7 @@ class XULListboxAccessible : public XULSelectControlAccessible,
virtual uint32_t SelectedCellCount() override;
virtual uint32_t SelectedColCount() override;
virtual uint32_t SelectedRowCount() override;
virtual void SelectedCells(nsTArray<LocalAccessible*>* aCells) override;
virtual void SelectedCells(nsTArray<Accessible*>* aCells) override;
virtual void SelectedCellIndices(nsTArray<uint32_t>* aCells) override;
virtual void SelectedColIndices(nsTArray<uint32_t>* aCols) override;
virtual void SelectedRowIndices(nsTArray<uint32_t>* aRows) override;

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

@ -62,7 +62,7 @@ uint32_t XULTreeGridAccessible::SelectedRowCount() {
return SelectedItemCount();
}
void XULTreeGridAccessible::SelectedCells(nsTArray<LocalAccessible*>* aCells) {
void XULTreeGridAccessible::SelectedCells(nsTArray<Accessible*>* aCells) {
uint32_t colCount = ColCount(), rowCount = RowCount();
for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
@ -489,7 +489,7 @@ uint32_t XULTreeGridCellAccessible::ColIdx() const {
uint32_t XULTreeGridCellAccessible::RowIdx() const { return mRow; }
void XULTreeGridCellAccessible::ColHeaderCells(
nsTArray<LocalAccessible*>* aHeaderCells) {
nsTArray<Accessible*>* aHeaderCells) {
dom::Element* columnElm = mColumn->Element();
LocalAccessible* headerCell = mDoc->GetAccessible(columnElm);

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

@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
@ -39,7 +40,7 @@ class XULTreeGridAccessible : public XULTreeAccessible, public TableAccessible {
virtual uint32_t SelectedCellCount() override;
virtual uint32_t SelectedColCount() override;
virtual uint32_t SelectedRowCount() override;
virtual void SelectedCells(nsTArray<LocalAccessible*>* aCells) override;
virtual void SelectedCells(nsTArray<Accessible*>* aCells) override;
virtual void SelectedCellIndices(nsTArray<uint32_t>* aCells) override;
virtual void SelectedColIndices(nsTArray<uint32_t>* aCols) override;
virtual void SelectedRowIndices(nsTArray<uint32_t>* aRows) override;
@ -140,9 +141,8 @@ class XULTreeGridCellAccessible : public LeafAccessible,
virtual TableAccessible* Table() const override;
virtual uint32_t ColIdx() const override;
virtual uint32_t RowIdx() const override;
virtual void ColHeaderCells(
nsTArray<LocalAccessible*>* aHeaderCells) override;
virtual void RowHeaderCells(nsTArray<LocalAccessible*>* aCells) override {}
virtual void ColHeaderCells(nsTArray<Accessible*>* aHeaderCells) override;
virtual void RowHeaderCells(nsTArray<Accessible*>* aCells) override {}
virtual bool Selected() override;
/**

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

@ -164,8 +164,10 @@ class AboutPrivateBrowsingParent extends JSWindowActorParent {
Services.prefs.setIntPref(SHOWN_PREF, MAX_SEARCH_BANNER_SHOW_COUNT);
break;
}
case "ShouldShowVPNPromo": {
return BrowserUtils.shouldShowVPNPromo();
case "ShouldShowPromo": {
return BrowserUtils.shouldShowPromo(
BrowserUtils.PromoType[aMessage.data.type]
);
}
case "SpecialMessageActionDispatch": {
SpecialMessageActions.handleAction(aMessage.data, browser);

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

@ -161,7 +161,7 @@ if CONFIG["MOZ_LINUX_32_SSE2_STARTUP_ERROR"]:
"-mfpmath=387",
]
for icon in ("firefox", "document", "newwindow", "newtab", "pbmode"):
for icon in ("firefox", "document", "newwindow", "newtab", "pbmode", "document_pdf"):
DEFINES[icon.upper() + "_ICO"] = '"%s/%s/%s.ico"' % (
TOPSRCDIR,
CONFIG["MOZ_BRANDING_DIRECTORY"],

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

@ -316,7 +316,7 @@ pref("browser.startup.preXulSkeletonUI", true);
#endif
// Show an upgrade dialog on major upgrades.
pref("browser.startup.upgradeDialog.enabled", false);
pref("browser.startup.upgradeDialog.enabled", true);
// Don't create the hidden window during startup on
// platforms that don't always need it (Win/Linux).

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

@ -12,6 +12,7 @@ IDI_APPLICATION ICON FIREFOX_ICO
IDI_NEWWINDOW ICON NEWWINDOW_ICO
IDI_NEWTAB ICON NEWTAB_ICO
IDI_PBMODE ICON PBMODE_ICO
IDI_DOCUMENT_PDF ICON DOCUMENT_PDF_ICO
STRINGTABLE DISCARDABLE
BEGIN

Двоичные данные
browser/branding/aurora/document_pdf.ico Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 20 KiB

Двоичные данные
browser/branding/nightly/document_pdf.ico Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 20 KiB

Двоичные данные
browser/branding/official/document_pdf.ico Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 20 KiB

Двоичные данные
browser/branding/unofficial/document_pdf.ico Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 20 KiB

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

@ -58,6 +58,8 @@ XPCOMUtils.defineLazyModuleGetters(this, {
NewTabUtils: "resource://gre/modules/NewTabUtils.jsm",
NimbusFeatures: "resource://nimbus/ExperimentAPI.jsm",
Normandy: "resource://normandy/Normandy.jsm",
OnboardingMessageProvider:
"resource://activity-stream/lib/OnboardingMessageProvider.jsm",
OsEnvironment: "resource://gre/modules/OsEnvironment.jsm",
PageActions: "resource:///modules/PageActions.jsm",
PageThumbs: "resource://gre/modules/PageThumbs.jsm",
@ -85,6 +87,8 @@ XPCOMUtils.defineLazyModuleGetters(this, {
ShellService: "resource:///modules/ShellService.jsm",
ShortcutUtils: "resource://gre/modules/ShortcutUtils.jsm",
SnapshotMonitor: "resource:///modules/SnapshotMonitor.jsm",
SpecialMessageActions:
"resource://messaging-system/lib/SpecialMessageActions.jsm",
TabCrashHandler: "resource:///modules/ContentCrashHandlers.jsm",
TabUnloader: "resource:///modules/TabUnloader.jsm",
TelemetryUtils: "resource://gre/modules/TelemetryUtils.jsm",
@ -4157,16 +4161,24 @@ BrowserGlue.prototype = {
Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
},
_showUpgradeDialog() {
BrowserWindowTracker.getTopWindow().gDialogBox.open(
"chrome://browser/content/upgradeDialog.html"
);
async _showUpgradeDialog() {
// TO DO Bug 1762666: Remove "chrome://browser/content/upgradeDialog.html"
const msg = await OnboardingMessageProvider.getUpgradeMessage();
const win = BrowserWindowTracker.getTopWindow();
const browser = win.gBrowser.selectedBrowser;
const config = {
type: "SHOW_SPOTLIGHT",
data: {
content: msg.content,
},
};
SpecialMessageActions.handleAction(config, browser);
},
async _maybeShowDefaultBrowserPrompt() {
// Highest priority is the upgrade dialog, which can include a "primary
// browser" request and is limited in various ways, e.g., major upgrades.
const dialogVersion = 94;
const dialogVersion = 100;
const dialogVersionPref = "browser.startup.upgradeDialog.version";
const dialogReason = await (async () => {
if (!BrowserHandler.majorUpgrade) {

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

@ -355,10 +355,12 @@ __webpack_require__.r(__webpack_exports__);
* 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/. */
const MS_STRING_PROP = "string_id";
const CONFIGURABLE_STYLES = ["color", "fontSize"];
const ZAP_SIZE_THRESHOLD = 160;
/**
* Based on the .text prop, localizes an inner element if a string_id
* is provided, OR renders plain text, OR hides it if nothing is provided.
* Allows configuring of some styles including zap underline and color.
*
* Examples:
*
@ -373,6 +375,7 @@ const MS_STRING_PROP = "string_id";
* Unlocalized text
* jsx:
* <Localized text="Welcome"><h1 /></Localized>
* <Localized text={{raw: "Welcome"}}><h1 /></Localized>
* output:
* <h1>Welcome</h1>
*/
@ -381,29 +384,55 @@ const Localized = ({
text,
children
}) => {
// Dynamically determine the size of the zap style.
const zapRef = /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createRef();
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
const {
current
} = zapRef;
if (current) requestAnimationFrame(() => current === null || current === void 0 ? void 0 : current.classList.replace("short", current.getBoundingClientRect().width > ZAP_SIZE_THRESHOLD ? "long" : "short"));
}); // Skip rendering of children with no text.
if (!text) {
return null;
}
} // Allow augmenting existing child container properties.
let props = children ? children.props : {};
let textNode;
if (typeof text === "object" && text[MS_STRING_PROP]) {
props = { ...props
};
props["data-l10n-id"] = text[MS_STRING_PROP];
const props = {
children: [],
className: "",
style: {},
...(children === null || children === void 0 ? void 0 : children.props)
}; // Support nested Localized by starting with their children.
const textNodes = props.children; // Pick desired fluent or raw/plain text to render.
if (text.string_id) {
props["data-l10n-id"] = text.string_id;
if (text.args) props["data-l10n-args"] = JSON.stringify(text.args);
} else if (text.raw) {
textNodes.push(text.raw);
} else if (typeof text === "string") {
textNode = text;
}
textNodes.push(text);
} // Add zap style and content in a way that allows fluent to insert too.
if (!children) {
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", props, textNode);
} else if (textNode) {
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().cloneElement(children, props, textNode);
}
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().cloneElement(children, props);
if (text.zap) {
props.className += " welcomeZap";
textNodes.push( /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", {
className: "short zap",
"data-l10n-name": "zap",
ref: zapRef
}, text.zap));
} // Apply certain configurable styles.
CONFIGURABLE_STYLES.forEach(style => {
if (text[style]) props.style[style] = text[style];
});
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().cloneElement( // Provide a default container for the text if necessary.
children ?? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null), props, // Conditionally pass in as void elements can't accept empty array.
textNodes.length ? textNodes : null);
};
/***/ }),
@ -497,9 +526,7 @@ const DEFAULT_RTAMO_CONTENT = {
string_id: "return-to-amo-addon-title"
},
help_text: {
text: {
string_id: "mr1-onboarding-welcome-image-caption"
}
string_id: "mr1-onboarding-welcome-image-caption"
},
backdrop: "#212121 url(chrome://activity-stream/content/data/content/assets/proton-bkg.avif) center/cover no-repeat fixed",
primary_button: {
@ -679,7 +706,7 @@ class ProtonScreen extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCom
}
render() {
var _this$props$appAndSys, _content$primary_butt;
var _this$props$appAndSys, _content$primary_butt, _content$primary_butt2;
const {
autoAdvance,
@ -716,11 +743,11 @@ class ProtonScreen extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCom
text: content.hero_text
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("h1", null)), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
className: "spacer-bottom"
})), content.help_text && content.help_text.text ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, {
text: content.help_text.text
})), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, {
text: content.help_text
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", {
className: "attrib-text"
})) : null) : null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
}))) : null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
className: "section-main"
}, content.secondary_button_top ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_5__.SecondaryCTA, {
content: content,
@ -749,19 +776,19 @@ class ProtonScreen extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCom
text: content.title
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("h1", {
id: "mainContentHeader"
})), content.subtitle ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, {
})), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, {
text: content.subtitle
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("h2", {
"data-l10n-args": JSON.stringify({
"addon-name": this.props.addonName,
...((_this$props$appAndSys = this.props.appAndSystemLocaleInfo) === null || _this$props$appAndSys === void 0 ? void 0 : _this$props$appAndSys.displayNames)
})
})) : null), this.renderContentTiles(), this.renderLanguageSwitcher(), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, {
text: content.primary_button ? content.primary_button.label : null
}))), this.renderContentTiles(), this.renderLanguageSwitcher(), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, {
text: (_content$primary_butt = content.primary_button) === null || _content$primary_butt === void 0 ? void 0 : _content$primary_butt.label
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", {
className: "primary",
value: "primary_button",
disabled: ((_content$primary_butt = content.primary_button) === null || _content$primary_butt === void 0 ? void 0 : _content$primary_butt.disabled) === true,
disabled: ((_content$primary_butt2 = content.primary_button) === null || _content$primary_butt2 === void 0 ? void 0 : _content$primary_butt2.disabled) === true,
onClick: this.props.handleAction
})), content.secondary_button ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_5__.SecondaryCTA, {
content: content,
@ -1077,7 +1104,7 @@ const Themes = props => {
onClick: props.handleAction
})), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
className: `icon ${theme === props.activeTheme ? " selected" : ""} ${theme}`
}), label && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, {
}), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, {
text: label
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
className: "text"
@ -1128,22 +1155,23 @@ function useLanguageSwitcher(appAndSystemLocaleInfo, screens, screenIndex, setSc
}
(async () => {
const langPack = await window.AWNegotiateLangPackForLanguageMismatch(appAndSystemLocaleInfo);
const {
langPack,
langPackDisplayName
} = await window.AWNegotiateLangPackForLanguageMismatch(appAndSystemLocaleInfo);
if (langPack) {
// Convert the BCP 47 identifiers into the proper display names.
// e.g. "fr-CA" -> "Canadian French".
const displayNames = new Intl.DisplayNames(appAndSystemLocaleInfo.appLocaleRaw, {
type: "language"
});
setNegotiatedLanguage({
displayName: displayNames.of(langPack.target_locale),
langPackDisplayName,
appDisplayName: appAndSystemLocaleInfo.displayNames.appLanguage,
langPack,
requestSystemLocales: [langPack.target_locale, appAndSystemLocaleInfo.appLocaleRaw]
requestSystemLocales: [langPack.target_locale, appAndSystemLocaleInfo.appLocaleRaw],
originalAppLocales: [appAndSystemLocaleInfo.appLocaleRaw]
});
} else {
setNegotiatedLanguage({
displayName: null,
langPackDisplayName: null,
appDisplayName: null,
langPack: null,
requestSystemLocales: null
});
@ -1226,12 +1254,12 @@ function LanguageSwitcher(props) {
}, [isAwaitingLangpack, langPackInstallPhase]); // The message args are the localized language names.
const withMessageArgs = obj => {
const displayName = negotiatedLanguage === null || negotiatedLanguage === void 0 ? void 0 : negotiatedLanguage.displayName;
const langPackDisplayName = negotiatedLanguage === null || negotiatedLanguage === void 0 ? void 0 : negotiatedLanguage.langPackDisplayName;
if (displayName) {
if (langPackDisplayName) {
return { ...obj,
args: { ...obj.args,
negotiatedLanguage: displayName
negotiatedLanguage: langPackDisplayName
}
};
}
@ -1311,25 +1339,24 @@ function LanguageSwitcher(props) {
style: {
display: showReadyScreen ? "block" : "none"
}
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, {
text: withMessageArgs(content.languageSwitcher.switch)
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", {
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", {
className: "primary",
value: "primary_button",
onClick: () => {
_lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_2__.AboutWelcomeUtils.sendActionTelemetry(messageId, "download_langpack");
setIsAwaitingLangpack(true);
}
}))), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
className: "secondary-cta"
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_1__.Localized, {
text: content.languageSwitcher.not_now
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", {
}, // This is the localized name from the Intl.DisplayNames API.
negotiatedLanguage === null || negotiatedLanguage === void 0 ? void 0 : negotiatedLanguage.langPackDisplayName)), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", {
type: "button",
className: "secondary text-link",
className: "secondary",
value: "decline",
onClick: handleAction
})))));
onClick: event => {
window.AWSetRequestedLocales(negotiatedLanguage.originalAppLocales);
handleAction(event);
}
}, // This is the localized name from the Intl.DisplayNames API.
negotiatedLanguage === null || negotiatedLanguage === void 0 ? void 0 : negotiatedLanguage.appDisplayName))));
}
/***/ }),

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

@ -266,11 +266,12 @@ body[lwt-newtab-brighttext] {
background-size: 100% 100%;
content: "";
position: absolute;
top: calc(100% - 0.15em);
top: 118%;
width: 100%;
height: 0.3em;
left: 0;
z-index: -1;
transform: scaleY(3);
}
.onboardingContainer .welcomeZap .zap.short::after {
background-image: url("chrome://activity-stream/content/data/content/assets/short-zap.svg");
@ -792,15 +793,21 @@ body[lwt-newtab-brighttext] {
.onboardingContainer .steps .indicator.current:last-of-type:first-of-type {
opacity: 0;
}
.onboardingContainer .primary {
.onboardingContainer .primary,
.onboardingContainer .secondary {
font-size: 13px;
line-height: 16px;
padding: 11px 15px;
transition: var(--transition);
}
.onboardingContainer .primary.rtamo {
.onboardingContainer .primary.rtamo,
.onboardingContainer .secondary.rtamo {
margin-top: 24px;
}
.onboardingContainer .secondary {
background-color: var(--in-content-button-background);
color: var(--in-content-button-text-color);
}
.onboardingContainer .noodle {
display: block;
background-repeat: no-repeat;
@ -845,7 +852,7 @@ body[lwt-newtab-brighttext] {
justify-content: center;
}
.onboardingContainer [pos=corner] .section-left .message-text .spacer-top {
flex: 2;
flex: 1;
}
.onboardingContainer [pos=corner] .section-left .message-text .spacer-bottom {
flex: 1;
@ -859,6 +866,7 @@ body[lwt-newtab-brighttext] {
max-width: 5em;
text-align: initial;
white-space: pre-wrap;
text-shadow: 0 4px 8px rgba(0, 0, 0, 0.35);
}
.onboardingContainer [pos=corner] .section-left .attrib-text {
height: 18px;
@ -876,12 +884,12 @@ body[lwt-newtab-brighttext] {
.onboardingContainer [pos=corner] .section-main .main-content {
background: transparent;
box-shadow: none;
display: block;
display: flex;
position: absolute;
height: 350px;
width: 295px;
bottom: -60px;
inset-inline-end: 80px;
height: auto;
width: 350px;
bottom: 0;
inset-inline-end: 30px;
transition: var(--transition);
}
.onboardingContainer [pos=corner] .section-main .brand-logo {
@ -898,6 +906,9 @@ body[lwt-newtab-brighttext] {
.onboardingContainer [pos=corner] .section-main .welcome-text {
transition-delay: 1.2s;
}
.onboardingContainer [pos=corner] .section-main .welcome-text h2 {
margin: 10px 6px;
}
.onboardingContainer [pos=corner] .solid-L {
width: 1300px;
height: 1050px;
@ -962,6 +973,7 @@ body[lwt-newtab-brighttext] {
transition-delay: 0.9s;
}
.onboardingContainer .dialog-initial .primary,
.onboardingContainer .dialog-initial .secondary,
.onboardingContainer .dialog-initial .secondary-cta,
.onboardingContainer .dialog-initial .steps {
transition-delay: 1s;
@ -971,6 +983,7 @@ body[lwt-newtab-brighttext] {
transition-delay: 0.2s;
}
.onboardingContainer .screen:not(.dialog-initial):not([pos=corner]) .primary,
.onboardingContainer .screen:not(.dialog-initial):not([pos=corner]) .secondary,
.onboardingContainer .screen:not(.dialog-initial):not([pos=corner]) .secondary-cta {
transition-delay: 0.4s;
}
@ -1013,6 +1026,7 @@ body[lwt-newtab-brighttext] {
.onboardingContainer.transition-in [pos=corner] .brand-logo,
.onboardingContainer.transition-in [pos=corner] .welcome-text,
.onboardingContainer.transition-in [pos=corner] .primary,
.onboardingContainer.transition-in [pos=corner] .secondary,
.onboardingContainer.transition-in [pos=corner] .secondary-cta:not(.top),
.onboardingContainer.transition-in [pos=corner] .message-text {
opacity: 0;
@ -1037,6 +1051,7 @@ body[lwt-newtab-brighttext] {
.onboardingContainer.transition-in .screen:not([pos=corner]) .colorway-variations,
.onboardingContainer.transition-in .screen:not([pos=corner]) .tiles-theme-section,
.onboardingContainer.transition-in .screen:not([pos=corner]) .primary,
.onboardingContainer.transition-in .screen:not([pos=corner]) .secondary,
.onboardingContainer.transition-in .screen:not([pos=corner]) .secondary-cta:not(.top) {
opacity: 0;
translate: 0 calc(-1 * var(--translate));
@ -1079,6 +1094,7 @@ body[lwt-newtab-brighttext] {
transition-delay: 0.2s;
}
.onboardingContainer.transition-out .screen:not(.dialog-last):not([pos=corner]) .primary,
.onboardingContainer.transition-out .screen:not(.dialog-last):not([pos=corner]) .secondary,
.onboardingContainer.transition-out .screen:not(.dialog-last):not([pos=corner]) .secondary-cta:not(.top) {
opacity: 0;
translate: 0 var(--translate);

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

@ -21,7 +21,7 @@ const DEFAULT_WELCOME_CONTENT = {
template: "multistage",
transitions: true,
backdrop:
"#212121 url(chrome://activity-stream/content/data/content/assets/proton-bkg.avif) center/cover no-repeat fixed",
"#F9F9FB url('chrome://activity-stream/content/data/content/assets/fx100-noodles.svg') center/cover no-repeat fixed",
screens: [
{
id: "AW_PIN_FIREFOX",
@ -30,20 +30,21 @@ const DEFAULT_WELCOME_CONTENT = {
position: "corner",
logo: {},
title: {
string_id: "mr1-onboarding-pin-header",
string_id: "onboarding-welcome-header",
},
subtitle: {
string_id: "fx100-thank-you-subtitle",
},
hero_text: {
string_id: "mr1-welcome-screen-hero-text",
},
help_text: {
text: {
string_id: "mr1-onboarding-welcome-image-caption",
},
string_id: "fx100-thank-you-hero-text",
color: "#321C64",
zap: true,
fontSize: "clamp(48px, 7vw, 137px)",
},
has_noodles: true,
primary_button: {
label: {
string_id: "mr1-onboarding-pin-primary-button-label",
string_id: "fx100-thank-you-pin-primary-button-label",
},
action: {
navigate: true,
@ -61,6 +62,7 @@ const DEFAULT_WELCOME_CONTENT = {
secondary_button_top: {
label: {
string_id: "mr1-onboarding-sign-in-button-label",
color: "#321C64",
},
action: {
data: {
@ -78,21 +80,14 @@ const DEFAULT_WELCOME_CONTENT = {
content: {
logo: {},
title: { string_id: "onboarding-live-language-header" },
subtitle: { string_id: "onboarding-live-language-subtitle" },
has_noodles: true,
languageSwitcher: {
switch: {
string_id: "onboarding-live-language-switch-button-label",
},
downloading: {
string_id: "onboarding-live-language-button-label-downloading",
},
cancel: {
string_id: "onboarding-live-language-secondary-cancel-download",
},
not_now: {
string_id: "onboarding-live-language-not-now-button-label",
},
waiting: { string_id: "onboarding-live-language-waiting-button" },
skip: { string_id: "onboarding-live-language-skip-button-label" },
action: {
@ -441,7 +436,7 @@ async function prepareContentForReact(content) {
if (Services.locale.appLocaleAsBCP47.split("-")[0] !== "en") {
delete content.screens?.find(
screen => screen.content?.help_text?.deleteIfNotEn
)?.content.help_text.text;
)?.content.help_text;
}
let shouldRemoveLanguageMismatchScreen = true;

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

@ -291,11 +291,12 @@ body {
background-size: 100% 100%;
content: '';
position: absolute;
top: calc(100% - 0.15em);
top: 118%;
width: 100%;
height: 0.3em;
left: 0;
z-index: -1;
transform: scaleY(3);
}
&.short::after {
@ -969,7 +970,8 @@ body {
}
}
.primary {
.primary,
.secondary {
font-size: 13px;
line-height: 16px;
padding: 11px 15px;
@ -980,6 +982,11 @@ body {
}
}
.secondary {
background-color: var(--in-content-button-background);
color: var(--in-content-button-text-color);
}
// Styles specific to background noodles, with screen-by-screen positions
.noodle {
display: block;
@ -1032,7 +1039,7 @@ body {
justify-content: center;
.spacer-top {
flex: 2;
flex: 1;
}
.spacer-bottom {
@ -1048,6 +1055,7 @@ body {
max-width: 5em;
text-align: initial;
white-space: pre-wrap;
text-shadow: 0 4px 8px rgba(0, 0, 0, 0.35);
}
}
@ -1069,12 +1077,12 @@ body {
.main-content {
background: transparent;
box-shadow: none;
display: block;
display: flex;
position: absolute;
height: 350px;
width: 295px;
bottom: -60px;
inset-inline-end: 80px;
height: auto;
width: 350px;
bottom: 0;
inset-inline-end: 30px;
transition: var(--transition);
}
@ -1094,6 +1102,10 @@ body {
.welcome-text {
transition-delay: 1.2s;
h2 {
margin: 10px 6px;
}
}
}
@ -1180,6 +1192,7 @@ body {
}
.primary,
.secondary,
.secondary-cta,
.steps {
transition-delay: 1s;
@ -1194,6 +1207,7 @@ body {
}
.primary,
.secondary,
.secondary-cta {
transition-delay: 0.4s;
}
@ -1249,6 +1263,7 @@ body {
.brand-logo,
.welcome-text,
.primary,
.secondary,
.secondary-cta:not(.top),
.message-text {
opacity: 0;
@ -1284,6 +1299,7 @@ body {
.colorway-variations,
.tiles-theme-section,
.primary,
.secondary,
.secondary-cta:not(.top) {
opacity: 0;
translate: 0 calc(-1 * var(--translate));
@ -1342,6 +1358,7 @@ body {
}
.primary,
.secondary,
.secondary-cta:not(.top) {
opacity: 0;
translate: 0 var(--translate);

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

@ -36,28 +36,27 @@ export function useLanguageSwitcher(
}
(async () => {
const langPack = await window.AWNegotiateLangPackForLanguageMismatch(
const {
langPack,
langPackDisplayName,
} = await window.AWNegotiateLangPackForLanguageMismatch(
appAndSystemLocaleInfo
);
if (langPack) {
// Convert the BCP 47 identifiers into the proper display names.
// e.g. "fr-CA" -> "Canadian French".
const displayNames = new Intl.DisplayNames(
appAndSystemLocaleInfo.appLocaleRaw,
{ type: "language" }
);
setNegotiatedLanguage({
displayName: displayNames.of(langPack.target_locale),
langPackDisplayName,
appDisplayName: appAndSystemLocaleInfo.displayNames.appLanguage,
langPack,
requestSystemLocales: [
langPack.target_locale,
appAndSystemLocaleInfo.appLocaleRaw,
],
originalAppLocales: [appAndSystemLocaleInfo.appLocaleRaw],
});
} else {
setNegotiatedLanguage({
displayName: null,
langPackDisplayName: null,
appDisplayName: null,
langPack: null,
requestSystemLocales: null,
});
@ -160,13 +159,13 @@ export function LanguageSwitcher(props) {
// The message args are the localized language names.
const withMessageArgs = obj => {
const displayName = negotiatedLanguage?.displayName;
if (displayName) {
const langPackDisplayName = negotiatedLanguage?.langPackDisplayName;
if (langPackDisplayName) {
return {
...obj,
args: {
...obj.args,
negotiatedLanguage: displayName,
negotiatedLanguage: langPackDisplayName,
},
};
}
@ -189,6 +188,7 @@ export function LanguageSwitcher(props) {
// the localized text elements rendering as blank, then filling in the text.
return (
<>
{/* Pre-loading screen */}
<div style={{ display: showPreloadingScreen ? "block" : "none" }}>
<button
className="primary"
@ -214,6 +214,7 @@ export function LanguageSwitcher(props) {
</Localized>
</div>
</div>
{/* Waiting to download the language screen. */}
<div style={{ display: showWaitingScreen ? "block" : "none" }}>
<button
className="primary"
@ -245,31 +246,43 @@ export function LanguageSwitcher(props) {
</Localized>
</div>
</div>
{/* The typical ready screen. */}
<div style={{ display: showReadyScreen ? "block" : "none" }}>
<div>
<Localized text={withMessageArgs(content.languageSwitcher.switch)}>
<button
className="primary"
value="primary_button"
onClick={() => {
AboutWelcomeUtils.sendActionTelemetry(
messageId,
"download_langpack"
);
setIsAwaitingLangpack(true);
}}
/>
</Localized>
<button
className="primary"
value="primary_button"
onClick={() => {
AboutWelcomeUtils.sendActionTelemetry(
messageId,
"download_langpack"
);
setIsAwaitingLangpack(true);
}}
>
{
// This is the localized name from the Intl.DisplayNames API.
negotiatedLanguage?.langPackDisplayName
}
</button>
</div>
<div className="secondary-cta">
<Localized text={content.languageSwitcher.not_now}>
<button
type="button"
className="secondary text-link"
value="decline"
onClick={handleAction}
/>
</Localized>
<div>
<button
type="button"
className="secondary"
value="decline"
onClick={event => {
window.AWSetRequestedLocales(
negotiatedLanguage.originalAppLocales
);
handleAction(event);
}}
>
{
// This is the localized name from the Intl.DisplayNames API.
negotiatedLanguage?.appDisplayName
}
</button>
</div>
</div>
</>

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

@ -2,12 +2,14 @@
* 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/. */
import React from "react";
const MS_STRING_PROP = "string_id";
import React, { useEffect } from "react";
const CONFIGURABLE_STYLES = ["color", "fontSize"];
const ZAP_SIZE_THRESHOLD = 160;
/**
* Based on the .text prop, localizes an inner element if a string_id
* is provided, OR renders plain text, OR hides it if nothing is provided.
* Allows configuring of some styles including zap underline and color.
*
* Examples:
*
@ -22,30 +24,67 @@ const MS_STRING_PROP = "string_id";
* Unlocalized text
* jsx:
* <Localized text="Welcome"><h1 /></Localized>
* <Localized text={{raw: "Welcome"}}><h1 /></Localized>
* output:
* <h1>Welcome</h1>
*/
export const Localized = ({ text, children }) => {
// Dynamically determine the size of the zap style.
const zapRef = React.createRef();
useEffect(() => {
const { current } = zapRef;
if (current)
requestAnimationFrame(() =>
current?.classList.replace(
"short",
current.getBoundingClientRect().width > ZAP_SIZE_THRESHOLD
? "long"
: "short"
)
);
});
// Skip rendering of children with no text.
if (!text) {
return null;
}
let props = children ? children.props : {};
let textNode;
// Allow augmenting existing child container properties.
const props = { children: [], className: "", style: {}, ...children?.props };
// Support nested Localized by starting with their children.
const textNodes = props.children;
if (typeof text === "object" && text[MS_STRING_PROP]) {
props = { ...props };
props["data-l10n-id"] = text[MS_STRING_PROP];
// Pick desired fluent or raw/plain text to render.
if (text.string_id) {
props["data-l10n-id"] = text.string_id;
if (text.args) props["data-l10n-args"] = JSON.stringify(text.args);
} else if (text.raw) {
textNodes.push(text.raw);
} else if (typeof text === "string") {
textNode = text;
textNodes.push(text);
}
if (!children) {
return React.createElement("span", props, textNode);
} else if (textNode) {
return React.cloneElement(children, props, textNode);
// Add zap style and content in a way that allows fluent to insert too.
if (text.zap) {
props.className += " welcomeZap";
textNodes.push(
<span className="short zap" data-l10n-name="zap" ref={zapRef}>
{text.zap}
</span>
);
}
return React.cloneElement(children, props);
// Apply certain configurable styles.
CONFIGURABLE_STYLES.forEach(style => {
if (text[style]) props.style[style] = text[style];
});
return React.cloneElement(
// Provide a default container for the text if necessary.
children ?? <span />,
props,
// Conditionally pass in as void elements can't accept empty array.
textNodes.length ? textNodes : null
);
};

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

@ -197,11 +197,9 @@ export class ProtonScreen extends React.PureComponent {
</Localized>
<div className="spacer-bottom" />
</div>
{content.help_text && content.help_text.text ? (
<Localized text={content.help_text.text}>
<span className="attrib-text" />
</Localized>
) : null}
<Localized text={content.help_text}>
<span className="attrib-text" />
</Localized>
</div>
) : null}
<div className="section-main">
@ -237,25 +235,19 @@ export class ProtonScreen extends React.PureComponent {
<Localized text={content.title}>
<h1 id="mainContentHeader" />
</Localized>
{content.subtitle ? (
<Localized text={content.subtitle}>
<h2
data-l10n-args={JSON.stringify({
"addon-name": this.props.addonName,
...this.props.appAndSystemLocaleInfo?.displayNames,
})}
/>
</Localized>
) : null}
<Localized text={content.subtitle}>
<h2
data-l10n-args={JSON.stringify({
"addon-name": this.props.addonName,
...this.props.appAndSystemLocaleInfo?.displayNames,
})}
/>
</Localized>
</div>
{this.renderContentTiles()}
{this.renderLanguageSwitcher()}
<div>
<Localized
text={
content.primary_button ? content.primary_button.label : null
}
>
<Localized text={content.primary_button?.label}>
<button
className="primary"
value="primary_button"

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

@ -37,11 +37,9 @@ export const Themes = props => {
theme === props.activeTheme ? " selected" : ""
} ${theme}`}
/>
{label && (
<Localized text={label}>
<div className="text" />
</Localized>
)}
<Localized text={label}>
<div className="text" />
</Localized>
</label>
</Localized>
)

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

@ -37,6 +37,11 @@
"type": "boolean",
"description": "Should we show the promo section."
},
"promoType": {
"type": "string",
"description": "Promo type used to determine if promo should show to a given user",
"enum": ["FOCUS", "RALLY", "VPN"]
},
"promoSectionStyle": {
"type": "string",
"description": "Sets the position of the promo section. Possible values are: top, below-search, bottom. Default bottom.",

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

@ -64,9 +64,7 @@ export const DEFAULT_RTAMO_CONTENT = {
string_id: "return-to-amo-addon-title",
},
help_text: {
text: {
string_id: "mr1-onboarding-welcome-image-caption",
},
string_id: "mr1-onboarding-welcome-image-caption",
},
backdrop:
"#212121 url(chrome://activity-stream/content/data/content/assets/proton-bkg.avif) center/cover no-repeat fixed",

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

@ -0,0 +1,34 @@
<!-- 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/. -->
<svg width="1300" height="715" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#a)">
<g opacity=".7" filter="url(#b)">
<path d="M125.07-5.46c-12.908-54.724 20.496-109.862 74.418-122.822 53.366-12.826 106.727 20.527 119.502 74.687l69.818 295.987c13.036 55.266-21.156 110.827-75.779 123.138L20.483 431.467c-53.53 12.065-106.427-22.041-118.457-76.384-12.155-54.91 22.008-109.567 76.095-121.757l193.012-43.503L125.07-5.461Z" fill="#E31587"/>
</g>
<path d="M64.835 670.269c-5.48-8.343-3.342-19.587 4.826-25.391l.489-.341c7.823-5.561 9.81-16.386 4.412-24.321-5.398-7.936-16.157-10.007-24.154-4.702l-.496.335c-8.434 5.593-19.779 3.41-25.47-4.957-5.748-8.451-3.552-20.011 4.907-25.82 24.937-17.127 58.894-10.81 75.844 14.108 16.949 24.918 10.474 59.002-14.464 76.128-8.374 5.751-19.746 3.709-25.55-4.532l-.174-.252-.17-.255Z" fill="#952BB9"/>
<path d="M764.826 415.888c23.537-8.214 36.193-33.844 28.189-57.094-7.922-23.01-33.109-35.013-56.403-26.884l-127.308 44.43c-23.771 8.296-36.397 34.321-27.984 57.679l45.061 125.096c8.245 22.89 33.603 34.541 56.789 26.089 23.428-8.541 35.723-34.339 27.392-57.467l-29.73-82.535 83.994-29.314Z" fill="url(#c)"/>
<path d="M939.5 153c13.531 0 24.5 11.034 24.5 24.646 0 13.611-10.969 24.646-24.5 24.646S915 191.257 915 177.646C915 164.034 925.969 153 939.5 153Z" fill="#E31587"/>
<path d="M121.156 558.957c-7.194 2.163-14.846-2.136-17.091-9.603-2.246-7.467 1.766-15.274 8.96-17.437 7.194-2.163 14.846 2.136 17.091 9.603 2.245 7.467-1.766 15.274-8.96 17.437Z" fill="#FFBD4F"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M724.773 71.552c10.252-6.893 24.438-4.396 31.757 5.662l43.934 60.551c7.416 10.213 5.031 24.276-5.295 31.48-10.325 7.203-24.652 4.738-32.068-5.474l-43.934-60.551c-7.304-10.12-5.09-24.028 4.982-31.29l.312-.19.312-.188Z" fill="#00B3F4"/>
<path fill="url(#d)" d="M0-2h1300v717H0z"/>
</g>
<defs>
<linearGradient id="c" x1="640.325" y1="564.576" x2="659.689" y2="229.176" gradientUnits="userSpaceOnUse">
<stop stop-color="#FF8A16"/>
<stop offset="1" stop-color="#FFE747"/>
</linearGradient>
<linearGradient id="d" x1="613.039" y1="325.083" x2="2023.59" y2="1251.63" gradientUnits="userSpaceOnUse">
<stop stop-color="#fff" stop-opacity="0"/>
<stop offset="1" stop-color="#E50080"/>
</linearGradient>
<clipPath id="a">
<path fill="#fff" d="M0 0h1300v715H0z"/>
</clipPath>
<filter id="b" x="-192.43" y="-223.025" width="676.011" height="748.918" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="46" result="effect1_foregroundBlur_1959_49340"/>
</filter>
</defs>
</svg>

После

Ширина:  |  Высота:  |  Размер: 3.0 KiB

Двоичные данные
browser/components/newtab/data/content/assets/heart.gif Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 70 KiB

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

@ -1,4 +1,4 @@
<!-- 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/. -->
<svg data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 16" width="400" height="16"><defs><linearGradient id="a" y1="13.69" x2="435.45" y2="13.69" gradientUnits="userSpaceOnUse" gradientTransform="matrix(.91716 0 0 .7708 .27 .687)"><stop offset="0" stop-color="#616eb3"/><stop offset=".5" stop-color="#ec1067"/><stop offset="1" stop-color="#f6901e"/></linearGradient></defs><path vector-effect="non-scaling-stroke" d="M4.45 2.81c96.1 9.33 158.63 4.37 195.55 2.68 51.53-2.35 183.67-4.32 193.85-1.91 9.32 2.21-81.45-.12-114.57 7.08C258 15.28 315.1 7.17 322.94 14" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" stroke="url(#a)"/></svg>
<svg data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 16" width="400" height="16"><defs><linearGradient id="a" y1="13.69" x2="435.45" y2="13.69" gradientUnits="userSpaceOnUse" gradientTransform="matrix(.91716 0 0 .7708 .27 .687)"><stop offset="0" stop-color="#616eb3"/><stop offset=".5" stop-color="#ec1067"/><stop offset="1" stop-color="#f6901e"/></linearGradient></defs><path d="M4.45 2.81c96.1 9.33 158.63 4.37 195.55 2.68 51.53-2.35 183.67-4.32 193.85-1.91 9.32 2.21-81.45-.12-114.57 7.08C258 15.28 315.1 7.17 322.94 14" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" stroke="url(#a)"/></svg>

До

Ширина:  |  Высота:  |  Размер: 895 B

После

Ширина:  |  Высота:  |  Размер: 860 B

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

@ -1,4 +1,4 @@
<!-- 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/. -->
<svg data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 16" width="400" height="16"><defs><linearGradient id="a" y1="13.69" x2="435.45" y2="13.69" gradientUnits="userSpaceOnUse" gradientTransform="matrix(.91716 0 0 .7708 .27 .687)"><stop offset="0" stop-color="#616eb3"/><stop offset=".5" stop-color="#ec1067"/><stop offset="1" stop-color="#f6901e"/></linearGradient></defs><path vector-effect="non-scaling-stroke" d="M3.12 14c161-19.73 207.41 3 223.21-.65 16.76-3.85 20-6.77 31.28-10.29 18.08-5.64-2.49 13.2 8.14 10.71 16.45-3.84 27.73-7.39 39.25-9.4 15-2.6-2 22.49 87.48-2.37" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" stroke="url(#a)"/></svg>
<svg data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 16" width="400" height="16"><defs><linearGradient id="a" y1="13.69" x2="435.45" y2="13.69" gradientUnits="userSpaceOnUse" gradientTransform="matrix(.91716 0 0 .7708 .27 .687)"><stop offset="0" stop-color="#616eb3"/><stop offset=".5" stop-color="#ec1067"/><stop offset="1" stop-color="#f6901e"/></linearGradient></defs><path d="M3.12 14c161-19.73 207.41 3 223.21-.65 16.76-3.85 20-6.77 31.28-10.29 18.08-5.64-2.49 13.2 8.14 10.71 16.45-3.84 27.73-7.39 39.25-9.4 15-2.6-2 22.49 87.48-2.37" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" stroke="url(#a)"/></svg>

До

Ширина:  |  Высота:  |  Размер: 913 B

После

Ширина:  |  Высота:  |  Размер: 878 B

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

@ -1432,11 +1432,25 @@ class _ASRouter {
}
// Update storage
this._storage.set("groupImpressions", newGroupImpressions);
// The groups parameter below can be removed once this method has test coverage
return this.setState(({ groups }) => ({
groupImpressions: newGroupImpressions,
}));
}
// Until this method has test coverage, it should only be used for testing
_resetMessageState() {
const newMessageImpressions = {};
for (let { id } of this.state.messages) {
newMessageImpressions[id] = [];
}
// Update storage
this._storage.set("messageImpressions", newMessageImpressions);
return this.setState(() => ({
messageImpressions: newMessageImpressions,
}));
}
_validPreviewEndpoint(url) {
try {
const endpoint = new URL(url);

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

@ -3,7 +3,15 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/* globals Localization */
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
XPCOMUtils.defineLazyModuleGetters(this, {
Services: "resource://gre/modules/Services.jsm",
ShellService: "resource:///modules/ShellService.jsm",
});
const L10N = new Localization([
"branding/brand.ftl",
@ -37,6 +45,54 @@ const ONBOARDING_MESSAGES = () => [
},
trigger: { id: "protectionsPanelOpen" },
},
{
id: "FX_100_UPGRADE",
template: "spotlight",
targeting: "false",
content: {
template: "multistage",
id: "FX_100_UPGRADE",
screens: [
{
id: "UPGRADE_PIN_FIREFOX",
order: 0,
content: {
logo: {
imageURL:
"chrome://activity-stream/content/data/content/assets/heart.gif",
height: "73px",
},
title: {
string_id: "fx100-upgrade-thanks-header",
},
title_style: "fancy",
background:
"url(chrome://activity-stream/content/data/content/assets/confetti.svg) top / 100% no-repeat var(--in-content-page-background)",
subtitle: {
string_id: "fx100-upgrade-thanks-keep-body",
},
primary_button: {
label: {
string_id: "fx100-thank-you-pin-primary-button-label",
},
action: {
navigate: true,
type: "PIN_FIREFOX_TO_TASKBAR",
},
},
secondary_button: {
label: {
string_id: "mr1-onboarding-set-default-secondary-button-label",
},
action: {
navigate: true,
},
},
},
},
],
},
},
{
id: "PB_NEWTAB_FOCUS_PROMO",
template: "pb_newtab",
@ -49,6 +105,7 @@ const ONBOARDING_MESSAGES = () => [
infoTitle: "",
infoTitleEnabled: false,
promoEnabled: true,
promoType: "FOCUS",
promoHeader: "fluent:about-private-browsing-focus-promo-header",
promoImageLarge: "chrome://browser/content/assets/focus-promo.png",
promoLinkText: "fluent:about-private-browsing-focus-promo-cta",
@ -208,6 +265,47 @@ const OnboardingMessageProvider = {
}
return translatedMessages;
},
async _doesAppNeedPin() {
const needPin = await ShellService.doesAppNeedPin();
return needPin;
},
async _doesAppNeedDefault() {
let checkDefault = Services.prefs.getBoolPref(
"browser.shell.checkDefaultBrowser",
false
);
let isDefault = await ShellService.isDefaultBrowser();
return checkDefault && !isDefault;
},
async getUpgradeMessage() {
let message = (await OnboardingMessageProvider.getMessages()).find(
({ id }) => id === "FX_100_UPGRADE"
);
let { content } = message;
let pinScreen = content.screens?.find(
screen => screen.id === "UPGRADE_PIN_FIREFOX"
);
const needPin = await this._doesAppNeedPin();
const needDefault = await this._doesAppNeedDefault();
// If user doesn't need pin, update screen to set "default" or "get started" configuration
if (!needPin && pinScreen) {
let primary = pinScreen.content.primary_button;
if (needDefault) {
pinScreen.id = "UPGRADE_ONLY_DEFAULT";
primary.label.string_id =
"mr1-onboarding-set-default-only-primary-button-label";
primary.action.type = "SET_DEFAULT_BROWSER";
} else {
pinScreen.id = "UPGRADE_GET_STARTED";
pinScreen.content.subtitle.string_id = "fx100-upgrade-thank-you-body";
primary.label.string_id = "mr2-onboarding-start-browsing-button-label";
delete primary.action.type;
delete pinScreen.content.secondary_button;
}
}
return message;
},
};
this.OnboardingMessageProvider = OnboardingMessageProvider;

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

@ -640,6 +640,7 @@ const MESSAGES = () => [
template: "pb_newtab",
content: {
promoEnabled: true,
promoType: "VPN",
infoEnabled: true,
infoIcon: "",
infoTitle: "",

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

@ -143,7 +143,7 @@ add_task(async function test_multistage_aboutwelcome_proton() {
[
"main.AW_STEP1",
"div.onboardingContainer",
"div.proton[style*='.avif']",
"div.proton[style*='chrome://activity-stream/content/data/content/assets']",
"div.section-left",
"span.attrib-text",
"div.secondary-cta.top",
@ -184,7 +184,7 @@ add_task(async function test_multistage_aboutwelcome_proton() {
[
"main.AW_STEP2.dialog-initial",
"div.onboardingContainer",
"div.proton[style*='.avif']",
"div.proton[style*='chrome://activity-stream/content/data/content/assets']",
"div.section-main",
"nav.steps",
"div.indicator.current",
@ -205,7 +205,7 @@ add_task(async function test_multistage_aboutwelcome_proton() {
[
"main.AW_STEP3",
"div.onboardingContainer",
"div.proton[style*='.avif']",
"div.proton[style*='chrome://activity-stream/content/data/content/assets']",
"div.section-main",
"div.tiles-theme-container",
"nav.steps",

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

@ -104,9 +104,9 @@ async function testScreenContent(
unexpectedSelectors: unexpected,
}) => {
function selectorIsVisible(selector) {
const el = content.document.querySelector(selector);
const els = content.document.querySelectorAll(selector);
// The offsetParent will be null if element is hidden through "display: none;"
return el && el.offsetParent !== null;
return [...els].some(el => el.offsetParent !== null);
}
for (let selector of expected) {
@ -165,7 +165,11 @@ const liveLanguageSwitchSelectors = [
*/
add_task(async function test_aboutwelcome_languageSwitcher_accept() {
sandbox.restore();
const { resolveLangPacks, resolveInstaller } = mockAddonAndLocaleAPIs({
const {
resolveLangPacks,
resolveInstaller,
mockable,
} = mockAddonAndLocaleAPIs({
systemLocale: "es-ES",
appLocale: "en-US",
});
@ -200,8 +204,8 @@ add_task(async function test_aboutwelcome_languageSwitcher_accept() {
// Expected selectors:
[
...liveLanguageSwitchSelectors,
`[data-l10n-id="onboarding-live-language-switch-button-label"]`,
`[data-l10n-id="onboarding-live-language-not-now-button-label"]`,
`button.primary[value="primary_button"]`,
`button.secondary[value="decline"]`,
],
// Unexpected selectors:
[
@ -239,17 +243,22 @@ add_task(async function test_aboutwelcome_languageSwitcher_accept() {
},
]);
sinon.assert.notCalled(mockable.setRequestedAppLocales);
await resolveInstaller();
await testScreenContent(
browser,
"Language selection declined",
"Language changed",
// Expected selectors:
[`.screen-2`],
// Unexpected selectors:
liveLanguageSwitchSelectors
);
info("The app locale was changed to the OS locale.");
sinon.assert.calledWith(mockable.setRequestedAppLocales, ["es-ES", "en-US"]);
eventsMatch(flushClickTelemetry(), [
{
event: "CLICK_BUTTON",
@ -269,7 +278,11 @@ add_task(async function test_aboutwelcome_languageSwitcher_accept() {
*/
add_task(async function test_aboutwelcome_languageSwitcher_accept() {
sandbox.restore();
const { resolveLangPacks, resolveInstaller } = mockAddonAndLocaleAPIs({
const {
resolveLangPacks,
resolveInstaller,
mockable,
} = mockAddonAndLocaleAPIs({
systemLocale: "es-ES",
appLocale: "en-US",
});
@ -304,8 +317,8 @@ add_task(async function test_aboutwelcome_languageSwitcher_accept() {
// Expected selectors:
[
...liveLanguageSwitchSelectors,
`[data-l10n-id="onboarding-live-language-switch-button-label"]`,
`[data-l10n-id="onboarding-live-language-not-now-button-label"]`,
`button.primary[value="primary_button"]`,
`button.secondary[value="decline"]`,
],
// Unexpected selectors:
[
@ -343,16 +356,20 @@ add_task(async function test_aboutwelcome_languageSwitcher_accept() {
},
]);
sinon.assert.notCalled(mockable.setRequestedAppLocales);
await resolveInstaller();
await testScreenContent(
browser,
"Language selection declined",
"Language selection accepted",
// Expected selectors:
[`.screen-2`],
// Unexpected selectors:
liveLanguageSwitchSelectors
);
info("The app locale was changed to the OS locale.");
sinon.assert.calledWith(mockable.setRequestedAppLocales, ["es-ES", "en-US"]);
});
/**
@ -362,7 +379,11 @@ add_task(async function test_aboutwelcome_languageSwitcher_accept() {
*/
add_task(async function test_aboutwelcome_languageSwitcher_decline() {
sandbox.restore();
const { resolveLangPacks, resolveInstaller } = mockAddonAndLocaleAPIs({
const {
resolveLangPacks,
resolveInstaller,
mockable,
} = mockAddonAndLocaleAPIs({
systemLocale: "es-ES",
appLocale: "en-US",
});
@ -398,8 +419,8 @@ add_task(async function test_aboutwelcome_languageSwitcher_decline() {
// Expected selectors:
[
...liveLanguageSwitchSelectors,
`[data-l10n-id="onboarding-live-language-switch-button-label"]`,
`[data-l10n-id="onboarding-live-language-not-now-button-label"]`,
`button.primary[value="primary_button"]`,
`button.secondary[value="decline"]`,
],
// Unexpected selectors:
[
@ -408,6 +429,8 @@ add_task(async function test_aboutwelcome_languageSwitcher_decline() {
]
);
sinon.assert.notCalled(mockable.setRequestedAppLocales);
info("Clicking the secondary button to skip installing the langpack.");
await clickVisibleButton(browser, "button.secondary");
@ -420,6 +443,9 @@ add_task(async function test_aboutwelcome_languageSwitcher_decline() {
liveLanguageSwitchSelectors
);
info("The requested locale should be set to the original en-US");
sinon.assert.calledWith(mockable.setRequestedAppLocales, ["en-US"]);
eventsMatch(flushClickTelemetry(), [
{
event: "CLICK_BUTTON",
@ -471,7 +497,7 @@ add_task(async function test_aboutwelcome_languageSwitcher_asyncCalls() {
*/
add_task(async function test_aboutwelcome_languageSwitcher_noMatch() {
sandbox.restore();
const { resolveLangPacks } = mockAddonAndLocaleAPIs({
const { resolveLangPacks, mockable } = mockAddonAndLocaleAPIs({
systemLocale: "tlh", // Klingon
appLocale: "en-US",
});
@ -495,6 +521,7 @@ add_task(async function test_aboutwelcome_languageSwitcher_noMatch() {
`[data-l10n-id="onboarding-live-language-header"]`,
]
);
sinon.assert.notCalled(mockable.setRequestedAppLocales);
});
/**
@ -504,7 +531,7 @@ add_task(async function test_aboutwelcome_languageSwitcher_bidiNotSupported() {
sandbox.restore();
await pushPrefs(["intl.multilingual.liveReloadBidirectional", false]);
mockAddonAndLocaleAPIs({
const { mockable } = mockAddonAndLocaleAPIs({
systemLocale: "ar-EG", // Arabic (Egypt)
appLocale: "en-US",
});
@ -525,6 +552,8 @@ add_task(async function test_aboutwelcome_languageSwitcher_bidiNotSupported() {
`[data-l10n-id="onboarding-live-language-header"]`,
]
);
sinon.assert.notCalled(mockable.setRequestedAppLocales);
});
/**
@ -534,7 +563,7 @@ add_task(async function test_aboutwelcome_languageSwitcher_bidiNotSupported() {
sandbox.restore();
await pushPrefs(["intl.multilingual.liveReloadBidirectional", true]);
const { resolveLangPacks } = mockAddonAndLocaleAPIs({
const { resolveLangPacks, mockable } = mockAddonAndLocaleAPIs({
systemLocale: "ar-EG", // Arabic (Egypt)
appLocale: "en-US",
});
@ -554,6 +583,8 @@ add_task(async function test_aboutwelcome_languageSwitcher_bidiNotSupported() {
// Unexpected selectors:
[]
);
sinon.assert.notCalled(mockable.setRequestedAppLocales);
});
/**
@ -561,7 +592,11 @@ add_task(async function test_aboutwelcome_languageSwitcher_bidiNotSupported() {
*/
add_task(async function test_aboutwelcome_languageSwitcher_cancelWaiting() {
sandbox.restore();
const { resolveLangPacks, resolveInstaller } = mockAddonAndLocaleAPIs({
const {
resolveLangPacks,
resolveInstaller,
mockable,
} = mockAddonAndLocaleAPIs({
systemLocale: "es-ES",
appLocale: "en-US",
});
@ -628,4 +663,5 @@ add_task(async function test_aboutwelcome_languageSwitcher_cancelWaiting() {
await resolveInstaller();
is(flushClickTelemetry().length, 0);
sinon.assert.notCalled(mockable.setRequestedAppLocales);
});

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

@ -61,7 +61,7 @@ describe("MultiStageAboutWelcomeProton module", () => {
assert.propertyVal(
data.screens[0].content.primary_button.label,
"string_id",
"mr1-onboarding-pin-primary-button-label"
"fx100-thank-you-pin-primary-button-label"
);
});
it("should have 'pin' button if we need default and pin", async () => {
@ -70,7 +70,7 @@ describe("MultiStageAboutWelcomeProton module", () => {
assert.propertyVal(
data.screens[0].content.primary_button.label,
"string_id",
"mr1-onboarding-pin-primary-button-label"
"fx100-thank-you-pin-primary-button-label"
);
assert.propertyVal(data.screens[0], "id", "AW_PIN_FIREFOX");
assert.propertyVal(data.screens[1], "id", "AW_SET_DEFAULT");
@ -111,10 +111,10 @@ describe("MultiStageAboutWelcomeProton module", () => {
assert.property(data, "skipFxA", true);
assert.notProperty(data.screens[0].content, "secondary_button_top");
});
it("should have an image caption", async () => {
it("should not have an image caption", async () => {
const data = await prepConfig();
assert.property(data.screens[0].content.help_text, "text");
assert.notProperty(data.screens[0].content, "help_text");
});
it("should remove the caption if deleteIfNotEn is true", async () => {
sandbox.stub(global.Services.locale, "appLocaleAsBCP47").value("de");
@ -132,16 +132,14 @@ describe("MultiStageAboutWelcomeProton module", () => {
position: "corner",
help_text: {
deleteIfNotEn: true,
text: {
string_id: "mr1-onboarding-welcome-image-caption",
},
string_id: "mr1-onboarding-welcome-image-caption",
},
},
},
],
});
assert.notProperty(data.screens[0].content.help_text, "text");
assert.notProperty(data.screens[0].content, "help_text");
});
});
describe("AboutWelcomeDefaults prepareContentForReact", () => {

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

@ -0,0 +1,73 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
XPCOMUtils.defineLazyModuleGetters(this, {
OnboardingMessageProvider:
"resource://activity-stream/lib/OnboardingMessageProvider.jsm",
sinon: "resource://testing-common/Sinon.jsm",
});
add_task(
async function test_OnboardingMessageProvider_getUpgradeMessage_no_pin() {
let sandbox = sinon.createSandbox();
sandbox.stub(OnboardingMessageProvider, "_doesAppNeedPin").resolves(true);
const message = await OnboardingMessageProvider.getUpgradeMessage();
// If Firefox is not pinned, the screen should have "pin" content
equal(
message.content.screens[0].id,
"UPGRADE_PIN_FIREFOX",
"Screen has pin screen id"
);
equal(
message.content.screens[0].content.primary_button.action.type,
"PIN_FIREFOX_TO_TASKBAR",
"Primary button has pin action type"
);
sandbox.restore();
}
);
add_task(
async function test_OnboardingMessageProvider_getUpgradeMessage_pin_no_default() {
let sandbox = sinon.createSandbox();
sandbox.stub(OnboardingMessageProvider, "_doesAppNeedPin").resolves(false);
sandbox
.stub(OnboardingMessageProvider, "_doesAppNeedDefault")
.resolves(true);
const message = await OnboardingMessageProvider.getUpgradeMessage();
// If Firefox is pinned, but not the default, the screen should have "make default" content
equal(
message.content.screens[0].id,
"UPGRADE_ONLY_DEFAULT",
"Screen has make default screen id"
);
equal(
message.content.screens[0].content.primary_button.action.type,
"SET_DEFAULT_BROWSER",
"Primary button has make default action"
);
sandbox.restore();
}
);
add_task(
async function test_OnboardingMessageProvider_getUpgradeMessage_pin_and_default() {
let sandbox = sinon.createSandbox();
sandbox.stub(OnboardingMessageProvider, "_doesAppNeedPin").resolves(false);
sandbox
.stub(OnboardingMessageProvider, "_doesAppNeedDefault")
.resolves(false);
const message = await OnboardingMessageProvider.getUpgradeMessage();
// If Firefox is pinned and the default, the screen should have "get started" content
equal(
message.content.screens[0].id,
"UPGRADE_GET_STARTED",
"Screen has get started screen id"
);
ok(
!message.content.screens[0].content.primary_button.action.type,
"Primary button has no action type"
);
sandbox.restore();
}
);

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

@ -19,4 +19,5 @@ skip-if =
[test_ASRouterTargeting_attribution.js]
skip-if = toolkit != "cocoa" # osx specific tests
[test_AboutWelcomeTelemetry.js]
[test_OnboardingMessageProvider.js]
[test_PanelTestProvider.js]

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

@ -10,8 +10,6 @@ const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
const VERSION_PREF = "browser.places.snapshots.version";
XPCOMUtils.defineLazyModuleGetters(this, {
BackgroundPageThumbs: "resource://gre/modules/BackgroundPageThumbs.jsm",
CommonNames: "resource:///modules/CommonNames.jsm",
@ -502,7 +500,6 @@ const Snapshots = new (class Snapshots {
sortDescending = true,
sortBy = "last_interaction_at",
} = {}) {
await this.#ensureVersionUpdates();
let db = await PlacesUtils.promiseDBConnection();
let clauses = [];
@ -568,7 +565,6 @@ const Snapshots = new (class Snapshots {
* place_id of the given url or -1 if not found
*/
async queryPlaceIdFromUrl(url) {
await this.#ensureVersionUpdates();
let db = await PlacesUtils.promiseDBConnection();
let rows = await db.executeCached(
@ -597,8 +593,6 @@ const Snapshots = new (class Snapshots {
* Returns array of overlapping snapshots in order of descending overlappingVisitScore (Calculated as 1.0 to 0.0, as the overlap gap goes to snapshot_overlap_limit)
*/
async queryOverlapping(context_url) {
await this.#ensureVersionUpdates();
let current_id = await this.queryPlaceIdFromUrl(context_url);
if (current_id == -1) {
logConsole.debug(`PlaceId not found for url ${context_url}`);
@ -660,7 +654,6 @@ const Snapshots = new (class Snapshots {
* Returns array of snapshots with the common referrer
*/
async queryCommonReferrer(context_url) {
await this.#ensureVersionUpdates();
let db = await PlacesUtils.promiseDBConnection();
let context_place_id = await this.queryPlaceIdFromUrl(context_url);
@ -695,39 +688,6 @@ const Snapshots = new (class Snapshots {
});
}
/**
* Ensures that the database is migrated to the latest version. Migrations
* should be exception-safe: don't throw an uncaught Error, or else we'll skip
* subsequent migrations.
*/
async #ensureVersionUpdates() {
let dbVersion = Services.prefs.getIntPref(VERSION_PREF, 0);
try {
if (dbVersion < 1) {
try {
// Delete legacy keyframes.sqlite DB.
let pathToKeyframes = PathUtils.join(
PathUtils.profileDir,
"keyframes.sqlite"
);
await IOUtils.remove(pathToKeyframes);
} catch (ex) {
console.warn(`Failed to delete keyframes.sqlite: ${ex}`);
}
}
} finally {
Services.prefs.setIntPref(VERSION_PREF, this.currentVersion);
}
}
/**
* Returns the database's most recent version number.
* @returns {number}
*/
get currentVersion() {
return 1;
}
/**
* Translates a database row to a Snapshot.
*

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

@ -24,6 +24,12 @@ const bookmarksInfo = [
];
const TEST_URL = "about:mozilla";
XPCOMUtils.defineLazyPreferenceGetter(
this,
"userContextEnabled",
"privacy.userContext.enabled"
);
add_setup(async function() {
await PlacesUtils.bookmarks.eraseEverything();
@ -113,6 +119,12 @@ add_task(async function test_bookmark_contextmenu_contents() {
"toggle_PersonalToolbar",
"show-other-bookmarks_PersonalToolbar",
];
if (!userContextEnabled) {
optionItems.splice(
optionItems.indexOf("placesContext_open:newcontainertab"),
1
);
}
await checkContextMenu(async function() {
let toolbarBookmark = await PlacesUtils.bookmarks.insert({
@ -392,6 +404,12 @@ add_task(async function test_sidebar_bookmark_contextmenu_contents() {
"placesContext_new:folder",
"placesContext_new:separator",
];
if (!userContextEnabled) {
optionItems.splice(
optionItems.indexOf("placesContext_open:newcontainertab"),
1
);
}
await withSidebarTree("bookmarks", async tree => {
await checkContextMenu(
@ -427,6 +445,12 @@ add_task(async function test_sidebar_bookmark_search_contextmenu_contents() {
"placesContext_cut",
"placesContext_copy",
];
if (!userContextEnabled) {
optionItems.splice(
optionItems.indexOf("placesContext_open:newcontainertab"),
1
);
}
await withSidebarTree("bookmarks", async tree => {
await checkContextMenu(
@ -472,6 +496,12 @@ add_task(async function test_library_bookmark_contextmenu_contents() {
"placesContext_new:folder",
"placesContext_new:separator",
];
if (!userContextEnabled) {
optionItems.splice(
optionItems.indexOf("placesContext_open:newcontainertab"),
1
);
}
await withLibraryWindow("BookmarksToolbar", async ({ left, right }) => {
await checkContextMenu(
@ -504,6 +534,12 @@ add_task(async function test_library_bookmark_search_contextmenu_contents() {
"placesContext_cut",
"placesContext_copy",
];
if (!userContextEnabled) {
optionItems.splice(
optionItems.indexOf("placesContext_open:newcontainertab"),
1
);
}
await withLibraryWindow("BookmarksToolbar", async ({ left, right }) => {
await checkContextMenu(

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

@ -12,13 +12,6 @@ const TEST_URL4 = "https://example.com/15234";
const TEST_URL5 = "https://example.com/54321";
const TEST_URL6 = "https://example.com/51432";
const VERSION_PREF = "browser.places.snapshots.version";
XPCOMUtils.defineLazyModuleGetters(this, {
Services: "resource://gre/modules/Services.jsm",
Sqlite: "resource://gre/modules/Sqlite.jsm",
});
add_task(async function setup() {
let now = Date.now();
await addInteractions([
@ -178,40 +171,6 @@ add_task(async function test_delete_snapshot() {
});
});
add_task(async function deleteKeyframesDb() {
Services.prefs.setIntPref(VERSION_PREF, 0);
let pathToKeyframes = PathUtils.join(
PathUtils.profileDir,
"keyframes.sqlite"
);
try {
let db = await Sqlite.openConnection({
path: pathToKeyframes,
});
await db.close();
Assert.ok(
await IOUtils.exists(pathToKeyframes),
"Sanity check: keyframes.sqlite exists."
);
await Snapshots.query();
Assert.ok(
!(await IOUtils.exists(pathToKeyframes)),
"Keyframes.sqlite was deleted."
);
} catch (ex) {
console.warn(`Error occured in deleteKeyframesDb: ${ex}`);
}
Assert.equal(
Services.prefs.getIntPref(VERSION_PREF, 0),
Snapshots.currentVersion,
"Calling Snapshots.query successfully updated to the most recent schema version."
);
});
add_task(async function test_add_titled_snapshot() {
let title = "test";
await Snapshots.add({ url: TEST_URL5, title });

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

@ -37,9 +37,8 @@ var HomeOverlay = function(options) {
};
HomeOverlay.prototype = {
create() {
create({ pockethost }) {
const { searchParams } = new URL(window.location.href);
const pockethost = searchParams.get(`pockethost`) || `getpocket.com`;
const locale = searchParams.get(`locale`) || ``;
const layoutRefresh = searchParams.get(`layoutRefresh`) === `true`;
const hideRecentSaves = searchParams.get(`hiderecentsaves`) === `true`;

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

@ -427,11 +427,12 @@ var HomeOverlay = function (options) {
};
HomeOverlay.prototype = {
create() {
create({
pockethost
}) {
const {
searchParams
} = new URL(window.location.href);
const pockethost = searchParams.get(`pockethost`) || `getpocket.com`;
const locale = searchParams.get(`locale`) || ``;
const layoutRefresh = searchParams.get(`layoutRefresh`) === `true`;
const hideRecentSaves = searchParams.get(`hiderecentsaves`) === `true`;
@ -625,7 +626,9 @@ var SignupOverlay = function (options) {
});
};
this.create = function () {
this.create = function ({
pockethost
}) {
const parser = new DOMParser();
let elBody = document.querySelector(`body`); // Extract local variables passed into template via URL query params
@ -633,7 +636,6 @@ var SignupOverlay = function (options) {
searchParams
} = new URL(window.location.href);
const isEmailSignupEnabled = searchParams.get(`emailButton`) === `true`;
const pockethost = searchParams.get(`pockethost`) || `getpocket.com`;
const locale = searchParams.get(`locale`) || ``;
const language = locale.split(`-`)[0].toLowerCase();
const layoutRefresh = searchParams.get(`layoutRefresh`) === `true`;
@ -1521,7 +1523,9 @@ var SavedOverlay = function (options) {
};
SavedOverlay.prototype = {
create() {
create({
pockethost
}) {
if (this.active) {
return;
}
@ -1531,7 +1535,6 @@ SavedOverlay.prototype = {
const {
searchParams
} = new URL(window.location.href);
const pockethost = searchParams.get(`pockethost`) || `getpocket.com`;
const premiumStatus = searchParams.get(`premiumStatus`) == `1`;
const locale = searchParams.get(`locale`) || ``;
const language = locale.split(`-`)[0].toLowerCase();
@ -1716,6 +1719,8 @@ StyleGuideOverlay.prototype = {
* 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/. */
/* global RPMGetStringPref:false */
@ -1824,7 +1829,10 @@ PKT_PANEL.prototype = {
},
create() {
this.overlay.create();
const pockethost = RPMGetStringPref("extensions.pocket.site") || "getpocket.com";
this.overlay.create({
pockethost
});
}
};

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

@ -1,6 +1,7 @@
/* 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/. */
/* global RPMGetStringPref:false */
import HomeOverlay from "./home/overlay.js";
import SignupOverlay from "./signup/overlay.js";
@ -107,7 +108,9 @@ PKT_PANEL.prototype = {
},
create() {
this.overlay.create();
const pockethost =
RPMGetStringPref("extensions.pocket.site") || "getpocket.com";
this.overlay.create({ pockethost });
},
};

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

@ -652,7 +652,7 @@ var SavedOverlay = function(options) {
};
SavedOverlay.prototype = {
create() {
create({ pockethost }) {
if (this.active) {
return;
}
@ -660,7 +660,6 @@ SavedOverlay.prototype = {
var myself = this;
const { searchParams } = new URL(window.location.href);
const pockethost = searchParams.get(`pockethost`) || `getpocket.com`;
const premiumStatus = searchParams.get(`premiumStatus`) == `1`;
const locale = searchParams.get(`locale`) || ``;
const language = locale.split(`-`)[0].toLowerCase();

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

@ -34,14 +34,13 @@ var SignupOverlay = function(options) {
source: `log_in`,
});
};
this.create = function() {
this.create = function({ pockethost }) {
const parser = new DOMParser();
let elBody = document.querySelector(`body`);
// Extract local variables passed into template via URL query params
const { searchParams } = new URL(window.location.href);
const isEmailSignupEnabled = searchParams.get(`emailButton`) === `true`;
const pockethost = searchParams.get(`pockethost`) || `getpocket.com`;
const locale = searchParams.get(`locale`) || ``;
const language = locale.split(`-`)[0].toLowerCase();
const layoutRefresh = searchParams.get(`layoutRefresh`) === `true`;

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

@ -254,10 +254,6 @@ var pktUI = (function() {
"layoutRefresh",
NimbusFeatures.saveToPocket.getVariable("layoutRefresh")
);
url.searchParams.append(
"pockethost",
Services.prefs.getCharPref("extensions.pocket.site")
);
url.searchParams.append("locale", getUILocale());
// We don't have to hide and show the panel again if it's already shown

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

@ -85,10 +85,7 @@ test_runner(async function test_pktUI_getAndShowRecsForItem_locale({
test_runner(async function test_pktUI_showPanel({ sandbox }) {
await SpecialPowers.pushPrefEnv({
set: [
["extensions.pocket.site", "test-site"],
["extensions.pocket.refresh.layout.enabled", true],
],
set: [["extensions.pocket.refresh.layout.enabled", true]],
});
const testFrame = {
setAttribute: sandbox.stub(),
@ -100,7 +97,7 @@ test_runner(async function test_pktUI_showPanel({ sandbox }) {
Assert.deepEqual(testFrame.setAttribute.args[0], [
"src",
`about:pocket-saved?utmSource=firefox_pocket_save_button&layoutRefresh=true&pockethost=test-site&locale=${SpecialPowers.Services.locale.appLocaleAsBCP47}`,
`about:pocket-saved?utmSource=firefox_pocket_save_button&layoutRefresh=true&locale=${SpecialPowers.Services.locale.appLocaleAsBCP47}`,
]);
Assert.deepEqual(testFrame.style, { width: "10px", height: "10px" });
});

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

@ -78,6 +78,7 @@ async function renderInfo({
async function renderPromo({
messageId = null,
promoEnabled = false,
promoType = "VPN",
promoTitle,
promoTitleEnabled,
promoLinkText,
@ -89,8 +90,10 @@ async function renderPromo({
promoImageSmall,
promoButton = null,
} = {}) {
const shouldShow = await RPMSendQuery("ShouldShowPromo", { type: promoType });
const container = document.querySelector(".promo");
if (promoEnabled === false) {
if (!promoEnabled || !shouldShow) {
container.remove();
return false;
}
@ -233,13 +236,9 @@ async function setupFeatureConfig() {
}
await renderInfo(config);
// Check the current geo and don't render if we're in the wrong one.
const shouldShow = await RPMSendQuery("ShouldShowVPNPromo", {});
if (shouldShow) {
let hasRendered = await renderPromo(config);
if (hasRendered && message) {
recordOnceVisible(message);
}
let hasRendered = await renderPromo(config);
if (hasRendered && message) {
recordOnceVisible(message);
}
// For tests
document.documentElement.setAttribute("PrivateBrowsingRenderComplete", true);

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

@ -46,6 +46,7 @@ skip-if = verify
[browser_privatebrowsing_downloadLastDir_c.js]
[browser_privatebrowsing_downloadLastDir_toggle.js]
[browser_privatebrowsing_favicon.js]
[browser_privatebrowsing_focus_promo.js]
[browser_privatebrowsing_history_shift_click.js]
[browser_privatebrowsing_last_private_browsing_context_exited.js]
[browser_privatebrowsing_lastpbcontextexited.js]

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

@ -12,19 +12,6 @@ const { ASRouter } = ChromeUtils.import(
"resource://activity-stream/lib/ASRouter.jsm"
);
async function openTabAndWaitForRender() {
let { win, tab } = await openAboutPrivateBrowsing();
await SpecialPowers.spawn(tab, [], async function() {
// Wait for render to complete
await ContentTaskUtils.waitForCondition(() =>
content.document.documentElement.hasAttribute(
"PrivateBrowsingRenderComplete"
)
);
});
return { win, tab };
}
async function setupMSExperimentWithMessage(message) {
let doExperimentCleanup = await ExperimentFakes.enrollWithFeatureConfig({
featureId: "pbNewtab",

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

@ -15,19 +15,6 @@ const { ASRouter } = ChromeUtils.import(
"resource://activity-stream/lib/ASRouter.jsm"
);
async function openTabAndWaitForRender() {
let { win, tab } = await openAboutPrivateBrowsing();
await SpecialPowers.spawn(tab, [], async function() {
// Wait for render to complete
await ContentTaskUtils.waitForCondition(() =>
content.document.documentElement.hasAttribute(
"PrivateBrowsingRenderComplete"
)
);
});
return { win, tab };
}
function waitForTelemetryEvent(category) {
info("waiting for telemetry event");
return TestUtils.waitForCondition(() => {

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