ia2AccessibleTable.cpp (14746B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:expandtab:shiftwidth=2:tabstop=2: 3 */ 4 /* This Source Code Form is subject to the terms of the Mozilla Public 5 * License, v. 2.0. If a copy of the MPL was not distributed with this 6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 7 8 #include "ia2AccessibleTable.h" 9 10 #include "Accessible2.h" 11 #include "AccessibleTable_i.c" 12 #include "AccessibleTable2_i.c" 13 14 #include "IUnknownImpl.h" 15 #include "mozilla/a11y/Accessible.h" 16 #include "mozilla/a11y/TableAccessible.h" 17 #include "nsCOMPtr.h" 18 #include "nsString.h" 19 20 using namespace mozilla::a11y; 21 22 TableAccessible* ia2AccessibleTable::TableAcc() { 23 Accessible* acc = MsaaAccessible::Acc(); 24 return acc ? acc->AsTable() : nullptr; 25 } 26 27 // IUnknown 28 29 STDMETHODIMP 30 ia2AccessibleTable::QueryInterface(REFIID iid, void** ppv) { 31 if (!ppv) return E_INVALIDARG; 32 33 *ppv = nullptr; 34 35 if (IID_IAccessibleTable == iid) { 36 *ppv = static_cast<IAccessibleTable*>(this); 37 (reinterpret_cast<IUnknown*>(*ppv))->AddRef(); 38 return S_OK; 39 } 40 41 if (IID_IAccessibleTable2 == iid) { 42 *ppv = static_cast<IAccessibleTable2*>(this); 43 (reinterpret_cast<IUnknown*>(*ppv))->AddRef(); 44 return S_OK; 45 } 46 47 if (IID_IGridProvider == iid) { 48 *ppv = static_cast<IGridProvider*>(this); 49 (reinterpret_cast<IUnknown*>(*ppv))->AddRef(); 50 return S_OK; 51 } 52 53 if (IID_ITableProvider == iid) { 54 *ppv = static_cast<ITableProvider*>(this); 55 (reinterpret_cast<IUnknown*>(*ppv))->AddRef(); 56 return S_OK; 57 } 58 59 return ia2AccessibleHypertext::QueryInterface(iid, ppv); 60 } 61 62 //////////////////////////////////////////////////////////////////////////////// 63 // IAccessibleTable 64 65 STDMETHODIMP 66 ia2AccessibleTable::get_accessibleAt(long aRowIdx, long aColIdx, 67 IUnknown** aAccessible) { 68 return get_cellAt(aRowIdx, aColIdx, aAccessible); 69 } 70 71 STDMETHODIMP 72 ia2AccessibleTable::get_caption(IUnknown** aAccessible) { 73 if (!aAccessible) return E_INVALIDARG; 74 75 *aAccessible = nullptr; 76 TableAccessible* table = TableAcc(); 77 if (!table) return CO_E_OBJNOTCONNECTED; 78 79 Accessible* caption = table->Caption(); 80 if (!caption) return S_FALSE; 81 82 RefPtr<IAccessible> result = MsaaAccessible::GetFrom(caption); 83 result.forget(aAccessible); 84 return S_OK; 85 } 86 87 STDMETHODIMP 88 ia2AccessibleTable::get_childIndex(long aRowIdx, long aColIdx, 89 long* aChildIdx) { 90 if (!aChildIdx) return E_INVALIDARG; 91 92 *aChildIdx = 0; 93 TableAccessible* table = TableAcc(); 94 if (!table) return CO_E_OBJNOTCONNECTED; 95 96 if (aRowIdx < 0 || aColIdx < 0 || 97 static_cast<uint32_t>(aRowIdx) >= table->RowCount() || 98 static_cast<uint32_t>(aColIdx) >= table->ColCount()) 99 return E_INVALIDARG; 100 101 *aChildIdx = table->CellIndexAt(aRowIdx, aColIdx); 102 return S_OK; 103 } 104 105 STDMETHODIMP 106 ia2AccessibleTable::get_columnDescription(long aColIdx, BSTR* aDescription) { 107 if (!aDescription) return E_INVALIDARG; 108 109 *aDescription = nullptr; 110 TableAccessible* table = TableAcc(); 111 if (!table) return CO_E_OBJNOTCONNECTED; 112 113 if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= table->ColCount()) 114 return E_INVALIDARG; 115 116 nsAutoString descr; 117 table->ColDescription(aColIdx, descr); 118 if (descr.IsEmpty()) return S_FALSE; 119 120 *aDescription = ::SysAllocStringLen(descr.get(), descr.Length()); 121 return *aDescription ? S_OK : E_OUTOFMEMORY; 122 } 123 124 STDMETHODIMP 125 ia2AccessibleTable::get_columnExtentAt(long aRowIdx, long aColIdx, 126 long* aSpan) { 127 if (!aSpan) return E_INVALIDARG; 128 129 *aSpan = 0; 130 TableAccessible* table = TableAcc(); 131 if (!table) return CO_E_OBJNOTCONNECTED; 132 133 if (aRowIdx < 0 || aColIdx < 0 || 134 static_cast<uint32_t>(aRowIdx) >= table->RowCount() || 135 static_cast<uint32_t>(aColIdx) >= table->ColCount()) 136 return E_INVALIDARG; 137 138 *aSpan = table->ColExtentAt(aRowIdx, aColIdx); 139 return S_OK; 140 } 141 142 STDMETHODIMP 143 ia2AccessibleTable::get_columnHeader(IAccessibleTable** aAccessibleTable, 144 long* aStartingRowIndex) { 145 if (!aAccessibleTable || !aStartingRowIndex) return E_INVALIDARG; 146 147 *aAccessibleTable = nullptr; 148 *aStartingRowIndex = -1; 149 return E_NOTIMPL; 150 } 151 152 STDMETHODIMP 153 ia2AccessibleTable::get_columnIndex(long aCellIdx, long* aColIdx) { 154 if (!aColIdx) return E_INVALIDARG; 155 156 *aColIdx = 0; 157 TableAccessible* table = TableAcc(); 158 if (!table) return CO_E_OBJNOTCONNECTED; 159 160 if (aCellIdx < 0) { 161 return E_INVALIDARG; 162 } 163 164 long colIdx = table->ColIndexAt(aCellIdx); 165 if (colIdx == -1) { // Indicates an error. 166 return E_INVALIDARG; 167 } 168 169 *aColIdx = colIdx; 170 return S_OK; 171 } 172 173 STDMETHODIMP 174 ia2AccessibleTable::get_nColumns(long* aColCount) { 175 if (!aColCount) return E_INVALIDARG; 176 177 *aColCount = 0; 178 TableAccessible* table = TableAcc(); 179 if (!table) return CO_E_OBJNOTCONNECTED; 180 181 *aColCount = table->ColCount(); 182 return S_OK; 183 } 184 185 STDMETHODIMP 186 ia2AccessibleTable::get_nRows(long* aRowCount) { 187 if (!aRowCount) return E_INVALIDARG; 188 189 *aRowCount = 0; 190 TableAccessible* table = TableAcc(); 191 if (!table) return CO_E_OBJNOTCONNECTED; 192 193 *aRowCount = table->RowCount(); 194 return S_OK; 195 } 196 197 STDMETHODIMP 198 ia2AccessibleTable::get_nSelectedChildren(long* aChildCount) { 199 return get_nSelectedCells(aChildCount); 200 } 201 202 STDMETHODIMP 203 ia2AccessibleTable::get_nSelectedColumns(long* aColCount) { 204 if (!aColCount) return E_INVALIDARG; 205 206 *aColCount = 0; 207 TableAccessible* table = TableAcc(); 208 if (!table) return CO_E_OBJNOTCONNECTED; 209 210 *aColCount = table->SelectedColCount(); 211 return S_OK; 212 } 213 214 STDMETHODIMP 215 ia2AccessibleTable::get_nSelectedRows(long* aRowCount) { 216 if (!aRowCount) return E_INVALIDARG; 217 218 *aRowCount = 0; 219 TableAccessible* table = TableAcc(); 220 if (!table) return CO_E_OBJNOTCONNECTED; 221 222 *aRowCount = table->SelectedRowCount(); 223 224 return S_OK; 225 } 226 227 STDMETHODIMP 228 ia2AccessibleTable::get_rowDescription(long aRowIdx, BSTR* aDescription) { 229 if (!aDescription) return E_INVALIDARG; 230 231 *aDescription = nullptr; 232 TableAccessible* table = TableAcc(); 233 if (!table) return CO_E_OBJNOTCONNECTED; 234 235 if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= table->RowCount()) 236 return E_INVALIDARG; 237 238 nsAutoString descr; 239 table->RowDescription(aRowIdx, descr); 240 if (descr.IsEmpty()) return S_FALSE; 241 242 *aDescription = ::SysAllocStringLen(descr.get(), descr.Length()); 243 return *aDescription ? S_OK : E_OUTOFMEMORY; 244 } 245 246 STDMETHODIMP 247 ia2AccessibleTable::get_rowExtentAt(long aRowIdx, long aColIdx, long* aSpan) { 248 if (!aSpan) return E_INVALIDARG; 249 250 *aSpan = 0; 251 TableAccessible* table = TableAcc(); 252 if (!table) return CO_E_OBJNOTCONNECTED; 253 254 if (aRowIdx < 0 || aColIdx < 0 || 255 static_cast<uint32_t>(aRowIdx) >= table->RowCount() || 256 static_cast<uint32_t>(aColIdx) >= table->ColCount()) 257 return E_INVALIDARG; 258 259 *aSpan = table->RowExtentAt(aRowIdx, aColIdx); 260 return S_OK; 261 } 262 263 STDMETHODIMP 264 ia2AccessibleTable::get_rowHeader(IAccessibleTable** aAccessibleTable, 265 long* aStartingColumnIndex) { 266 if (!aAccessibleTable || !aStartingColumnIndex) return E_INVALIDARG; 267 268 *aAccessibleTable = nullptr; 269 *aStartingColumnIndex = -1; 270 return E_NOTIMPL; 271 } 272 273 STDMETHODIMP 274 ia2AccessibleTable::get_rowIndex(long aCellIdx, long* aRowIdx) { 275 if (!aRowIdx) return E_INVALIDARG; 276 277 *aRowIdx = 0; 278 TableAccessible* table = TableAcc(); 279 if (!table) return CO_E_OBJNOTCONNECTED; 280 281 if (aCellIdx < 0) { 282 return E_INVALIDARG; 283 } 284 285 long rowIdx = table->RowIndexAt(aCellIdx); 286 if (rowIdx == -1) { // Indicates an error. 287 return E_INVALIDARG; 288 } 289 290 *aRowIdx = rowIdx; 291 return S_OK; 292 } 293 294 STDMETHODIMP 295 ia2AccessibleTable::get_selectedChildren(long aMaxChildren, long** aChildren, 296 long* aNChildren) { 297 if (!aChildren || !aNChildren) return E_INVALIDARG; 298 299 *aChildren = nullptr; 300 *aNChildren = 0; 301 TableAccessible* table = TableAcc(); 302 if (!table) return CO_E_OBJNOTCONNECTED; 303 304 AutoTArray<uint32_t, 30> cellIndices; 305 table->SelectedCellIndices(&cellIndices); 306 307 uint32_t maxCells = cellIndices.Length(); 308 if (maxCells == 0) return S_FALSE; 309 310 *aChildren = static_cast<LONG*>(moz_xmalloc(sizeof(LONG) * maxCells)); 311 *aNChildren = maxCells; 312 for (uint32_t i = 0; i < maxCells; i++) (*aChildren)[i] = cellIndices[i]; 313 314 return S_OK; 315 } 316 317 STDMETHODIMP 318 ia2AccessibleTable::get_selectedColumns(long aMaxColumns, long** aColumns, 319 long* aNColumns) { 320 return get_selectedColumns(aColumns, aNColumns); 321 } 322 323 STDMETHODIMP 324 ia2AccessibleTable::get_selectedRows(long aMaxRows, long** aRows, 325 long* aNRows) { 326 return get_selectedRows(aRows, aNRows); 327 } 328 329 STDMETHODIMP 330 ia2AccessibleTable::get_summary(IUnknown** aAccessible) { 331 if (!aAccessible) return E_INVALIDARG; 332 333 // Neither html:table nor xul:tree nor ARIA grid/tree have an ability to 334 // link an accessible object to specify a summary. There is closes method 335 // in Table::summary to get a summary as a string which is not mapped 336 // directly to IAccessible2. 337 338 *aAccessible = nullptr; 339 return S_FALSE; 340 } 341 342 STDMETHODIMP 343 ia2AccessibleTable::get_isColumnSelected(long aColIdx, boolean* aIsSelected) { 344 if (!aIsSelected) return E_INVALIDARG; 345 346 *aIsSelected = false; 347 TableAccessible* table = TableAcc(); 348 if (!table) return CO_E_OBJNOTCONNECTED; 349 350 if (aColIdx < 0 || static_cast<uint32_t>(aColIdx) >= table->ColCount()) 351 return E_INVALIDARG; 352 353 *aIsSelected = table->IsColSelected(aColIdx); 354 return S_OK; 355 } 356 357 STDMETHODIMP 358 ia2AccessibleTable::get_isRowSelected(long aRowIdx, boolean* aIsSelected) { 359 if (!aIsSelected) return E_INVALIDARG; 360 361 *aIsSelected = false; 362 TableAccessible* table = TableAcc(); 363 if (!table) return CO_E_OBJNOTCONNECTED; 364 365 if (aRowIdx < 0 || static_cast<uint32_t>(aRowIdx) >= table->RowCount()) 366 return E_INVALIDARG; 367 368 *aIsSelected = table->IsRowSelected(aRowIdx); 369 return S_OK; 370 } 371 372 STDMETHODIMP 373 ia2AccessibleTable::get_isSelected(long aRowIdx, long aColIdx, 374 boolean* aIsSelected) { 375 if (!aIsSelected) return E_INVALIDARG; 376 377 *aIsSelected = false; 378 TableAccessible* table = TableAcc(); 379 if (!table) return CO_E_OBJNOTCONNECTED; 380 381 if (aRowIdx < 0 || aColIdx < 0 || 382 static_cast<uint32_t>(aColIdx) >= table->ColCount() || 383 static_cast<uint32_t>(aRowIdx) >= table->RowCount()) 384 return E_INVALIDARG; 385 386 *aIsSelected = table->IsCellSelected(aRowIdx, aColIdx); 387 return S_OK; 388 } 389 390 STDMETHODIMP 391 ia2AccessibleTable::selectRow(long aRowIdx) { return E_NOTIMPL; } 392 393 STDMETHODIMP 394 ia2AccessibleTable::selectColumn(long aColIdx) { return E_NOTIMPL; } 395 396 STDMETHODIMP 397 ia2AccessibleTable::unselectRow(long aRowIdx) { return E_NOTIMPL; } 398 399 STDMETHODIMP 400 ia2AccessibleTable::unselectColumn(long aColIdx) { return E_NOTIMPL; } 401 402 STDMETHODIMP 403 ia2AccessibleTable::get_rowColumnExtentsAtIndex(long aCellIdx, long* aRowIdx, 404 long* aColIdx, 405 long* aRowExtents, 406 long* aColExtents, 407 boolean* aIsSelected) { 408 if (!aRowIdx || !aColIdx || !aRowExtents || !aColExtents || !aIsSelected) 409 return E_INVALIDARG; 410 411 *aRowIdx = 0; 412 *aColIdx = 0; 413 *aRowExtents = 0; 414 *aColExtents = 0; 415 *aIsSelected = false; 416 TableAccessible* table = TableAcc(); 417 if (!table) return CO_E_OBJNOTCONNECTED; 418 419 if (aCellIdx < 0) { 420 return E_INVALIDARG; 421 } 422 423 int32_t colIdx = 0, rowIdx = 0; 424 table->RowAndColIndicesAt(aCellIdx, &rowIdx, &colIdx); 425 if (rowIdx == -1 || colIdx == -1) { // Indicates an error. 426 return E_INVALIDARG; 427 } 428 429 *aRowIdx = rowIdx; 430 *aColIdx = colIdx; 431 *aRowExtents = table->RowExtentAt(rowIdx, colIdx); 432 *aColExtents = table->ColExtentAt(rowIdx, colIdx); 433 *aIsSelected = table->IsCellSelected(rowIdx, colIdx); 434 435 return S_OK; 436 } 437 438 STDMETHODIMP 439 ia2AccessibleTable::get_modelChange(IA2TableModelChange* aModelChange) { 440 return E_NOTIMPL; 441 } 442 443 //////////////////////////////////////////////////////////////////////////////// 444 // IAccessibleTable2 445 446 STDMETHODIMP 447 ia2AccessibleTable::get_cellAt(long aRowIdx, long aColIdx, IUnknown** aCell) { 448 if (!aCell) return E_INVALIDARG; 449 450 *aCell = nullptr; 451 452 TableAccessible* table = TableAcc(); 453 if (!table) return CO_E_OBJNOTCONNECTED; 454 455 Accessible* cell = table->CellAt(aRowIdx, aColIdx); 456 if (!cell) return E_INVALIDARG; 457 458 RefPtr<IAccessible> result = MsaaAccessible::GetFrom(cell); 459 result.forget(aCell); 460 return S_OK; 461 } 462 463 STDMETHODIMP 464 ia2AccessibleTable::get_nSelectedCells(long* aCellCount) { 465 if (!aCellCount) return E_INVALIDARG; 466 467 *aCellCount = 0; 468 TableAccessible* table = TableAcc(); 469 if (!table) return CO_E_OBJNOTCONNECTED; 470 471 *aCellCount = table->SelectedCellCount(); 472 return S_OK; 473 } 474 475 STDMETHODIMP 476 ia2AccessibleTable::get_selectedCells(IUnknown*** aCells, 477 long* aNSelectedCells) { 478 if (!aCells || !aNSelectedCells) return E_INVALIDARG; 479 480 *aCells = nullptr; 481 *aNSelectedCells = 0; 482 TableAccessible* table = TableAcc(); 483 if (!table) return CO_E_OBJNOTCONNECTED; 484 485 AutoTArray<Accessible*, 30> cells; 486 table->SelectedCells(&cells); 487 if (cells.IsEmpty()) return S_FALSE; 488 489 *aCells = static_cast<IUnknown**>( 490 ::CoTaskMemAlloc(sizeof(IUnknown*) * cells.Length())); 491 if (!*aCells) return E_OUTOFMEMORY; 492 493 for (uint32_t i = 0; i < cells.Length(); i++) { 494 RefPtr<IAccessible> cell = MsaaAccessible::GetFrom(cells[i]); 495 cell.forget(&(*aCells)[i]); 496 } 497 498 *aNSelectedCells = cells.Length(); 499 return S_OK; 500 } 501 502 STDMETHODIMP 503 ia2AccessibleTable::get_selectedColumns(long** aColumns, long* aNColumns) { 504 if (!aColumns || !aNColumns) return E_INVALIDARG; 505 506 *aColumns = nullptr; 507 *aNColumns = 0; 508 TableAccessible* table = TableAcc(); 509 if (!table) return CO_E_OBJNOTCONNECTED; 510 511 AutoTArray<uint32_t, 30> colIndices; 512 table->SelectedColIndices(&colIndices); 513 514 uint32_t maxCols = colIndices.Length(); 515 if (maxCols == 0) return S_FALSE; 516 517 *aColumns = static_cast<LONG*>(moz_xmalloc(sizeof(LONG) * maxCols)); 518 *aNColumns = maxCols; 519 for (uint32_t i = 0; i < maxCols; i++) (*aColumns)[i] = colIndices[i]; 520 521 return S_OK; 522 } 523 524 STDMETHODIMP 525 ia2AccessibleTable::get_selectedRows(long** aRows, long* aNRows) { 526 if (!aRows || !aNRows) return E_INVALIDARG; 527 528 *aRows = nullptr; 529 *aNRows = 0; 530 TableAccessible* table = TableAcc(); 531 if (!table) return CO_E_OBJNOTCONNECTED; 532 533 AutoTArray<uint32_t, 30> rowIndices; 534 table->SelectedRowIndices(&rowIndices); 535 536 uint32_t maxRows = rowIndices.Length(); 537 if (maxRows == 0) return S_FALSE; 538 539 *aRows = static_cast<LONG*>(moz_xmalloc(sizeof(LONG) * maxRows)); 540 *aNRows = maxRows; 541 for (uint32_t i = 0; i < maxRows; i++) (*aRows)[i] = rowIndices[i]; 542 543 return S_OK; 544 }