michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:expandtab:shiftwidth=2:tabstop=2: michael@0: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "ia2AccessibleText.h" michael@0: michael@0: #include "Accessible2.h" michael@0: #include "AccessibleText_i.c" michael@0: michael@0: #include "HyperTextAccessibleWrap.h" michael@0: #include "HyperTextAccessible-inl.h" michael@0: michael@0: using namespace mozilla::a11y; michael@0: michael@0: // IAccessibleText michael@0: michael@0: STDMETHODIMP michael@0: ia2AccessibleText::addSelection(long aStartOffset, long aEndOffset) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: HyperTextAccessible* textAcc = static_cast(this); michael@0: if (textAcc->IsDefunct()) michael@0: return CO_E_OBJNOTCONNECTED; michael@0: michael@0: return textAcc->AddToSelection(aStartOffset, aEndOffset) ? michael@0: S_OK : E_INVALIDARG; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: ia2AccessibleText::get_attributes(long aOffset, long *aStartOffset, michael@0: long *aEndOffset, BSTR *aTextAttributes) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: if (!aStartOffset || !aEndOffset || !aTextAttributes) michael@0: return E_INVALIDARG; michael@0: michael@0: *aStartOffset = 0; michael@0: *aEndOffset = 0; michael@0: *aTextAttributes = nullptr; michael@0: michael@0: HyperTextAccessible* textAcc = static_cast(this); michael@0: if (textAcc->IsDefunct()) michael@0: return CO_E_OBJNOTCONNECTED; michael@0: michael@0: int32_t startOffset = 0, endOffset = 0; michael@0: nsCOMPtr attributes = michael@0: textAcc->TextAttributes(true, aOffset, &startOffset, &endOffset); michael@0: michael@0: HRESULT hr = AccessibleWrap::ConvertToIA2Attributes(attributes, michael@0: aTextAttributes); michael@0: if (FAILED(hr)) michael@0: return hr; michael@0: michael@0: *aStartOffset = startOffset; michael@0: *aEndOffset = endOffset; michael@0: michael@0: return S_OK; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: ia2AccessibleText::get_caretOffset(long *aOffset) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: if (!aOffset) michael@0: return E_INVALIDARG; michael@0: michael@0: *aOffset = -1; michael@0: michael@0: HyperTextAccessible* textAcc = static_cast(this); michael@0: if (textAcc->IsDefunct()) michael@0: return CO_E_OBJNOTCONNECTED; michael@0: michael@0: *aOffset = textAcc->CaretOffset(); michael@0: return *aOffset != -1 ? S_OK : S_FALSE; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: ia2AccessibleText::get_characterExtents(long aOffset, michael@0: enum IA2CoordinateType aCoordType, michael@0: long* aX, long* aY, michael@0: long* aWidth, long* aHeight) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: if (!aX || !aY || !aWidth || !aHeight) michael@0: return E_INVALIDARG; michael@0: *aX = *aY = *aWidth = *aHeight = 0; michael@0: michael@0: HyperTextAccessible* textAcc = static_cast(this); michael@0: if (textAcc->IsDefunct()) michael@0: return CO_E_OBJNOTCONNECTED; michael@0: michael@0: uint32_t geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ? michael@0: nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE : michael@0: nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE; michael@0: michael@0: nsIntRect rect = textAcc->CharBounds(aOffset, geckoCoordType); michael@0: michael@0: *aX = rect.x; michael@0: *aY = rect.y; michael@0: *aWidth = rect.width; michael@0: *aHeight = rect.height; michael@0: return S_OK; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: ia2AccessibleText::get_nSelections(long* aNSelections) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: if (!aNSelections) michael@0: return E_INVALIDARG; michael@0: *aNSelections = 0; michael@0: michael@0: HyperTextAccessible* textAcc = static_cast(this); michael@0: if (textAcc->IsDefunct()) michael@0: return CO_E_OBJNOTCONNECTED; michael@0: michael@0: *aNSelections = textAcc->SelectionCount(); michael@0: return S_OK; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: ia2AccessibleText::get_offsetAtPoint(long aX, long aY, michael@0: enum IA2CoordinateType aCoordType, michael@0: long* aOffset) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: if (!aOffset) michael@0: return E_INVALIDARG; michael@0: *aOffset = 0; michael@0: michael@0: HyperTextAccessible* textAcc = static_cast(this); michael@0: if (textAcc->IsDefunct()) michael@0: return CO_E_OBJNOTCONNECTED; michael@0: michael@0: uint32_t geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ? michael@0: nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE : michael@0: nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE; michael@0: michael@0: *aOffset = textAcc->OffsetAtPoint(aX, aY, geckoCoordType); michael@0: return *aOffset == -1 ? S_FALSE : S_OK; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: ia2AccessibleText::get_selection(long aSelectionIndex, long* aStartOffset, michael@0: long* aEndOffset) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: if (!aStartOffset || !aEndOffset) michael@0: return E_INVALIDARG; michael@0: *aStartOffset = *aEndOffset = 0; michael@0: michael@0: HyperTextAccessible* textAcc = static_cast(this); michael@0: if (textAcc->IsDefunct()) michael@0: return CO_E_OBJNOTCONNECTED; michael@0: michael@0: int32_t startOffset = 0, endOffset = 0; michael@0: if (!textAcc->SelectionBoundsAt(aSelectionIndex, &startOffset, &endOffset)) michael@0: return E_INVALIDARG; michael@0: michael@0: *aStartOffset = startOffset; michael@0: *aEndOffset = endOffset; michael@0: return S_OK; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: ia2AccessibleText::get_text(long aStartOffset, long aEndOffset, BSTR* aText) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: if (!aText) michael@0: return E_INVALIDARG; michael@0: michael@0: *aText = nullptr; michael@0: michael@0: HyperTextAccessible* textAcc = static_cast(this); michael@0: if (textAcc->IsDefunct()) michael@0: return CO_E_OBJNOTCONNECTED; michael@0: michael@0: if (!textAcc->IsValidRange(aStartOffset, aEndOffset)) michael@0: return E_INVALIDARG; michael@0: michael@0: nsAutoString text; michael@0: textAcc->TextSubstring(aStartOffset, aEndOffset, text); michael@0: if (text.IsEmpty()) michael@0: return S_FALSE; michael@0: michael@0: *aText = ::SysAllocStringLen(text.get(), text.Length()); michael@0: return *aText ? S_OK : E_OUTOFMEMORY; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: ia2AccessibleText::get_textBeforeOffset(long aOffset, michael@0: enum IA2TextBoundaryType aBoundaryType, michael@0: long* aStartOffset, long* aEndOffset, michael@0: BSTR* aText) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: if (!aStartOffset || !aEndOffset || !aText) michael@0: return E_INVALIDARG; michael@0: michael@0: *aStartOffset = *aEndOffset = 0; michael@0: *aText = nullptr; michael@0: michael@0: HyperTextAccessible* textAcc = static_cast(this); michael@0: if (textAcc->IsDefunct()) michael@0: return CO_E_OBJNOTCONNECTED; michael@0: michael@0: if (!textAcc->IsValidOffset(aOffset)) michael@0: return E_INVALIDARG; michael@0: michael@0: nsAutoString text; michael@0: int32_t startOffset = 0, endOffset = 0; michael@0: michael@0: if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) { michael@0: startOffset = 0; michael@0: endOffset = textAcc->CharacterCount(); michael@0: textAcc->TextSubstring(startOffset, endOffset, text); michael@0: } else { michael@0: AccessibleTextBoundary boundaryType = GetGeckoTextBoundary(aBoundaryType); michael@0: if (boundaryType == -1) michael@0: return S_FALSE; michael@0: michael@0: textAcc->TextBeforeOffset(aOffset, boundaryType, &startOffset, &endOffset, text); michael@0: } michael@0: michael@0: *aStartOffset = startOffset; michael@0: *aEndOffset = endOffset; michael@0: michael@0: if (text.IsEmpty()) michael@0: return S_FALSE; michael@0: michael@0: *aText = ::SysAllocStringLen(text.get(), text.Length()); michael@0: return *aText ? S_OK : E_OUTOFMEMORY; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: ia2AccessibleText::get_textAfterOffset(long aOffset, michael@0: enum IA2TextBoundaryType aBoundaryType, michael@0: long* aStartOffset, long* aEndOffset, michael@0: BSTR* aText) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: if (!aStartOffset || !aEndOffset || !aText) michael@0: return E_INVALIDARG; michael@0: michael@0: *aStartOffset = 0; michael@0: *aEndOffset = 0; michael@0: *aText = nullptr; michael@0: michael@0: HyperTextAccessible* textAcc = static_cast(this); michael@0: if (textAcc->IsDefunct()) michael@0: return CO_E_OBJNOTCONNECTED; michael@0: michael@0: if (!textAcc->IsValidOffset(aOffset)) michael@0: return E_INVALIDARG; michael@0: michael@0: nsAutoString text; michael@0: int32_t startOffset = 0, endOffset = 0; michael@0: michael@0: if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) { michael@0: startOffset = 0; michael@0: endOffset = textAcc->CharacterCount(); michael@0: textAcc->TextSubstring(startOffset, endOffset, text); michael@0: } else { michael@0: AccessibleTextBoundary boundaryType = GetGeckoTextBoundary(aBoundaryType); michael@0: if (boundaryType == -1) michael@0: return S_FALSE; michael@0: textAcc->TextAfterOffset(aOffset, boundaryType, &startOffset, &endOffset, text); michael@0: } michael@0: michael@0: *aStartOffset = startOffset; michael@0: *aEndOffset = endOffset; michael@0: michael@0: if (text.IsEmpty()) michael@0: return S_FALSE; michael@0: michael@0: *aText = ::SysAllocStringLen(text.get(), text.Length()); michael@0: return *aText ? S_OK : E_OUTOFMEMORY; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: ia2AccessibleText::get_textAtOffset(long aOffset, michael@0: enum IA2TextBoundaryType aBoundaryType, michael@0: long* aStartOffset, long* aEndOffset, michael@0: BSTR* aText) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: if (!aStartOffset || !aEndOffset || !aText) michael@0: return E_INVALIDARG; michael@0: michael@0: *aStartOffset = *aEndOffset = 0; michael@0: *aText = nullptr; michael@0: michael@0: HyperTextAccessible* textAcc = static_cast(this); michael@0: if (textAcc->IsDefunct()) michael@0: return CO_E_OBJNOTCONNECTED; michael@0: michael@0: if (!textAcc->IsValidOffset(aOffset)) michael@0: return E_INVALIDARG; michael@0: michael@0: nsAutoString text; michael@0: int32_t startOffset = 0, endOffset = 0; michael@0: if (aBoundaryType == IA2_TEXT_BOUNDARY_ALL) { michael@0: startOffset = 0; michael@0: endOffset = textAcc->CharacterCount(); michael@0: textAcc->TextSubstring(startOffset, endOffset, text); michael@0: } else { michael@0: AccessibleTextBoundary boundaryType = GetGeckoTextBoundary(aBoundaryType); michael@0: if (boundaryType == -1) michael@0: return S_FALSE; michael@0: textAcc->TextAtOffset(aOffset, boundaryType, &startOffset, &endOffset, text); michael@0: } michael@0: michael@0: *aStartOffset = startOffset; michael@0: *aEndOffset = endOffset; michael@0: michael@0: if (text.IsEmpty()) michael@0: return S_FALSE; michael@0: michael@0: *aText = ::SysAllocStringLen(text.get(), text.Length()); michael@0: return *aText ? S_OK : E_OUTOFMEMORY; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: ia2AccessibleText::removeSelection(long aSelectionIndex) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: HyperTextAccessible* textAcc = static_cast(this); michael@0: if (textAcc->IsDefunct()) michael@0: return CO_E_OBJNOTCONNECTED; michael@0: michael@0: return textAcc->RemoveFromSelection(aSelectionIndex) ? michael@0: S_OK : E_INVALIDARG; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: ia2AccessibleText::setCaretOffset(long aOffset) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: HyperTextAccessible* textAcc = static_cast(this); michael@0: if (textAcc->IsDefunct()) michael@0: return CO_E_OBJNOTCONNECTED; michael@0: michael@0: if (!textAcc->IsValidOffset(aOffset)) michael@0: return E_INVALIDARG; michael@0: michael@0: textAcc->SetCaretOffset(aOffset); michael@0: return S_OK; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: ia2AccessibleText::setSelection(long aSelectionIndex, long aStartOffset, michael@0: long aEndOffset) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: HyperTextAccessible* textAcc = static_cast(this); michael@0: if (textAcc->IsDefunct()) michael@0: return CO_E_OBJNOTCONNECTED; michael@0: michael@0: return textAcc->SetSelectionBoundsAt(aSelectionIndex, aStartOffset, aEndOffset) ? michael@0: S_OK : E_INVALIDARG; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: ia2AccessibleText::get_nCharacters(long* aNCharacters) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: if (!aNCharacters) michael@0: return E_INVALIDARG; michael@0: *aNCharacters = 0; michael@0: michael@0: HyperTextAccessible* textAcc = static_cast(this); michael@0: if (textAcc->IsDefunct()) michael@0: return CO_E_OBJNOTCONNECTED; michael@0: michael@0: *aNCharacters = textAcc->CharacterCount(); michael@0: return S_OK; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: ia2AccessibleText::scrollSubstringTo(long aStartIndex, long aEndIndex, michael@0: enum IA2ScrollType aScrollType) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: HyperTextAccessible* textAcc = static_cast(this); michael@0: if (textAcc->IsDefunct()) michael@0: return CO_E_OBJNOTCONNECTED; michael@0: michael@0: if (!textAcc->IsValidRange(aStartIndex, aEndIndex)) michael@0: return E_INVALIDARG; michael@0: michael@0: textAcc->ScrollSubstringTo(aStartIndex, aEndIndex, aScrollType); michael@0: return S_OK; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: ia2AccessibleText::scrollSubstringToPoint(long aStartIndex, long aEndIndex, michael@0: enum IA2CoordinateType aCoordType, michael@0: long aX, long aY) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: HyperTextAccessible* textAcc = static_cast(this); michael@0: if (textAcc->IsDefunct()) michael@0: return CO_E_OBJNOTCONNECTED; michael@0: michael@0: if (!textAcc->IsValidRange(aStartIndex, aEndIndex)) michael@0: return E_INVALIDARG; michael@0: michael@0: uint32_t geckoCoordType = (aCoordType == IA2_COORDTYPE_SCREEN_RELATIVE) ? michael@0: nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE : michael@0: nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE; michael@0: michael@0: textAcc->ScrollSubstringToPoint(aStartIndex, aEndIndex, michael@0: geckoCoordType, aX, aY); michael@0: return S_OK; michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: ia2AccessibleText::get_newText(IA2TextSegment *aNewText) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: return GetModifiedText(true, aNewText); michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: STDMETHODIMP michael@0: ia2AccessibleText::get_oldText(IA2TextSegment *aOldText) michael@0: { michael@0: A11Y_TRYBLOCK_BEGIN michael@0: michael@0: return GetModifiedText(false, aOldText); michael@0: michael@0: A11Y_TRYBLOCK_END michael@0: } michael@0: michael@0: // ia2AccessibleText michael@0: michael@0: HRESULT michael@0: ia2AccessibleText::GetModifiedText(bool aGetInsertedText, michael@0: IA2TextSegment *aText) michael@0: { michael@0: if (!aText) michael@0: return E_INVALIDARG; michael@0: michael@0: uint32_t startOffset = 0, endOffset = 0; michael@0: nsAutoString text; michael@0: michael@0: nsresult rv = GetModifiedText(aGetInsertedText, text, michael@0: &startOffset, &endOffset); michael@0: if (NS_FAILED(rv)) michael@0: return GetHRESULT(rv); michael@0: michael@0: aText->start = startOffset; michael@0: aText->end = endOffset; michael@0: michael@0: if (text.IsEmpty()) michael@0: return S_FALSE; michael@0: michael@0: aText->text = ::SysAllocStringLen(text.get(), text.Length()); michael@0: return aText->text ? S_OK : E_OUTOFMEMORY; michael@0: } michael@0: michael@0: AccessibleTextBoundary michael@0: ia2AccessibleText::GetGeckoTextBoundary(enum IA2TextBoundaryType aBoundaryType) michael@0: { michael@0: switch (aBoundaryType) { michael@0: case IA2_TEXT_BOUNDARY_CHAR: michael@0: return nsIAccessibleText::BOUNDARY_CHAR; michael@0: case IA2_TEXT_BOUNDARY_WORD: michael@0: return nsIAccessibleText::BOUNDARY_WORD_START; michael@0: case IA2_TEXT_BOUNDARY_LINE: michael@0: return nsIAccessibleText::BOUNDARY_LINE_START; michael@0: //case IA2_TEXT_BOUNDARY_SENTENCE: michael@0: //case IA2_TEXT_BOUNDARY_PARAGRAPH: michael@0: // XXX: not implemented michael@0: default: michael@0: return -1; michael@0: } michael@0: } michael@0: