Home | History | Annotate | Download | only in win
      1 /*
      2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "AccessibilityUIElement.h"
     28 
     29 #include "AccessibilityController.h"
     30 #include "DumpRenderTree.h"
     31 #include "FrameLoadDelegate.h"
     32 #include <JavaScriptCore/JSStringRef.h>
     33 #include <tchar.h>
     34 #include <string>
     35 
     36 using std::wstring;
     37 
     38 static COMPtr<IAccessibleComparable> comparableObject(IAccessible* accessible)
     39 {
     40     COMPtr<IServiceProvider> serviceProvider(Query, accessible);
     41     if (!serviceProvider)
     42         return 0;
     43     COMPtr<IAccessibleComparable> comparable;
     44     serviceProvider->QueryService(SID_AccessibleComparable, __uuidof(IAccessibleComparable), reinterpret_cast<void**>(&comparable));
     45     return comparable;
     46 }
     47 
     48 AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element)
     49     : m_element(element)
     50 {
     51 }
     52 
     53 AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other)
     54     : m_element(other.m_element)
     55 {
     56 }
     57 
     58 AccessibilityUIElement::~AccessibilityUIElement()
     59 {
     60 }
     61 
     62 bool AccessibilityUIElement::isEqual(AccessibilityUIElement* otherElement)
     63 {
     64     COMPtr<IAccessibleComparable> comparable = comparableObject(m_element.get());
     65     COMPtr<IAccessibleComparable> otherComparable = comparableObject(otherElement->m_element.get());
     66     if (!comparable || !otherComparable)
     67         return false;
     68     BOOL isSame = FALSE;
     69     if (FAILED(comparable->isSameObject(otherComparable.get(), &isSame)))
     70         return false;
     71     return isSame;
     72 }
     73 
     74 void AccessibilityUIElement::getLinkedUIElements(Vector<AccessibilityUIElement>&)
     75 {
     76 }
     77 
     78 void AccessibilityUIElement::getDocumentLinks(Vector<AccessibilityUIElement>&)
     79 {
     80 }
     81 
     82 void AccessibilityUIElement::getChildren(Vector<AccessibilityUIElement>& children)
     83 {
     84     long childCount;
     85     if (FAILED(m_element->get_accChildCount(&childCount)))
     86         return;
     87     for (long i = 0; i < childCount; ++i)
     88         children.append(getChildAtIndex(i));
     89 }
     90 
     91 void AccessibilityUIElement::getChildrenWithRange(Vector<AccessibilityUIElement>& elementVector, unsigned location, unsigned length)
     92 {
     93     long childCount;
     94     unsigned appendedCount = 0;
     95     if (FAILED(m_element->get_accChildCount(&childCount)))
     96         return;
     97     for (long i = location; i < childCount && appendedCount < length; ++i, ++appendedCount)
     98         elementVector.append(getChildAtIndex(i));
     99 }
    100 
    101 int AccessibilityUIElement::childrenCount()
    102 {
    103     long childCount;
    104     m_element->get_accChildCount(&childCount);
    105     return childCount;
    106 }
    107 
    108 int AccessibilityUIElement::rowCount()
    109 {
    110     // FIXME: implement
    111     return 0;
    112 }
    113 
    114 int AccessibilityUIElement::columnCount()
    115 {
    116     // FIXME: implement
    117     return 0;
    118 }
    119 
    120 AccessibilityUIElement AccessibilityUIElement::elementAtPoint(int x, int y)
    121 {
    122     return 0;
    123 }
    124 
    125 AccessibilityUIElement AccessibilityUIElement::linkedUIElementAtIndex(unsigned index)
    126 {
    127     // FIXME: implement
    128     return 0;
    129 }
    130 
    131 AccessibilityUIElement AccessibilityUIElement::getChildAtIndex(unsigned index)
    132 {
    133     COMPtr<IDispatch> child;
    134     VARIANT vChild;
    135     ::VariantInit(&vChild);
    136     V_VT(&vChild) = VT_I4;
    137     // In MSAA, index 0 is the object itself.
    138     V_I4(&vChild) = index + 1;
    139     if (FAILED(m_element->get_accChild(vChild, &child)))
    140         return 0;
    141     return COMPtr<IAccessible>(Query, child);
    142 }
    143 
    144 unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element)
    145 {
    146     // FIXME: implement
    147     return 0;
    148 }
    149 
    150 JSStringRef AccessibilityUIElement::allAttributes()
    151 {
    152     return JSStringCreateWithCharacters(0, 0);
    153 }
    154 
    155 JSStringRef AccessibilityUIElement::attributesOfLinkedUIElements()
    156 {
    157     return JSStringCreateWithCharacters(0, 0);
    158 }
    159 
    160 JSStringRef AccessibilityUIElement::attributesOfDocumentLinks()
    161 {
    162     return JSStringCreateWithCharacters(0, 0);
    163 }
    164 
    165 AccessibilityUIElement AccessibilityUIElement::titleUIElement()
    166 {
    167     return 0;
    168 }
    169 
    170 AccessibilityUIElement AccessibilityUIElement::parentElement()
    171 {
    172     COMPtr<IDispatch> parent;
    173     m_element->get_accParent(&parent);
    174 
    175     COMPtr<IAccessible> parentAccessible(Query, parent);
    176     return parentAccessible;
    177 }
    178 
    179 JSStringRef AccessibilityUIElement::attributesOfChildren()
    180 {
    181     return JSStringCreateWithCharacters(0, 0);
    182 }
    183 
    184 JSStringRef AccessibilityUIElement::parameterizedAttributeNames()
    185 {
    186     return JSStringCreateWithCharacters(0, 0);
    187 }
    188 
    189 static VARIANT& self()
    190 {
    191     static VARIANT vSelf;
    192     static bool haveInitialized;
    193 
    194     if (!haveInitialized) {
    195         ::VariantInit(&vSelf);
    196         V_VT(&vSelf) = VT_I4;
    197         V_I4(&vSelf) = CHILDID_SELF;
    198     }
    199     return vSelf;
    200 }
    201 
    202 JSStringRef AccessibilityUIElement::role()
    203 {
    204     VARIANT vRole;
    205     if (FAILED(m_element->get_accRole(self(), &vRole)))
    206         return JSStringCreateWithCharacters(0, 0);
    207 
    208     ASSERT(V_VT(&vRole) == VT_I4 || V_VT(&vRole) == VT_BSTR);
    209 
    210     wstring result;
    211     if (V_VT(&vRole) == VT_I4) {
    212         unsigned roleTextLength = ::GetRoleText(V_I4(&vRole), 0, 0) + 1;
    213 
    214         Vector<TCHAR> roleText(roleTextLength);
    215 
    216         ::GetRoleText(V_I4(&vRole), roleText.data(), roleTextLength);
    217 
    218         result = roleText.data();
    219     } else if (V_VT(&vRole) == VT_BSTR)
    220         result = wstring(V_BSTR(&vRole), ::SysStringLen(V_BSTR(&vRole)));
    221 
    222     ::VariantClear(&vRole);
    223 
    224     return JSStringCreateWithCharacters(result.data(), result.length());
    225 }
    226 
    227 JSStringRef AccessibilityUIElement::subrole()
    228 {
    229     return 0;
    230 }
    231 
    232 JSStringRef AccessibilityUIElement::roleDescription()
    233 {
    234     return 0;
    235 }
    236 
    237 JSStringRef AccessibilityUIElement::title()
    238 {
    239     BSTR titleBSTR;
    240     if (FAILED(m_element->get_accName(self(), &titleBSTR)) || !titleBSTR)
    241         return JSStringCreateWithCharacters(0, 0);
    242     wstring title(titleBSTR, SysStringLen(titleBSTR));
    243     ::SysFreeString(titleBSTR);
    244     return JSStringCreateWithCharacters(title.data(), title.length());
    245 }
    246 
    247 JSStringRef AccessibilityUIElement::description()
    248 {
    249     BSTR descriptionBSTR;
    250     if (FAILED(m_element->get_accDescription(self(), &descriptionBSTR)) || !descriptionBSTR)
    251         return JSStringCreateWithCharacters(0, 0);
    252     wstring description(descriptionBSTR, SysStringLen(descriptionBSTR));
    253     ::SysFreeString(descriptionBSTR);
    254     return JSStringCreateWithCharacters(description.data(), description.length());
    255 }
    256 
    257 JSStringRef AccessibilityUIElement::stringValue()
    258 {
    259     return JSStringCreateWithCharacters(0, 0);
    260 }
    261 
    262 JSStringRef AccessibilityUIElement::language()
    263 {
    264     return JSStringCreateWithCharacters(0, 0);
    265 }
    266 
    267 JSStringRef AccessibilityUIElement::helpText() const
    268 {
    269     return 0;
    270 }
    271 
    272 double AccessibilityUIElement::x()
    273 {
    274     long x, y, width, height;
    275     if (FAILED(m_element->accLocation(&x, &y, &width, &height, self())))
    276         return 0;
    277     return x;
    278 }
    279 
    280 double AccessibilityUIElement::y()
    281 {
    282     long x, y, width, height;
    283     if (FAILED(m_element->accLocation(&x, &y, &width, &height, self())))
    284         return 0;
    285     return y;
    286 }
    287 
    288 double AccessibilityUIElement::width()
    289 {
    290     long x, y, width, height;
    291     if (FAILED(m_element->accLocation(&x, &y, &width, &height, self())))
    292         return 0;
    293     return width;
    294 }
    295 
    296 double AccessibilityUIElement::height()
    297 {
    298     long x, y, width, height;
    299     if (FAILED(m_element->accLocation(&x, &y, &width, &height, self())))
    300         return 0;
    301     return height;
    302 }
    303 
    304 double AccessibilityUIElement::clickPointX()
    305 {
    306     return 0;
    307 }
    308 
    309 double AccessibilityUIElement::clickPointY()
    310 {
    311     return 0;
    312 }
    313 
    314 JSStringRef AccessibilityUIElement::valueDescription()
    315 {
    316     return 0;
    317 }
    318 
    319 static DWORD accessibilityState(COMPtr<IAccessible> element)
    320 {
    321     VARIANT state;
    322     element->get_accState(self(), &state);
    323 
    324     ASSERT(V_VT(&state) == VT_I4);
    325 
    326     DWORD result = state.lVal;
    327     VariantClear(&state);
    328 
    329     return result;
    330 }
    331 
    332 bool AccessibilityUIElement::isFocused() const
    333 {
    334     // FIXME: implement
    335     return false;
    336 }
    337 
    338 bool AccessibilityUIElement::isSelected() const
    339 {
    340     DWORD state = accessibilityState(m_element);
    341     return (state & STATE_SYSTEM_SELECTED) == STATE_SYSTEM_SELECTED;
    342 }
    343 
    344 int AccessibilityUIElement::hierarchicalLevel() const
    345 {
    346     return 0;
    347 }
    348 
    349 bool AccessibilityUIElement::ariaIsGrabbed() const
    350 {
    351     return false;
    352 }
    353 
    354 JSStringRef AccessibilityUIElement::ariaDropEffects() const
    355 {
    356     return 0;
    357 }
    358 
    359 bool AccessibilityUIElement::isExpanded() const
    360 {
    361     return false;
    362 }
    363 
    364 bool AccessibilityUIElement::isChecked() const
    365 {
    366     VARIANT vState;
    367     if (FAILED(m_element->get_accState(self(), &vState)))
    368         return false;
    369 
    370     return vState.lVal & STATE_SYSTEM_CHECKED;
    371 }
    372 
    373 JSStringRef AccessibilityUIElement::orientation() const
    374 {
    375     return 0;
    376 }
    377 
    378 double AccessibilityUIElement::intValue() const
    379 {
    380     BSTR valueBSTR;
    381     if (FAILED(m_element->get_accValue(self(), &valueBSTR)) || !valueBSTR)
    382         return 0;
    383     wstring value(valueBSTR, SysStringLen(valueBSTR));
    384     ::SysFreeString(valueBSTR);
    385     TCHAR* ignored;
    386     return _tcstod(value.data(), &ignored);
    387 }
    388 
    389 double AccessibilityUIElement::minValue()
    390 {
    391     return 0;
    392 }
    393 
    394 double AccessibilityUIElement::maxValue()
    395 {
    396     return 0;
    397 }
    398 
    399 bool AccessibilityUIElement::isActionSupported(JSStringRef action)
    400 {
    401     return false;
    402 }
    403 
    404 bool AccessibilityUIElement::isEnabled()
    405 {
    406     DWORD state = accessibilityState(m_element);
    407     return (state & STATE_SYSTEM_UNAVAILABLE) != STATE_SYSTEM_UNAVAILABLE;
    408 }
    409 
    410 bool AccessibilityUIElement::isRequired() const
    411 {
    412     return false;
    413 }
    414 
    415 
    416 int AccessibilityUIElement::insertionPointLineNumber()
    417 {
    418     return 0;
    419 }
    420 
    421 JSStringRef AccessibilityUIElement::attributesOfColumnHeaders()
    422 {
    423     return JSStringCreateWithCharacters(0, 0);
    424 }
    425 
    426 JSStringRef AccessibilityUIElement::attributesOfRowHeaders()
    427 {
    428     return JSStringCreateWithCharacters(0, 0);
    429 }
    430 
    431 JSStringRef AccessibilityUIElement::attributesOfColumns()
    432 {
    433     return JSStringCreateWithCharacters(0, 0);
    434 }
    435 
    436 JSStringRef AccessibilityUIElement::attributesOfRows()
    437 {
    438     return JSStringCreateWithCharacters(0, 0);
    439 }
    440 
    441 JSStringRef AccessibilityUIElement::attributesOfVisibleCells()
    442 {
    443     return JSStringCreateWithCharacters(0, 0);
    444 }
    445 
    446 JSStringRef AccessibilityUIElement::attributesOfHeader()
    447 {
    448     return JSStringCreateWithCharacters(0, 0);
    449 }
    450 
    451 int AccessibilityUIElement::indexInTable()
    452 {
    453     return 0;
    454 }
    455 
    456 JSStringRef AccessibilityUIElement::rowIndexRange()
    457 {
    458     return JSStringCreateWithCharacters(0, 0);
    459 }
    460 
    461 JSStringRef AccessibilityUIElement::columnIndexRange()
    462 {
    463     return JSStringCreateWithCharacters(0, 0);
    464 }
    465 
    466 int AccessibilityUIElement::lineForIndex(int)
    467 {
    468     return 0;
    469 }
    470 
    471 JSStringRef AccessibilityUIElement::boundsForRange(unsigned location, unsigned length)
    472 {
    473     return JSStringCreateWithCharacters(0, 0);
    474 }
    475 
    476 JSStringRef AccessibilityUIElement::stringForRange(unsigned, unsigned)
    477 {
    478     return JSStringCreateWithCharacters(0, 0);
    479 }
    480 
    481 JSStringRef AccessibilityUIElement::attributedStringForRange(unsigned, unsigned)
    482 {
    483     return JSStringCreateWithCharacters(0, 0);
    484 }
    485 
    486 bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned, unsigned)
    487 {
    488     return false;
    489 }
    490 
    491 AccessibilityUIElement AccessibilityUIElement::cellForColumnAndRow(unsigned column, unsigned row)
    492 {
    493     return 0;
    494 }
    495 
    496 JSStringRef AccessibilityUIElement::selectedTextRange()
    497 {
    498     return JSStringCreateWithCharacters(0, 0);
    499 }
    500 
    501 void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length)
    502 {
    503 }
    504 
    505 JSStringRef AccessibilityUIElement::stringAttributeValue(JSStringRef attribute)
    506 {
    507     // FIXME: implement
    508     return JSStringCreateWithCharacters(0, 0);
    509 }
    510 
    511 bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute)
    512 {
    513     // FIXME: implement
    514     return false;
    515 }
    516 
    517 bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute)
    518 {
    519     return false;
    520 }
    521 
    522 bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute)
    523 {
    524     return false;
    525 }
    526 
    527 void AccessibilityUIElement::increment()
    528 {
    529 }
    530 
    531 void AccessibilityUIElement::decrement()
    532 {
    533 }
    534 
    535 void AccessibilityUIElement::showMenu()
    536 {
    537     ASSERT(hasPopup());
    538     m_element->accDoDefaultAction(self());
    539 }
    540 
    541 void AccessibilityUIElement::press()
    542 {
    543     // FIXME: implement
    544 }
    545 
    546 AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
    547 {
    548     return 0;
    549 }
    550 
    551 AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index)
    552 {
    553     return 0;
    554 }
    555 
    556 AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index)
    557 {
    558     return 0;
    559 }
    560 
    561 AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index)
    562 {
    563     return 0;
    564 }
    565 
    566 AccessibilityUIElement AccessibilityUIElement::disclosedByRow()
    567 {
    568     return 0;
    569 }
    570 
    571 JSStringRef AccessibilityUIElement::accessibilityValue() const
    572 {
    573     BSTR valueBSTR;
    574     if (FAILED(m_element->get_accValue(self(), &valueBSTR)) || !valueBSTR)
    575         return JSStringCreateWithCharacters(0, 0);
    576 
    577     wstring value(valueBSTR, SysStringLen(valueBSTR));
    578     ::SysFreeString(valueBSTR);
    579 
    580     return JSStringCreateWithCharacters(value.data(), value.length());
    581 }
    582 
    583 
    584 JSStringRef AccessibilityUIElement::documentEncoding()
    585 {
    586     return JSStringCreateWithCharacters(0, 0);
    587 }
    588 
    589 JSStringRef AccessibilityUIElement::documentURI()
    590 {
    591     return JSStringCreateWithCharacters(0, 0);
    592 }
    593 
    594 JSStringRef AccessibilityUIElement::url()
    595 {
    596     // FIXME: implement
    597     return JSStringCreateWithCharacters(0, 0);
    598 }
    599 
    600 bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallback)
    601 {
    602     if (!functionCallback)
    603         return false;
    604 
    605     sharedFrameLoadDelegate->accessibilityController()->addNotificationListener(m_element, functionCallback);
    606     return true;
    607 }
    608 
    609 void AccessibilityUIElement::removeNotificationListener()
    610 {
    611     // FIXME: implement
    612 }
    613 
    614 bool AccessibilityUIElement::isFocusable() const
    615 {
    616     // FIXME: implement
    617     return false;
    618 }
    619 
    620 bool AccessibilityUIElement::isSelectable() const
    621 {
    622     DWORD state = accessibilityState(m_element);
    623     return (state & STATE_SYSTEM_SELECTABLE) == STATE_SYSTEM_SELECTABLE;
    624 }
    625 
    626 bool AccessibilityUIElement::isMultiSelectable() const
    627 {
    628     DWORD multiSelectable = STATE_SYSTEM_EXTSELECTABLE | STATE_SYSTEM_MULTISELECTABLE;
    629     DWORD state = accessibilityState(m_element);
    630     return (state & multiSelectable) == multiSelectable;
    631 }
    632 
    633 bool AccessibilityUIElement::isVisible() const
    634 {
    635     DWORD state = accessibilityState(m_element);
    636     return (state & STATE_SYSTEM_INVISIBLE) != STATE_SYSTEM_INVISIBLE;
    637 }
    638 
    639 bool AccessibilityUIElement::isOffScreen() const
    640 {
    641     DWORD state = accessibilityState(m_element);
    642     return (state & STATE_SYSTEM_OFFSCREEN) == STATE_SYSTEM_OFFSCREEN;
    643 }
    644 
    645 bool AccessibilityUIElement::isCollapsed() const
    646 {
    647     DWORD state = accessibilityState(m_element);
    648     return (state & STATE_SYSTEM_COLLAPSED) == STATE_SYSTEM_COLLAPSED;
    649 }
    650 
    651 bool AccessibilityUIElement::isIgnored() const
    652 {
    653     // FIXME: implement
    654     return false;
    655 }
    656 
    657 bool AccessibilityUIElement::hasPopup() const
    658 {
    659     DWORD state = accessibilityState(m_element);
    660     return (state & STATE_SYSTEM_HASPOPUP) == STATE_SYSTEM_HASPOPUP;
    661 }
    662 
    663 void AccessibilityUIElement::takeFocus()
    664 {
    665     m_element->accSelect(SELFLAG_TAKEFOCUS, self());
    666 }
    667 
    668 void AccessibilityUIElement::takeSelection()
    669 {
    670     m_element->accSelect(SELFLAG_TAKESELECTION, self());
    671 }
    672 
    673 void AccessibilityUIElement::addSelection()
    674 {
    675     m_element->accSelect(SELFLAG_ADDSELECTION, self());
    676 }
    677 
    678 void AccessibilityUIElement::removeSelection()
    679 {
    680     m_element->accSelect(SELFLAG_REMOVESELECTION, self());
    681 }
    682