diff options
Diffstat (limited to 'accessible/windows/ia2/ia2AccessibleText.cpp')
-rw-r--r-- | accessible/windows/ia2/ia2AccessibleText.cpp | 598 |
1 files changed, 598 insertions, 0 deletions
diff --git a/accessible/windows/ia2/ia2AccessibleText.cpp b/accessible/windows/ia2/ia2AccessibleText.cpp new file mode 100644 index 000000000..7ac766f30 --- /dev/null +++ b/accessible/windows/ia2/ia2AccessibleText.cpp @@ -0,0 +1,598 @@ +/* -*- 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 "ia2AccessibleText.h" + +#include "Accessible2.h" +#include "AccessibleText_i.c" + +#include "HyperTextAccessibleWrap.h" +#include "HyperTextAccessible-inl.h" +#include "ProxyWrappers.h" +#include "mozilla/ClearOnShutdown.h" + +using namespace mozilla::a11y; + +StaticRefPtr<HyperTextAccessibleWrap> ia2AccessibleText::sLastTextChangeAcc; +StaticAutoPtr<nsString> ia2AccessibleText::sLastTextChangeString; +uint32_t ia2AccessibleText::sLastTextChangeStart = 0; +uint32_t ia2AccessibleText::sLastTextChangeEnd = 0; +bool ia2AccessibleText::sLastTextChangeWasInsert = false; + +// IAccessibleText + +STDMETHODIMP +ia2AccessibleText::addSelection(long aStartOffset, long aEndOffset) +{ + A11Y_TRYBLOCK_BEGIN + + MOZ_ASSERT(!HyperTextProxyFor(this)); + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) + return CO_E_OBJNOTCONNECTED; + + return textAcc->AddToSelection(aStartOffset, aEndOffset) ? + S_OK : E_INVALIDARG; + + A11Y_TRYBLOCK_END +} + +STDMETHODIMP +ia2AccessibleText::get_attributes(long aOffset, long *aStartOffset, + long *aEndOffset, BSTR *aTextAttributes) +{ + A11Y_TRYBLOCK_BEGIN + + if (!aStartOffset || !aEndOffset || !aTextAttributes) + return E_INVALIDARG; + + *aStartOffset = 0; + *aEndOffset = 0; + *aTextAttributes = nullptr; + + int32_t startOffset = 0, endOffset = 0; + HRESULT hr; + MOZ_ASSERT(!HyperTextProxyFor(this)); + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) { + return CO_E_OBJNOTCONNECTED; + } + + nsCOMPtr<nsIPersistentProperties> attributes = + textAcc->TextAttributes(true, aOffset, &startOffset, &endOffset); + + hr = AccessibleWrap::ConvertToIA2Attributes(attributes, aTextAttributes); + if (FAILED(hr)) + return hr; + + *aStartOffset = startOffset; + *aEndOffset = endOffset; + + return S_OK; + + A11Y_TRYBLOCK_END +} + +STDMETHODIMP +ia2AccessibleText::get_caretOffset(long *aOffset) +{ + A11Y_TRYBLOCK_BEGIN + + if (!aOffset) + return E_INVALIDARG; + + *aOffset = -1; + + MOZ_ASSERT(!HyperTextProxyFor(this)); + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) { + return CO_E_OBJNOTCONNECTED; + } + + *aOffset = textAcc->CaretOffset(); + + return *aOffset != -1 ? S_OK : S_FALSE; + + A11Y_TRYBLOCK_END +} + +STDMETHODIMP +ia2AccessibleText::get_characterExtents(long aOffset, + enum IA2CoordinateType aCoordType, + long* aX, long* aY, + long* aWidth, long* aHeight) +{ + A11Y_TRYBLOCK_BEGIN + + if (!aX || !aY || !aWidth || !aHeight) + return E_INVALIDARG; + *aX = *aY = *aWidth = *aHeight = 0; + + uint32_t geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ? + nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE : + nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE; + nsIntRect rect; + MOZ_ASSERT(!HyperTextProxyFor(this)); + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) + return CO_E_OBJNOTCONNECTED; + + rect = textAcc->CharBounds(aOffset, geckoCoordType); + + *aX = rect.x; + *aY = rect.y; + *aWidth = rect.width; + *aHeight = rect.height; + return S_OK; + + A11Y_TRYBLOCK_END +} + +STDMETHODIMP +ia2AccessibleText::get_nSelections(long* aNSelections) +{ + A11Y_TRYBLOCK_BEGIN + + if (!aNSelections) + return E_INVALIDARG; + *aNSelections = 0; + + MOZ_ASSERT(!HyperTextProxyFor(this)); + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) { + return CO_E_OBJNOTCONNECTED; + } + + *aNSelections = textAcc->SelectionCount(); + + return S_OK; + + A11Y_TRYBLOCK_END +} + +STDMETHODIMP +ia2AccessibleText::get_offsetAtPoint(long aX, long aY, + enum IA2CoordinateType aCoordType, + long* aOffset) +{ + A11Y_TRYBLOCK_BEGIN + + if (!aOffset) + return E_INVALIDARG; + *aOffset = 0; + + uint32_t geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ? + nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE : + nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE; + + MOZ_ASSERT(!HyperTextProxyFor(this)); + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) { + return CO_E_OBJNOTCONNECTED; + } + + *aOffset = textAcc->OffsetAtPoint(aX, aY, geckoCoordType); + + return *aOffset == -1 ? S_FALSE : S_OK; + + A11Y_TRYBLOCK_END +} + +STDMETHODIMP +ia2AccessibleText::get_selection(long aSelectionIndex, long* aStartOffset, + long* aEndOffset) +{ + A11Y_TRYBLOCK_BEGIN + + if (!aStartOffset || !aEndOffset) + return E_INVALIDARG; + *aStartOffset = *aEndOffset = 0; + + int32_t startOffset = 0, endOffset = 0; + MOZ_ASSERT(!HyperTextProxyFor(this)); + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) { + return CO_E_OBJNOTCONNECTED; + } + + if (!textAcc->SelectionBoundsAt(aSelectionIndex, &startOffset, &endOffset)) { + return E_INVALIDARG; + } + + *aStartOffset = startOffset; + *aEndOffset = endOffset; + return S_OK; + + A11Y_TRYBLOCK_END +} + +STDMETHODIMP +ia2AccessibleText::get_text(long aStartOffset, long aEndOffset, BSTR* aText) +{ + A11Y_TRYBLOCK_BEGIN + + if (!aText) + return E_INVALIDARG; + + *aText = nullptr; + + nsAutoString text; + MOZ_ASSERT(!HyperTextProxyFor(this)); + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) { + return CO_E_OBJNOTCONNECTED; + } + + if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) { + return E_INVALIDARG; + } + + textAcc->TextSubstring(aStartOffset, aEndOffset, text); + + if (text.IsEmpty()) + return S_FALSE; + + *aText = ::SysAllocStringLen(text.get(), text.Length()); + return *aText ? S_OK : E_OUTOFMEMORY; + + A11Y_TRYBLOCK_END +} + +STDMETHODIMP +ia2AccessibleText::get_textBeforeOffset(long aOffset, + enum IA2TextBoundaryType aBoundaryType, + long* aStartOffset, long* aEndOffset, + BSTR* aText) +{ + A11Y_TRYBLOCK_BEGIN + + if (!aStartOffset || !aEndOffset || !aText) + return E_INVALIDARG; + + *aStartOffset = *aEndOffset = 0; + *aText = nullptr; + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) + return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidOffset(aOffset)) + return E_INVALIDARG; + + nsAutoString text; + int32_t startOffset = 0, endOffset = 0; + + if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) { + startOffset = 0; + endOffset = textAcc->CharacterCount(); + textAcc->TextSubstring(startOffset, endOffset, text); + } else { + AccessibleTextBoundary boundaryType = GetGeckoTextBoundary(aBoundaryType); + if (boundaryType == -1) + return S_FALSE; + + textAcc->TextBeforeOffset(aOffset, boundaryType, &startOffset, &endOffset, text); + } + + *aStartOffset = startOffset; + *aEndOffset = endOffset; + + if (text.IsEmpty()) + return S_FALSE; + + *aText = ::SysAllocStringLen(text.get(), text.Length()); + return *aText ? S_OK : E_OUTOFMEMORY; + + A11Y_TRYBLOCK_END +} + +STDMETHODIMP +ia2AccessibleText::get_textAfterOffset(long aOffset, + enum IA2TextBoundaryType aBoundaryType, + long* aStartOffset, long* aEndOffset, + BSTR* aText) +{ + A11Y_TRYBLOCK_BEGIN + + if (!aStartOffset || !aEndOffset || !aText) + return E_INVALIDARG; + + *aStartOffset = 0; + *aEndOffset = 0; + *aText = nullptr; + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) + return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidOffset(aOffset)) + return E_INVALIDARG; + + nsAutoString text; + int32_t startOffset = 0, endOffset = 0; + + if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) { + startOffset = 0; + endOffset = textAcc->CharacterCount(); + textAcc->TextSubstring(startOffset, endOffset, text); + } else { + AccessibleTextBoundary boundaryType = GetGeckoTextBoundary(aBoundaryType); + if (boundaryType == -1) + return S_FALSE; + textAcc->TextAfterOffset(aOffset, boundaryType, &startOffset, &endOffset, text); + } + + *aStartOffset = startOffset; + *aEndOffset = endOffset; + + if (text.IsEmpty()) + return S_FALSE; + + *aText = ::SysAllocStringLen(text.get(), text.Length()); + return *aText ? S_OK : E_OUTOFMEMORY; + + A11Y_TRYBLOCK_END +} + +STDMETHODIMP +ia2AccessibleText::get_textAtOffset(long aOffset, + enum IA2TextBoundaryType aBoundaryType, + long* aStartOffset, long* aEndOffset, + BSTR* aText) +{ + A11Y_TRYBLOCK_BEGIN + + if (!aStartOffset || !aEndOffset || !aText) + return E_INVALIDARG; + + *aStartOffset = *aEndOffset = 0; + *aText = nullptr; + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) + return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidOffset(aOffset)) + return E_INVALIDARG; + + nsAutoString text; + int32_t startOffset = 0, endOffset = 0; + if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) { + startOffset = 0; + endOffset = textAcc->CharacterCount(); + textAcc->TextSubstring(startOffset, endOffset, text); + } else { + AccessibleTextBoundary boundaryType = GetGeckoTextBoundary(aBoundaryType); + if (boundaryType == -1) + return S_FALSE; + textAcc->TextAtOffset(aOffset, boundaryType, &startOffset, &endOffset, text); + } + + *aStartOffset = startOffset; + *aEndOffset = endOffset; + + if (text.IsEmpty()) + return S_FALSE; + + *aText = ::SysAllocStringLen(text.get(), text.Length()); + return *aText ? S_OK : E_OUTOFMEMORY; + + A11Y_TRYBLOCK_END +} + +STDMETHODIMP +ia2AccessibleText::removeSelection(long aSelectionIndex) +{ + A11Y_TRYBLOCK_BEGIN + + MOZ_ASSERT(!HyperTextProxyFor(this)); + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) + return CO_E_OBJNOTCONNECTED; + + return textAcc->RemoveFromSelection(aSelectionIndex) ? + S_OK : E_INVALIDARG; + + A11Y_TRYBLOCK_END +} + +STDMETHODIMP +ia2AccessibleText::setCaretOffset(long aOffset) +{ + A11Y_TRYBLOCK_BEGIN + + MOZ_ASSERT(!HyperTextProxyFor(this)); + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) + return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidOffset(aOffset)) + return E_INVALIDARG; + + textAcc->SetCaretOffset(aOffset); + return S_OK; + + A11Y_TRYBLOCK_END +} + +STDMETHODIMP +ia2AccessibleText::setSelection(long aSelectionIndex, long aStartOffset, + long aEndOffset) +{ + A11Y_TRYBLOCK_BEGIN + + MOZ_ASSERT(!HyperTextProxyFor(this)); + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) + return CO_E_OBJNOTCONNECTED; + + return textAcc->SetSelectionBoundsAt(aSelectionIndex, aStartOffset, aEndOffset) ? + S_OK : E_INVALIDARG; + + A11Y_TRYBLOCK_END +} + +STDMETHODIMP +ia2AccessibleText::get_nCharacters(long* aNCharacters) +{ + A11Y_TRYBLOCK_BEGIN + + if (!aNCharacters) + return E_INVALIDARG; + *aNCharacters = 0; + + MOZ_ASSERT(!HyperTextProxyFor(this)); + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) + return CO_E_OBJNOTCONNECTED; + + *aNCharacters = textAcc->CharacterCount(); + return S_OK; + + A11Y_TRYBLOCK_END +} + +STDMETHODIMP +ia2AccessibleText::scrollSubstringTo(long aStartIndex, long aEndIndex, + enum IA2ScrollType aScrollType) +{ + A11Y_TRYBLOCK_BEGIN + + MOZ_ASSERT(!HyperTextProxyFor(this)); + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) + return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidRange(aStartIndex, aEndIndex)) + return E_INVALIDARG; + + textAcc->ScrollSubstringTo(aStartIndex, aEndIndex, aScrollType); + return S_OK; + + A11Y_TRYBLOCK_END +} + +STDMETHODIMP +ia2AccessibleText::scrollSubstringToPoint(long aStartIndex, long aEndIndex, + enum IA2CoordinateType aCoordType, + long aX, long aY) +{ + A11Y_TRYBLOCK_BEGIN + + uint32_t geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ? + nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE : + nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE; + + MOZ_ASSERT(!HyperTextProxyFor(this)); + + HyperTextAccessible* textAcc = static_cast<HyperTextAccessibleWrap*>(this); + if (textAcc->IsDefunct()) + return CO_E_OBJNOTCONNECTED; + + if (!textAcc->IsValidRange(aStartIndex, aEndIndex)) + return E_INVALIDARG; + + textAcc->ScrollSubstringToPoint(aStartIndex, aEndIndex, + geckoCoordType, aX, aY); + return S_OK; + + A11Y_TRYBLOCK_END +} + +STDMETHODIMP +ia2AccessibleText::get_newText(IA2TextSegment *aNewText) +{ + A11Y_TRYBLOCK_BEGIN + + return GetModifiedText(true, aNewText); + + A11Y_TRYBLOCK_END +} + +STDMETHODIMP +ia2AccessibleText::get_oldText(IA2TextSegment *aOldText) +{ + A11Y_TRYBLOCK_BEGIN + + return GetModifiedText(false, aOldText); + + A11Y_TRYBLOCK_END +} + +// ia2AccessibleText + +HRESULT +ia2AccessibleText::GetModifiedText(bool aGetInsertedText, + IA2TextSegment *aText) +{ + if (!aText) + return E_INVALIDARG; + + if (!sLastTextChangeAcc) + return S_OK; + + if (aGetInsertedText != sLastTextChangeWasInsert) + return S_OK; + + if (sLastTextChangeAcc != this) + return S_OK; + + aText->start = sLastTextChangeStart; + aText->end = sLastTextChangeEnd; + + if (sLastTextChangeString->IsEmpty()) + return S_FALSE; + + aText->text = ::SysAllocStringLen(sLastTextChangeString->get(), sLastTextChangeString->Length()); + return aText->text ? S_OK : E_OUTOFMEMORY; +} + +AccessibleTextBoundary +ia2AccessibleText::GetGeckoTextBoundary(enum IA2TextBoundaryType aBoundaryType) +{ + switch (aBoundaryType) { + case IA2_TEXT_BOUNDARY_CHAR: + return nsIAccessibleText::BOUNDARY_CHAR; + case IA2_TEXT_BOUNDARY_WORD: + return nsIAccessibleText::BOUNDARY_WORD_START; + case IA2_TEXT_BOUNDARY_LINE: + return nsIAccessibleText::BOUNDARY_LINE_START; + //case IA2_TEXT_BOUNDARY_SENTENCE: + //case IA2_TEXT_BOUNDARY_PARAGRAPH: + // XXX: not implemented + default: + return -1; + } +} + +void +ia2AccessibleText::InitTextChangeData() +{ + ClearOnShutdown(&sLastTextChangeAcc); + ClearOnShutdown(&sLastTextChangeString); +} + +void +ia2AccessibleText::UpdateTextChangeData(HyperTextAccessibleWrap* aAcc, + bool aInsert, const nsString& aStr, + int32_t aStart, uint32_t aLen) +{ + if (!sLastTextChangeString) + sLastTextChangeString = new nsString(); + + sLastTextChangeAcc = aAcc; + sLastTextChangeStart = aStart; + sLastTextChangeEnd = aStart + aLen; + sLastTextChangeWasInsert = aInsert; + *sLastTextChangeString = aStr; +} |