Merge autoland to mozilla-central. a=merge
19
.eslintrc.js
|
@ -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
|
||||
|
|
После Ширина: | Высота: | Размер: 20 KiB |
После Ширина: | Высота: | Размер: 20 KiB |
После Ширина: | Высота: | Размер: 20 KiB |
После Ширина: | Высота: | Размер: 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 |
После Ширина: | Высота: | Размер: 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(() => {
|
||||
|
|