mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 02:14:43 +00:00
Bug 1868552 - Refactor nsIContent::IsFocusable for clarity. r=masayuki
Make it be output-only, not having that confusing in-out tab-index parameter that is special for XUL to become focusable with -moz-user-focus: normal. Instead, do that explicitly in nsIFrame::IsFocusable(). Also, call it IsFocusableWithoutStyle(), since that's what it is. Differential Revision: https://phabricator.services.mozilla.com/D195644
This commit is contained in:
parent
cc338968d0
commit
633cce158c
@ -6151,8 +6151,9 @@ nsresult Document::EditingStateChanged() {
|
||||
getter_AddRefs(focusedWindow));
|
||||
if (focusedContent) {
|
||||
nsIFrame* focusedFrame = focusedContent->GetPrimaryFrame();
|
||||
bool clearFocus = focusedFrame ? !focusedFrame->IsFocusable()
|
||||
: !focusedContent->IsFocusable();
|
||||
bool clearFocus = focusedFrame
|
||||
? !focusedFrame->IsFocusable()
|
||||
: !focusedContent->IsFocusableWithoutStyle();
|
||||
if (clearFocus) {
|
||||
if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
|
||||
fm->ClearFocus(window);
|
||||
|
@ -1032,16 +1032,6 @@ void nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
|
||||
}
|
||||
}
|
||||
|
||||
bool nsIContent::IsFocusable(int32_t* aTabIndex, bool aWithMouse) {
|
||||
bool focusable = IsFocusableInternal(aTabIndex, aWithMouse);
|
||||
// Ensure that the return value and aTabIndex are consistent in the case
|
||||
// we're in userfocusignored context.
|
||||
if (focusable || (aTabIndex && *aTabIndex != -1)) {
|
||||
return focusable;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Element* nsIContent::GetAutofocusDelegate(bool aWithMouse) const {
|
||||
for (nsINode* node = GetFirstChild(); node; node = node->GetNextNode(this)) {
|
||||
auto* descendant = Element::FromNode(*node);
|
||||
@ -1068,7 +1058,7 @@ Element* nsIContent::GetFocusDelegate(bool aWithMouse) const {
|
||||
whereToLook = root;
|
||||
}
|
||||
|
||||
auto IsFocusable = [&](Element* aElement) -> nsIFrame::Focusable {
|
||||
auto IsFocusable = [&](Element* aElement) -> Focusable {
|
||||
nsIFrame* frame = aElement->GetPrimaryFrame();
|
||||
|
||||
if (!frame) {
|
||||
@ -1094,7 +1084,7 @@ Element* nsIContent::GetFocusDelegate(bool aWithMouse) const {
|
||||
return el;
|
||||
}
|
||||
} else if (!potentialFocus) {
|
||||
if (nsIFrame::Focusable focusable = IsFocusable(el)) {
|
||||
if (Focusable focusable = IsFocusable(el)) {
|
||||
if (IsHTMLElement(nsGkAtoms::dialog)) {
|
||||
if (focusable.mTabIndex >= 0) {
|
||||
// If focusTarget is a dialog element and descendant is sequentially
|
||||
@ -1134,11 +1124,9 @@ Element* nsIContent::GetFocusDelegate(bool aWithMouse) const {
|
||||
return potentialFocus;
|
||||
}
|
||||
|
||||
bool nsIContent::IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) {
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = -1; // Default, not tabbable
|
||||
}
|
||||
return false;
|
||||
Focusable nsIContent::IsFocusableWithoutStyle(bool aWithMouse) {
|
||||
// Default, not tabbable
|
||||
return {};
|
||||
}
|
||||
|
||||
void nsIContent::SetAssignedSlot(HTMLSlotElement* aSlot) {
|
||||
|
@ -3377,13 +3377,9 @@ nsresult nsFocusManager::DetermineElementToMoveFocus(
|
||||
int32_t tabIndex = forward ? 1 : 0;
|
||||
if (startContent) {
|
||||
nsIFrame* frame = startContent->GetPrimaryFrame();
|
||||
if (startContent->IsHTMLElement(nsGkAtoms::area)) {
|
||||
startContent->IsFocusable(&tabIndex);
|
||||
} else if (frame) {
|
||||
tabIndex = frame->IsFocusable().mTabIndex;
|
||||
} else {
|
||||
startContent->IsFocusable(&tabIndex);
|
||||
}
|
||||
tabIndex = (frame && !startContent->IsHTMLElement(nsGkAtoms::area))
|
||||
? frame->IsFocusable().mTabIndex
|
||||
: startContent->IsFocusableWithoutStyle().mTabIndex;
|
||||
|
||||
// if the current element isn't tabbable, ignore the tabindex and just
|
||||
// look for the next element. The root content won't have a tabindex
|
||||
@ -4038,7 +4034,7 @@ nsIContent* nsFocusManager::GetNextTabbableContentInAncestorScopes(
|
||||
} else if (nsIFrame* frame = startContent->GetPrimaryFrame()) {
|
||||
tabIndex = frame->IsFocusable().mTabIndex;
|
||||
} else {
|
||||
startContent->IsFocusable(&tabIndex);
|
||||
tabIndex = startContent->IsFocusableWithoutStyle().mTabIndex;
|
||||
}
|
||||
nsIContent* contentToFocus = GetNextTabbableContentInScope(
|
||||
owner, startContent, aOriginalStartContent, aForward, tabIndex,
|
||||
@ -4214,7 +4210,7 @@ nsresult nsFocusManager::GetNextTabbableContent(
|
||||
if (iterStartContent == aRootContent) {
|
||||
if (!aForward) {
|
||||
frameTraversal->Last();
|
||||
} else if (aRootContent->IsFocusable()) {
|
||||
} else if (aRootContent->IsFocusableWithoutStyle()) {
|
||||
frameTraversal->Next();
|
||||
}
|
||||
frame = frameTraversal->CurrentItem();
|
||||
@ -4282,11 +4278,12 @@ nsresult nsFocusManager::GetNextTabbableContent(
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (invokerContent && invokerContent->IsFocusable()) {
|
||||
invokerContent.forget(aResultContent);
|
||||
return NS_OK;
|
||||
}
|
||||
} else if (invokerContent &&
|
||||
invokerContent->IsFocusableWithoutStyle()) {
|
||||
// FIXME(emilio): The check above should probably use
|
||||
// nsIFrame::IsFocusable, not IsFocusableWithoutStyle.
|
||||
invokerContent.forget(aResultContent);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4619,11 +4616,11 @@ nsIContent* nsFocusManager::GetNextTabbableMapArea(bool aForward,
|
||||
// First see if the the start content is in this map
|
||||
Maybe<uint32_t> indexOfStartContent =
|
||||
mapContent->ComputeIndexOf(aStartContent);
|
||||
int32_t tabIndex;
|
||||
nsIContent* scanStartContent;
|
||||
Focusable focusable;
|
||||
if (indexOfStartContent.isNothing() ||
|
||||
(aStartContent->IsFocusable(&tabIndex) &&
|
||||
tabIndex != aCurrentTabIndex)) {
|
||||
((focusable = aStartContent->IsFocusableWithoutStyle()) &&
|
||||
focusable.mTabIndex != aCurrentTabIndex)) {
|
||||
// If aStartContent is in this map we must start iterating past it.
|
||||
// We skip the case where aStartContent has tabindex == aStartContent
|
||||
// since the next tab ordered element might be before it
|
||||
@ -4638,7 +4635,8 @@ nsIContent* nsFocusManager::GetNextTabbableMapArea(bool aForward,
|
||||
for (nsCOMPtr<nsIContent> areaContent = scanStartContent; areaContent;
|
||||
areaContent = aForward ? areaContent->GetNextSibling()
|
||||
: areaContent->GetPreviousSibling()) {
|
||||
if (areaContent->IsFocusable(&tabIndex) && tabIndex == aCurrentTabIndex) {
|
||||
focusable = areaContent->IsFocusableWithoutStyle();
|
||||
if (focusable && focusable.mTabIndex == aCurrentTabIndex) {
|
||||
return areaContent;
|
||||
}
|
||||
}
|
||||
@ -5459,7 +5457,8 @@ Element* nsFocusManager::GetTheFocusableArea(Element* aTarget,
|
||||
// HTML areas do not have their own frame, and the img frame we get from
|
||||
// GetPrimaryFrame() is not relevant as to whether it is focusable or
|
||||
// not, so we have to do all the relevant checks manually for them.
|
||||
return frame->IsVisibleConsideringAncestors() && aTarget->IsFocusable()
|
||||
return frame->IsVisibleConsideringAncestors() &&
|
||||
aTarget->IsFocusableWithoutStyle()
|
||||
? aTarget
|
||||
: nullptr;
|
||||
}
|
||||
|
@ -30,6 +30,16 @@ struct IMEState;
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
struct Focusable {
|
||||
bool mFocusable = false;
|
||||
// The computed tab index:
|
||||
// < 0 if not tabbable
|
||||
// == 0 if in normal tab order
|
||||
// > 0 can be tabbed to in the order specified by this value
|
||||
int32_t mTabIndex = -1;
|
||||
explicit operator bool() const { return mFocusable; }
|
||||
};
|
||||
|
||||
// IID for the nsIContent interface
|
||||
// Must be kept in sync with xpcom/rust/xpcom/src/interfaces/nonidl.rs
|
||||
#define NS_ICONTENT_IID \
|
||||
@ -280,17 +290,9 @@ class nsIContent : public nsINode {
|
||||
* Also, depending on either the accessibility.tabfocus pref or
|
||||
* a system setting (nowadays: Full keyboard access, mac only)
|
||||
* some widgets may be focusable but removed from the tab order.
|
||||
* @param [inout, optional] aTabIndex the computed tab index
|
||||
* In: default tabindex for element (-1 nonfocusable, == 0 focusable)
|
||||
* Out: computed tabindex
|
||||
* @param [optional] aTabIndex the computed tab index
|
||||
* < 0 if not tabbable
|
||||
* == 0 if in normal tab order
|
||||
* > 0 can be tabbed to in the order specified by this value
|
||||
* @return whether the content is focusable via mouse, kbd or script.
|
||||
*/
|
||||
bool IsFocusable(int32_t* aTabIndex = nullptr, bool aWithMouse = false);
|
||||
virtual bool IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse);
|
||||
virtual Focusable IsFocusableWithoutStyle(bool aWithMouse = false);
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/interaction.html#focus-delegate
|
||||
mozilla::dom::Element* GetFocusDelegate(bool aWithMouse) const;
|
||||
|
@ -211,7 +211,7 @@ nsresult nsStyledElement::BindToTree(BindContext& aContext, nsINode& aParent) {
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (HasAttr(nsGkAtoms::autofocus) && aContext.AllowsAutoFocus() &&
|
||||
(!IsSVGElement() || IsFocusable())) {
|
||||
(!IsSVGElement() || IsFocusableWithoutStyle())) {
|
||||
aContext.OwnerDoc().ElementWithAutoFocusInserted(this);
|
||||
}
|
||||
|
||||
|
@ -1564,24 +1564,23 @@ MOZ_CAN_RUN_SCRIPT static bool IsNextFocusableElementTextControl(
|
||||
if (!nextElement) {
|
||||
return false;
|
||||
}
|
||||
bool focusable = false;
|
||||
nextElement->IsHTMLFocusable(false, &focusable, nullptr);
|
||||
if (!focusable) {
|
||||
|
||||
// FIXME: Should probably use nsIFrame::IsFocusable if possible, to account
|
||||
// for things like visibility: hidden or so.
|
||||
if (!nextElement->IsFocusableWithoutStyle(false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check readonly attribute.
|
||||
if (nextElement->IsHTMLElement(nsGkAtoms::textarea)) {
|
||||
HTMLTextAreaElement* textAreaElement =
|
||||
HTMLTextAreaElement::FromNodeOrNull(nextElement);
|
||||
auto* textAreaElement = HTMLTextAreaElement::FromNode(nextElement);
|
||||
return !textAreaElement->ReadOnly();
|
||||
}
|
||||
|
||||
// If neither textarea nor input, what element type?
|
||||
MOZ_DIAGNOSTIC_ASSERT(nextElement->IsHTMLElement(nsGkAtoms::input));
|
||||
|
||||
HTMLInputElement* inputElement =
|
||||
HTMLInputElement::FromNodeOrNull(nextElement);
|
||||
auto* inputElement = HTMLInputElement::FromNode(nextElement);
|
||||
return !inputElement->ReadOnly();
|
||||
}
|
||||
|
||||
|
@ -98,6 +98,7 @@ bool HTMLAnchorElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
|
||||
|
||||
// cannot focus links if there is no link handler
|
||||
if (!OwnerDoc()->LinkHandlingEnabled()) {
|
||||
*aTabIndex = -1;
|
||||
*aIsFocusable = false;
|
||||
return false;
|
||||
}
|
||||
@ -105,12 +106,8 @@ bool HTMLAnchorElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
|
||||
// Links that are in an editable region should never be focusable, even if
|
||||
// they are in a contenteditable="false" region.
|
||||
if (nsContentUtils::IsNodeInEditableRegion(this)) {
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
|
||||
*aTabIndex = -1;
|
||||
*aIsFocusable = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -119,22 +116,16 @@ bool HTMLAnchorElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
|
||||
if (!IsLink()) {
|
||||
// Not tabbable or focusable without href (bug 17605), unless
|
||||
// forced to be via presence of nonnegative tabindex attribute
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
|
||||
*aTabIndex = -1;
|
||||
*aIsFocusable = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (aTabIndex && (sTabFocusModel & eTabFocus_linksMask) == 0) {
|
||||
if ((sTabFocusModel & eTabFocus_linksMask) == 0) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
|
||||
*aIsFocusable = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -492,22 +492,16 @@ bool HTMLImageElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
|
||||
int32_t tabIndex = TabIndex();
|
||||
|
||||
if (IsInComposedDoc() && FindImageMap()) {
|
||||
if (aTabIndex) {
|
||||
// Use tab index on individual map areas
|
||||
*aTabIndex = (sTabFocusModel & eTabFocus_linksMask) ? 0 : -1;
|
||||
}
|
||||
// Use tab index on individual map areas.
|
||||
*aTabIndex = (sTabFocusModel & eTabFocus_linksMask) ? 0 : -1;
|
||||
// Image map is not focusable itself, but flag as tabbable
|
||||
// so that image map areas get walked into.
|
||||
*aIsFocusable = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aTabIndex) {
|
||||
// Can be in tab order if tabindex >=0 and form controls are tabbable.
|
||||
*aTabIndex = (sTabFocusModel & eTabFocus_formElementsMask) ? tabIndex : -1;
|
||||
}
|
||||
|
||||
// Can be in tab order if tabindex >=0 and form controls are tabbable.
|
||||
*aTabIndex = (sTabFocusModel & eTabFocus_formElementsMask) ? tabIndex : -1;
|
||||
*aIsFocusable = IsFormControlDefaultFocusable(aWithMouse) &&
|
||||
(tabIndex >= 0 || GetTabIndexAttrValue().isSome());
|
||||
|
||||
|
@ -2286,6 +2286,8 @@ void nsGenericHTMLElement::Click(CallerType aCallerType) {
|
||||
|
||||
bool nsGenericHTMLElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
|
||||
int32_t* aTabIndex) {
|
||||
MOZ_ASSERT(aIsFocusable);
|
||||
MOZ_ASSERT(aTabIndex);
|
||||
if (ShadowRoot* root = GetShadowRoot()) {
|
||||
if (root->DelegatesFocus()) {
|
||||
*aIsFocusable = false;
|
||||
@ -2293,23 +2295,17 @@ bool nsGenericHTMLElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
|
||||
}
|
||||
}
|
||||
|
||||
Document* doc = GetComposedDoc();
|
||||
if (!doc || IsInDesignMode()) {
|
||||
if (!IsInComposedDoc() || IsInDesignMode()) {
|
||||
// In designMode documents we only allow focusing the document.
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
|
||||
*aTabIndex = -1;
|
||||
*aIsFocusable = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t tabIndex = TabIndex();
|
||||
*aTabIndex = TabIndex();
|
||||
bool disabled = false;
|
||||
bool disallowOverridingFocusability = true;
|
||||
Maybe<int32_t> attrVal = GetTabIndexAttrValue();
|
||||
|
||||
if (IsEditingHost()) {
|
||||
// Editable roots should always be focusable.
|
||||
disallowOverridingFocusability = true;
|
||||
@ -2319,7 +2315,7 @@ bool nsGenericHTMLElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
|
||||
if (attrVal.isNothing()) {
|
||||
// The default value for tabindex should be 0 for editable
|
||||
// contentEditable roots.
|
||||
tabIndex = 0;
|
||||
*aTabIndex = 0;
|
||||
}
|
||||
} else {
|
||||
disallowOverridingFocusability = false;
|
||||
@ -2327,18 +2323,13 @@ bool nsGenericHTMLElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable,
|
||||
// Just check for disabled attribute on form controls
|
||||
disabled = IsDisabled();
|
||||
if (disabled) {
|
||||
tabIndex = -1;
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = tabIndex;
|
||||
}
|
||||
|
||||
// If a tabindex is specified at all, or the default tabindex is 0, we're
|
||||
// focusable
|
||||
*aIsFocusable = (tabIndex >= 0 || (!disabled && attrVal.isSome()));
|
||||
|
||||
// focusable.
|
||||
*aIsFocusable = (*aTabIndex >= 0 || (!disabled && attrVal.isSome()));
|
||||
return disallowOverridingFocusability;
|
||||
}
|
||||
|
||||
|
@ -334,10 +334,10 @@ class nsGenericHTMLElement : public nsGenericHTMLElementBase {
|
||||
nsresult BindToTree(BindContext&, nsINode& aParent) override;
|
||||
void UnbindFromTree(bool aNullParent = true) override;
|
||||
|
||||
bool IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) override {
|
||||
bool isFocusable = false;
|
||||
IsHTMLFocusable(aWithMouse, &isFocusable, aTabIndex);
|
||||
return isFocusable;
|
||||
Focusable IsFocusableWithoutStyle(bool aWithMouse) override {
|
||||
Focusable result;
|
||||
IsHTMLFocusable(aWithMouse, &result.mFocusable, &result.mTabIndex);
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Returns true if a subclass is not allowed to override the value returned
|
||||
|
@ -612,43 +612,36 @@ void MathMLElement::SetIncrementScriptLevel(bool aIncrementScriptLevel,
|
||||
int32_t MathMLElement::TabIndexDefault() { return IsLink() ? 0 : -1; }
|
||||
|
||||
// XXX Bug 1586011: Share logic with other element classes.
|
||||
bool MathMLElement::IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) {
|
||||
Focusable MathMLElement::IsFocusableWithoutStyle(bool aWithMouse) {
|
||||
if (!IsInComposedDoc() || IsInDesignMode()) {
|
||||
// In designMode documents we only allow focusing the document.
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
return false;
|
||||
return {};
|
||||
}
|
||||
|
||||
int32_t tabIndex = TabIndex();
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = tabIndex;
|
||||
}
|
||||
|
||||
if (!IsLink()) {
|
||||
// If a tabindex is specified at all we're focusable
|
||||
return GetTabIndexAttrValue().isSome();
|
||||
if (GetTabIndexAttrValue().isSome()) {
|
||||
return {true, tabIndex};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!OwnerDoc()->LinkHandlingEnabled()) {
|
||||
return false;
|
||||
return {};
|
||||
}
|
||||
|
||||
// Links that are in an editable region should never be focusable, even if
|
||||
// they are in a contenteditable="false" region.
|
||||
if (nsContentUtils::IsNodeInEditableRegion(this)) {
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
return false;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (aTabIndex && (sTabFocusModel & eTabFocus_linksMask) == 0) {
|
||||
*aTabIndex = -1;
|
||||
if ((sTabFocusModel & eTabFocus_linksMask) == 0) {
|
||||
tabIndex = -1;
|
||||
}
|
||||
|
||||
return true;
|
||||
return {true, tabIndex};
|
||||
}
|
||||
|
||||
already_AddRefed<nsIURI> MathMLElement::GetHrefURI() const {
|
||||
|
@ -74,7 +74,7 @@ class MathMLElement final : public MathMLElementBase, public Link {
|
||||
|
||||
int32_t TabIndexDefault() final;
|
||||
|
||||
bool IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) override;
|
||||
Focusable IsFocusableWithoutStyle(bool aWithMouse) override;
|
||||
already_AddRefed<nsIURI> GetHrefURI() const override;
|
||||
|
||||
void NodeInfoChanged(Document* aOldDoc) override {
|
||||
|
@ -157,23 +157,20 @@ void SVGAElement::UnbindFromTree(bool aNullParent) {
|
||||
|
||||
int32_t SVGAElement::TabIndexDefault() { return 0; }
|
||||
|
||||
bool SVGAElement::IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) {
|
||||
bool isFocusable = false;
|
||||
if (IsSVGFocusable(&isFocusable, aTabIndex)) {
|
||||
return isFocusable;
|
||||
Focusable SVGAElement::IsFocusableWithoutStyle(bool aWithMouse) {
|
||||
Focusable result;
|
||||
if (IsSVGFocusable(&result.mFocusable, &result.mTabIndex)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!OwnerDoc()->LinkHandlingEnabled()) {
|
||||
return false;
|
||||
return {};
|
||||
}
|
||||
|
||||
// Links that are in an editable region should never be focusable, even if
|
||||
// they are in a contenteditable="false" region.
|
||||
if (nsContentUtils::IsNodeInEditableRegion(this)) {
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
return false;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (GetTabIndexAttrValue().isNothing()) {
|
||||
@ -181,18 +178,13 @@ bool SVGAElement::IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) {
|
||||
if (!IsLink()) {
|
||||
// Not tabbable or focusable without href (bug 17605), unless
|
||||
// forced to be via presence of nonnegative tabindex attribute
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
return false;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
if (aTabIndex && (sTabFocusModel & eTabFocus_linksMask) == 0) {
|
||||
*aTabIndex = -1;
|
||||
if ((sTabFocusModel & eTabFocus_linksMask) == 0) {
|
||||
result.mTabIndex = -1;
|
||||
}
|
||||
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SVGAElement::HasHref() const {
|
||||
|
@ -53,7 +53,7 @@ class SVGAElement final : public SVGAElementBase,
|
||||
void UnbindFromTree(bool aNullParent = true) override;
|
||||
|
||||
int32_t TabIndexDefault() override;
|
||||
bool IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) override;
|
||||
Focusable IsFocusableWithoutStyle(bool aWithMouse) override;
|
||||
|
||||
void GetLinkTarget(nsAString& aTarget) override;
|
||||
already_AddRefed<nsIURI> GetHrefURI() const override;
|
||||
|
@ -25,10 +25,7 @@ class SVGDefsElement final : public SVGGraphicsElement {
|
||||
|
||||
public:
|
||||
// defs elements are not focusable.
|
||||
bool IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) override {
|
||||
return nsIContent::IsFocusableInternal(aTabIndex, aWithMouse);
|
||||
}
|
||||
|
||||
Focusable IsFocusableWithoutStyle(bool aWithMouse) override { return {}; }
|
||||
nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
|
||||
};
|
||||
|
||||
|
@ -154,33 +154,22 @@ bool SVGGraphicsElement::IsSVGFocusable(bool* aIsFocusable,
|
||||
// MathML elements, see bug 1586011.
|
||||
if (!IsInComposedDoc() || IsInDesignMode()) {
|
||||
// In designMode documents we only allow focusing the document.
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
|
||||
*aTabIndex = -1;
|
||||
*aIsFocusable = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t tabIndex = TabIndex();
|
||||
|
||||
if (aTabIndex) {
|
||||
*aTabIndex = tabIndex;
|
||||
}
|
||||
|
||||
*aTabIndex = TabIndex();
|
||||
// If a tabindex is specified at all, or the default tabindex is 0, we're
|
||||
// focusable
|
||||
*aIsFocusable = tabIndex >= 0 || GetTabIndexAttrValue().isSome();
|
||||
|
||||
*aIsFocusable = *aTabIndex >= 0 || GetTabIndexAttrValue().isSome();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SVGGraphicsElement::IsFocusableInternal(int32_t* aTabIndex,
|
||||
bool aWithMouse) {
|
||||
bool isFocusable = false;
|
||||
IsSVGFocusable(&isFocusable, aTabIndex);
|
||||
return isFocusable;
|
||||
Focusable SVGGraphicsElement::IsFocusableWithoutStyle(bool aWithMouse) {
|
||||
Focusable result;
|
||||
IsSVGFocusable(&result.mFocusable, &result.mTabIndex);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
@ -34,7 +34,7 @@ class SVGGraphicsElement : public SVGGraphicsElementBase, public SVGTests {
|
||||
already_AddRefed<SVGMatrix> GetCTM();
|
||||
already_AddRefed<SVGMatrix> GetScreenCTM();
|
||||
|
||||
bool IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) override;
|
||||
Focusable IsFocusableWithoutStyle(bool aWithMouse) override;
|
||||
bool IsSVGGraphicsElement() const final { return true; }
|
||||
|
||||
using nsINode::Clone;
|
||||
|
@ -373,91 +373,54 @@ static bool IsNonList(mozilla::dom::NodeInfo* aNodeInfo) {
|
||||
!aNodeInfo->Equals(nsGkAtoms::richlistbox);
|
||||
}
|
||||
|
||||
bool nsXULElement::IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) {
|
||||
/*
|
||||
* Returns true if an element may be focused, and false otherwise. The inout
|
||||
* argument aTabIndex will be set to the tab order index to be used; -1 for
|
||||
* elements that should not be part of the tab order and a greater value to
|
||||
* indicate its tab order.
|
||||
*
|
||||
* Confusingly, the supplied value for the aTabIndex argument may indicate
|
||||
* whether the element may be focused as a result of the -moz-user-focus
|
||||
* property, where -1 means no and 0 means yes.
|
||||
*
|
||||
* For controls, the element cannot be focused and is not part of the tab
|
||||
* order if it is disabled.
|
||||
*
|
||||
* -moz-user-focus is overridden if a tabindex (even -1) is specified.
|
||||
*
|
||||
* Specifically, the behaviour for all XUL elements is as follows:
|
||||
* *aTabIndex = -1 no tabindex Not focusable or tabbable
|
||||
* *aTabIndex = -1 tabindex="-1" Focusable but not tabbable
|
||||
* *aTabIndex = -1 tabindex=">=0" Focusable and tabbable
|
||||
* *aTabIndex >= 0 no tabindex Focusable and tabbable
|
||||
* *aTabIndex >= 0 tabindex="-1" Focusable but not tabbable
|
||||
* *aTabIndex >= 0 tabindex=">=0" Focusable and tabbable
|
||||
*
|
||||
* If aTabIndex is null, then the tabindex is not computed, and
|
||||
* true is returned for non-disabled controls and false otherwise.
|
||||
*/
|
||||
|
||||
// elements are not focusable by default
|
||||
bool shouldFocus = false;
|
||||
|
||||
// XUL elements are not focusable unless explicitly opted-into it with
|
||||
// -moz-user-focus: normal, or the tabindex attribute.
|
||||
Focusable nsXULElement::IsFocusableWithoutStyle(bool aWithMouse) {
|
||||
#ifdef XP_MACOSX
|
||||
// on Mac, mouse interactions only focus the element if it's a list,
|
||||
// or if it's a remote target, since the remote target must handle
|
||||
// the focus.
|
||||
if (aWithMouse && IsNonList(mNodeInfo) &&
|
||||
!EventStateManager::IsTopLevelRemoteTarget(this)) {
|
||||
return false;
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
bool shouldFocus = false;
|
||||
nsCOMPtr<nsIDOMXULControlElement> xulControl = AsXULControl();
|
||||
if (xulControl) {
|
||||
// a disabled element cannot be focused and is not part of the tab order
|
||||
bool disabled;
|
||||
xulControl->GetDisabled(&disabled);
|
||||
if (disabled) {
|
||||
if (aTabIndex) *aTabIndex = -1;
|
||||
return false;
|
||||
return {};
|
||||
}
|
||||
shouldFocus = true;
|
||||
}
|
||||
|
||||
if (aTabIndex) {
|
||||
Maybe<int32_t> attrVal = GetTabIndexAttrValue();
|
||||
if (attrVal.isSome()) {
|
||||
// The tabindex attribute was specified, so the element becomes
|
||||
// focusable.
|
||||
shouldFocus = true;
|
||||
*aTabIndex = attrVal.value();
|
||||
} else {
|
||||
// otherwise, if there is no tabindex attribute, just use the value of
|
||||
// *aTabIndex to indicate focusability. Reset any supplied tabindex to 0.
|
||||
shouldFocus = *aTabIndex >= 0;
|
||||
if (shouldFocus) {
|
||||
*aTabIndex = 0;
|
||||
}
|
||||
}
|
||||
int32_t tabIndex = -1;
|
||||
if (Maybe<int32_t> attrVal = GetTabIndexAttrValue()) {
|
||||
// The tabindex attribute was specified, so the element becomes
|
||||
// focusable.
|
||||
shouldFocus = true;
|
||||
tabIndex = attrVal.value();
|
||||
}
|
||||
|
||||
if (xulControl && shouldFocus && sTabFocusModelAppliesToXUL &&
|
||||
!(sTabFocusModel & eTabFocus_formElementsMask)) {
|
||||
// By default, the tab focus model doesn't apply to xul element on any
|
||||
// system but OS X. on OS X we're following it for UI elements (XUL) as
|
||||
// sTabFocusModel is based on "Full Keyboard Access" system setting (see
|
||||
// mac/nsILookAndFeel). both textboxes and list elements (i.e. trees and
|
||||
// list) should always be focusable (textboxes are handled as html:input)
|
||||
// For compatibility, we only do this for controls, otherwise elements
|
||||
// like <browser> cannot take this focus.
|
||||
if (IsNonList(mNodeInfo)) {
|
||||
*aTabIndex = -1;
|
||||
}
|
||||
if (xulControl && shouldFocus && sTabFocusModelAppliesToXUL &&
|
||||
!(sTabFocusModel & eTabFocus_formElementsMask)) {
|
||||
// By default, the tab focus model doesn't apply to xul element on any
|
||||
// system but OS X. on OS X we're following it for UI elements (XUL) as
|
||||
// sTabFocusModel is based on "Full Keyboard Access" system setting (see
|
||||
// mac/nsILookAndFeel). both textboxes and list elements (i.e. trees and
|
||||
// list) should always be focusable (textboxes are handled as html:input)
|
||||
// For compatibility, we only do this for controls, otherwise elements
|
||||
// like <browser> cannot take this focus.
|
||||
if (IsNonList(mNodeInfo)) {
|
||||
tabIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return shouldFocus;
|
||||
return {shouldFocus, tabIndex};
|
||||
}
|
||||
|
||||
bool nsXULElement::HasMenu() {
|
||||
|
@ -393,7 +393,7 @@ class nsXULElement : public nsStyledElement {
|
||||
MOZ_CAN_RUN_SCRIPT void ClickWithInputSource(uint16_t aInputSource,
|
||||
bool aIsTrustedEvent);
|
||||
|
||||
bool IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) override;
|
||||
Focusable IsFocusableWithoutStyle(bool aWithMouse) override;
|
||||
|
||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override;
|
||||
|
||||
|
@ -10665,8 +10665,7 @@ bool nsIFrame::IsFocusableDueToScrollFrame() {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsIFrame::Focusable nsIFrame::IsFocusable(bool aWithMouse,
|
||||
bool aCheckVisibility) {
|
||||
Focusable nsIFrame::IsFocusable(bool aWithMouse, bool aCheckVisibility) {
|
||||
// cannot focus content in print preview mode. Only the root can be focused,
|
||||
// but that's handled elsewhere.
|
||||
if (PresContext()->Type() == nsPresContext::eContext_PrintPreview) {
|
||||
@ -10691,16 +10690,20 @@ nsIFrame::Focusable nsIFrame::IsFocusable(bool aWithMouse,
|
||||
return {};
|
||||
}
|
||||
|
||||
int32_t tabIndex = -1;
|
||||
if (ui.UserFocus() != StyleUserFocus::Ignore &&
|
||||
ui.UserFocus() != StyleUserFocus::None) {
|
||||
// Pass in default tabindex of -1 for nonfocusable and 0 for focusable
|
||||
tabIndex = 0;
|
||||
auto focusable = mContent->IsFocusableWithoutStyle(aWithMouse);
|
||||
auto* xul = nsXULElement::FromNode(mContent);
|
||||
if (xul && !xul->GetXULBoolAttr(nsGkAtoms::disabled) &&
|
||||
xul->GetTabIndexAttrValue().isNothing()) {
|
||||
// As a legacy special-case, -moz-user-focus controls focusability and
|
||||
// tabability of XUL elements in some circumstances (which default to
|
||||
// -moz-user-focus: ignore).
|
||||
focusable.mFocusable = ui.UserFocus() == StyleUserFocus::Normal;
|
||||
focusable.mTabIndex =
|
||||
std::max(focusable.mTabIndex, focusable.mFocusable ? 0 : -1);
|
||||
}
|
||||
|
||||
if (mContent->IsFocusable(&tabIndex, aWithMouse)) {
|
||||
// If the content is focusable, then we're done.
|
||||
return {true, tabIndex};
|
||||
if (focusable) {
|
||||
return focusable;
|
||||
}
|
||||
|
||||
// If we're focusing with the mouse we never focus scroll areas.
|
||||
@ -10708,7 +10711,10 @@ nsIFrame::Focusable nsIFrame::IsFocusable(bool aWithMouse,
|
||||
return {true, 0};
|
||||
}
|
||||
|
||||
return {false, tabIndex};
|
||||
// FIXME(emilio): some callers rely on somewhat broken return values
|
||||
// (focusable = false, but non-negative tab-index) from
|
||||
// IsFocusableWithoutStyle (for image maps in particular).
|
||||
return focusable;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4316,17 +4316,6 @@ class nsIFrame : public nsQueryFrame {
|
||||
const nsStyleEffects* aEffects,
|
||||
const nsSize& aSize) const;
|
||||
|
||||
struct Focusable {
|
||||
bool mFocusable = false;
|
||||
// The computed tab index:
|
||||
// < 0 if not tabbable
|
||||
// == 0 if in normal tab order
|
||||
// > 0 can be tabbed to in the order specified by this value
|
||||
int32_t mTabIndex = -1;
|
||||
|
||||
explicit operator bool() const { return mFocusable; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if this frame is focusable and in the current tab order.
|
||||
* Tabbable is indicated by a nonnegative tabindex & is a subset of focusable.
|
||||
|
Loading…
Reference in New Issue
Block a user