diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp index 770f80811a2f..558606274182 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -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 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) { - return; +static already_AddRefed FindTopWindowForElement( + Element* element) { + Document* document = element->OwnerDoc(); + if (!document) { + return nullptr; } - // If target is not fully active, then return. - if (!IsCurrentActiveDocument()) { - return; + nsCOMPtr window = document->GetWindow(); + if (!window) { + return nullptr; } - // If target's active sandboxing flag set has the sandboxed automatic features - // browsing context flag, then return. - if (GetSandboxFlags() & SANDBOXED_AUTOMATIC_FEATURES) { - return; + // Trying to find the top window (equivalent to window.top). + if (nsCOMPtr top = window->GetInProcessTop()) { + window = std::move(top); } - - // 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; - } - - Document* currentDocument = bc->GetDocument(); - if (!currentDocument) { - return; - } - - 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); + return window.forget(); } -void Document::ScheduleFlushAutoFocusCandidates() { - MOZ_ASSERT(mPresShell && mPresShell->DidInitialize()); - MOZ_ASSERT(GetBrowsingContext()->IsTop()); - if (nsRefreshDriver* rd = mPresShell->GetRefreshDriver()) { - rd->ScheduleAutoFocusFlush(this); +/** + * nsAutoFocusEvent is used to dispatch a focus event for an + * nsGenericHTMLFormElement with the autofocus attribute enabled. + */ +class nsAutoFocusEvent : public Runnable { + public: + explicit nsAutoFocusEvent(nsCOMPtr&& aElement, + nsCOMPtr&& aTopWindow) + : mozilla::Runnable("nsAutoFocusEvent"), + mElement(std::move(aElement)), + mTopWindow(std::move(aTopWindow)) {} + + NS_IMETHOD Run() override { + nsCOMPtr 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 mElement; + nsCOMPtr mTopWindow; +}; + +void Document::SetAutoFocusElement(Element* aAutoFocusElement) { + if (mAutoFocusFired) { + // Too late. + return; + } + + if (mAutoFocusElement) { + // The spec disallows multiple autofocus elements, so we consider only the + // first one to preserve the old behavior. + return; + } + + mAutoFocusElement = do_GetWeakReference(aAutoFocusElement); + TriggerAutoFocus(); } -void Document::AppendAutoFocusCandidateToTopDocument( - Element* aAutoFocusCandidate) { - MOZ_ASSERT(GetBrowsingContext()->IsTop()); +void Document::SetAutoFocusFired() { mAutoFocusFired = true; } + +bool Document::IsAutoFocusFired() { return mAutoFocusFired; } + +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 topWindow = GetWindow(); - // We should be the top document - if (!topWindow) { - return; - } - -#ifdef DEBUG - { - // Trying to find the top window (equivalent to window.top). - nsCOMPtr top = topWindow->GetInProcessTop(); - MOZ_ASSERT(topWindow == top); - } -#endif - - // Don't steal the focus from the user - if (topWindow->GetFocusedElement()) { - SetAutoFocusFired(); - 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; - } - - nsTObserverArray::ForwardIterator iter(mAutoFocusCandidates); - while (iter.HasMore()) { - nsCOMPtr autoFocusElement = do_QueryReferent(iter.GetNext()); - if (!autoFocusElement) { - continue; - } - RefPtr 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) { + nsCOMPtr autoFocusElement = do_QueryReferent(mAutoFocusElement); + if (autoFocusElement && autoFocusElement->OwnerDoc() == this) { + nsCOMPtr topWindow = + FindTopWindowForElement(autoFocusElement); + if (!topWindow) { return; } - // Re-get the element because the ownerDoc() might have changed - autoFocusElementDoc = autoFocusElement->OwnerDoc(); - BrowsingContext* bc = autoFocusElementDoc->GetBrowsingContext(); - if (!bc) { - continue; + // NOTE: This may be removed in the future since the spec technically + // allows autofocus after load. + nsCOMPtr topDoc = topWindow->GetExtantDoc(); + if (topDoc && + topDoc->GetReadyStateEnum() == Document::READYSTATE_COMPLETE) { + return; } - // If doc is not fully active, then remove element from candidates, and - // continue. - if (!autoFocusElementDoc->IsCurrentActiveDocument()) { - iter.Remove(); - continue; - } - - nsCOMPtr sink = - do_QueryInterface(autoFocusElementDoc->GetCurrentContentSink()); - if (sink) { - nsHtml5TreeOpExecutor* executor = - static_cast(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; - } + nsCOMPtr event = + new nsAutoFocusEvent(std::move(autoFocusElement), topWindow.forget()); + nsresult rv = NS_DispatchToCurrentThread(event.forget()); + NS_ENSURE_SUCCESS_VOID(rv); } - - if (HasAutoFocusCandidates()) { - ScheduleFlushAutoFocusCandidates(); - } -} - -bool Document::TryAutoFocusCandidate(Element& aElement) { - const FocusOptions options; - if (RefPtr target = nsFocusManager::GetTheFocusableArea( - &aElement, nsFocusManager::ProgrammaticFocusFlags(options))) { - target->Focus(options, CallerType::NonSystem, IgnoreErrors()); - return true; - } - - return false; } void Document::SetScrollToRef(nsIURI* aDocumentURI) { diff --git a/dom/base/Document.h b/dom/base/Document.h index 10b4d23adc85..e8e16ad6b9fb 100644 --- a/dom/base/Document.h +++ b/dom/base/Document.h @@ -1927,8 +1927,6 @@ class Document : public nsINode, // layer. The removed element, if any, is returned. Element* TopLayerPop(FunctionRef 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 mAutoFocusCandidates; + nsWeakPtr mAutoFocusElement; nsCString mScrollToRef; diff --git a/dom/base/nsContentSink.h b/dom/base/nsContentSink.h index 39b14217135a..ec89ff95877f 100644 --- a/dom/base/nsContentSink.h +++ b/dom/base/nsContentSink.h @@ -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() { diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 3e205ae7a4d4..7e57bf923da8 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -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 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 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 Maybe nsContentUtils::ComparePoints( diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 6e2ea5454ed4..10bb61f8f0dd 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -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. diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp index 10d3d2ec14d3..90b538473462 100644 --- a/dom/base/nsFocusManager.cpp +++ b/dom/base/nsFocusManager.cpp @@ -380,7 +380,8 @@ nsFocusManager::GetActiveBrowsingContext(BrowsingContext** aBrowsingContext) { void nsFocusManager::FocusWindow(nsPIDOMWindowOuter* aWindow, CallerType aCallerType) { if (RefPtr 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(("<>")); + mozIDOMWindowProxy* aWindowToFocus, CallerType aCallerType, + uint64_t aActionId) { + LOGFOCUS(("<>", aActionId)); nsCOMPtr windowToFocus = nsPIDOMWindowOuter::From(aWindowToFocus); NS_ENSURE_TRUE(windowToFocus, NS_ERROR_FAILURE); nsCOMPtr frameElement = windowToFocus->GetFrameElementInternal(); - Maybe 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 rootWindow = windowToFocus->GetPrivateRoot(); - const uint64_t actionId = actionIdFromSetFocusInner.isSome() - ? actionIdFromSetFocusInner.value() - : sInstance->GenerateFocusActionId(); if (rootWindow) { - RaiseWindow(rootWindow, aCallerType, actionId); + RaiseWindow(rootWindow, aCallerType, aActionId); } - LOGFOCUS(("<>", actionId)); + LOGFOCUS(("<>", 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(("<>")); @@ -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 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 elementToFocus = FlushAndCheckIfFocusable(aNewContent, aFlags); if (!elementToFocus) { - return Nothing(); + return; } const RefPtr focusedBrowsingContext = @@ -1517,7 +1515,7 @@ Maybe 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 nsFocusManager::SetFocusInner(Element* aNewContent, BrowsingContext* walk = focusedBrowsingContext; while (walk) { if (walk == bc) { - return Nothing(); + return; } walk = walk->GetParent(); } @@ -1551,13 +1549,13 @@ Maybe 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 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 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 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 blurredInfo; @@ -1788,19 +1785,19 @@ Maybe 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 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 nsFocusManager::SetFocusInner(Element* aNewContent, aFlags & FLAG_NONSYSTEMCALLER ? CallerType::NonSystem : CallerType::System, - actionId); + aActionId); } } } } - return Some(actionId); } static already_AddRefed GetParentIgnoreChromeBoundary( diff --git a/dom/base/nsFocusManager.h b/dom/base/nsFocusManager.h index 9a60e73a2a3c..50a714237370 100644 --- a/dom/base/nsFocusManager.h +++ b/dom/base/nsFocusManager.h @@ -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 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 diff --git a/dom/base/nsStyledElement.cpp b/dom/base/nsStyledElement.cpp index 36918cb430be..01672eec8449 100644 --- a/dom/base/nsStyledElement.cpp +++ b/dom/base/nsStyledElement.cpp @@ -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; diff --git a/dom/html/nsHTMLContentSink.cpp b/dom/html/nsHTMLContentSink.cpp index e7956d674ce6..ddf596d4174f 100644 --- a/dom/html/nsHTMLContentSink.cpp +++ b/dom/html/nsHTMLContentSink.cpp @@ -114,7 +114,6 @@ class HTMLContentSink : public nsContentSink, public nsIHTMLContentSink { virtual void SetDocumentCharset(NotNull 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 ev = NewRunnableMethod( "HTMLContentSink::ContinueInterruptedParsingIfEnabled", this, diff --git a/dom/html/reftests/autofocus/autofocus-after-load-ref.html b/dom/html/reftests/autofocus/autofocus-after-load-ref.html index f28f06f0f353..eab4f2ce2980 100644 --- a/dom/html/reftests/autofocus/autofocus-after-load-ref.html +++ b/dom/html/reftests/autofocus/autofocus-after-load-ref.html @@ -2,6 +2,6 @@ - + diff --git a/dom/tests/browser/browser_autofocus_background.js b/dom/tests/browser/browser_autofocus_background.js index a252e8a99cc4..ab494b54417b 100644 --- a/dom/tests/browser/browser_autofocus_background.js +++ b/dom/tests/browser/browser_autofocus_background.js @@ -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; } ); diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp index 253e2f16d41e..d9fb953d6de5 100644 --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp @@ -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 target = - nsContentUtils::GetTargetElement(mDocument, aAnchorName); + RefPtr 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 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 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. diff --git a/layout/base/nsRefreshDriver.cpp b/layout/base/nsRefreshDriver.cpp index 5a859ddb9ae4..848de6a395c5 100644 --- a/layout/base/nsRefreshDriver.cpp +++ b/layout/base/nsRefreshDriver.cpp @@ -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> 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(); diff --git a/layout/base/nsRefreshDriver.h b/layout/base/nsRefreshDriver.h index 63fea15d7fca..aabc94a04836 100644 --- a/layout/base/nsRefreshDriver.h +++ b/layout/base/nsRefreshDriver.h @@ -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> VisualViewportResizeEventArray; typedef nsTArray> ScrollEventArray; @@ -478,8 +474,6 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator, operator RefPtr() { return mObserver; } }; typedef nsTObserverArray 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 mFrameRequestCallbackDocs; nsTArray mThrottledFrameRequestCallbackDocs; - nsTArray> mAutoFocusFlushDocuments; nsTObserverArray mPostRefreshObservers; nsTArray> mPendingFullscreenEvents; diff --git a/parser/html/nsHtml5TreeOpExecutor.h b/parser/html/nsHtml5TreeOpExecutor.h index e47d99a1b2f2..65a1f619e911 100644 --- a/parser/html/nsHtml5TreeOpExecutor.h +++ b/parser/html/nsHtml5TreeOpExecutor.h @@ -131,8 +131,6 @@ class nsHtml5TreeOpExecutor final */ void WillResume() override; - virtual nsIContentSink* AsExecutor() override { return this; } - virtual void InitialTranslationCompleted() override; /** diff --git a/parser/htmlparser/nsIContentSink.h b/parser/htmlparser/nsIContentSink.h index aa77c192c79e..10a872a3e578 100644 --- a/parser/htmlparser/nsIContentSink.h +++ b/parser/htmlparser/nsIContentSink.h @@ -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 diff --git a/parser/htmlparser/nsIHTMLContentSink.h b/parser/htmlparser/nsIHTMLContentSink.h index 3e81d5d77090..835044be6578 100644 --- a/parser/htmlparser/nsIHTMLContentSink.h +++ b/parser/htmlparser/nsIHTMLContentSink.h @@ -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) diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/autofocus-dialog.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/autofocus-dialog.html.ini new file mode 100644 index 000000000000..cf3fd9fe130d --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/autofocus-dialog.html.ini @@ -0,0 +1,5 @@ +[autofocus-dialog.html] + expected: + if (os == "android") and fission: [OK, TIMEOUT] + [ can contain autofocus, without stopping page autofocus content from working] + expected: FAIL diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/autofocus-in-not-fully-active-document.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/autofocus-in-not-fully-active-document.html.ini new file mode 100644 index 000000000000..a3413efdea20 --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/autofocus-in-not-fully-active-document.html.ini @@ -0,0 +1,3 @@ +[autofocus-in-not-fully-active-document.html] + expected: + if (os == "android") and fission: [OK, TIMEOUT] diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/autofocus-on-stable-document.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/autofocus-on-stable-document.html.ini new file mode 100644 index 000000000000..61e9f4f855dc --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/autofocus-on-stable-document.html.ini @@ -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 diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/document-with-fragment-empty.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/document-with-fragment-empty.html.ini new file mode 100644 index 000000000000..3f3882403294 --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/document-with-fragment-empty.html.ini @@ -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] diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/document-with-fragment-nonexistent.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/document-with-fragment-nonexistent.html.ini new file mode 100644 index 000000000000..d2db37600e03 --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/document-with-fragment-nonexistent.html.ini @@ -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] diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/document-with-fragment-top.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/document-with-fragment-top.html.ini new file mode 100644 index 000000000000..cba72c3f37b4 --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/document-with-fragment-top.html.ini @@ -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] diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/first-reconnected.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/first-reconnected.html.ini new file mode 100644 index 000000000000..9456576c798c --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/first-reconnected.html.ini @@ -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 diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/first-when-later-but-before.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/first-when-later-but-before.html.ini new file mode 100644 index 000000000000..c35fd39fe575 --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/first-when-later-but-before.html.ini @@ -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] diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/first-when-later.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/first-when-later.html.ini new file mode 100644 index 000000000000..843deaa73a6e --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/first-when-later.html.ini @@ -0,0 +1,3 @@ +[first-when-later.html] + [The first autofocus in the document wins, even if elements are inserted later.] + expected: [PASS, FAIL] diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/first.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/first.html.ini new file mode 100644 index 000000000000..0e4e85a322f1 --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/first.html.ini @@ -0,0 +1,3 @@ +[first.html] + [The first autofocus element in the document should win.] + expected: [PASS, FAIL] diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/focusable-area-in-top-document.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/focusable-area-in-top-document.html.ini new file mode 100644 index 000000000000..68dacc0f0c01 --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/focusable-area-in-top-document.html.ini @@ -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] diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/no-autofocus-on-changing-input-type.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/no-autofocus-on-changing-input-type.html.ini new file mode 100644 index 000000000000..b25fdb1d7fda --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/no-autofocus-on-changing-input-type.html.ini @@ -0,0 +1,3 @@ +[no-autofocus-on-changing-input-type.html] + [Changing input type should not refocus on the element.] + expected: [PASS, FAIL] diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/no-cross-origin-autofocus.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/no-cross-origin-autofocus.html.ini new file mode 100644 index 000000000000..408547496e7f --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/no-cross-origin-autofocus.html.ini @@ -0,0 +1,3 @@ +[no-cross-origin-autofocus.html] + expected: + if (os == "android") and fission: [OK, TIMEOUT] diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/no-sandboxed-automatic-features.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/no-sandboxed-automatic-features.html.ini new file mode 100644 index 000000000000..86628b01fdce --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/no-sandboxed-automatic-features.html.ini @@ -0,0 +1,3 @@ +[no-sandboxed-automatic-features.html] + expected: + if (os == "android") and fission: [OK, TIMEOUT] diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/not-on-first-task.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/not-on-first-task.html.ini new file mode 100644 index 000000000000..51e8358f6360 --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/not-on-first-task.html.ini @@ -0,0 +1,3 @@ +[not-on-first-task.html] + expected: + if (os == "android") and fission: [OK, TIMEOUT] diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/queue-non-focusable.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/queue-non-focusable.html.ini new file mode 100644 index 000000000000..08514da2f20c --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/queue-non-focusable.html.ini @@ -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] diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/same-origin-autofocus.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/same-origin-autofocus.html.ini new file mode 100644 index 000000000000..20e82e31e079 --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/same-origin-autofocus.html.ini @@ -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 diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/skip-another-top-level-browsing-context.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/skip-another-top-level-browsing-context.html.ini new file mode 100644 index 000000000000..c2c68debc39f --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/skip-another-top-level-browsing-context.html.ini @@ -0,0 +1,3 @@ +[skip-another-top-level-browsing-context.html] + expected: + if (os == "android") and fission: [OK, TIMEOUT] diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/skip-non-focusable.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/skip-non-focusable.html.ini new file mode 100644 index 000000000000..d267e3d2ea9c --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/skip-non-focusable.html.ini @@ -0,0 +1,5 @@ +[skip-non-focusable.html] + expected: + if (os == "android") and fission: [OK, TIMEOUT] + [Non-focusable autofocus element is skipped.] + expected: FAIL diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/skip-not-fully-active.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/skip-not-fully-active.html.ini new file mode 100644 index 000000000000..ffc1e87c1699 --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/skip-not-fully-active.html.ini @@ -0,0 +1,3 @@ +[skip-not-fully-active.html] + expected: + if (os == "android") and fission: [OK, TIMEOUT] diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/spin-by-blocking-style-sheet.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/spin-by-blocking-style-sheet.html.ini new file mode 100644 index 000000000000..4805d3e402bd --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/spin-by-blocking-style-sheet.html.ini @@ -0,0 +1,5 @@ +[spin-by-blocking-style-sheet.html] + expected: TIMEOUT + [Script-blocking style sheet should pause flushing autofocus candidates.] + expected: TIMEOUT + diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/supported-elements.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/supported-elements.html.ini new file mode 100644 index 000000000000..94142b4d0c01 --- /dev/null +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/supported-elements.html.ini @@ -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 diff --git a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/update-the-rendering.html.ini b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/update-the-rendering.html.ini index 77840237a753..e78f7bb3a7ae 100644 --- a/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/update-the-rendering.html.ini +++ b/testing/web-platform/meta/html/interaction/focus/the-autofocus-attribute/update-the-rendering.html.ini @@ -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 diff --git a/testing/web-platform/tests/html/interaction/focus/the-autofocus-attribute/document-with-fragment-top.html b/testing/web-platform/tests/html/interaction/focus/the-autofocus-attribute/document-with-fragment-top.html index f2d2aaae609c..ea3cc41f81b3 100644 --- a/testing/web-platform/tests/html/interaction/focus/the-autofocus-attribute/document-with-fragment-top.html +++ b/testing/web-platform/tests/html/interaction/focus/the-autofocus-attribute/document-with-fragment-top.html @@ -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; diff --git a/testing/web-platform/tests/html/interaction/focus/the-autofocus-attribute/document-with-fragment-valid.html b/testing/web-platform/tests/html/interaction/focus/the-autofocus-attribute/document-with-fragment-valid.html index 5078f1a0ac3b..7a7b01a21b90 100644 --- a/testing/web-platform/tests/html/interaction/focus/the-autofocus-attribute/document-with-fragment-valid.html +++ b/testing/web-platform/tests/html/interaction/focus/the-autofocus-attribute/document-with-fragment-valid.html @@ -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'); diff --git a/testing/web-platform/tests/html/interaction/focus/the-autofocus-attribute/resources/frame-with-a.html b/testing/web-platform/tests/html/interaction/focus/the-autofocus-attribute/resources/frame-with-a.html deleted file mode 100644 index 1f317369028a..000000000000 --- a/testing/web-platform/tests/html/interaction/focus/the-autofocus-attribute/resources/frame-with-a.html +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/testing/web-platform/tests/html/interaction/focus/the-autofocus-attribute/resources/utils.js b/testing/web-platform/tests/html/interaction/focus/the-autofocus-attribute/resources/utils.js index e928e275407c..c4f38fcb209e 100644 --- a/testing/web-platform/tests/html/interaction/focus/the-autofocus-attribute/resources/utils.js +++ b/testing/web-platform/tests/html/interaction/focus/the-autofocus-attribute/resources/utils.js @@ -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; -} diff --git a/testing/web-platform/tests/html/interaction/focus/the-autofocus-attribute/spin-by-blocking-style-sheet.html b/testing/web-platform/tests/html/interaction/focus/the-autofocus-attribute/spin-by-blocking-style-sheet.html index fb87eca77a6e..22a4c3573ccc 100644 --- a/testing/web-platform/tests/html/interaction/focus/the-autofocus-attribute/spin-by-blocking-style-sheet.html +++ b/testing/web-platform/tests/html/interaction/focus/the-autofocus-attribute/spin-by-blocking-style-sheet.html @@ -2,18 +2,16 @@ + - -