static bool IsElementClickable(nsIFrame* aFrame, nsIAtom* stopAt = nullptr) { // Input events propagate up the content tree so we'll follow the content // ancestors to look for elements accepting the click. for (nsIContent* content = aFrame->GetContent(); content; content = content->GetFlattenedTreeParent()) { nsIAtom* tag = content->Tag(); if (content->IsHTML() && stopAt && tag == stopAt) { break; } if (HasMouseListener(content)) { return true; } if (content->IsHTML()) { if (tag == nsGkAtoms::button || tag == nsGkAtoms::input || tag == nsGkAtoms::select || tag == nsGkAtoms::textarea || tag == nsGkAtoms::label) { return true; } } else if (content->IsXUL()) { nsIAtom* tag = content->Tag(); // See nsCSSFrameConstructor::FindXULTagData. This code is not // really intended to be used with XUL, though. if (tag == nsGkAtoms::button || tag == nsGkAtoms::checkbox || tag == nsGkAtoms::radio || tag == nsGkAtoms::autorepeatbutton || tag == nsGkAtoms::menu || tag == nsGkAtoms::menubutton || tag == nsGkAtoms::menuitem || tag == nsGkAtoms::menulist || tag == nsGkAtoms::scrollbarbutton || tag == nsGkAtoms::resizer) { return true; } } if (content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::role, nsGkAtoms::button, eIgnoreCase)) { return true; } if (content->IsEditable()) { return true; } nsCOMPtr<nsIURI> linkURI; if (content->IsLink(getter_AddRefs(linkURI))) { return true; } } return false; }
static nsIContent* GetClickableAncestor(nsIFrame* aFrame, nsIAtom* stopAt = nullptr, nsAutoString* aLabelTargetId = nullptr) { // Input events propagate up the content tree so we'll follow the content // ancestors to look for elements accepting the click. for (nsIContent* content = aFrame->GetContent(); content; content = content->GetFlattenedTreeParent()) { if (stopAt && content->IsHTMLElement(stopAt)) { break; } if (HasTouchListener(content) || HasMouseListener(content)) { return content; } if (content->IsAnyOfHTMLElements(nsGkAtoms::button, nsGkAtoms::input, nsGkAtoms::select, nsGkAtoms::textarea)) { return content; } if (content->IsHTMLElement(nsGkAtoms::label)) { if (aLabelTargetId) { content->GetAttr(kNameSpaceID_None, nsGkAtoms::_for, *aLabelTargetId); } return content; } // Bug 921928: we don't have access to the content of remote iframe. // So fluffing won't go there. We do an optimistic assumption here: // that the content of the remote iframe needs to be a target. if (content->IsHTMLElement(nsGkAtoms::iframe) && content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::mozbrowser, nsGkAtoms::_true, eIgnoreCase) && content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::Remote, nsGkAtoms::_true, eIgnoreCase)) { return content; } // See nsCSSFrameConstructor::FindXULTagData. This code is not // really intended to be used with XUL, though. if (content->IsAnyOfXULElements(nsGkAtoms::button, nsGkAtoms::checkbox, nsGkAtoms::radio, nsGkAtoms::autorepeatbutton, nsGkAtoms::menu, nsGkAtoms::menubutton, nsGkAtoms::menuitem, nsGkAtoms::menulist, nsGkAtoms::scrollbarbutton, nsGkAtoms::resizer)) { return content; } static nsIContent::AttrValuesArray clickableRoles[] = { &nsGkAtoms::button, &nsGkAtoms::key, nullptr }; if (content->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::role, clickableRoles, eIgnoreCase) >= 0) { return content; } if (content->IsEditable()) { return content; } nsCOMPtr<nsIURI> linkURI; if (content->IsLink(getter_AddRefs(linkURI))) { return content; } } return nullptr; }