nsIFrame* nsHTMLSelectOptionAccessible::GetBoundsFrame() { PRUint32 state; nsCOMPtr<nsIContent> content = GetSelectState(&state); if (state & nsIAccessibleStates::STATE_COLLAPSED) { nsCOMPtr<nsIPresShell> presShell(GetPresShell()); if (!presShell) { return nsnull; } return presShell->GetPrimaryFrameFor(content); } return nsAccessible::GetBoundsFrame(); }
// nsAccessible protected nsIFrame* nsHTMLSelectOptionAccessible::GetBoundsFrame() { PRUint32 state = 0; nsCOMPtr<nsIContent> content = GetSelectState(&state); if (state & nsIAccessibleStates::STATE_COLLAPSED) { if (content) { return content->GetPrimaryFrame(); } return nsnull; } return nsAccessible::GetBoundsFrame(); }
/** * As a nsHTMLSelectOptionAccessible we can have the following states: * STATE_SELECTABLE * STATE_SELECTED * STATE_FOCUSED * STATE_FOCUSABLE * STATE_OFFSCREEN */ nsresult nsHTMLSelectOptionAccessible::GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState) { // Upcall to nsAccessible, but skip nsHyperTextAccessible impl // because we don't want EXT_STATE_EDITABLE or EXT_STATE_SELECTABLE_TEXT nsresult rv = nsAccessible::GetStateInternal(aState, aExtraState); NS_ENSURE_A11Y_SUCCESS(rv, rv); PRUint32 selectState, selectExtState; nsCOMPtr<nsIContent> selectContent = GetSelectState(&selectState, &selectExtState); if (selectState & nsIAccessibleStates::STATE_INVISIBLE) { return NS_OK; } nsCOMPtr<nsIDOMNode> selectNode = do_QueryInterface(selectContent); NS_ENSURE_TRUE(selectNode, NS_ERROR_FAILURE); // Is disabled? if (0 == (*aState & nsIAccessibleStates::STATE_UNAVAILABLE)) { *aState |= (nsIAccessibleStates::STATE_FOCUSABLE | nsIAccessibleStates::STATE_SELECTABLE); // When the list is focused but no option is actually focused, // Firefox draws a focus ring around the first non-disabled option. // We need to indicated STATE_FOCUSED in that case, because it // prevents JAWS from ignoring the list // GetFocusedOptionNode() ensures that an option node is // returned in this case, as long as some focusable option exists // in the listbox nsCOMPtr<nsIDOMNode> focusedOptionNode; GetFocusedOptionNode(selectNode, getter_AddRefs(focusedOptionNode)); if (focusedOptionNode == mDOMNode) { *aState |= nsIAccessibleStates::STATE_FOCUSED; } } // Are we selected? PRBool isSelected = PR_FALSE; nsCOMPtr<nsIDOMHTMLOptionElement> option (do_QueryInterface(mDOMNode)); if (option) { option->GetSelected(&isSelected); if ( isSelected ) *aState |= nsIAccessibleStates::STATE_SELECTED; } if (selectState & nsIAccessibleStates::STATE_OFFSCREEN) { *aState |= nsIAccessibleStates::STATE_OFFSCREEN; } else if (selectState & nsIAccessibleStates::STATE_COLLAPSED) { // <select> is COLLAPSED: add STATE_OFFSCREEN, if not the currently // visible option if (!isSelected) { *aState |= nsIAccessibleStates::STATE_OFFSCREEN; } else { // Clear offscreen and invisible for currently showing option *aState &= ~nsIAccessibleStates::STATE_OFFSCREEN; *aState &= ~nsIAccessibleStates::STATE_INVISIBLE; if (aExtraState) { *aExtraState |= selectExtState & nsIAccessibleStates::EXT_STATE_OPAQUE; } } } else { // XXX list frames are weird, don't rely on nsAccessible's general // visibility implementation unless they get reimplemented in layout *aState &= ~nsIAccessibleStates::STATE_OFFSCREEN; // <select> is not collapsed: compare bounds to calculate STATE_OFFSCREEN nsCOMPtr<nsIAccessible> listAccessible = GetParent(); if (listAccessible) { PRInt32 optionX, optionY, optionWidth, optionHeight; PRInt32 listX, listY, listWidth, listHeight; GetBounds(&optionX, &optionY, &optionWidth, &optionHeight); listAccessible->GetBounds(&listX, &listY, &listWidth, &listHeight); if (optionY < listY || optionY + optionHeight > listY + listHeight) { *aState |= nsIAccessibleStates::STATE_OFFSCREEN; } } } return NS_OK; }