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 "nsIX509Cert.h"
#include "nsIX509CertValidity.h" #include "nsIX509CertValidity.h"
#include "nsIXMLContentSink.h" #include "nsIXMLContentSink.h"
#include "nsIHTMLContentSink.h"
#include "nsIXULRuntime.h" #include "nsIXULRuntime.h"
#include "nsImageLoadingContent.h" #include "nsImageLoadingContent.h"
#include "nsImportModule.h" #include "nsImportModule.h"
@@ -6843,9 +6842,6 @@ already_AddRefed<PresShell> Document::CreatePresShell(
mDocumentL10n->OnCreatePresShell(); mDocumentL10n->OnCreatePresShell();
} }
if (HasAutoFocusCandidates()) {
ScheduleFlushAutoFocusCandidates();
}
// Now that we have a shell, we might have @font-face rules (the presence of a // 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 // 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 // like EnsureStyleFlush or such, there's nothing to update yet and when stuff
@@ -6952,7 +6948,6 @@ void Document::DeletePresShell() {
mExternalResourceMap.HideViewers(); mExternalResourceMap.HideViewers();
if (nsPresContext* presContext = mPresShell->GetPresContext()) { if (nsPresContext* presContext = mPresShell->GetPresContext()) {
presContext->RefreshDriver()->CancelPendingFullscreenEvents(this); presContext->RefreshDriver()->CancelPendingFullscreenEvents(this);
presContext->RefreshDriver()->CancelFlushAutoFocus(this);
} }
// When our shell goes away, request that all our images be immediately // When our shell goes away, request that all our images be immediately
@@ -12630,254 +12625,121 @@ Document* Document::GetTemplateContentsOwner() {
return mTemplateContentsOwner; return mTemplateContentsOwner;
} }
// https://html.spec.whatwg.org/#the-autofocus-attribute static already_AddRefed<nsPIDOMWindowOuter> FindTopWindowForElement(
void Document::ElementWithAutoFocusInserted(Element* aAutoFocusCandidate) { Element* element) {
BrowsingContext* bc = GetBrowsingContext(); Document* document = element->OwnerDoc();
if (!bc) { if (!document) {
return; return nullptr;
} }
// If target is not fully active, then return. nsCOMPtr<nsPIDOMWindowOuter> window = document->GetWindow();
if (!IsCurrentActiveDocument()) { if (!window) {
return; return nullptr;
} }
// If target's active sandboxing flag set has the sandboxed automatic features // Trying to find the top window (equivalent to window.top).
// browsing context flag, then return. if (nsCOMPtr<nsPIDOMWindowOuter> top = window->GetInProcessTop()) {
if (GetSandboxFlags() & SANDBOXED_AUTOMATIC_FEATURES) { window = std::move(top);
return;
} }
return window.forget();
// 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);
} }
void Document::ScheduleFlushAutoFocusCandidates() { /**
MOZ_ASSERT(mPresShell && mPresShell->DidInitialize()); * nsAutoFocusEvent is used to dispatch a focus event for an
MOZ_ASSERT(GetBrowsingContext()->IsTop()); * nsGenericHTMLFormElement with the autofocus attribute enabled.
if (nsRefreshDriver* rd = mPresShell->GetRefreshDriver()) { */
rd->ScheduleAutoFocusFlush(this); 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 (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( void Document::SetAutoFocusFired() { mAutoFocusFired = true; }
Element* aAutoFocusCandidate) {
MOZ_ASSERT(GetBrowsingContext()->IsTop()); bool Document::IsAutoFocusFired() { return mAutoFocusFired; }
void Document::TriggerAutoFocus() {
if (mAutoFocusFired) { if (mAutoFocusFired) {
return; return;
} }
if (!HasAutoFocusCandidates()) { if (!mPresShell || !mPresShell->DidInitialize()) {
// PresShell may be initialized later // Delay autofocus until frames are constructed so that we don't thrash
if (mPresShell && mPresShell->DidInitialize()) { // style and layout calculations.
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) {
return; return;
} }
if (!mPresShell) { nsCOMPtr<Element> autoFocusElement = do_QueryReferent(mAutoFocusElement);
return; if (autoFocusElement && autoFocusElement->OwnerDoc() == this) {
} nsCOMPtr<nsPIDOMWindowOuter> topWindow =
FindTopWindowForElement(autoFocusElement);
MOZ_ASSERT(HasAutoFocusCandidates()); if (!topWindow) {
MOZ_ASSERT(mPresShell->DidInitialize());
nsCOMPtr<nsPIDOMWindowOuter> topWindow = GetWindow();
// We should be the top document
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();
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<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; return;
} }
// Re-get the element because the ownerDoc() might have changed // NOTE: This may be removed in the future since the spec technically
autoFocusElementDoc = autoFocusElement->OwnerDoc(); // allows autofocus after load.
BrowsingContext* bc = autoFocusElementDoc->GetBrowsingContext(); nsCOMPtr<Document> topDoc = topWindow->GetExtantDoc();
if (!bc) { if (topDoc &&
continue; topDoc->GetReadyStateEnum() == Document::READYSTATE_COMPLETE) {
return;
} }
// If doc is not fully active, then remove element from candidates, and nsCOMPtr<nsIRunnable> event =
// continue. new nsAutoFocusEvent(std::move(autoFocusElement), topWindow.forget());
if (!autoFocusElementDoc->IsCurrentActiveDocument()) { nsresult rv = NS_DispatchToCurrentThread(event.forget());
iter.Remove(); NS_ENSURE_SUCCESS_VOID(rv);
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) { void Document::SetScrollToRef(nsIURI* aDocumentURI) {

View File

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

View File

@@ -169,10 +169,6 @@ class nsContentSink : public nsICSSLoaderObserver,
Document* GetDocument() { return mDocument; } 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: protected:
inline int32_t GetNotificationInterval() { inline int32_t GetNotificationInterval() {
if (mDynamicLowerValue) { if (mDynamicLowerValue) {
@@ -184,6 +180,10 @@ class nsContentSink : public nsICSSLoaderObserver,
virtual nsresult FlushTags() = 0; 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 DoProcessLinkHeader();
void StopDeflecting() { 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 */ /* static */
template <typename FPT, typename FRT, typename SPT, typename SRT> template <typename FPT, typename FRT, typename SPT, typename SRT>
Maybe<int32_t> nsContentUtils::ComparePoints( Maybe<int32_t> nsContentUtils::ComparePoints(

View File

@@ -526,10 +526,6 @@ class nsContentUtils {
mozilla::dom::BrowserParent* aBrowserParent1, mozilla::dom::BrowserParent* aBrowserParent1,
mozilla::dom::BrowserParent* aBrowserParent2); 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 * Returns true if aNode1 is before aNode2 in the same connected
* tree. * tree.

View File

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

View File

@@ -214,7 +214,8 @@ class nsFocusManager final : public nsIFocusManager,
* Setter for focusedWindow with CallerType * Setter for focusedWindow with CallerType
*/ */
MOZ_CAN_RUN_SCRIPT nsresult SetFocusedWindowWithCallerType( 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 * 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 * 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). * 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( MOZ_CAN_RUN_SCRIPT void SetFocusInner(mozilla::dom::Element* aNewContent,
mozilla::dom::Element* aNewContent, int32_t aFlags, bool aFocusChanged, int32_t aFlags, bool aFocusChanged,
bool aAdjustWidget); bool aAdjustWidget, uint64_t aActionId);
/** /**
* Returns true if aPossibleAncestor is the same as aWindow or an * 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() && if (HasAttr(nsGkAtoms::autofocus) && aContext.AllowsAutoFocus() &&
(!IsSVGElement() || IsFocusable())) { (!IsSVGElement() || IsFocusable())) {
aContext.OwnerDoc().ElementWithAutoFocusInserted(this); aContext.OwnerDoc().SetAutoFocusElement(this);
} }
return NS_OK; return NS_OK;

View File

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

View File

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

View File

@@ -25,13 +25,6 @@ add_task(async function() {
backgroundTab.linkedBrowser, backgroundTab.linkedBrowser,
[], [],
async function() { 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; return content.document.activeElement.tagName;
} }
); );

View File

@@ -1850,9 +1850,7 @@ nsresult PresShell::Initialize() {
NS_ENSURE_STATE(!mHaveShutDown); NS_ENSURE_STATE(!mHaveShutDown);
} }
if (mDocument->HasAutoFocusCandidates()) { mDocument->TriggerAutoFocus();
mDocument->ScheduleFlushAutoFocusCandidates();
}
NS_ASSERTION(rootFrame, "How did that happen?"); 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/#target-element
// https://html.spec.whatwg.org/#find-a-potential-indicated-element // https://html.spec.whatwg.org/#find-a-potential-indicated-element
RefPtr<Element> target = RefPtr<Element> target = [&]() -> Element* {
nsContentUtils::GetTargetElement(mDocument, aAnchorName); // 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 // 1. If there is no indicated part of the document, set the Document's
// target element to null. // target element to null.

View File

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

View File

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

View File

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

View File

@@ -89,12 +89,6 @@ class nsIContentSink : public nsISupports {
*/ */
virtual void WillResume() = 0; 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 * This method gets called by the parser so that the content
* sink can retain a reference to the parser. The expectation * 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. * @param aTag - The tag to be closed.
*/ */
NS_IMETHOD CloseContainer(ElementType aTag) = 0; 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) 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: expected:
if (os == "android") and fission: [OK, TIMEOUT] if (os == "android") and fission: [OK, TIMEOUT]
["Flush autofocus candidates" should be happen before a scroll event and animation frame callbacks] ["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 () => { promise_test(async () => {
await waitForLoad(window); await waitForLoad(window);
const iframe = document.querySelector('iframe');
await waitUntilStableAutofocusState(); await waitUntilStableAutofocusState();
assert_equals(document.activeElement, iframe, assert_equals(document.activeElement, document.querySelector('iframe'),
'Autofocus elements in iframes should be focused.'); 'Autofocus elements in iframes should be focused.');
const doc = iframe.contentDocument;
assert_true(!doc.querySelector(':target'));
let input = document.createElement('input'); let input = document.createElement('input');
input.autofocus = true; input.autofocus = true;

View File

@@ -21,23 +21,7 @@ promise_test(async () => {
doc.body.appendChild(input); doc.body.appendChild(input);
await waitUntilStableAutofocusState(); await waitUntilStableAutofocusState();
assert_not_equals(doc.activeElement, input); assert_not_equals(doc.activeElement, input);
iframe.remove(); }, 'Autofocus elements in iframed documents with URL fragments should be skipped.');
}, '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)');
promise_test(async () => { promise_test(async () => {
let w = window.open('resources/frame-with-anchor.html'); 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. // Awaiting one animation frame is an easy way to determine autofocus state.
await waitForAnimationFrame(targetWindow); 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/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script> <script src="/resources/testharnessreport.js"></script>
<script src="resources/utils.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="first" autofocus>
<input id="second" autofocus> <input id="second" autofocus>
<link rel="stylesheet" href="resources/erase-first.css?pipe=trickle(d1)">
<script> <script>
'use strict'; 'use strict';
promise_test(async () => { promise_test(async () => {
await waitForLoad(window); await waitForEvent(document.body, 'focus', {capture:true});
await waitForAnimationFrame();
assert_equals(document.activeElement.id, 'second'); assert_equals(document.activeElement.id, 'second');
}, 'Script-blocking style sheet should pause flushing autofocus candidates.'); }, 'Script-blocking style sheet should pause flushing autofocus candidates.');
</script> </script>