| /* |
| * Copyright (C) 2008-2018 Apple Inc. All Rights Reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "AccessibilityUIElement.h" |
| |
| #include "AccessibilityController.h" |
| #include "DumpRenderTree.h" |
| #include "FrameLoadDelegate.h" |
| #include <JavaScriptCore/JSStringRef.h> |
| #include <JavaScriptCore/JSStringRefBSTR.h> |
| #include <wtf/text/WTFString.h> |
| #include <comutil.h> |
| #include <tchar.h> |
| #include <string> |
| |
| using std::wstring; |
| |
| static JSRetainPtr<JSStringRef> createEmptyJSString() |
| { |
| return adopt(JSStringCreateWithCharacters(nullptr, 0)); |
| } |
| |
| static COMPtr<IAccessibleComparable> comparableObject(IAccessible* accessible) |
| { |
| COMPtr<IServiceProvider> serviceProvider(Query, accessible); |
| if (!serviceProvider) |
| return 0; |
| COMPtr<IAccessibleComparable> comparable; |
| serviceProvider->QueryService(SID_AccessibleComparable, __uuidof(IAccessibleComparable), reinterpret_cast<void**>(&comparable)); |
| return comparable; |
| } |
| |
| AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element) |
| : m_element(element) |
| { |
| } |
| |
| bool AccessibilityUIElement::isEqual(AccessibilityUIElement* otherElement) |
| { |
| COMPtr<IAccessibleComparable> comparable = comparableObject(m_element.get()); |
| COMPtr<IAccessibleComparable> otherComparable = comparableObject(otherElement->m_element.get()); |
| if (!comparable || !otherComparable) |
| return false; |
| BOOL isSame = FALSE; |
| if (FAILED(comparable->isSameObject(otherComparable.get(), &isSame))) |
| return false; |
| return isSame; |
| } |
| |
| void AccessibilityUIElement::getLinkedUIElements(Vector<AccessibilityUIElement>&) |
| { |
| } |
| |
| void AccessibilityUIElement::getDocumentLinks(Vector<AccessibilityUIElement>&) |
| { |
| } |
| |
| void AccessibilityUIElement::getChildren(Vector<AccessibilityUIElement>& children) |
| { |
| if (!m_element) |
| return; |
| |
| long childCount; |
| if (FAILED(m_element->get_accChildCount(&childCount))) |
| return; |
| for (long i = 0; i < childCount; ++i) |
| children.append(getChildAtIndex(i)); |
| } |
| |
| void AccessibilityUIElement::getChildrenWithRange(Vector<AccessibilityUIElement>& elementVector, unsigned location, unsigned length) |
| { |
| if (!m_element) |
| return; |
| |
| long childCount; |
| unsigned appendedCount = 0; |
| if (FAILED(m_element->get_accChildCount(&childCount))) |
| return; |
| for (long i = location; i < childCount && appendedCount < length; ++i, ++appendedCount) |
| elementVector.append(getChildAtIndex(i)); |
| } |
| |
| int AccessibilityUIElement::childrenCount() |
| { |
| if (!m_element) |
| return 0; |
| |
| long childCount; |
| if (FAILED(m_element->get_accChildCount(&childCount))) |
| return 0; |
| |
| return childCount; |
| } |
| |
| int AccessibilityUIElement::rowCount() |
| { |
| // FIXME: implement |
| return 0; |
| } |
| |
| int AccessibilityUIElement::columnCount() |
| { |
| // FIXME: implement |
| return 0; |
| } |
| |
| AccessibilityUIElement AccessibilityUIElement::elementAtPoint(int x, int y) |
| { |
| return { nullptr }; |
| } |
| |
| AccessibilityUIElement AccessibilityUIElement::linkedUIElementAtIndex(unsigned index) |
| { |
| // FIXME: implement |
| return { nullptr }; |
| } |
| |
| AccessibilityUIElement AccessibilityUIElement::getChildAtIndex(unsigned index) |
| { |
| if (!m_element) |
| return { nullptr }; |
| |
| COMPtr<IDispatch> child; |
| _variant_t vChild; |
| V_VT(&vChild) = VT_I4; |
| // In MSAA, index 0 is the object itself. |
| V_I4(&vChild) = index + 1; |
| if (FAILED(m_element->get_accChild(vChild.GetVARIANT(), &child))) |
| return { nullptr }; |
| return COMPtr<IAccessible>(Query, child); |
| } |
| |
| unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element) |
| { |
| // FIXME: implement |
| return 0; |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::allAttributes() |
| { |
| return createEmptyJSString(); |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfLinkedUIElements() |
| { |
| return createEmptyJSString(); |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfDocumentLinks() |
| { |
| return createEmptyJSString(); |
| } |
| |
| AccessibilityUIElement AccessibilityUIElement::titleUIElement() |
| { |
| COMPtr<IAccessible> platformElement = platformUIElement(); |
| |
| COMPtr<IAccessibleComparable> comparable = comparableObject(platformElement.get()); |
| if (!comparable) |
| return { nullptr }; |
| |
| _variant_t value; |
| _bstr_t titleUIElementAttributeKey(L"AXTitleUIElementAttribute"); |
| if (FAILED(comparable->get_attribute(titleUIElementAttributeKey, &value.GetVARIANT()))) |
| return { nullptr }; |
| |
| if (V_VT(&value) == VT_EMPTY) |
| return { nullptr }; |
| |
| ASSERT(V_VT(&value) == VT_UNKNOWN); |
| |
| if (V_VT(&value) != VT_UNKNOWN) |
| return { nullptr }; |
| |
| COMPtr<IAccessible> titleElement(Query, value.punkVal); |
| |
| return titleElement; |
| } |
| |
| AccessibilityUIElement AccessibilityUIElement::parentElement() |
| { |
| if (!m_element) |
| return { nullptr }; |
| |
| COMPtr<IDispatch> parent; |
| m_element->get_accParent(&parent); |
| |
| COMPtr<IAccessible> parentAccessible(Query, parent); |
| return parentAccessible; |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfChildren() |
| { |
| return createEmptyJSString(); |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::parameterizedAttributeNames() |
| { |
| return createEmptyJSString(); |
| } |
| |
| static VARIANT& self() |
| { |
| static _variant_t vSelf; |
| static bool haveInitialized; |
| |
| if (!haveInitialized) { |
| V_VT(&vSelf) = VT_I4; |
| V_I4(&vSelf) = CHILDID_SELF; |
| } |
| return vSelf; |
| } |
| |
| static _bstr_t convertToDRTLabel(const _bstr_t roleName) |
| { |
| if (!wcscmp(roleName, L"cell")) |
| return _bstr_t(L"AXCell"); |
| if (!wcscmp(roleName, L"check box")) |
| return _bstr_t(L"AXCheckBox"); |
| if (!wcscmp(roleName, L"client")) |
| return _bstr_t(L"AXWebArea"); |
| if (!wcscmp(roleName, L"column")) |
| return _bstr_t(L"AXColumn"); |
| if (!wcscmp(roleName, L"column header")) |
| return _bstr_t(L"AXCell"); |
| if (!wcscmp(roleName, L"combo box")) |
| return _bstr_t(L"AXComboBox"); |
| if (!wcscmp(roleName, L"grouping")) |
| return _bstr_t(L"AXGroup"); |
| if (!wcscmp(roleName, L"editable text")) |
| return _bstr_t(L"AXStaticText"); // Might be AXTextField, too. |
| if (!wcscmp(roleName, L"graphic")) |
| return _bstr_t(L"AXImage"); |
| if (!wcscmp(roleName, L"link")) |
| return _bstr_t(L"AXLink"); |
| if (!wcscmp(roleName, L"list item")) |
| return _bstr_t(L"AXTab"); |
| if (!wcscmp(roleName, L"list")) |
| return _bstr_t(L"AXList"); |
| if (!wcscmp(roleName, L"menu bar")) |
| return _bstr_t(L"AXMenuBar"); |
| if (!wcscmp(roleName, L"page tab list")) |
| return _bstr_t(L"AXTabGroup"); |
| if (!wcscmp(roleName, L"page tab")) |
| return _bstr_t(L"AXTab"); |
| if (!wcscmp(roleName, L"push button")) |
| return _bstr_t(L"AXButton"); |
| if (!wcscmp(roleName, L"progress bar")) |
| return _bstr_t(L"AXProgressIndicator"); |
| if (!wcscmp(roleName, L"radio button")) |
| return _bstr_t(L"AXRadioButton"); |
| if (!wcscmp(roleName, L"row")) |
| return _bstr_t(L"AXRow"); |
| if (!wcscmp(roleName, L"table")) |
| return _bstr_t(L"AXTable"); |
| if (!wcscmp(roleName, L"text")) |
| return _bstr_t(L"AXStaticText"); |
| |
| return roleName; |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::role() |
| { |
| if (!m_element) |
| return adopt(JSStringCreateWithUTF8CString("AXRole: ")); |
| |
| _variant_t vRole; |
| if (FAILED(m_element->get_accRole(self(), &vRole.GetVARIANT()))) |
| return adopt(JSStringCreateWithUTF8CString("AXRole: ")); |
| |
| ASSERT(V_VT(&vRole) == VT_I4 || V_VT(&vRole) == VT_BSTR); |
| |
| _bstr_t result; |
| if (V_VT(&vRole) == VT_I4) { |
| unsigned roleTextLength = ::GetRoleText(V_I4(&vRole), nullptr, 0) + 1; |
| |
| Vector<TCHAR> roleText(roleTextLength); |
| |
| ::GetRoleText(V_I4(&vRole), roleText.data(), roleTextLength); |
| |
| result = roleText.data(); |
| } else if (V_VT(&vRole) == VT_BSTR) |
| result = V_BSTR(&vRole); |
| |
| return adopt(JSStringCreateWithBSTR(_bstr_t(L"AXRole: ") + convertToDRTLabel(result))); |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::subrole() |
| { |
| return 0; |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::roleDescription() |
| { |
| return 0; |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::computedRoleString() |
| { |
| return 0; |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::title() |
| { |
| if (!m_element) |
| return adopt(JSStringCreateWithUTF8CString("AXTitle: ")); |
| |
| _bstr_t titleBSTR; |
| if (FAILED(m_element->get_accName(self(), &titleBSTR.GetBSTR()))) |
| return adopt(JSStringCreateWithUTF8CString("AXTitle: ")); |
| |
| return adopt(JSStringCreateWithBSTR(_bstr_t(L"AXTitle: ") + titleBSTR)); |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::description() |
| { |
| if (!m_element) |
| return adopt(JSStringCreateWithUTF8CString("AXDescription: ")); |
| |
| _bstr_t descriptionBSTR; |
| if (FAILED(m_element->get_accDescription(self(), &descriptionBSTR.GetBSTR()))) |
| return adopt(JSStringCreateWithUTF8CString("AXDescription: ")); |
| |
| if (!descriptionBSTR.length()) |
| return adopt(JSStringCreateWithUTF8CString("AXDescription: ")); |
| |
| if (wcsstr(static_cast<wchar_t*>(descriptionBSTR), L"Description: ") == static_cast<wchar_t*>(descriptionBSTR)) { |
| // The Mozilla MSAA implementation requires that the string returned to us be prefixed with "Description: " |
| // To match the Mac test results, we will just prefix with AX -> AXDescription: |
| return adopt(JSStringCreateWithBSTR(_bstr_t(L"AX") + descriptionBSTR)); |
| } |
| |
| return adopt(JSStringCreateWithBSTR(descriptionBSTR)); |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::stringValue() |
| { |
| if (!m_element) |
| return adopt(JSStringCreateWithUTF8CString("AXValue: ")); |
| |
| _bstr_t valueBSTR; |
| if (FAILED(m_element->get_accValue(self(), &valueBSTR.GetBSTR()))) |
| return adopt(JSStringCreateWithUTF8CString("AXValue: ")); |
| |
| return adopt(JSStringCreateWithBSTR(_bstr_t(L"AXValue: ") + valueBSTR)); |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::language() |
| { |
| if (!m_element) |
| return adopt(JSStringCreateWithUTF8CString("AXLanguage: ")); |
| |
| COMPtr<IAccessibleComparable> accessible2Element = comparableObject(m_element.get()); |
| if (!accessible2Element) |
| return adopt(JSStringCreateWithUTF8CString("AXLanguage: ")); |
| |
| IA2Locale locale; |
| if (FAILED(accessible2Element->get_locale(&locale))) |
| return adopt(JSStringCreateWithUTF8CString("AXLanguage: ")); |
| |
| return adopt(JSStringCreateWithBSTR(_bstr_t(L"AXLanguage: ") + _bstr_t(locale.language, false))); |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::helpText() const |
| { |
| if (!m_element) |
| return adopt(JSStringCreateWithUTF8CString("AXHelp: ")); |
| |
| _bstr_t helpTextBSTR; |
| if (FAILED(m_element->get_accHelp(self(), &helpTextBSTR.GetBSTR()))) |
| return adopt(JSStringCreateWithUTF8CString("AXHelp: ")); |
| |
| return adopt(JSStringCreateWithBSTR(_bstr_t(L"AXHelp: ") + helpTextBSTR)); |
| } |
| |
| double AccessibilityUIElement::x() |
| { |
| if (!m_element) |
| return 0; |
| |
| long x, y, width, height; |
| if (FAILED(m_element->accLocation(&x, &y, &width, &height, self()))) |
| return 0; |
| return x; |
| } |
| |
| double AccessibilityUIElement::y() |
| { |
| if (!m_element) |
| return 0; |
| |
| long x, y, width, height; |
| if (FAILED(m_element->accLocation(&x, &y, &width, &height, self()))) |
| return 0; |
| return y; |
| } |
| |
| double AccessibilityUIElement::width() |
| { |
| if (!m_element) |
| return 0; |
| |
| long x, y, width, height; |
| if (FAILED(m_element->accLocation(&x, &y, &width, &height, self()))) |
| return 0; |
| return width; |
| } |
| |
| double AccessibilityUIElement::height() |
| { |
| if (!m_element) |
| return 0; |
| |
| long x, y, width, height; |
| if (FAILED(m_element->accLocation(&x, &y, &width, &height, self()))) |
| return 0; |
| return height; |
| } |
| |
| double AccessibilityUIElement::clickPointX() |
| { |
| return 0; |
| } |
| |
| double AccessibilityUIElement::clickPointY() |
| { |
| return 0; |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::valueDescription() |
| { |
| return nullptr; |
| } |
| |
| static DWORD accessibilityState(COMPtr<IAccessible> element) |
| { |
| _variant_t state; |
| if (FAILED(element->get_accState(self(), &state.GetVARIANT()))) |
| return 0; |
| |
| ASSERT(V_VT(&state) == VT_I4); |
| |
| DWORD result = state.lVal; |
| |
| return result; |
| } |
| |
| bool AccessibilityUIElement::isFocused() const |
| { |
| DWORD state = accessibilityState(m_element); |
| return (state & STATE_SYSTEM_FOCUSED) == STATE_SYSTEM_FOCUSED; |
| } |
| |
| bool AccessibilityUIElement::isSelected() const |
| { |
| DWORD state = accessibilityState(m_element); |
| return (state & STATE_SYSTEM_SELECTED) == STATE_SYSTEM_SELECTED; |
| } |
| |
| int AccessibilityUIElement::hierarchicalLevel() const |
| { |
| return 0; |
| } |
| |
| bool AccessibilityUIElement::ariaIsGrabbed() const |
| { |
| return false; |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::ariaDropEffects() const |
| { |
| return 0; |
| } |
| |
| bool AccessibilityUIElement::isExpanded() const |
| { |
| return false; |
| } |
| |
| bool AccessibilityUIElement::isChecked() const |
| { |
| if (!m_element) |
| return false; |
| |
| _variant_t vState; |
| if (FAILED(m_element->get_accState(self(), &vState.GetVARIANT()))) |
| return false; |
| |
| return vState.lVal & STATE_SYSTEM_CHECKED; |
| } |
| |
| bool AccessibilityUIElement::isIndeterminate() const |
| { |
| // FIXME: implement |
| return false; |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::orientation() const |
| { |
| return 0; |
| } |
| |
| bool AccessibilityUIElement::isAtomicLiveRegion() const |
| { |
| return false; |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::liveRegionRelevant() const |
| { |
| return 0; |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::liveRegionStatus() const |
| { |
| return 0; |
| } |
| |
| double AccessibilityUIElement::intValue() const |
| { |
| if (!m_element) |
| return 0; |
| |
| _bstr_t valueBSTR; |
| if (FAILED(m_element->get_accValue(self(), &valueBSTR.GetBSTR())) || !valueBSTR.length()) |
| return 0; |
| |
| TCHAR* ignored; |
| return _tcstod(static_cast<TCHAR*>(valueBSTR), &ignored); |
| } |
| |
| double AccessibilityUIElement::minValue() |
| { |
| return 0; |
| } |
| |
| double AccessibilityUIElement::maxValue() |
| { |
| return 0; |
| } |
| |
| bool AccessibilityUIElement::isPressActionSupported() |
| { |
| if (!m_element) |
| return 0; |
| |
| _bstr_t valueBSTR; |
| if (FAILED(m_element->get_accDefaultAction(self(), &valueBSTR.GetBSTR()))) |
| return false; |
| |
| if (!valueBSTR.length()) |
| return false; |
| |
| return true; |
| } |
| |
| bool AccessibilityUIElement::isIncrementActionSupported() |
| { |
| return false; |
| } |
| |
| bool AccessibilityUIElement::isDecrementActionSupported() |
| { |
| return false; |
| } |
| |
| bool AccessibilityUIElement::isBusy() const |
| { |
| // FIXME: Implement. |
| return false; |
| } |
| |
| bool AccessibilityUIElement::isEnabled() |
| { |
| DWORD state = accessibilityState(m_element); |
| return (state & STATE_SYSTEM_UNAVAILABLE) != STATE_SYSTEM_UNAVAILABLE; |
| } |
| |
| bool AccessibilityUIElement::isRequired() const |
| { |
| return false; |
| } |
| |
| |
| int AccessibilityUIElement::insertionPointLineNumber() |
| { |
| return 0; |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumnHeaders() |
| { |
| return createEmptyJSString(); |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRowHeaders() |
| { |
| return createEmptyJSString(); |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumns() |
| { |
| return createEmptyJSString(); |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRows() |
| { |
| return createEmptyJSString(); |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfVisibleCells() |
| { |
| return createEmptyJSString(); |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfHeader() |
| { |
| return createEmptyJSString(); |
| } |
| |
| int AccessibilityUIElement::indexInTable() |
| { |
| return 0; |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::rowIndexRange() |
| { |
| return createEmptyJSString(); |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::columnIndexRange() |
| { |
| return createEmptyJSString(); |
| } |
| |
| int AccessibilityUIElement::lineForIndex(int) |
| { |
| return 0; |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::boundsForRange(unsigned location, unsigned length) |
| { |
| return createEmptyJSString(); |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForRange(unsigned, unsigned) |
| { |
| return createEmptyJSString(); |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::attributedStringForRange(unsigned, unsigned) |
| { |
| return createEmptyJSString(); |
| } |
| |
| bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned, unsigned) |
| { |
| return false; |
| } |
| |
| unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly) |
| { |
| return 0; |
| } |
| |
| AccessibilityUIElement AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly) |
| { |
| return { nullptr }; |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::selectTextWithCriteria(JSContextRef context, JSStringRef ambiguityResolution, JSValueRef searchStrings, JSStringRef replacementString, JSStringRef activity) |
| { |
| return 0; |
| } |
| |
| AccessibilityUIElement AccessibilityUIElement::cellForColumnAndRow(unsigned column, unsigned row) |
| { |
| return { nullptr }; |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::selectedTextRange() |
| { |
| COMPtr<IAccessibleComparable> comparable = comparableObject(platformUIElement().get()); |
| if (!comparable) |
| return createEmptyJSString(); |
| |
| _variant_t value; |
| if (FAILED(comparable->get_attribute(_bstr_t(L"AXSelectedTextRangeAttribute"), &value.GetVARIANT()))) |
| return createEmptyJSString(); |
| |
| ASSERT(V_VT(&value) == VT_BSTR); |
| return adopt(JSStringCreateWithBSTR(value.bstrVal)); |
| } |
| |
| void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length) |
| { |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::stringAttributeValue(JSStringRef attribute) |
| { |
| // FIXME: implement |
| return createEmptyJSString(); |
| } |
| |
| double AccessibilityUIElement::numberAttributeValue(JSStringRef attribute) |
| { |
| // FIXME: implement |
| return 0; |
| } |
| |
| bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute) |
| { |
| // FIXME: implement |
| return false; |
| } |
| |
| bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute) |
| { |
| return false; |
| } |
| |
| bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute) |
| { |
| return false; |
| } |
| |
| void AccessibilityUIElement::increment() |
| { |
| } |
| |
| void AccessibilityUIElement::decrement() |
| { |
| } |
| |
| void AccessibilityUIElement::showMenu() |
| { |
| if (!m_element) |
| return; |
| |
| ASSERT(hasPopup()); |
| m_element->accDoDefaultAction(self()); |
| } |
| |
| void AccessibilityUIElement::press() |
| { |
| if (!m_element) |
| return; |
| |
| m_element->accDoDefaultAction(self()); |
| } |
| |
| void AccessibilityUIElement::dismiss() |
| { |
| } |
| |
| AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index) |
| { |
| return { nullptr }; |
| } |
| |
| AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index) |
| { |
| return { nullptr }; |
| } |
| |
| AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index) |
| { |
| return { nullptr }; |
| } |
| |
| AccessibilityUIElement AccessibilityUIElement::ariaControlsElementAtIndex(unsigned index) |
| { |
| return { nullptr }; |
| } |
| |
| AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index) |
| { |
| return { nullptr }; |
| } |
| |
| AccessibilityUIElement AccessibilityUIElement::rowAtIndex(unsigned index) |
| { |
| return { nullptr }; |
| } |
| |
| AccessibilityUIElement AccessibilityUIElement::disclosedByRow() |
| { |
| return { nullptr }; |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::accessibilityValue() const |
| { |
| if (!m_element) |
| return createEmptyJSString(); |
| |
| _bstr_t valueBSTR; |
| if (FAILED(m_element->get_accValue(self(), &valueBSTR.GetBSTR())) || !valueBSTR.length()) |
| return createEmptyJSString(); |
| |
| return adopt(JSStringCreateWithBSTR(valueBSTR)); |
| } |
| |
| void AccessibilityUIElement::clearSelectedChildren() const |
| { |
| // FIXME: implement |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::documentEncoding() |
| { |
| return createEmptyJSString(); |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::documentURI() |
| { |
| return createEmptyJSString(); |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::url() |
| { |
| // FIXME: implement |
| return createEmptyJSString(); |
| } |
| |
| bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallback) |
| { |
| if (!functionCallback) |
| return false; |
| |
| sharedFrameLoadDelegate->accessibilityController()->winAddNotificationListener(m_element, functionCallback); |
| return true; |
| } |
| |
| void AccessibilityUIElement::removeNotificationListener() |
| { |
| // FIXME: implement |
| } |
| |
| bool AccessibilityUIElement::isFocusable() const |
| { |
| // FIXME: implement |
| return false; |
| } |
| |
| bool AccessibilityUIElement::isSelectable() const |
| { |
| DWORD state = accessibilityState(m_element); |
| return (state & STATE_SYSTEM_SELECTABLE) == STATE_SYSTEM_SELECTABLE; |
| } |
| |
| bool AccessibilityUIElement::isMultiSelectable() const |
| { |
| DWORD multiSelectable = STATE_SYSTEM_EXTSELECTABLE | STATE_SYSTEM_MULTISELECTABLE; |
| DWORD state = accessibilityState(m_element); |
| return (state & multiSelectable) == multiSelectable; |
| } |
| |
| bool AccessibilityUIElement::isSelectedOptionActive() const |
| { |
| // FIXME: implement |
| return false; |
| } |
| |
| bool AccessibilityUIElement::isVisible() const |
| { |
| DWORD state = accessibilityState(m_element); |
| return (state & STATE_SYSTEM_INVISIBLE) != STATE_SYSTEM_INVISIBLE; |
| } |
| |
| bool AccessibilityUIElement::isOffScreen() const |
| { |
| DWORD state = accessibilityState(m_element); |
| return (state & STATE_SYSTEM_OFFSCREEN) == STATE_SYSTEM_OFFSCREEN; |
| } |
| |
| bool AccessibilityUIElement::isCollapsed() const |
| { |
| DWORD state = accessibilityState(m_element); |
| return (state & STATE_SYSTEM_COLLAPSED) == STATE_SYSTEM_COLLAPSED; |
| } |
| |
| bool AccessibilityUIElement::isIgnored() const |
| { |
| // FIXME: implement |
| return false; |
| } |
| |
| bool AccessibilityUIElement::isSingleLine() const |
| { |
| // FIXME: implement |
| return false; |
| } |
| |
| bool AccessibilityUIElement::isMultiLine() const |
| { |
| // FIXME: implement |
| return false; |
| } |
| |
| bool AccessibilityUIElement::hasPopup() const |
| { |
| DWORD state = accessibilityState(m_element); |
| return (state & STATE_SYSTEM_HASPOPUP) == STATE_SYSTEM_HASPOPUP; |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::popupValue() const |
| { |
| return createEmptyJSString(); |
| } |
| |
| bool AccessibilityUIElement::hasDocumentRoleAncestor() const |
| { |
| // FIXME: Implement. |
| return false; |
| } |
| |
| bool AccessibilityUIElement::hasWebApplicationAncestor() const |
| { |
| // FIXME: Implement. |
| return false; |
| } |
| |
| bool AccessibilityUIElement::isInDescriptionListDetail() const |
| { |
| // FIXME: Implement. |
| return false; |
| } |
| |
| bool AccessibilityUIElement::isInDescriptionListTerm() const |
| { |
| // FIXME: Implement. |
| return false; |
| } |
| |
| bool AccessibilityUIElement::isInCell() const |
| { |
| // FIXME: Implement. |
| return false; |
| } |
| |
| void AccessibilityUIElement::takeFocus() |
| { |
| if (!m_element) |
| return; |
| |
| m_element->accSelect(SELFLAG_TAKEFOCUS, self()); |
| } |
| |
| void AccessibilityUIElement::takeSelection() |
| { |
| if (!m_element) |
| return; |
| |
| m_element->accSelect(SELFLAG_TAKESELECTION, self()); |
| } |
| |
| void AccessibilityUIElement::addSelection() |
| { |
| if (!m_element) |
| return; |
| |
| m_element->accSelect(SELFLAG_ADDSELECTION, self()); |
| } |
| |
| void AccessibilityUIElement::removeSelection() |
| { |
| if (!m_element) |
| return; |
| |
| m_element->accSelect(SELFLAG_REMOVESELECTION, self()); |
| } |
| |
| void AccessibilityUIElement::scrollToMakeVisible() |
| { |
| // FIXME: implement |
| } |
| |
| void AccessibilityUIElement::scrollToMakeVisibleWithSubFocus(int x, int y, int width, int height) |
| { |
| // FIXME: implement |
| } |
| |
| void AccessibilityUIElement::scrollToGlobalPoint(int x, int y) |
| { |
| // FIXME: implement |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::classList() const |
| { |
| // FIXME: implement |
| return 0; |
| } |
| |
| JSRetainPtr<JSStringRef> AccessibilityUIElement::domIdentifier() const |
| { |
| // FIXME: implement |
| return 0; |
| } |
| |
| unsigned AccessibilityUIElement::selectedChildrenCount() const |
| { |
| // FIXME: implement |
| return 0; |
| } |
| |
| AccessibilityUIElement AccessibilityUIElement::selectedChildAtIndex(unsigned) const |
| { |
| // FIXME: implement |
| return { nullptr }; |
| } |
| |
| void AccessibilityUIElement::columnHeaders(Vector<AccessibilityUIElement>&) const |
| { |
| // FIXME: implement |
| } |
| |
| void AccessibilityUIElement::rowHeaders(Vector<AccessibilityUIElement>&) const |
| { |
| // FIXME: implement |
| } |