Backed out 7 changesets (bug 1444491, bug 1801761) for causing failures on autofocus-attribute.svg. CLOSED TREE

Backed out changeset 1cee414009cb (bug 1444491)
Backed out changeset 30f786b79191 (bug 1444491)
Backed out changeset ce06375518a7 (bug 1801761)
Backed out changeset 64c8bb293e5c (bug 1444491)
Backed out changeset 94aa0ce630f2 (bug 1444491)
Backed out changeset 80010eabc0c1 (bug 1444491)
Backed out changeset 7d8da1f44177 (bug 1444491)
This commit is contained in:
Csoregi Natalia
2023-02-15 19:03:59 +02:00
parent f385e27c16
commit 35e053d28d
45 changed files with 301 additions and 453 deletions

View File

@@ -381,7 +381,6 @@
#include "nsIX509Cert.h"
#include "nsIX509CertValidity.h"
#include "nsIXMLContentSink.h"
#include "nsIHTMLContentSink.h"
#include "nsIXULRuntime.h"
#include "nsImageLoadingContent.h"
#include "nsImportModule.h"
@@ -6843,9 +6842,6 @@ already_AddRefed<PresShell> Document::CreatePresShell(
mDocumentL10n->OnCreatePresShell();
}
if (HasAutoFocusCandidates()) {
ScheduleFlushAutoFocusCandidates();
}
// Now that we have a shell, we might have @font-face rules (the presence of a
// shell may change which rules apply to us). We don't need to do anything
// like EnsureStyleFlush or such, there's nothing to update yet and when stuff
@@ -6952,7 +6948,6 @@ void Document::DeletePresShell() {
mExternalResourceMap.HideViewers();
if (nsPresContext* presContext = mPresShell->GetPresContext()) {
presContext->RefreshDriver()->CancelPendingFullscreenEvents(this);
presContext->RefreshDriver()->CancelFlushAutoFocus(this);
}
// When our shell goes away, request that all our images be immediately
@@ -12630,254 +12625,121 @@ Document* Document::GetTemplateContentsOwner() {
return mTemplateContentsOwner;
}
// https://html.spec.whatwg.org/#the-autofocus-attribute
void Document::ElementWithAutoFocusInserted(Element* aAutoFocusCandidate) {
BrowsingContext* bc = GetBrowsingContext();
if (!bc) {
static already_AddRefed<nsPIDOMWindowOuter> FindTopWindowForElement(
Element* element) {
Document* document = element->OwnerDoc();
if (!document) {
return nullptr;
}
nsCOMPtr<nsPIDOMWindowOuter> window = document->GetWindow();
if (!window) {
return nullptr;
}
// Trying to find the top window (equivalent to window.top).
if (nsCOMPtr<nsPIDOMWindowOuter> top = window->GetInProcessTop()) {
window = std::move(top);
}
return window.forget();
}
/**
* nsAutoFocusEvent is used to dispatch a focus event for an
* nsGenericHTMLFormElement with the autofocus attribute enabled.
*/
class nsAutoFocusEvent : public Runnable {
public:
explicit nsAutoFocusEvent(nsCOMPtr<Element>&& aElement,
nsCOMPtr<nsPIDOMWindowOuter>&& aTopWindow)
: mozilla::Runnable("nsAutoFocusEvent"),
mElement(std::move(aElement)),
mTopWindow(std::move(aTopWindow)) {}
NS_IMETHOD Run() override {
nsCOMPtr<nsPIDOMWindowOuter> currentTopWindow =
FindTopWindowForElement(mElement);
if (currentTopWindow != mTopWindow) {
// The element's top window changed from when the event was queued.
// Don't take away focus from an unrelated window.
return NS_OK;
}
if (Document* doc = mTopWindow->GetExtantDoc()) {
if (doc->IsAutoFocusFired()) {
return NS_OK;
}
doc->SetAutoFocusFired();
}
// Don't steal focus from the user.
if (mTopWindow->GetFocusedElement()) {
return NS_OK;
}
FocusOptions options;
ErrorResult rv;
mElement->Focus(options, CallerType::System, rv);
return rv.StealNSResult();
}
private:
nsCOMPtr<Element> mElement;
nsCOMPtr<nsPIDOMWindowOuter> mTopWindow;
};
void Document::SetAutoFocusElement(Element* aAutoFocusElement) {
if (mAutoFocusFired) {
// Too late.
return;
}
// If target is not fully active, then return.
if (!IsCurrentActiveDocument()) {
if (mAutoFocusElement) {
// The spec disallows multiple autofocus elements, so we consider only the
// first one to preserve the old behavior.
return;
}
// If target's active sandboxing flag set has the sandboxed automatic features
// browsing context flag, then return.
if (GetSandboxFlags() & SANDBOXED_AUTOMATIC_FEATURES) {
return;
mAutoFocusElement = do_GetWeakReference(aAutoFocusElement);
TriggerAutoFocus();
}
// For each ancestorBC of target's browsing context's ancestor browsing
// contexts: if ancestorBC's active document's origin is not same origin with
// target's origin, then return.
while (bc) {
BrowsingContext* parent = bc->GetParent();
if (!parent) {
break;
}
// AncestorBC is not the same site
if (!parent->IsInProcess()) {
return;
}
void Document::SetAutoFocusFired() { mAutoFocusFired = true; }
Document* currentDocument = bc->GetDocument();
if (!currentDocument) {
return;
}
bool Document::IsAutoFocusFired() { return mAutoFocusFired; }
Document* parentDocument = parent->GetDocument();
if (!parentDocument) {
return;
}
// Not same origin
if (!currentDocument->NodePrincipal()->Equals(
parentDocument->NodePrincipal())) {
return;
}
bc = parent;
}
MOZ_ASSERT(bc->IsTop());
Document* topDocument = bc->GetDocument();
MOZ_ASSERT(topDocument);
topDocument->AppendAutoFocusCandidateToTopDocument(aAutoFocusCandidate);
}
void Document::ScheduleFlushAutoFocusCandidates() {
MOZ_ASSERT(mPresShell && mPresShell->DidInitialize());
MOZ_ASSERT(GetBrowsingContext()->IsTop());
if (nsRefreshDriver* rd = mPresShell->GetRefreshDriver()) {
rd->ScheduleAutoFocusFlush(this);
}
}
void Document::AppendAutoFocusCandidateToTopDocument(
Element* aAutoFocusCandidate) {
MOZ_ASSERT(GetBrowsingContext()->IsTop());
void Document::TriggerAutoFocus() {
if (mAutoFocusFired) {
return;
}
if (!HasAutoFocusCandidates()) {
// PresShell may be initialized later
if (mPresShell && mPresShell->DidInitialize()) {
ScheduleFlushAutoFocusCandidates();
}
}
nsWeakPtr element = do_GetWeakReference(aAutoFocusCandidate);
mAutoFocusCandidates.RemoveElement(element);
mAutoFocusCandidates.AppendElement(element);
}
void Document::SetAutoFocusFired() {
mAutoFocusCandidates.Clear();
mAutoFocusFired = true;
}
// https://html.spec.whatwg.org/#flush-autofocus-candidates
void Document::FlushAutoFocusCandidates() {
MOZ_ASSERT(GetBrowsingContext()->IsTop());
if (mAutoFocusFired) {
if (!mPresShell || !mPresShell->DidInitialize()) {
// Delay autofocus until frames are constructed so that we don't thrash
// style and layout calculations.
return;
}
if (!mPresShell) {
return;
}
MOZ_ASSERT(HasAutoFocusCandidates());
MOZ_ASSERT(mPresShell->DidInitialize());
nsCOMPtr<nsPIDOMWindowOuter> topWindow = GetWindow();
// We should be the top document
nsCOMPtr<Element> autoFocusElement = do_QueryReferent(mAutoFocusElement);
if (autoFocusElement && autoFocusElement->OwnerDoc() == this) {
nsCOMPtr<nsPIDOMWindowOuter> topWindow =
FindTopWindowForElement(autoFocusElement);
if (!topWindow) {
return;
}
#ifdef DEBUG
{
// Trying to find the top window (equivalent to window.top).
nsCOMPtr<nsPIDOMWindowOuter> top = topWindow->GetInProcessTop();
MOZ_ASSERT(topWindow == top);
}
#endif
// Don't steal the focus from the user
if (topWindow->GetFocusedElement()) {
SetAutoFocusFired();
// NOTE: This may be removed in the future since the spec technically
// allows autofocus after load.
nsCOMPtr<Document> topDoc = topWindow->GetExtantDoc();
if (topDoc &&
topDoc->GetReadyStateEnum() == Document::READYSTATE_COMPLETE) {
return;
}
MOZ_ASSERT(mDocumentURI);
nsAutoCString ref;
// GetRef never fails
nsresult rv = mDocumentURI->GetRef(ref);
if (NS_SUCCEEDED(rv) &&
nsContentUtils::GetTargetElement(this, NS_ConvertUTF8toUTF16(ref))) {
SetAutoFocusFired();
return;
nsCOMPtr<nsIRunnable> event =
new nsAutoFocusEvent(std::move(autoFocusElement), topWindow.forget());
nsresult rv = NS_DispatchToCurrentThread(event.forget());
NS_ENSURE_SUCCESS_VOID(rv);
}
nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mAutoFocusCandidates);
while (iter.HasMore()) {
nsCOMPtr<Element> autoFocusElement = do_QueryReferent(iter.GetNext());
if (!autoFocusElement) {
continue;
}
RefPtr<Document> autoFocusElementDoc = autoFocusElement->OwnerDoc();
// Get the latest info about the frame and allow scripts
// to run which might affect the focusability of this element.
autoFocusElementDoc->FlushPendingNotifications(FlushType::Frames);
// Above layout flush may cause the PresShell to disappear.
if (!mPresShell) {
return;
}
// Re-get the element because the ownerDoc() might have changed
autoFocusElementDoc = autoFocusElement->OwnerDoc();
BrowsingContext* bc = autoFocusElementDoc->GetBrowsingContext();
if (!bc) {
continue;
}
// If doc is not fully active, then remove element from candidates, and
// continue.
if (!autoFocusElementDoc->IsCurrentActiveDocument()) {
iter.Remove();
continue;
}
nsCOMPtr<nsIContentSink> sink =
do_QueryInterface(autoFocusElementDoc->GetCurrentContentSink());
if (sink) {
nsHtml5TreeOpExecutor* executor =
static_cast<nsHtml5TreeOpExecutor*>(sink->AsExecutor());
if (executor) {
// This is a HTML5 document
MOZ_ASSERT(autoFocusElementDoc->IsHTMLDocument());
// If doc's script-blocking style sheet counter is greater than 0, th
// return.
if (executor->WaitForPendingSheets()) {
// In this case, element is the currently-best candidate, but doc is
// not ready for autofocusing. We'll try again next time flush
// autofocus candidates is called.
ScheduleFlushAutoFocusCandidates();
return;
}
}
}
// The autofocus element could be moved to a different
// top level BC.
if (bc->Top()->GetDocument() != this) {
continue;
}
iter.Remove();
// Let inclusiveAncestorDocuments be a list consisting of doc, plus the
// active documents of each of doc's browsing context's ancestor browsing
// contexts.
// If any Document in inclusiveAncestorDocuments has non-null target
// element, then continue.
bool shouldFocus = true;
while (bc) {
Document* doc = bc->GetDocument();
if (!doc) {
shouldFocus = false;
break;
}
nsIURI* uri = doc->GetDocumentURI();
if (!uri) {
shouldFocus = false;
break;
}
nsAutoCString ref;
nsresult rv = uri->GetRef(ref);
// If there is an element in the document tree that has an ID equal to
// fragment
if (NS_SUCCEEDED(rv) &&
nsContentUtils::GetTargetElement(doc, NS_ConvertUTF8toUTF16(ref))) {
shouldFocus = false;
break;
}
bc = bc->GetParent();
}
if (!shouldFocus) {
continue;
}
MOZ_ASSERT(topWindow);
if (TryAutoFocusCandidate(*autoFocusElement)) {
// We've successfully autofocused an element, don't
// need to try to focus the rest.
SetAutoFocusFired();
break;
}
}
if (HasAutoFocusCandidates()) {
ScheduleFlushAutoFocusCandidates();
}
}
bool Document::TryAutoFocusCandidate(Element& aElement) {
const FocusOptions options;
if (RefPtr<Element> target = nsFocusManager::GetTheFocusableArea(
&aElement, nsFocusManager::ProgrammaticFocusFlags(options))) {
target->Focus(options, CallerType::NonSystem, IgnoreErrors());
return true;
}
return false;
}
void Document::SetScrollToRef(nsIURI* aDocumentURI) {

View File

@@ -1927,8 +1927,6 @@ class Document : public nsINode,
// layer. The removed element, if any, is returned.
Element* TopLayerPop(FunctionRef<bool(Element*)> aPredicate);
MOZ_CAN_RUN_SCRIPT bool TryAutoFocusCandidate(Element& aElement);
public:
// Removes all the elements with fullscreen flag set from the top layer, and
// clears their fullscreen flag.
@@ -3105,14 +3103,10 @@ class Document : public nsINode,
nsISupports* GetCurrentContentSink();
void ElementWithAutoFocusInserted(Element* aAutoFocusCandidate);
MOZ_CAN_RUN_SCRIPT void FlushAutoFocusCandidates();
void ScheduleFlushAutoFocusCandidates();
bool HasAutoFocusCandidates() const {
return !mAutoFocusCandidates.IsEmpty();
}
void SetAutoFocusElement(Element* aAutoFocusElement);
void TriggerAutoFocus();
void SetAutoFocusFired();
bool IsAutoFocusFired();
void SetScrollToRef(nsIURI* aDocumentURI);
MOZ_CAN_RUN_SCRIPT void ScrollToRef();
@@ -3956,8 +3950,6 @@ class Document : public nsINode,
void RecomputeLanguageFromCharset();
bool GetSHEntryHasUserInteraction();
void AppendAutoFocusCandidateToTopDocument(Element* aAutoFocusCandidate);
public:
void SetMayNeedFontPrefsUpdate() { mMayNeedFontPrefsUpdate = true; }
@@ -5147,11 +5139,7 @@ class Document : public nsINode,
// Recorded time of change to 'loading' state.
TimeStamp mLoadingTimeStamp;
// Decided to use nsTObserverArray because it allows us to
// remove candidates while iterating them and this is what
// the spec defines. We could implement the spec without
// using nsTObserverArray, however using nsTObserverArray is more clear.
nsTObserverArray<nsWeakPtr> mAutoFocusCandidates;
nsWeakPtr mAutoFocusElement;
nsCString mScrollToRef;

View File

@@ -169,10 +169,6 @@ class nsContentSink : public nsICSSLoaderObserver,
Document* GetDocument() { return mDocument; }
// Later on we might want to make this more involved somehow
// (e.g. stop waiting after some timeout or whatnot).
bool WaitForPendingSheets() { return mPendingSheetCount > 0; }
protected:
inline int32_t GetNotificationInterval() {
if (mDynamicLowerValue) {
@@ -184,6 +180,10 @@ class nsContentSink : public nsICSSLoaderObserver,
virtual nsresult FlushTags() = 0;
// Later on we might want to make this more involved somehow
// (e.g. stop waiting after some timeout or whatnot).
bool WaitForPendingSheets() { return mPendingSheetCount > 0; }
void DoProcessLinkHeader();
void StopDeflecting() {

View File

@@ -2982,59 +2982,6 @@ BrowserParent* nsContentUtils::GetCommonBrowserParentAncestor(
});
}
/* static */
Element* nsContentUtils::GetTargetElement(Document* aDocument,
const nsAString& aAnchorName) {
MOZ_ASSERT(aDocument);
if (aAnchorName.IsEmpty()) {
return nullptr;
}
// 1. If there is an element in the document tree that has an ID equal to
// fragment, then return the first such element in tree order.
if (Element* el = aDocument->GetElementById(aAnchorName)) {
return el;
}
// 2. If there is an a element in the document tree that has a name
// attribute whose value is equal to fragment, then return the first such
// element in tree order.
//
// FIXME(emilio): Why the different code-paths for HTML and non-HTML docs?
if (aDocument->IsHTMLDocument()) {
nsCOMPtr<nsINodeList> list = aDocument->GetElementsByName(aAnchorName);
// Loop through the named nodes looking for the first anchor
uint32_t length = list->Length();
for (uint32_t i = 0; i < length; i++) {
nsIContent* node = list->Item(i);
if (node->IsHTMLElement(nsGkAtoms::a)) {
return node->AsElement();
}
}
} else {
constexpr auto nameSpace = u"http://www.w3.org/1999/xhtml"_ns;
// Get the list of anchor elements
nsCOMPtr<nsINodeList> list =
aDocument->GetElementsByTagNameNS(nameSpace, u"a"_ns);
// Loop through the anchors looking for the first one with the given name.
for (uint32_t i = 0; true; i++) {
nsIContent* node = list->Item(i);
if (!node) { // End of list
break;
}
// Compare the name attribute
if (node->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
aAnchorName, eCaseMatters)) {
return node->AsElement();
}
}
}
// 3. Return null.
return nullptr;
}
/* static */
template <typename FPT, typename FRT, typename SPT, typename SRT>
Maybe<int32_t> nsContentUtils::ComparePoints(

View File

@@ -526,10 +526,6 @@ class nsContentUtils {
mozilla::dom::BrowserParent* aBrowserParent1,
mozilla::dom::BrowserParent* aBrowserParent2);
// https://html.spec.whatwg.org/#target-element
// https://html.spec.whatwg.org/#find-a-potential-indicated-element
static Element* GetTargetElement(Document* aDocument,
const nsAString& aAnchorName);
/**
* Returns true if aNode1 is before aNode2 in the same connected
* tree.

View File

@@ -380,7 +380,8 @@ nsFocusManager::GetActiveBrowsingContext(BrowsingContext** aBrowsingContext) {
void nsFocusManager::FocusWindow(nsPIDOMWindowOuter* aWindow,
CallerType aCallerType) {
if (RefPtr<nsFocusManager> fm = sInstance) {
fm->SetFocusedWindowWithCallerType(aWindow, aCallerType);
fm->SetFocusedWindowWithCallerType(aWindow, aCallerType,
sInstance->GenerateFocusActionId());
}
}
@@ -401,19 +402,19 @@ nsFocusManager::GetFocusedContentBrowsingContext(
}
nsresult nsFocusManager::SetFocusedWindowWithCallerType(
mozIDOMWindowProxy* aWindowToFocus, CallerType aCallerType) {
LOGFOCUS(("<<SetFocusedWindow begin>>"));
mozIDOMWindowProxy* aWindowToFocus, CallerType aCallerType,
uint64_t aActionId) {
LOGFOCUS(("<<SetFocusedWindow begin actionid: %" PRIu64 ">>", aActionId));
nsCOMPtr<nsPIDOMWindowOuter> windowToFocus =
nsPIDOMWindowOuter::From(aWindowToFocus);
NS_ENSURE_TRUE(windowToFocus, NS_ERROR_FAILURE);
nsCOMPtr<Element> frameElement = windowToFocus->GetFrameElementInternal();
Maybe<uint64_t> actionIdFromSetFocusInner;
if (frameElement) {
// pass false for aFocusChanged so that the caret does not get updated
// and scrolling does not occur.
actionIdFromSetFocusInner = SetFocusInner(frameElement, 0, false, true);
SetFocusInner(frameElement, 0, false, true, aActionId);
} else {
// this is a top-level window. If the window has a child frame focused,
// clear the focus. Otherwise, focus should already be in this frame, or
@@ -427,21 +428,19 @@ nsresult nsFocusManager::SetFocusedWindowWithCallerType(
}
nsCOMPtr<nsPIDOMWindowOuter> rootWindow = windowToFocus->GetPrivateRoot();
const uint64_t actionId = actionIdFromSetFocusInner.isSome()
? actionIdFromSetFocusInner.value()
: sInstance->GenerateFocusActionId();
if (rootWindow) {
RaiseWindow(rootWindow, aCallerType, actionId);
RaiseWindow(rootWindow, aCallerType, aActionId);
}
LOGFOCUS(("<<SetFocusedWindow end actionid: %" PRIu64 ">>", actionId));
LOGFOCUS(("<<SetFocusedWindow end actionid: %" PRIu64 ">>", aActionId));
return NS_OK;
}
NS_IMETHODIMP nsFocusManager::SetFocusedWindow(
mozIDOMWindowProxy* aWindowToFocus) {
return SetFocusedWindowWithCallerType(aWindowToFocus, CallerType::System);
return SetFocusedWindowWithCallerType(aWindowToFocus, CallerType::System,
GenerateFocusActionId());
}
NS_IMETHODIMP
@@ -471,7 +470,7 @@ nsFocusManager::SetFocus(Element* aElement, uint32_t aFlags) {
NS_ENSURE_ARG(aElement);
SetFocusInner(aElement, aFlags, true, true);
SetFocusInner(aElement, aFlags, true, true, GenerateFocusActionId());
LOGFOCUS(("<<SetFocus end>>"));
@@ -544,7 +543,7 @@ nsFocusManager::MoveFocus(mozIDOMWindowProxy* aWindow, Element* aStartElement,
// would be a problem because the caret would move to the beginning of the
// focused link making it impossible to navigate the caret over a link.
SetFocusInner(MOZ_KnownLive(newFocus->AsElement()), aFlags,
aType != MOVEFOCUS_CARET, true);
aType != MOVEFOCUS_CARET, true, GenerateFocusActionId());
*aElement = do_AddRef(newFocus->AsElement()).take();
} else if (aType == MOVEFOCUS_ROOT || aType == MOVEFOCUS_CARET) {
// no content was found, so clear the focus for these two types.
@@ -1473,15 +1472,14 @@ static bool IsEmeddededInNoautofocusPopup(BrowsingContext& aBc) {
.GetXULBoolAttr(nsGkAtoms::noautofocus);
}
Maybe<uint64_t> nsFocusManager::SetFocusInner(Element* aNewContent,
int32_t aFlags,
bool aFocusChanged,
bool aAdjustWidget) {
void nsFocusManager::SetFocusInner(Element* aNewContent, int32_t aFlags,
bool aFocusChanged, bool aAdjustWidget,
uint64_t aActionId) {
// if the element is not focusable, just return and leave the focus as is
RefPtr<Element> elementToFocus =
FlushAndCheckIfFocusable(aNewContent, aFlags);
if (!elementToFocus) {
return Nothing();
return;
}
const RefPtr<BrowsingContext> focusedBrowsingContext =
@@ -1517,7 +1515,7 @@ Maybe<uint64_t> nsFocusManager::SetFocusInner(Element* aNewContent,
// focused rather than the frame it is in.
if (!newWindow || (newBrowsingContext == GetFocusedBrowsingContext() &&
elementToFocus == mFocusedElement)) {
return Nothing();
return;
}
MOZ_ASSERT(newBrowsingContext);
@@ -1534,7 +1532,7 @@ Maybe<uint64_t> nsFocusManager::SetFocusInner(Element* aNewContent,
BrowsingContext* walk = focusedBrowsingContext;
while (walk) {
if (walk == bc) {
return Nothing();
return;
}
walk = walk->GetParent();
}
@@ -1551,13 +1549,13 @@ Maybe<uint64_t> nsFocusManager::SetFocusInner(Element* aNewContent,
bool inUnload;
docShell->GetIsInUnload(&inUnload);
if (inUnload) {
return Nothing();
return;
}
bool beingDestroyed;
docShell->IsBeingDestroyed(&beingDestroyed);
if (beingDestroyed) {
return Nothing();
return;
}
BrowsingContext* bc = docShell->GetBrowsingContext();
@@ -1572,7 +1570,7 @@ Maybe<uint64_t> nsFocusManager::SetFocusInner(Element* aNewContent,
do {
bc = bc->GetParent();
if (bc && bc->IsDiscarded()) {
return Nothing();
return;
}
} while (bc && !bc->IsInProcess());
if (bc) {
@@ -1618,12 +1616,12 @@ Maybe<uint64_t> nsFocusManager::SetFocusInner(Element* aNewContent,
}
if (!focusedPrincipal || !newPrincipal) {
return Nothing();
return;
}
if (!focusedPrincipal->Subsumes(newPrincipal)) {
NS_WARNING("Not allowed to focus the new window!");
return Nothing();
return;
}
}
@@ -1730,12 +1728,11 @@ Maybe<uint64_t> nsFocusManager::SetFocusInner(Element* aNewContent,
LOGFOCUS((" Flags: %x Current Window: %p New Window: %p Current Element: %p",
aFlags, mFocusedWindow.get(), newWindow.get(),
mFocusedElement.get()));
const uint64_t actionId = GenerateFocusActionId();
LOGFOCUS(
(" In Active Window: %d Moves to different BrowsingContext: %d "
"SendFocus: %d actionid: %" PRIu64,
isElementInActiveWindow, focusMovesToDifferentBC, sendFocusEvent,
actionId));
aActionId));
if (sendFocusEvent) {
Maybe<BlurredElementInfo> blurredInfo;
@@ -1788,19 +1785,19 @@ Maybe<uint64_t> nsFocusManager::SetFocusInner(Element* aNewContent,
? focusedBrowsingContext.get()
: nullptr),
commonAncestor, focusMovesToDifferentBC, aAdjustWidget,
remainActive, actionId, elementToFocus)) {
return Some(actionId);
remainActive, aActionId, elementToFocus)) {
return;
}
}
Focus(newWindow, elementToFocus, aFlags, focusMovesToDifferentBC,
aFocusChanged, false, aAdjustWidget, actionId, blurredInfo);
aFocusChanged, false, aAdjustWidget, aActionId, blurredInfo);
} else {
// otherwise, for inactive windows and when the caller cannot steal the
// focus, update the node in the window, and raise the window if desired.
if (allowFrameSwitch) {
AdjustWindowFocus(newBrowsingContext, true, IsWindowVisible(newWindow),
actionId);
aActionId);
}
// set the focus node and method as needed
@@ -1832,7 +1829,7 @@ Maybe<uint64_t> nsFocusManager::SetFocusInner(Element* aNewContent,
RaiseWindow(outerWindow,
aFlags & FLAG_NONSYSTEMCALLER ? CallerType::NonSystem
: CallerType::System,
actionId);
aActionId);
} else {
mozilla::dom::ContentChild* contentChild =
mozilla::dom::ContentChild::GetSingleton();
@@ -1841,12 +1838,11 @@ Maybe<uint64_t> nsFocusManager::SetFocusInner(Element* aNewContent,
aFlags & FLAG_NONSYSTEMCALLER
? CallerType::NonSystem
: CallerType::System,
actionId);
aActionId);
}
}
}
}
return Some(actionId);
}
static already_AddRefed<BrowsingContext> GetParentIgnoreChromeBoundary(

View File

@@ -214,7 +214,8 @@ class nsFocusManager final : public nsIFocusManager,
* Setter for focusedWindow with CallerType
*/
MOZ_CAN_RUN_SCRIPT nsresult SetFocusedWindowWithCallerType(
mozIDOMWindowProxy* aWindowToFocus, mozilla::dom::CallerType aCallerType);
mozIDOMWindowProxy* aWindowToFocus, mozilla::dom::CallerType aCallerType,
uint64_t aActionId);
/**
* Given an element, which must be the focused element, activate the remote
@@ -313,13 +314,10 @@ class nsFocusManager final : public nsIFocusManager,
*
* All actual focus changes must use this method to do so. (as opposed
* to those that update the focus in an inactive window for instance).
*
* Returns Nothing() if we end up not trying to focus the element,
* otherwise returns the generated action id.
*/
MOZ_CAN_RUN_SCRIPT Maybe<uint64_t> SetFocusInner(
mozilla::dom::Element* aNewContent, int32_t aFlags, bool aFocusChanged,
bool aAdjustWidget);
MOZ_CAN_RUN_SCRIPT void SetFocusInner(mozilla::dom::Element* aNewContent,
int32_t aFlags, bool aFocusChanged,
bool aAdjustWidget, uint64_t aActionId);
/**
* Returns true if aPossibleAncestor is the same as aWindow or an

View File

@@ -216,7 +216,7 @@ nsresult nsStyledElement::BindToTree(BindContext& aContext, nsINode& aParent) {
if (HasAttr(nsGkAtoms::autofocus) && aContext.AllowsAutoFocus() &&
(!IsSVGElement() || IsFocusable())) {
aContext.OwnerDoc().ElementWithAutoFocusInserted(this);
aContext.OwnerDoc().SetAutoFocusElement(this);
}
return NS_OK;

View File

@@ -114,7 +114,6 @@ class HTMLContentSink : public nsContentSink, public nsIHTMLContentSink {
virtual void SetDocumentCharset(NotNull<const Encoding*> aEncoding) override;
virtual nsISupports* GetTarget() override;
virtual bool IsScriptExecuting() override;
virtual bool WaitForPendingSheets() override;
virtual void ContinueInterruptedParsingAsync() override;
// nsIHTMLContentSink
@@ -925,10 +924,6 @@ void HTMLContentSink::ContinueInterruptedParsingIfEnabled() {
}
}
bool HTMLContentSink::WaitForPendingSheets() {
return nsContentSink::WaitForPendingSheets();
}
void HTMLContentSink::ContinueInterruptedParsingAsync() {
nsCOMPtr<nsIRunnable> ev = NewRunnableMethod(
"HTMLContentSink::ContinueInterruptedParsingIfEnabled", this,

View File

@@ -2,6 +2,6 @@
<html>
<link rel='stylesheet' type='text/css' href='style.css'>
<body>
<input autofocus><textarea></textarea><select></select><button></button>
<input><textarea></textarea><select></select><button></button>
</body>
</html>

View File

@@ -25,13 +25,6 @@ add_task(async function() {
backgroundTab.linkedBrowser,
[],
async function() {
// Spec asks us to flush autofocus candidates in the
// `update-the-rendering` step, so we need to wait
// for a rAF to ensure autofocus candidates are
// flushed.
await new Promise(r => {
content.requestAnimationFrame(r);
});
return content.document.activeElement.tagName;
}
);

View File

@@ -1850,9 +1850,7 @@ nsresult PresShell::Initialize() {
NS_ENSURE_STATE(!mHaveShutDown);
}
if (mDocument->HasAutoFocusCandidates()) {
mDocument->ScheduleFlushAutoFocusCandidates();
}
mDocument->TriggerAutoFocus();
NS_ASSERTION(rootFrame, "How did that happen?");
@@ -3138,8 +3136,52 @@ nsresult PresShell::GoToAnchor(const nsAString& aAnchorName, bool aScroll,
//
// https://html.spec.whatwg.org/#target-element
// https://html.spec.whatwg.org/#find-a-potential-indicated-element
RefPtr<Element> target =
nsContentUtils::GetTargetElement(mDocument, aAnchorName);
RefPtr<Element> target = [&]() -> Element* {
// 1. If there is an element in the document tree that has an ID equal to
// fragment, then return the first such element in tree order.
if (Element* el = mDocument->GetElementById(aAnchorName)) {
return el;
}
// 2. If there is an a element in the document tree that has a name
// attribute whose value is equal to fragment, then return the first such
// element in tree order.
//
// FIXME(emilio): Why the different code-paths for HTML and non-HTML docs?
if (mDocument->IsHTMLDocument()) {
nsCOMPtr<nsINodeList> list = mDocument->GetElementsByName(aAnchorName);
// Loop through the named nodes looking for the first anchor
uint32_t length = list->Length();
for (uint32_t i = 0; i < length; i++) {
nsIContent* node = list->Item(i);
if (node->IsHTMLElement(nsGkAtoms::a)) {
return node->AsElement();
}
}
} else {
constexpr auto nameSpace = u"http://www.w3.org/1999/xhtml"_ns;
// Get the list of anchor elements
nsCOMPtr<nsINodeList> list =
mDocument->GetElementsByTagNameNS(nameSpace, u"a"_ns);
// Loop through the anchors looking for the first one with the given name.
for (uint32_t i = 0; true; i++) {
nsIContent* node = list->Item(i);
if (!node) { // End of list
break;
}
// Compare the name attribute
if (node->IsElement() &&
node->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
aAnchorName, eCaseMatters)) {
return node->AsElement();
}
}
}
// 3. Return null.
return nullptr;
}();
// 1. If there is no indicated part of the document, set the Document's
// target element to null.

View File

@@ -1843,7 +1843,6 @@ uint32_t nsRefreshDriver::ObserverCount() const {
sum += mViewManagerFlushIsPending;
sum += mEarlyRunners.Length();
sum += mTimerAdjustmentObservers.Length();
sum += mAutoFocusFlushDocuments.Length();
return sum;
}
@@ -1864,7 +1863,7 @@ bool nsRefreshDriver::HasObservers() const {
!mPendingFullscreenEvents.IsEmpty() ||
!mFrameRequestCallbackDocs.IsEmpty() ||
!mThrottledFrameRequestCallbackDocs.IsEmpty() ||
!mAutoFocusFlushDocuments.IsEmpty() || !mEarlyRunners.IsEmpty();
!mEarlyRunners.IsEmpty();
}
void nsRefreshDriver::AppendObserverDescriptionsToString(
@@ -1906,10 +1905,6 @@ void nsRefreshDriver::AppendObserverDescriptionsToString(
aStr.AppendPrintf("%zux Throttled frame request callback doc, ",
mThrottledFrameRequestCallbackDocs.Length());
}
if (!mAutoFocusFlushDocuments.IsEmpty()) {
aStr.AppendPrintf("%zux AutoFocus flush doc, ",
mAutoFocusFlushDocuments.Length());
}
if (!mEarlyRunners.IsEmpty()) {
aStr.AppendPrintf("%zux Early runner, ", mEarlyRunners.Length());
}
@@ -2139,24 +2134,6 @@ static void TakeFrameRequestCallbacksFrom(
aDocument->TakeFrameRequestCallbacks(aTarget.LastElement().mCallbacks);
}
void nsRefreshDriver::ScheduleAutoFocusFlush(Document* aDocument) {
MOZ_ASSERT(!mAutoFocusFlushDocuments.Contains(aDocument));
mAutoFocusFlushDocuments.AppendElement(aDocument);
EnsureTimerStarted();
}
void nsRefreshDriver::FlushAutoFocusDocuments() {
nsTArray<RefPtr<Document>> docs(std::move(mAutoFocusFlushDocuments));
for (const auto& doc : docs) {
MOZ_KnownLive(doc)->FlushAutoFocusCandidates();
}
}
void nsRefreshDriver::CancelFlushAutoFocus(Document* aDocument) {
mAutoFocusFlushDocuments.RemoveElement(aDocument);
}
// https://fullscreen.spec.whatwg.org/#run-the-fullscreen-steps
void nsRefreshDriver::RunFullscreenSteps() {
// Swap out the current pending events
@@ -2597,7 +2574,6 @@ void nsRefreshDriver::Tick(VsyncId aId, TimeStamp aNowTime,
if (i == 1) {
// This is the FlushType::Style case.
FlushAutoFocusDocuments();
DispatchScrollEvents();
DispatchVisualViewportScrollEvents();
DispatchAnimationEvents();

View File

@@ -346,8 +346,6 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator,
bool IsWaitingForPaint(mozilla::TimeStamp aTime);
void ScheduleAutoFocusFlush(Document* aDocument);
// nsARefreshObserver
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override {
return TransactionIdAllocator::AddRef();
@@ -449,8 +447,6 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator,
// paints to one per vsync (see CanDoExtraTick).
void FinishedVsyncTick() { mAttemptedExtraTickSinceLastVsync = false; }
void CancelFlushAutoFocus(Document* aDocument);
private:
typedef nsTArray<RefPtr<VVPResizeEvent>> VisualViewportResizeEventArray;
typedef nsTArray<RefPtr<mozilla::Runnable>> ScrollEventArray;
@@ -478,8 +474,6 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator,
operator RefPtr<nsARefreshObserver>() { return mObserver; }
};
typedef nsTObserverArray<ObserverData> ObserverArray;
MOZ_CAN_RUN_SCRIPT
void FlushAutoFocusDocuments();
void RunFullscreenSteps();
void DispatchAnimationEvents();
MOZ_CAN_RUN_SCRIPT
@@ -675,7 +669,6 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator,
// nsTArray on purpose, because we want to be able to swap.
nsTArray<Document*> mFrameRequestCallbackDocs;
nsTArray<Document*> mThrottledFrameRequestCallbackDocs;
nsTArray<RefPtr<Document>> mAutoFocusFlushDocuments;
nsTObserverArray<nsAPostRefreshObserver*> mPostRefreshObservers;
nsTArray<mozilla::UniquePtr<mozilla::PendingFullscreenEvent>>
mPendingFullscreenEvents;

View File

@@ -131,8 +131,6 @@ class nsHtml5TreeOpExecutor final
*/
void WillResume() override;
virtual nsIContentSink* AsExecutor() override { return this; }
virtual void InitialTranslationCompleted() override;
/**

View File

@@ -89,12 +89,6 @@ class nsIContentSink : public nsISupports {
*/
virtual void WillResume() = 0;
/**
* This method returns nullptr unless `this` can
* be cast as nsHtml5TreeOpExecutor.
*/
virtual nsIContentSink* AsExecutor() { return nullptr; }
/**
* This method gets called by the parser so that the content
* sink can retain a reference to the parser. The expectation

View File

@@ -83,12 +83,6 @@ class nsIHTMLContentSink : public nsIContentSink {
* @param aTag - The tag to be closed.
*/
NS_IMETHOD CloseContainer(ElementType aTag) = 0;
/**
* This method returns true if there are more than one
* pending style sheets, false otherwise.
*/
virtual bool WaitForPendingSheets() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIHTMLContentSink, NS_IHTML_CONTENT_SINK_IID)

View File

@@ -0,0 +1,5 @@
[autofocus-dialog.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[<dialog> can contain autofocus, without stopping page autofocus content from working]
expected: FAIL

View File

@@ -0,0 +1,3 @@
[autofocus-in-not-fully-active-document.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]

View File

@@ -0,0 +1,5 @@
[autofocus-on-stable-document.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Autofocus should work if an element with autofocus is inserted into a document which was loaded some time ago.]
expected: FAIL

View File

@@ -0,0 +1,8 @@
[document-with-fragment-empty.html]
[Autofocus elements in iframed documents with empty fragments should work.]
expected:
if not debug and (os == "win") and (processor == "x86"): [FAIL, PASS]
if debug and (os == "android"): PASS
if debug and (os == "mac"): PASS
if debug and (os == "linux"): PASS
[PASS, FAIL]

View File

@@ -0,0 +1,6 @@
[document-with-fragment-nonexistent.html]
[Autofocus elements in iframed documents with non-existent fragments should work.]
expected:
if debug and (os == "linux"): PASS
if debug and (os == "android"): PASS
[PASS, FAIL]

View File

@@ -0,0 +1,7 @@
[document-with-fragment-top.html]
[Autofocus elements in iframed documents with "top" fragments should work.]
expected:
if debug and (os == "android"): PASS
if debug and (os == "linux"): PASS
if debug and (os == "mac"): PASS
[PASS, FAIL]

View File

@@ -0,0 +1,5 @@
[first-reconnected.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[The second autofocus element wins if the first autofocus element was disconnected and reconnected before flushing the autofocus candidates.]
expected: FAIL

View File

@@ -0,0 +1,3 @@
[first-when-later-but-before.html]
[The temporally first autofocus in the document wins, even if an element is inserted later that is previous in the document tree.]
expected: [PASS, FAIL]

View File

@@ -0,0 +1,3 @@
[first-when-later.html]
[The first autofocus in the document wins, even if elements are inserted later.]
expected: [PASS, FAIL]

View File

@@ -0,0 +1,3 @@
[first.html]
[The first autofocus element in the document should win.]
expected: [PASS, FAIL]

View File

@@ -0,0 +1,5 @@
[focusable-area-in-top-document.html]
[If topDocument's focused area is not topDocument, autofocus is not processed.]
expected:
if (processor == "x86") and (os == "linux"): [FAIL, PASS]
[PASS, FAIL]

View File

@@ -0,0 +1,3 @@
[no-autofocus-on-changing-input-type.html]
[Changing input type should not refocus on the element.]
expected: [PASS, FAIL]

View File

@@ -0,0 +1,3 @@
[no-cross-origin-autofocus.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]

View File

@@ -0,0 +1,3 @@
[no-sandboxed-automatic-features.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]

View File

@@ -0,0 +1,3 @@
[not-on-first-task.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]

View File

@@ -0,0 +1,8 @@
[queue-non-focusable.html]
[If the first autofocus element is not focusable, but becomes focusable before a frame, it should be focused.]
expected:
if debug and (os == "win") and swgl: PASS
if debug and (os == "android"): PASS
if debug and (os == "linux"): PASS
if debug and (os == "mac"): PASS
[PASS, FAIL]

View File

@@ -0,0 +1,5 @@
[same-origin-autofocus.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Autofocus should not work in the same origin grand child iframe]
expected: FAIL

View File

@@ -0,0 +1,3 @@
[skip-another-top-level-browsing-context.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]

View File

@@ -0,0 +1,5 @@
[skip-non-focusable.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Non-focusable autofocus element is skipped.]
expected: FAIL

View File

@@ -0,0 +1,3 @@
[skip-not-fully-active.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]

View File

@@ -0,0 +1,5 @@
[spin-by-blocking-style-sheet.html]
expected: TIMEOUT
[Script-blocking style sheet should pause flushing autofocus candidates.]
expected: TIMEOUT

View File

@@ -0,0 +1,17 @@
[supported-elements.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Contenteditable element should support autofocus]
expected: FAIL
[Element with tabindex should support autofocus]
expected: FAIL
[Host element with delegatesFocus including no focusable descendants should be skipped]
expected: FAIL
[Area element should support autofocus]
expected: FAIL
[Host element with delegatesFocus should support autofocus]
expected: FAIL

View File

@@ -2,4 +2,4 @@
expected:
if (os == "android") and fission: [OK, TIMEOUT]
["Flush autofocus candidates" should be happen before a scroll event and animation frame callbacks]
expected: [PASS, FAIL]
expected: FAIL

View File

@@ -10,12 +10,9 @@
promise_test(async () => {
await waitForLoad(window);
const iframe = document.querySelector('iframe');
await waitUntilStableAutofocusState();
assert_equals(document.activeElement, iframe,
assert_equals(document.activeElement, document.querySelector('iframe'),
'Autofocus elements in iframes should be focused.');
const doc = iframe.contentDocument;
assert_true(!doc.querySelector(':target'));
let input = document.createElement('input');
input.autofocus = true;

View File

@@ -21,23 +21,7 @@ promise_test(async () => {
doc.body.appendChild(input);
await waitUntilStableAutofocusState();
assert_not_equals(doc.activeElement, input);
iframe.remove();
}, 'Autofocus elements in iframed documents with URL fragments should be skipped. (id matches)');
promise_test(async () => {
let iframe = await waitForIframeLoad("resources/frame-with-a.html");
iframe.contentWindow.location.hash = 'anchor1';
await waitForEvent(iframe.contentWindow, 'hashchange');
const doc = iframe.contentDocument;
assert_true(!!doc.querySelector(':target'));
let input = doc.createElement('input');
input.autofocus = true;
doc.body.appendChild(input);
await waitUntilStableAutofocusState();
assert_not_equals(doc.activeElement, input);
iframe.remove();
}, 'Autofocus elements in iframed documents with URL fragments should be skipped.(a element)');
}, 'Autofocus elements in iframed documents with URL fragments should be skipped.');
promise_test(async () => {
let w = window.open('resources/frame-with-anchor.html');

View File

@@ -1,4 +0,0 @@
<!DOCTYPE html>
<body>
<a name="anchor1"></a>
</body>

View File

@@ -39,13 +39,3 @@ async function waitUntilStableAutofocusState(w) {
// Awaiting one animation frame is an easy way to determine autofocus state.
await waitForAnimationFrame(targetWindow);
}
async function waitForIframeLoad(src, w = window) {
const iframe = w.document.createElement("iframe");
let loadPromise = new Promise(resolve => {
iframe.addEventListener("load", () => resolve(iframe));
});
iframe.src = src;
w.document.body.appendChild(iframe);
return loadPromise;
}

View File

@@ -2,18 +2,16 @@
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/utils.js"></script>
<link rel="stylesheet" href="resources/erase-first.css?pipe=trickle(d1)">
<input id="first" autofocus>
<input id="second" autofocus>
<link rel="stylesheet" href="resources/erase-first.css?pipe=trickle(d1)">
<script>
'use strict';
promise_test(async () => {
await waitForLoad(window);
await waitForAnimationFrame();
await waitForEvent(document.body, 'focus', {capture:true});
assert_equals(document.activeElement.id, 'second');
}, 'Script-blocking style sheet should pause flushing autofocus candidates.');
</script>