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
122 lines
3.8 KiB
C++
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);
|
|
}
|