Don't consider browsing contexts with empty names for named lookup.

TBR=dcheng@chromium.org

(cherry picked from commit 0c236612e5b506d3b1e3ab9b75b3a355e2ba620f)

Bug: 803620
Change-Id: I6c28067a10d812faf815a04360a701aee741abc5
Reviewed-on: https://chromium-review.googlesource.com/925541
Reviewed-by: Yuki Shiino <yukishiino@chromium.org>
Reviewed-by: Kentaro Hara <haraken@chromium.org>
Commit-Queue: Daniel Cheng <dcheng@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#537735}
Reviewed-on: https://chromium-review.googlesource.com/932912
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/branch-heads/3325@{#557}
Cr-Branched-From: bc084a8b5afa3744a74927344e304c02ae54189f-refs/heads/master@{#530369}
diff --git a/third_party/WebKit/Source/core/exported/WebFrameTest.cpp b/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
index 5236bf46..5e9b5b0 100644
--- a/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
@@ -11821,6 +11821,20 @@
   EXPECT_EQ(0, area->LayerForScrolling()->GetPosition().X());
 }
 
+TEST_P(WebFrameSimTest, NamedLookupIgnoresEmptyNames) {
+  SimRequest main_resource("https://example.com/main.html", "text/html");
+  LoadURL("https://example.com/main.html");
+  main_resource.Complete(R"HTML(
+    <body>
+    <iframe name="" src="data:text/html,"></iframe>
+    </body>)HTML");
+
+  EXPECT_EQ(nullptr, MainFrame().GetFrame()->Tree().ScopedChild(""));
+  EXPECT_EQ(nullptr,
+            MainFrame().GetFrame()->Tree().ScopedChild(AtomicString()));
+  EXPECT_EQ(nullptr, MainFrame().GetFrame()->Tree().ScopedChild(g_empty_atom));
+}
+
 TEST_P(ParameterizedWebFrameTest, NoLoadingCompletionCallbacksInDetach) {
   class LoadingObserverFrameClient
       : public FrameTestHelpers::TestWebFrameClient {
diff --git a/third_party/WebKit/Source/core/page/FrameTree.cpp b/third_party/WebKit/Source/core/page/FrameTree.cpp
index 348ac7c..d95a45a 100644
--- a/third_party/WebKit/Source/core/page/FrameTree.cpp
+++ b/third_party/WebKit/Source/core/page/FrameTree.cpp
@@ -139,6 +139,9 @@
 }
 
 Frame* FrameTree::ScopedChild(const AtomicString& name) const {
+  if (name.IsEmpty())
+    return nullptr;
+
   for (Frame* child = FirstChild(); child;
        child = child->Tree().NextSibling()) {
     if (child->Client()->InShadowTree())
diff --git a/third_party/WebKit/Source/core/page/FrameTree.h b/third_party/WebKit/Source/core/page/FrameTree.h
index db84875..26d9adf 100644
--- a/third_party/WebKit/Source/core/page/FrameTree.h
+++ b/third_party/WebKit/Source/core/page/FrameTree.h
@@ -62,6 +62,11 @@
   unsigned ChildCount() const;
 
   Frame* ScopedChild(unsigned index) const;
+  // https://whatwg.org/C/window-object.html#named-access-on-the-window-object
+  // This implements the steps needed for looking up a child browsing context
+  // that matches |name|. If |name.IsEmpty()| is true, this is guaranteed to
+  // return null: the spec specifically states that browsing contexts with a
+  // name are never considered.
   Frame* ScopedChild(const AtomicString& name) const;
   unsigned ScopedChildCount() const;
   void InvalidateScopedChildCount();