Files
tubestation/accessible/windows/ia2/ia2AccessibleTextSelectionContainer.cpp
James Teh 7932ffe32b Bug 1963996: Clear the selection if IAccessibleTextSelectionContainer::setSelections is called with nSelections set to 0. r=eeejay
I removed this behaviour in bug 1951573.
Unfortunately, it turns out that contrary to the spec (which says "1 or more selections"), NVDA depends on this behaviour.
Reinstate this by supporting kRemoveAllExistingSelectedRanges in HyperTextAccessibleBase::RemoveFromSelection and using that.

Differential Revision: https://phabricator.services.mozilla.com/D247875
2025-05-08 06:52:14 +00:00

122 lines
3.8 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:expandtab:shiftwidth=2:tabstop=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/. */
#include "ia2AccessibleTextSelectionContainer.h"
#include "AccessibleTextSelectionContainer_i.c"
#include "ia2AccessibleHypertext.h"
#include "mozilla/a11y/HyperTextAccessibleBase.h"
#include "TextRange.h"
#include "TextLeafRange.h"
using namespace mozilla::a11y;
// IAccessibleTextSelectionContainer
STDMETHODIMP
ia2AccessibleTextSelectionContainer::get_selections(
IA2TextSelection** selections, long* nSelections) {
if (!selections || !nSelections) {
return E_INVALIDARG;
}
*nSelections = 0;
HyperTextAccessibleBase* text = TextAcc();
if (!text) {
return CO_E_OBJNOTCONNECTED;
}
AutoTArray<TextRange, 1> ranges;
text->CroppedSelectionRanges(ranges);
*nSelections = ranges.Length();
*selections = static_cast<IA2TextSelection*>(
::CoTaskMemAlloc(sizeof(IA2TextSelection) * *nSelections));
if (!*selections) {
return E_OUTOFMEMORY;
}
for (uint32_t idx = 0; idx < static_cast<uint32_t>(*nSelections); idx++) {
RefPtr<IAccessibleText> startObj =
GetIATextFrom(ranges[idx].StartContainer());
startObj.forget(&(*selections)[idx].startObj);
(*selections)[idx].startOffset = ranges[idx].StartOffset();
RefPtr<IAccessibleText> endObj = GetIATextFrom(ranges[idx].EndContainer());
endObj.forget(&(*selections)[idx].endObj);
(*selections)[idx].endOffset = ranges[idx].EndOffset();
// XXX Expose this properly somehow.
(*selections)[idx].startIsActive = true;
}
return S_OK;
}
STDMETHODIMP
ia2AccessibleTextSelectionContainer::setSelections(
long nSelections, IA2TextSelection* selections) {
if (nSelections < 0 || !selections) {
return E_INVALIDARG;
}
HyperTextAccessibleBase* text = TextAcc();
if (!text) {
return CO_E_OBJNOTCONNECTED;
}
if (nSelections == 0) {
text->RemoveFromSelection(TextLeafRange::kRemoveAllExistingSelectedRanges);
return S_OK;
}
// Build and validate new selection ranges.
AutoTArray<TextLeafRange, 1> newRanges;
newRanges.SetCapacity(nSelections);
for (long r = 0; r < nSelections; ++r) {
TextLeafRange range(
GetTextLeafPointFrom(selections[r].startObj, selections[r].startOffset),
GetTextLeafPointFrom(selections[r].endObj, selections[r].endOffset));
if (!range) {
return E_INVALIDARG;
}
newRanges.AppendElement(range);
}
// Set the new selections.
newRanges[0].SetSelection(TextLeafRange::kRemoveAllExistingSelectedRanges);
for (long r = 1; r < nSelections; ++r) {
newRanges[r].SetSelection(r);
}
return S_OK;
}
// ia2AccessibleTextSelectionContainer
HyperTextAccessibleBase* ia2AccessibleTextSelectionContainer::TextAcc() {
auto hyp = static_cast<ia2AccessibleHypertext*>(this);
Accessible* acc = hyp->Acc();
return acc ? acc->AsHyperTextBase() : nullptr;
}
/* static */
RefPtr<IAccessibleText> ia2AccessibleTextSelectionContainer::GetIATextFrom(
Accessible* aAcc) {
MsaaAccessible* msaa = MsaaAccessible::GetFrom(aAcc);
MOZ_ASSERT(msaa);
RefPtr<IAccessibleText> text;
msaa->QueryInterface(IID_IAccessibleText, getter_AddRefs(text));
MOZ_ASSERT(text);
return text;
}
/* static */
TextLeafPoint ia2AccessibleTextSelectionContainer::GetTextLeafPointFrom(
IAccessibleText* aText, long aOffset) {
if (!aText) {
return TextLeafPoint();
}
Accessible* acc = MsaaAccessible::GetAccessibleFrom(aText);
if (!acc) {
return TextLeafPoint();
}
HyperTextAccessibleBase* hyp = acc->AsHyperTextBase();
if (!hyp) {
return TextLeafPoint();
}
return hyp->ToTextLeafPoint(aOffset);
}