Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "XULTreeGridAccessibleWrap.h"
8 #include "nsAccCache.h"
9 #include "nsAccessibilityService.h"
10 #include "nsAccUtils.h"
11 #include "DocAccessible.h"
12 #include "nsEventShell.h"
13 #include "Relation.h"
14 #include "Role.h"
15 #include "States.h"
17 #include "nsIBoxObject.h"
18 #include "nsIMutableArray.h"
19 #include "nsIPersistentProperties2.h"
20 #include "nsITreeSelection.h"
21 #include "nsComponentManagerUtils.h"
23 using namespace mozilla::a11y;
25 ////////////////////////////////////////////////////////////////////////////////
26 // XULTreeGridAccessible: nsISupports implementation
28 NS_IMPL_ISUPPORTS_INHERITED(XULTreeGridAccessible,
29 XULTreeAccessible,
30 nsIAccessibleTable)
32 ////////////////////////////////////////////////////////////////////////////////
33 // XULTreeGridAccessible: nsIAccessibleTable implementation
35 uint32_t
36 XULTreeGridAccessible::ColCount()
37 {
38 return nsCoreUtils::GetSensibleColumnCount(mTree);
39 }
41 uint32_t
42 XULTreeGridAccessible::RowCount()
43 {
44 if (!mTreeView)
45 return 0;
47 int32_t rowCount = 0;
48 mTreeView->GetRowCount(&rowCount);
49 return rowCount >= 0 ? rowCount : 0;
50 }
52 uint32_t
53 XULTreeGridAccessible::SelectedCellCount()
54 {
55 return SelectedRowCount() * ColCount();
56 }
58 uint32_t
59 XULTreeGridAccessible::SelectedColCount()
60 {
61 // If all the row has been selected, then all the columns are selected,
62 // because we can't select a column alone.
64 uint32_t selectedRowCount = SelectedItemCount();
65 return selectedRowCount > 0 && selectedRowCount == RowCount() ? ColCount() : 0;
66 }
68 uint32_t
69 XULTreeGridAccessible::SelectedRowCount()
70 {
71 return SelectedItemCount();
72 }
74 void
75 XULTreeGridAccessible::SelectedCells(nsTArray<Accessible*>* aCells)
76 {
77 uint32_t colCount = ColCount(), rowCount = RowCount();
79 for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
80 if (IsRowSelected(rowIdx)) {
81 for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) {
82 Accessible* cell = CellAt(rowIdx, colIdx);
83 aCells->AppendElement(cell);
84 }
85 }
86 }
87 }
89 void
90 XULTreeGridAccessible::SelectedCellIndices(nsTArray<uint32_t>* aCells)
91 {
92 uint32_t colCount = ColCount(), rowCount = RowCount();
94 for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++)
95 if (IsRowSelected(rowIdx))
96 for (uint32_t colIdx = 0; colIdx < colCount; colIdx++)
97 aCells->AppendElement(rowIdx * colCount + colIdx);
98 }
100 void
101 XULTreeGridAccessible::SelectedColIndices(nsTArray<uint32_t>* aCols)
102 {
103 if (RowCount() != SelectedRowCount())
104 return;
106 uint32_t colCount = ColCount();
107 aCols->SetCapacity(colCount);
108 for (uint32_t colIdx = 0; colIdx < colCount; colIdx++)
109 aCols->AppendElement(colIdx);
110 }
112 void
113 XULTreeGridAccessible::SelectedRowIndices(nsTArray<uint32_t>* aRows)
114 {
115 uint32_t rowCount = RowCount();
116 for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++)
117 if (IsRowSelected(rowIdx))
118 aRows->AppendElement(rowIdx);
119 }
121 Accessible*
122 XULTreeGridAccessible::CellAt(uint32_t aRowIndex, uint32_t aColumnIndex)
123 {
124 Accessible* row = GetTreeItemAccessible(aRowIndex);
125 if (!row)
126 return nullptr;
128 nsCOMPtr<nsITreeColumn> column =
129 nsCoreUtils::GetSensibleColumnAt(mTree, aColumnIndex);
130 if (!column)
131 return nullptr;
133 nsRefPtr<XULTreeItemAccessibleBase> rowAcc = do_QueryObject(row);
134 if (!rowAcc)
135 return nullptr;
137 return rowAcc->GetCellAccessible(column);
138 }
140 void
141 XULTreeGridAccessible::ColDescription(uint32_t aColIdx, nsString& aDescription)
142 {
143 aDescription.Truncate();
145 nsCOMPtr<nsIAccessible> treeColumns;
146 Accessible::GetFirstChild(getter_AddRefs(treeColumns));
147 if (treeColumns) {
148 nsCOMPtr<nsIAccessible> treeColumnItem;
149 treeColumns->GetChildAt(aColIdx, getter_AddRefs(treeColumnItem));
150 if (treeColumnItem)
151 treeColumnItem->GetName(aDescription);
152 }
153 }
155 bool
156 XULTreeGridAccessible::IsColSelected(uint32_t aColIdx)
157 {
158 // If all the row has been selected, then all the columns are selected.
159 // Because we can't select a column alone.
160 return SelectedItemCount() == RowCount();
161 }
163 bool
164 XULTreeGridAccessible::IsRowSelected(uint32_t aRowIdx)
165 {
166 if (!mTreeView)
167 return false;
169 nsCOMPtr<nsITreeSelection> selection;
170 nsresult rv = mTreeView->GetSelection(getter_AddRefs(selection));
171 NS_ENSURE_SUCCESS(rv, false);
173 bool isSelected = false;
174 selection->IsSelected(aRowIdx, &isSelected);
175 return isSelected;
176 }
178 bool
179 XULTreeGridAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx)
180 {
181 return IsRowSelected(aRowIdx);
182 }
184 void
185 XULTreeGridAccessible::SelectRow(uint32_t aRowIdx)
186 {
187 if (!mTreeView)
188 return;
190 nsCOMPtr<nsITreeSelection> selection;
191 mTreeView->GetSelection(getter_AddRefs(selection));
192 NS_ASSERTION(selection, "GetSelection() Shouldn't fail!");
194 selection->Select(aRowIdx);
195 }
197 void
198 XULTreeGridAccessible::UnselectRow(uint32_t aRowIdx)
199 {
200 if (!mTreeView)
201 return;
203 nsCOMPtr<nsITreeSelection> selection;
204 mTreeView->GetSelection(getter_AddRefs(selection));
206 if (selection)
207 selection->ClearRange(aRowIdx, aRowIdx);
208 }
210 ////////////////////////////////////////////////////////////////////////////////
211 // XULTreeGridAccessible: Accessible implementation
213 void
214 XULTreeGridAccessible::Shutdown()
215 {
216 mTable = nullptr;
217 XULTreeAccessible::Shutdown();
218 }
220 role
221 XULTreeGridAccessible::NativeRole()
222 {
223 nsCOMPtr<nsITreeColumns> treeColumns;
224 mTree->GetColumns(getter_AddRefs(treeColumns));
225 if (!treeColumns) {
226 NS_ERROR("No treecolumns object for tree!");
227 return roles::NOTHING;
228 }
230 nsCOMPtr<nsITreeColumn> primaryColumn;
231 treeColumns->GetPrimaryColumn(getter_AddRefs(primaryColumn));
233 return primaryColumn ? roles::TREE_TABLE : roles::TABLE;
234 }
236 ////////////////////////////////////////////////////////////////////////////////
237 // XULTreeGridAccessible: XULTreeAccessible implementation
239 already_AddRefed<Accessible>
240 XULTreeGridAccessible::CreateTreeItemAccessible(int32_t aRow) const
241 {
242 nsRefPtr<Accessible> accessible =
243 new XULTreeGridRowAccessible(mContent, mDoc,
244 const_cast<XULTreeGridAccessible*>(this),
245 mTree, mTreeView, aRow);
247 return accessible.forget();
248 }
251 ////////////////////////////////////////////////////////////////////////////////
252 // XULTreeGridRowAccessible
253 ////////////////////////////////////////////////////////////////////////////////
255 XULTreeGridRowAccessible::
256 XULTreeGridRowAccessible(nsIContent* aContent, DocAccessible* aDoc,
257 Accessible* aTreeAcc, nsITreeBoxObject* aTree,
258 nsITreeView* aTreeView, int32_t aRow) :
259 XULTreeItemAccessibleBase(aContent, aDoc, aTreeAcc, aTree, aTreeView, aRow),
260 mAccessibleCache(kDefaultTreeCacheSize)
261 {
262 mGenericTypes |= eTableRow;
263 }
265 ////////////////////////////////////////////////////////////////////////////////
266 // XULTreeGridRowAccessible: nsISupports and cycle collection implementation
268 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeGridRowAccessible,
269 XULTreeItemAccessibleBase,
270 mAccessibleCache)
272 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(XULTreeGridRowAccessible)
273 NS_INTERFACE_MAP_END_INHERITING(XULTreeItemAccessibleBase)
275 NS_IMPL_ADDREF_INHERITED(XULTreeGridRowAccessible,
276 XULTreeItemAccessibleBase)
277 NS_IMPL_RELEASE_INHERITED(XULTreeGridRowAccessible,
278 XULTreeItemAccessibleBase)
280 ////////////////////////////////////////////////////////////////////////////////
281 // XULTreeGridRowAccessible: Accessible implementation
283 void
284 XULTreeGridRowAccessible::Shutdown()
285 {
286 ClearCache(mAccessibleCache);
287 XULTreeItemAccessibleBase::Shutdown();
288 }
290 role
291 XULTreeGridRowAccessible::NativeRole()
292 {
293 return roles::ROW;
294 }
296 ENameValueFlag
297 XULTreeGridRowAccessible::Name(nsString& aName)
298 {
299 aName.Truncate();
301 // XXX: the row name sholdn't be a concatenation of cell names (bug 664384).
302 nsCOMPtr<nsITreeColumn> column = nsCoreUtils::GetFirstSensibleColumn(mTree);
303 while (column) {
304 if (!aName.IsEmpty())
305 aName.AppendLiteral(" ");
307 nsAutoString cellName;
308 GetCellName(column, cellName);
309 aName.Append(cellName);
311 column = nsCoreUtils::GetNextSensibleColumn(column);
312 }
314 return eNameOK;
315 }
317 Accessible*
318 XULTreeGridRowAccessible::ChildAtPoint(int32_t aX, int32_t aY,
319 EWhichChildAtPoint aWhichChild)
320 {
321 nsIFrame *frame = GetFrame();
322 if (!frame)
323 return nullptr;
325 nsPresContext *presContext = frame->PresContext();
326 nsIPresShell* presShell = presContext->PresShell();
328 nsIFrame *rootFrame = presShell->GetRootFrame();
329 NS_ENSURE_TRUE(rootFrame, nullptr);
331 nsIntRect rootRect = rootFrame->GetScreenRect();
333 int32_t clientX = presContext->DevPixelsToIntCSSPixels(aX) - rootRect.x;
334 int32_t clientY = presContext->DevPixelsToIntCSSPixels(aY) - rootRect.y;
336 int32_t row = -1;
337 nsCOMPtr<nsITreeColumn> column;
338 nsAutoCString childEltUnused;
339 mTree->GetCellAt(clientX, clientY, &row, getter_AddRefs(column),
340 childEltUnused);
342 // Return if we failed to find tree cell in the row for the given point.
343 if (row != mRow || !column)
344 return nullptr;
346 return GetCellAccessible(column);
347 }
349 Accessible*
350 XULTreeGridRowAccessible::GetChildAt(uint32_t aIndex) const
351 {
352 if (IsDefunct())
353 return nullptr;
355 nsCOMPtr<nsITreeColumn> column =
356 nsCoreUtils::GetSensibleColumnAt(mTree, aIndex);
357 if (!column)
358 return nullptr;
360 return GetCellAccessible(column);
361 }
363 uint32_t
364 XULTreeGridRowAccessible::ChildCount() const
365 {
366 return nsCoreUtils::GetSensibleColumnCount(mTree);
367 }
369 ////////////////////////////////////////////////////////////////////////////////
370 // XULTreeGridRowAccessible: XULTreeItemAccessibleBase implementation
372 Accessible*
373 XULTreeGridRowAccessible::GetCellAccessible(nsITreeColumn* aColumn) const
374 {
375 NS_PRECONDITION(aColumn, "No tree column!");
377 void* key = static_cast<void*>(aColumn);
378 Accessible* cachedCell = mAccessibleCache.GetWeak(key);
379 if (cachedCell)
380 return cachedCell;
382 nsRefPtr<Accessible> cell =
383 new XULTreeGridCellAccessibleWrap(mContent, mDoc,
384 const_cast<XULTreeGridRowAccessible*>(this),
385 mTree, mTreeView, mRow, aColumn);
386 mAccessibleCache.Put(key, cell);
387 Document()->BindToDocument(cell, nullptr);
388 return cell;
389 }
391 void
392 XULTreeGridRowAccessible::RowInvalidated(int32_t aStartColIdx,
393 int32_t aEndColIdx)
394 {
395 nsCOMPtr<nsITreeColumns> treeColumns;
396 mTree->GetColumns(getter_AddRefs(treeColumns));
397 if (!treeColumns)
398 return;
400 bool nameChanged = false;
401 for (int32_t colIdx = aStartColIdx; colIdx <= aEndColIdx; ++colIdx) {
402 nsCOMPtr<nsITreeColumn> column;
403 treeColumns->GetColumnAt(colIdx, getter_AddRefs(column));
404 if (column && !nsCoreUtils::IsColumnHidden(column)) {
405 Accessible* cellAccessible = GetCellAccessible(column);
406 if (cellAccessible) {
407 nsRefPtr<XULTreeGridCellAccessible> cellAcc = do_QueryObject(cellAccessible);
409 nameChanged |= cellAcc->CellInvalidated();
410 }
411 }
412 }
414 if (nameChanged)
415 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
417 }
419 ////////////////////////////////////////////////////////////////////////////////
420 // XULTreeGridRowAccessible: Accessible protected implementation
422 void
423 XULTreeGridRowAccessible::CacheChildren()
424 {
425 }
427 ////////////////////////////////////////////////////////////////////////////////
428 // XULTreeGridCellAccessible
429 ////////////////////////////////////////////////////////////////////////////////
431 XULTreeGridCellAccessible::
432 XULTreeGridCellAccessible(nsIContent* aContent, DocAccessible* aDoc,
433 XULTreeGridRowAccessible* aRowAcc,
434 nsITreeBoxObject* aTree, nsITreeView* aTreeView,
435 int32_t aRow, nsITreeColumn* aColumn) :
436 LeafAccessible(aContent, aDoc), xpcAccessibleTableCell(this), mTree(aTree),
437 mTreeView(aTreeView), mRow(aRow), mColumn(aColumn)
438 {
439 mParent = aRowAcc;
440 mStateFlags |= eSharedNode;
441 mGenericTypes |= eTableCell;
443 NS_ASSERTION(mTreeView, "mTreeView is null");
445 int16_t type = -1;
446 mColumn->GetType(&type);
447 if (type == nsITreeColumn::TYPE_CHECKBOX)
448 mTreeView->GetCellValue(mRow, mColumn, mCachedTextEquiv);
449 else
450 mTreeView->GetCellText(mRow, mColumn, mCachedTextEquiv);
451 }
453 ////////////////////////////////////////////////////////////////////////////////
454 // XULTreeGridCellAccessible: nsISupports implementation
456 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeGridCellAccessible, LeafAccessible,
457 mTree, mColumn)
459 NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(XULTreeGridCellAccessible)
460 NS_INTERFACE_TABLE_INHERITED(XULTreeGridCellAccessible,
461 nsIAccessibleTableCell,
462 XULTreeGridCellAccessible)
463 NS_INTERFACE_TABLE_TAIL_INHERITING(LeafAccessible)
464 NS_IMPL_ADDREF_INHERITED(XULTreeGridCellAccessible, LeafAccessible)
465 NS_IMPL_RELEASE_INHERITED(XULTreeGridCellAccessible, LeafAccessible)
467 ////////////////////////////////////////////////////////////////////////////////
468 // XULTreeGridCellAccessible: nsIAccessible implementation
470 void
471 XULTreeGridCellAccessible::Shutdown()
472 {
473 mTableCell = nullptr;
474 LeafAccessible::Shutdown();
475 }
477 Accessible*
478 XULTreeGridCellAccessible::FocusedChild()
479 {
480 return nullptr;
481 }
483 ENameValueFlag
484 XULTreeGridCellAccessible::Name(nsString& aName)
485 {
486 aName.Truncate();
488 if (!mTreeView)
489 return eNameOK;
491 mTreeView->GetCellText(mRow, mColumn, aName);
493 // If there is still no name try the cell value:
494 // This is for graphical cells. We need tree/table view implementors to implement
495 // FooView::GetCellValue to return a meaningful string for cases where there is
496 // something shown in the cell (non-text) such as a star icon; in which case
497 // GetCellValue for that cell would return "starred" or "flagged" for example.
498 if (aName.IsEmpty())
499 mTreeView->GetCellValue(mRow, mColumn, aName);
501 return eNameOK;
502 }
504 NS_IMETHODIMP
505 XULTreeGridCellAccessible::GetBounds(int32_t* aX, int32_t* aY,
506 int32_t* aWidth, int32_t* aHeight)
507 {
508 NS_ENSURE_ARG_POINTER(aX);
509 *aX = 0;
510 NS_ENSURE_ARG_POINTER(aY);
511 *aY = 0;
512 NS_ENSURE_ARG_POINTER(aWidth);
513 *aWidth = 0;
514 NS_ENSURE_ARG_POINTER(aHeight);
515 *aHeight = 0;
517 if (IsDefunct())
518 return NS_ERROR_FAILURE;
520 // Get bounds for tree cell and add x and y of treechildren element to
521 // x and y of the cell.
522 nsCOMPtr<nsIBoxObject> boxObj = nsCoreUtils::GetTreeBodyBoxObject(mTree);
523 NS_ENSURE_STATE(boxObj);
525 int32_t x = 0, y = 0, width = 0, height = 0;
526 nsresult rv = mTree->GetCoordsForCellItem(mRow, mColumn,
527 NS_LITERAL_CSTRING("cell"),
528 &x, &y, &width, &height);
529 NS_ENSURE_SUCCESS(rv, rv);
531 int32_t tcX = 0, tcY = 0;
532 boxObj->GetScreenX(&tcX);
533 boxObj->GetScreenY(&tcY);
534 x += tcX;
535 y += tcY;
537 nsPresContext* presContext = mDoc->PresContext();
538 *aX = presContext->CSSPixelsToDevPixels(x);
539 *aY = presContext->CSSPixelsToDevPixels(y);
540 *aWidth = presContext->CSSPixelsToDevPixels(width);
541 *aHeight = presContext->CSSPixelsToDevPixels(height);
543 return NS_OK;
544 }
546 uint8_t
547 XULTreeGridCellAccessible::ActionCount()
548 {
549 bool isCycler = false;
550 mColumn->GetCycler(&isCycler);
551 if (isCycler)
552 return 1;
554 int16_t type;
555 mColumn->GetType(&type);
556 if (type == nsITreeColumn::TYPE_CHECKBOX && IsEditable())
557 return 1;
559 return 0;
560 }
562 NS_IMETHODIMP
563 XULTreeGridCellAccessible::GetActionName(uint8_t aIndex, nsAString& aName)
564 {
565 aName.Truncate();
567 if (aIndex != eAction_Click)
568 return NS_ERROR_INVALID_ARG;
570 if (IsDefunct() || !mTreeView)
571 return NS_ERROR_FAILURE;
573 bool isCycler = false;
574 mColumn->GetCycler(&isCycler);
575 if (isCycler) {
576 aName.AssignLiteral("cycle");
577 return NS_OK;
578 }
580 int16_t type;
581 mColumn->GetType(&type);
582 if (type == nsITreeColumn::TYPE_CHECKBOX && IsEditable()) {
583 nsAutoString value;
584 mTreeView->GetCellValue(mRow, mColumn, value);
585 if (value.EqualsLiteral("true"))
586 aName.AssignLiteral("uncheck");
587 else
588 aName.AssignLiteral("check");
590 return NS_OK;
591 }
593 return NS_ERROR_INVALID_ARG;
594 }
596 NS_IMETHODIMP
597 XULTreeGridCellAccessible::DoAction(uint8_t aIndex)
598 {
599 if (aIndex != eAction_Click)
600 return NS_ERROR_INVALID_ARG;
602 if (IsDefunct())
603 return NS_ERROR_FAILURE;
605 bool isCycler = false;
606 mColumn->GetCycler(&isCycler);
607 if (isCycler) {
608 DoCommand();
609 return NS_OK;
610 }
612 int16_t type;
613 mColumn->GetType(&type);
614 if (type == nsITreeColumn::TYPE_CHECKBOX && IsEditable()) {
615 DoCommand();
616 return NS_OK;
617 }
619 return NS_ERROR_INVALID_ARG;
620 }
622 ////////////////////////////////////////////////////////////////////////////////
623 // XULTreeGridCellAccessible: nsIAccessibleTableCell implementation
625 TableAccessible*
626 XULTreeGridCellAccessible::Table() const
627 {
628 Accessible* grandParent = mParent->Parent();
629 if (grandParent)
630 return grandParent->AsTable();
632 return nullptr;
633 }
635 uint32_t
636 XULTreeGridCellAccessible::ColIdx() const
637 {
638 uint32_t colIdx = 0;
639 nsCOMPtr<nsITreeColumn> column = mColumn;
640 while ((column = nsCoreUtils::GetPreviousSensibleColumn(column)))
641 colIdx++;
643 return colIdx;
644 }
646 uint32_t
647 XULTreeGridCellAccessible::RowIdx() const
648 {
649 return mRow;
650 }
652 void
653 XULTreeGridCellAccessible::ColHeaderCells(nsTArray<Accessible*>* aHeaderCells)
654 {
655 nsCOMPtr<nsIDOMElement> columnElm;
656 mColumn->GetElement(getter_AddRefs(columnElm));
658 nsCOMPtr<nsIContent> columnContent(do_QueryInterface(columnElm));
659 Accessible* headerCell = mDoc->GetAccessible(columnContent);
660 if (headerCell)
661 aHeaderCells->AppendElement(headerCell);
662 }
664 bool
665 XULTreeGridCellAccessible::Selected()
666 {
667 nsCOMPtr<nsITreeSelection> selection;
668 nsresult rv = mTreeView->GetSelection(getter_AddRefs(selection));
669 NS_ENSURE_SUCCESS(rv, false);
671 bool selected = false;
672 selection->IsSelected(mRow, &selected);
673 return selected;
674 }
676 ////////////////////////////////////////////////////////////////////////////////
677 // XULTreeGridCellAccessible: Accessible public implementation
679 already_AddRefed<nsIPersistentProperties>
680 XULTreeGridCellAccessible::NativeAttributes()
681 {
682 nsCOMPtr<nsIPersistentProperties> attributes =
683 do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID);
685 // "table-cell-index" attribute
686 TableAccessible* table = Table();
687 if (!table)
688 return attributes.forget();
690 nsAutoString stringIdx;
691 stringIdx.AppendInt(table->CellIndexAt(mRow, ColIdx()));
692 nsAccUtils::SetAccAttr(attributes, nsGkAtoms::tableCellIndex, stringIdx);
694 // "cycles" attribute
695 bool isCycler = false;
696 nsresult rv = mColumn->GetCycler(&isCycler);
697 if (NS_SUCCEEDED(rv) && isCycler)
698 nsAccUtils::SetAccAttr(attributes, nsGkAtoms::cycles,
699 NS_LITERAL_STRING("true"));
701 return attributes.forget();
702 }
704 role
705 XULTreeGridCellAccessible::NativeRole()
706 {
707 return roles::GRID_CELL;
708 }
710 uint64_t
711 XULTreeGridCellAccessible::NativeState()
712 {
713 if (!mTreeView)
714 return states::DEFUNCT;
716 // selectable/selected state
717 uint64_t states = states::SELECTABLE; // keep in sync with NativeInteractiveState
719 nsCOMPtr<nsITreeSelection> selection;
720 mTreeView->GetSelection(getter_AddRefs(selection));
721 if (selection) {
722 bool isSelected = false;
723 selection->IsSelected(mRow, &isSelected);
724 if (isSelected)
725 states |= states::SELECTED;
726 }
728 // checked state
729 int16_t type;
730 mColumn->GetType(&type);
731 if (type == nsITreeColumn::TYPE_CHECKBOX) {
732 states |= states::CHECKABLE;
733 nsAutoString checked;
734 mTreeView->GetCellValue(mRow, mColumn, checked);
735 if (checked.EqualsIgnoreCase("true"))
736 states |= states::CHECKED;
737 }
739 return states;
740 }
742 uint64_t
743 XULTreeGridCellAccessible::NativeInteractiveState() const
744 {
745 return states::SELECTABLE;
746 }
748 int32_t
749 XULTreeGridCellAccessible::IndexInParent() const
750 {
751 return ColIdx();
752 }
754 Relation
755 XULTreeGridCellAccessible::RelationByType(RelationType aType)
756 {
757 return Relation();
758 }
760 ////////////////////////////////////////////////////////////////////////////////
761 // XULTreeGridCellAccessible: public implementation
763 bool
764 XULTreeGridCellAccessible::CellInvalidated()
765 {
767 nsAutoString textEquiv;
769 int16_t type;
770 mColumn->GetType(&type);
771 if (type == nsITreeColumn::TYPE_CHECKBOX) {
772 mTreeView->GetCellValue(mRow, mColumn, textEquiv);
773 if (mCachedTextEquiv != textEquiv) {
774 bool isEnabled = textEquiv.EqualsLiteral("true");
775 nsRefPtr<AccEvent> accEvent =
776 new AccStateChangeEvent(this, states::CHECKED, isEnabled);
777 nsEventShell::FireEvent(accEvent);
779 mCachedTextEquiv = textEquiv;
780 return true;
781 }
783 return false;
784 }
786 mTreeView->GetCellText(mRow, mColumn, textEquiv);
787 if (mCachedTextEquiv != textEquiv) {
788 nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
789 mCachedTextEquiv = textEquiv;
790 return true;
791 }
793 return false;
794 }
796 ////////////////////////////////////////////////////////////////////////////////
797 // XULTreeGridCellAccessible: Accessible protected implementation
799 Accessible*
800 XULTreeGridCellAccessible::GetSiblingAtOffset(int32_t aOffset,
801 nsresult* aError) const
802 {
803 if (aError)
804 *aError = NS_OK; // fail peacefully
806 nsCOMPtr<nsITreeColumn> columnAtOffset(mColumn), column;
807 if (aOffset < 0) {
808 for (int32_t index = aOffset; index < 0 && columnAtOffset; index++) {
809 column = nsCoreUtils::GetPreviousSensibleColumn(columnAtOffset);
810 column.swap(columnAtOffset);
811 }
812 } else {
813 for (int32_t index = aOffset; index > 0 && columnAtOffset; index--) {
814 column = nsCoreUtils::GetNextSensibleColumn(columnAtOffset);
815 column.swap(columnAtOffset);
816 }
817 }
819 if (!columnAtOffset)
820 return nullptr;
822 nsRefPtr<XULTreeItemAccessibleBase> rowAcc = do_QueryObject(Parent());
823 return rowAcc->GetCellAccessible(columnAtOffset);
824 }
826 void
827 XULTreeGridCellAccessible::DispatchClickEvent(nsIContent* aContent,
828 uint32_t aActionIndex)
829 {
830 if (IsDefunct())
831 return;
833 nsCoreUtils::DispatchClickEvent(mTree, mRow, mColumn);
834 }
836 ////////////////////////////////////////////////////////////////////////////////
837 // XULTreeGridCellAccessible: protected implementation
839 bool
840 XULTreeGridCellAccessible::IsEditable() const
841 {
843 // XXX: logic corresponds to tree.xml, it's preferable to have interface
844 // method to check it.
845 bool isEditable = false;
846 nsresult rv = mTreeView->IsEditable(mRow, mColumn, &isEditable);
847 if (NS_FAILED(rv) || !isEditable)
848 return false;
850 nsCOMPtr<nsIDOMElement> columnElm;
851 mColumn->GetElement(getter_AddRefs(columnElm));
852 if (!columnElm)
853 return false;
855 nsCOMPtr<nsIContent> columnContent(do_QueryInterface(columnElm));
856 if (!columnContent->AttrValueIs(kNameSpaceID_None,
857 nsGkAtoms::editable,
858 nsGkAtoms::_true,
859 eCaseMatters))
860 return false;
862 return mContent->AttrValueIs(kNameSpaceID_None,
863 nsGkAtoms::editable,
864 nsGkAtoms::_true, eCaseMatters);
865 }