diff options
Diffstat (limited to 'accessible/mac/AccessibleWrap.mm')
-rw-r--r-- | accessible/mac/AccessibleWrap.mm | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/accessible/mac/AccessibleWrap.mm b/accessible/mac/AccessibleWrap.mm new file mode 100644 index 000000000..65f2e1db4 --- /dev/null +++ b/accessible/mac/AccessibleWrap.mm @@ -0,0 +1,256 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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 "DocAccessible.h" +#include "nsObjCExceptions.h" + +#include "Accessible-inl.h" +#include "nsAccUtils.h" +#include "Role.h" + +#import "mozAccessible.h" +#import "mozActionElements.h" +#import "mozHTMLAccessible.h" +#import "mozTableAccessible.h" +#import "mozTextAccessible.h" + +using namespace mozilla; +using namespace mozilla::a11y; + +AccessibleWrap:: + AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) : + Accessible(aContent, aDoc), mNativeObject(nil), + mNativeInited(false) +{ +} + +AccessibleWrap::~AccessibleWrap() +{ +} + +mozAccessible* +AccessibleWrap::GetNativeObject() +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + if (!mNativeInited && !mNativeObject && !IsDefunct() && !AncestorIsFlat()) { + uintptr_t accWrap = reinterpret_cast<uintptr_t>(this); + mNativeObject = [[GetNativeType() alloc] initWithAccessible:accWrap]; + } + + mNativeInited = true; + + return mNativeObject; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +void +AccessibleWrap::GetNativeInterface(void** aOutInterface) +{ + *aOutInterface = static_cast<void*>(GetNativeObject()); +} + +// overridden in subclasses to create the right kind of object. by default we create a generic +// 'mozAccessible' node. +Class +AccessibleWrap::GetNativeType () +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + if (IsXULTabpanels()) + return [mozPaneAccessible class]; + + if (IsTable()) + return [mozTableAccessible class]; + + if (IsTableRow()) + return [mozTableRowAccessible class]; + + if (IsTableCell()) + return [mozTableCellAccessible class]; + + return GetTypeFromRole(Role()); + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +// this method is very important. it is fired when an accessible object "dies". after this point +// the object might still be around (because some 3rd party still has a ref to it), but it is +// in fact 'dead'. +void +AccessibleWrap::Shutdown () +{ + // this ensure we will not try to re-create the native object. + mNativeInited = true; + + // we really intend to access the member directly. + if (mNativeObject) { + [mNativeObject expire]; + [mNativeObject release]; + mNativeObject = nil; + } + + Accessible::Shutdown(); +} + +nsresult +AccessibleWrap::HandleAccEvent(AccEvent* aEvent) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + nsresult rv = Accessible::HandleAccEvent(aEvent); + NS_ENSURE_SUCCESS(rv, rv); + + if (IPCAccessibilityActive()) { + return NS_OK; + } + + uint32_t eventType = aEvent->GetEventType(); + + // ignore everything but focus-changed, value-changed, caret, selection + // and document load complete events for now. + if (eventType != nsIAccessibleEvent::EVENT_FOCUS && + eventType != nsIAccessibleEvent::EVENT_VALUE_CHANGE && + eventType != nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE && + eventType != nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED && + eventType != nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED && + eventType != nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE) + return NS_OK; + + Accessible* accessible = aEvent->GetAccessible(); + NS_ENSURE_STATE(accessible); + + mozAccessible *nativeAcc = nil; + accessible->GetNativeInterface((void**)&nativeAcc); + if (!nativeAcc) + return NS_ERROR_FAILURE; + + FireNativeEvent(nativeAcc, eventType); + + return NS_OK; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + +bool +AccessibleWrap::InsertChildAt(uint32_t aIdx, Accessible* aAccessible) +{ + bool inserted = Accessible::InsertChildAt(aIdx, aAccessible); + if (inserted && mNativeObject) + [mNativeObject appendChild:aAccessible]; + + return inserted; +} + +bool +AccessibleWrap::RemoveChild(Accessible* aAccessible) +{ + bool removed = Accessible::RemoveChild(aAccessible); + + if (removed && mNativeObject) + [mNativeObject invalidateChildren]; + + return removed; +} + +//////////////////////////////////////////////////////////////////////////////// +// AccessibleWrap protected + +bool +AccessibleWrap::AncestorIsFlat() +{ + // We don't create a native object if we're child of a "flat" accessible; + // for example, on OS X buttons shouldn't have any children, because that + // makes the OS confused. + // + // To maintain a scripting environment where the XPCOM accessible hierarchy + // look the same on all platforms, we still let the C++ objects be created + // though. + + Accessible* parent = Parent(); + while (parent) { + if (nsAccUtils::MustPrune(parent)) + return true; + + parent = parent->Parent(); + } + // no parent was flat + return false; +} + +void +a11y::FireNativeEvent(mozAccessible* aNativeAcc, uint32_t aEventType) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + + switch (aEventType) { + case nsIAccessibleEvent::EVENT_FOCUS: + [aNativeAcc didReceiveFocus]; + break; + case nsIAccessibleEvent::EVENT_VALUE_CHANGE: + case nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE: + [aNativeAcc valueDidChange]; + break; + case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED: + case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED: + [aNativeAcc selectedTextDidChange]; + break; + case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE: + [aNativeAcc documentLoadComplete]; + break; + } + + NS_OBJC_END_TRY_ABORT_BLOCK; +} + +Class +a11y::GetTypeFromRole(roles::Role aRole) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + switch (aRole) { + case roles::COMBOBOX: + case roles::PUSHBUTTON: + case roles::SPLITBUTTON: + case roles::TOGGLE_BUTTON: + { + return [mozButtonAccessible class]; + } + + case roles::PAGETAB: + return [mozButtonAccessible class]; + + case roles::CHECKBUTTON: + return [mozCheckboxAccessible class]; + + case roles::HEADING: + return [mozHeadingAccessible class]; + + case roles::PAGETABLIST: + return [mozTabsAccessible class]; + + case roles::ENTRY: + case roles::STATICTEXT: + case roles::CAPTION: + case roles::ACCEL_LABEL: + case roles::PASSWORD_TEXT: + // normal textfield (static or editable) + return [mozTextAccessible class]; + + case roles::TEXT_LEAF: + return [mozTextLeafAccessible class]; + + case roles::LINK: + return [mozLinkAccessible class]; + + default: + return [mozAccessible class]; + } + + return nil; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} |