This test checks select attribute of content element is valid.
authormorrita@google.com <morrita@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 24 Feb 2012 00:54:45 +0000 (00:54 +0000)
committermorrita@google.com <morrita@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 24 Feb 2012 00:54:45 +0000 (00:54 +0000)
https://bugs.webkit.org/show_bug.cgi?id=65595

Reviewed by Dimitri Glazkov.

Source/WebCore:

This change introduces FrameTree::scopedChild() and
FrameTree::scopedChild(), which can be used for scope-aware
frame lookup. Using these, the named accessor and the indexed
acceccor on Document, and Window.length are now TreeScope
aware. They don't count iframes in Shadow DOM.

This change also removes FrameTree::m_childCount since
Frame::childCount() is no longer in the hot
path. m_scopedChildCount is added instead.

Test: fast/dom/shadow/iframe-shadow.html

* bindings/js/JSDOMWindowCustom.cpp:
(WebCore::childFrameGetter):
(WebCore::indexGetter):
(WebCore::JSDOMWindow::getOwnPropertySlot):
(WebCore::JSDOMWindow::getOwnPropertyDescriptor):
* bindings/v8/custom/V8DOMWindowCustom.cpp:
(WebCore::V8DOMWindow::indexedPropertyGetter):
(WebCore::V8DOMWindow::namedPropertyGetter):
(WebCore::V8DOMWindow::namedSecurityCheck):
(WebCore::V8DOMWindow::indexedSecurityCheck):
* page/DOMWindow.cpp:
(WebCore::DOMWindow::length):
* page/Frame.cpp:
(WebCore::Frame::inScope):
(WebCore):
* page/Frame.h:
(WebCore):
(Frame):
* page/FrameTree.cpp:
(WebCore::FrameTree::actuallyAppendChild):
(WebCore::FrameTree::removeChild):
(WebCore::FrameTree::scopedChild):
(WebCore):
(WebCore::FrameTree::scopedChildCount):
(WebCore::FrameTree::childCount):
* page/FrameTree.h:
(WebCore):
(FrameTree):
(WebCore::FrameTree::FrameTree):

LayoutTests:

* fast/dom/shadow/iframe-shadow-expected.txt: Added.
* fast/dom/shadow/iframe-shadow.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@108700 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/dom/shadow/iframe-shadow-expected.txt [new file with mode: 0644]
LayoutTests/fast/dom/shadow/iframe-shadow.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/WebCore.exp.in
Source/WebCore/bindings/js/JSDOMWindowCustom.cpp
Source/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp
Source/WebCore/page/DOMWindow.cpp
Source/WebCore/page/Frame.cpp
Source/WebCore/page/Frame.h
Source/WebCore/page/FrameTree.cpp
Source/WebCore/page/FrameTree.h

index 580dc91..8383851 100644 (file)
@@ -1,3 +1,13 @@
+2012-02-23  MORITA Hajime  <morrita@google.com>
+
+        This test checks select attribute of content element is valid.
+        https://bugs.webkit.org/show_bug.cgi?id=65595
+
+        Reviewed by Dimitri Glazkov.
+
+        * fast/dom/shadow/iframe-shadow-expected.txt: Added.
+        * fast/dom/shadow/iframe-shadow.html: Added.
+
 2012-02-23  Philip Rogers  <pdr@google.com>
 
         Recompute font metrics on scale changes
diff --git a/LayoutTests/fast/dom/shadow/iframe-shadow-expected.txt b/LayoutTests/fast/dom/shadow/iframe-shadow-expected.txt
new file mode 100644 (file)
index 0000000..1576d16
--- /dev/null
@@ -0,0 +1,23 @@
+This test ensures that iframe inside shadow isn't visible from the host document.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS window.length is 4
+PASS i0byname.length is 1
+PASS i0 is i0byname[0].contentWindow
+PASS i1.length is 2
+PASS window.length is 4
+PASS i2byname.length is 1
+PASS i2byname[0].contentWindow is i2
+PASS i3byname.length is 0
+PASS i3 is undefined
+PASS window.length is 3
+PASS document['i0'] is undefined
+PASS window.length is 4
+PASS document['i3'] is i3InShadow.contentWindow
+PASS successfullyParsed is true
+
+TEST COMPLETE
+   
+
diff --git a/LayoutTests/fast/dom/shadow/iframe-shadow.html b/LayoutTests/fast/dom/shadow/iframe-shadow.html
new file mode 100644 (file)
index 0000000..177df4f
--- /dev/null
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/resources/js-test-pre.js"></script>
+</head>
+<body>
+<pre id="console"></pre>
+<iframe name="i0"></iframe>
+<iframe name="i1"></iframe>
+<iframe name="i1"></iframe>
+<iframe name="i2"></iframe>
+
+<div id="host"></div>
+
+<script>
+
+description("This test ensures that iframe inside shadow isn't visible from the host document.");
+
+// At first, check iframe in usual way
+shouldBe("window.length", "4");
+var i0 = document["i0"];
+var i0byname = document.getElementsByName("i0");
+shouldBe("i0byname.length", "1");
+shouldBe("i0", "i0byname[0].contentWindow");
+
+var i1 = document["i1"];
+var i2byname = document.getElementsByName("i0");
+shouldBe("i1.length", "2");
+
+// Then Adding some iframes into a shadow.
+
+var host = document.getElementById("host");
+var shadow = new WebKitShadowRoot(host);
+var i2InShadow = document.createElement("iframe");
+i2InShadow.setAttribute("name", "i2");
+shadow.appendChild(i2InShadow);
+
+var i3InShadow = document.createElement("iframe");
+i3InShadow.setAttribute("name", "i3");
+shadow.appendChild(i3InShadow);
+
+shouldBe("window.length", "4");
+
+var i2 = document["i2"];
+var i2byname = document.getElementsByName("i2");
+shouldBe("i2byname.length", "1");
+shouldBe("i2byname[0].contentWindow", "i2");
+
+var i3 = document["i3"];
+var i3byname = document.getElementsByName("i3");
+shouldBe("i3byname.length", "0");
+shouldBe("i3", "undefined");
+
+// Moving iframes across shadow boundary to ensure
+// That window.length and property availability are
+// correctly updated.
+
+shadow.appendChild(i0.frameElement);
+
+shouldBe("window.length", "3");
+shouldBe("document['i0']", "undefined");
+
+document.body.appendChild(i3InShadow);
+shouldBe("window.length", "4");
+shouldBe("document['i3']", "i3InShadow.contentWindow");
+
+</script>
+
+<script src="../../js/resources/js-test-post.js"></script>
+</body>
+</html>
index a52a66c..ba21d23 100644 (file)
@@ -1,3 +1,52 @@
+2012-02-23  MORITA Hajime  <morrita@google.com>
+
+        This test checks select attribute of content element is valid.
+        https://bugs.webkit.org/show_bug.cgi?id=65595
+
+        Reviewed by Dimitri Glazkov.
+
+        This change introduces FrameTree::scopedChild() and
+        FrameTree::scopedChild(), which can be used for scope-aware
+        frame lookup. Using these, the named accessor and the indexed
+        acceccor on Document, and Window.length are now TreeScope
+        aware. They don't count iframes in Shadow DOM.
+
+        This change also removes FrameTree::m_childCount since
+        Frame::childCount() is no longer in the hot
+        path. m_scopedChildCount is added instead.
+
+        Test: fast/dom/shadow/iframe-shadow.html
+
+        * bindings/js/JSDOMWindowCustom.cpp:
+        (WebCore::childFrameGetter):
+        (WebCore::indexGetter):
+        (WebCore::JSDOMWindow::getOwnPropertySlot):
+        (WebCore::JSDOMWindow::getOwnPropertyDescriptor):
+        * bindings/v8/custom/V8DOMWindowCustom.cpp:
+        (WebCore::V8DOMWindow::indexedPropertyGetter):
+        (WebCore::V8DOMWindow::namedPropertyGetter):
+        (WebCore::V8DOMWindow::namedSecurityCheck):
+        (WebCore::V8DOMWindow::indexedSecurityCheck):
+        * page/DOMWindow.cpp:
+        (WebCore::DOMWindow::length):
+        * page/Frame.cpp:
+        (WebCore::Frame::inScope):
+        (WebCore):
+        * page/Frame.h:
+        (WebCore):
+        (Frame):
+        * page/FrameTree.cpp:
+        (WebCore::FrameTree::actuallyAppendChild):
+        (WebCore::FrameTree::removeChild):
+        (WebCore::FrameTree::scopedChild):
+        (WebCore):
+        (WebCore::FrameTree::scopedChildCount):
+        (WebCore::FrameTree::childCount):
+        * page/FrameTree.h:
+        (WebCore):
+        (FrameTree):
+        (WebCore::FrameTree::FrameTree):
+
 2012-02-23  Philip Rogers  <pdr@google.com>
 
         Recompute font metrics on scale changes
index 12a4b98..e812fff 100644 (file)
@@ -1481,6 +1481,7 @@ __ZNK7WebCore9FrameTree20traverseNextWithWrapEb
 __ZNK7WebCore9FrameTree24traversePreviousWithWrapEb
 __ZNK7WebCore9FrameTree4findERKN3WTF12AtomicStringE
 __ZNK7WebCore9FrameTree6parentEb
+__ZNK7WebCore9FrameTree10childCountEv
 __ZNK7WebCore9FrameView11needsLayoutEv
 __ZNK7WebCore9FrameView13isTransparentEv
 __ZNK7WebCore9FrameView13paintBehaviorEv
index baf80d3..0ba259e 100644 (file)
@@ -99,12 +99,12 @@ JSValue nonCachingStaticFunctionGetter(ExecState* exec, JSValue, const Identifie
 
 static JSValue childFrameGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName)
 {
-    return toJS(exec, static_cast<JSDOMWindow*>(asObject(slotBase))->impl()->frame()->tree()->child(identifierToAtomicString(propertyName))->domWindow());
+    return toJS(exec, static_cast<JSDOMWindow*>(asObject(slotBase))->impl()->frame()->tree()->scopedChild(identifierToAtomicString(propertyName))->domWindow());
 }
 
 static JSValue indexGetter(ExecState* exec, JSValue slotBase, unsigned index)
 {
-    return toJS(exec, static_cast<JSDOMWindow*>(asObject(slotBase))->impl()->frame()->tree()->child(index)->domWindow());
+    return toJS(exec, static_cast<JSDOMWindow*>(asObject(slotBase))->impl()->frame()->tree()->scopedChild(index)->domWindow());
 }
 
 static JSValue namedItemGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName)
@@ -220,7 +220,7 @@ bool JSDOMWindow::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identi
     // naming frames things that conflict with window properties that
     // are in Moz but not IE. Since we have some of these, we have to do
     // it the Moz way.
-    if (thisObject->impl()->frame()->tree()->child(identifierToAtomicString(propertyName))) {
+    if (thisObject->impl()->frame()->tree()->scopedChild(identifierToAtomicString(propertyName))) {
         slot.setCustom(thisObject, childFrameGetter);
         return true;
     }
@@ -244,7 +244,7 @@ bool JSDOMWindow::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identi
     // allow window[1] or parent[1] etc. (#56983)
     bool ok;
     unsigned i = propertyName.toArrayIndex(ok);
-    if (ok && i < thisObject->impl()->frame()->tree()->childCount()) {
+    if (ok && i < thisObject->impl()->frame()->tree()->scopedChildCount()) {
         slot.setCustomIndex(thisObject, i, indexGetter);
         return true;
     }
@@ -310,7 +310,7 @@ bool JSDOMWindow::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, co
     // naming frames things that conflict with window properties that
     // are in Moz but not IE. Since we have some of these, we have to do
     // it the Moz way.
-    if (thisObject->impl()->frame()->tree()->child(identifierToAtomicString(propertyName))) {
+    if (thisObject->impl()->frame()->tree()->scopedChild(identifierToAtomicString(propertyName))) {
         PropertySlot slot;
         slot.setCustom(thisObject, childFrameGetter);
         descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
@@ -319,7 +319,7 @@ bool JSDOMWindow::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, co
     
     bool ok;
     unsigned i = propertyName.toArrayIndex(ok);
-    if (ok && i < thisObject->impl()->frame()->tree()->childCount()) {
+    if (ok && i < thisObject->impl()->frame()->tree()->scopedChildCount()) {
         PropertySlot slot;
         slot.setCustomIndex(thisObject, i, indexGetter);
         descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
index fb7628e..cbae113 100644 (file)
@@ -476,7 +476,7 @@ v8::Handle<v8::Value> V8DOMWindow::indexedPropertyGetter(uint32_t index, const v
     if (!frame)
         return notHandledByInterceptor();
 
-    Frame* child = frame->tree()->child(index);
+    Frame* child = frame->tree()->scopedChild(index);
     if (child)
         return toV8(child->domWindow());
 
@@ -499,7 +499,7 @@ v8::Handle<v8::Value> V8DOMWindow::namedPropertyGetter(v8::Local<v8::String> nam
 
     // Search sub-frames.
     AtomicString propName = v8StringToAtomicWebCoreString(name);
-    Frame* child = frame->tree()->child(propName);
+    Frame* child = frame->tree()->scopedChild(propName);
     if (child)
         return toV8(child->domWindow());
 
@@ -556,14 +556,15 @@ bool V8DOMWindow::namedSecurityCheck(v8::Local<v8::Object> host, v8::Local<v8::V
         DEFINE_STATIC_LOCAL(AtomicString, nameOfProtoProperty, ("__proto__"));
 
         String name = toWebCoreString(key);
+        Frame* childFrame = target->tree()->scopedChild(name);
         // Notice that we can't call HasRealNamedProperty for ACCESS_HAS
         // because that would generate infinite recursion.
-        if (type == v8::ACCESS_HAS && target->tree()->child(name))
+        if (type == v8::ACCESS_HAS && childFrame)
             return true;
         // We need to explicitly compare against nameOfProtoProperty because
         // V8's JSObject::LocalLookup finds __proto__ before
         // interceptors and even when __proto__ isn't a "real named property".
-        if (type == v8::ACCESS_GET && target->tree()->child(name) && !host->HasRealNamedProperty(key->ToString()) && name != nameOfProtoProperty)
+        if (type == v8::ACCESS_GET && childFrame && !host->HasRealNamedProperty(key->ToString()) && name != nameOfProtoProperty)
             return true;
     }
 
@@ -583,12 +584,13 @@ bool V8DOMWindow::indexedSecurityCheck(v8::Local<v8::Object> host, uint32_t inde
     Frame* target = targetWindow->frame();
     if (!target)
         return false;
+    Frame* childFrame =  target->tree()->scopedChild(index);
 
     // Notice that we can't call HasRealNamedProperty for ACCESS_HAS
     // because that would generate infinite recursion.
-    if (type == v8::ACCESS_HAS && target->tree()->child(index))
+    if (type == v8::ACCESS_HAS && childFrame)
         return true;
-    if (type == v8::ACCESS_GET && target->tree()->child(index) && !host->HasRealIndexedProperty(index))
+    if (type == v8::ACCESS_GET && childFrame && !host->HasRealIndexedProperty(index))
         return true;
 
     return V8BindingSecurity::canAccessFrame(V8BindingState::Only(), target, false);
index 9ff0af8..051bbf0 100644 (file)
@@ -1138,7 +1138,7 @@ unsigned DOMWindow::length() const
     if (!isCurrentlyDisplayedInFrame())
         return 0;
 
-    return m_frame->tree()->childCount();
+    return m_frame->tree()->scopedChildCount();
 }
 
 String DOMWindow::name() const
index 9344e12..ee3c068 100644 (file)
@@ -229,6 +229,15 @@ Frame::~Frame()
     }
 }
 
+bool Frame::inScope(TreeScope* scope) const
+{
+    ASSERT(scope);
+    HTMLFrameOwnerElement* owner = document()->ownerElement();
+    // Scoping test should be done only for child frames.
+    ASSERT(owner);
+    return owner->treeScope() == scope;
+}
+
 void Frame::addDestructionObserver(FrameDestructionObserver* observer)
 {
     m_destructionObservers.add(observer);
index 2832cb0..e06c0df 100644 (file)
@@ -74,6 +74,8 @@ namespace WebCore {
     class TiledBackingStoreClient { };
 #endif
 
+    class TreeScope;
+
     class Frame : public RefCounted<Frame>, public TiledBackingStoreClient {
     public:
         static PassRefPtr<Frame> create(Page*, HTMLFrameOwnerElement*, FrameLoaderClient*);
@@ -123,6 +125,7 @@ namespace WebCore {
         void setIsDisconnected(bool);
         bool excludeFromTextSearch() const;
         void setExcludeFromTextSearch(bool);
+        bool inScope(TreeScope*) const;
 
         void injectUserScripts(UserScriptInjectionTime);
         
index fa4982c..ced6200 100644 (file)
@@ -103,7 +103,7 @@ void FrameTree::actuallyAppendChild(PassRefPtr<Frame> child)
     } else
         m_firstChild = child;
 
-    m_childCount++;
+    m_scopedChildCount = invalidCount;
 
     ASSERT(!m_lastChild->tree()->m_nextSibling);
 }
@@ -125,7 +125,7 @@ void FrameTree::removeChild(Frame* child)
     child->tree()->m_previousSibling = 0;
     child->tree()->m_nextSibling = 0;
 
-    m_childCount--;
+    m_scopedChildCount = invalidCount;
 }
 
 AtomicString FrameTree::uniqueChildName(const AtomicString& requestedName) const
@@ -177,6 +177,64 @@ AtomicString FrameTree::uniqueChildName(const AtomicString& requestedName) const
     return AtomicString(name);
 }
 
+inline Frame* FrameTree::scopedChild(unsigned index, TreeScope* scope) const
+{
+    unsigned scopedIndex = 0;
+    for (Frame* result = firstChild(); result; result = result->tree()->nextSibling()) {
+        if (result->inScope(scope)) {
+            if (scopedIndex == index)
+                return result;
+            scopedIndex++;
+        }
+    }
+
+    return 0;
+}
+
+inline Frame* FrameTree::scopedChild(const AtomicString& name, TreeScope* scope) const
+{
+    for (Frame* child = firstChild(); child; child = child->tree()->nextSibling())
+        if (child->tree()->uniqueName() == name && child->inScope(scope))
+            return child;
+    return 0;
+}
+
+inline unsigned FrameTree::scopedChildCount(TreeScope* scope) const
+{
+    unsigned scopedCount = 0;
+    for (Frame* result = firstChild(); result; result = result->tree()->nextSibling()) {
+        if (result->inScope(scope))
+            scopedCount++;
+    }
+
+    return scopedCount;
+}
+
+Frame* FrameTree::scopedChild(unsigned index) const
+{
+    return scopedChild(index, m_thisFrame->document());
+}
+
+Frame* FrameTree::scopedChild(const AtomicString& name) const
+{
+    return scopedChild(name, m_thisFrame->document());
+}
+
+unsigned FrameTree::scopedChildCount() const
+{
+    if (m_scopedChildCount == invalidCount)
+        m_scopedChildCount = scopedChildCount(m_thisFrame->document());
+    return m_scopedChildCount;
+}
+
+unsigned FrameTree::childCount() const
+{
+    unsigned count = 0;
+    for (Frame* result = firstChild(); result; result = result->tree()->nextSibling())
+        ++count;
+    return count;
+}
+
 Frame* FrameTree::child(unsigned index) const
 {
     Frame* result = firstChild();
index d8291f7..5f9e317 100644 (file)
 #ifndef FrameTree_h
 #define FrameTree_h
 
+#include <wtf/NotFound.h>
 #include <wtf/text/AtomicString.h>
 
 namespace WebCore {
 
     class Frame;
+    class TreeScope;
 
     class FrameTree {
         WTF_MAKE_NONCOPYABLE(FrameTree);
     public:
+        const static unsigned invalidCount = static_cast<unsigned>(WTF::notFound);
+
         FrameTree(Frame* thisFrame, Frame* parentFrame) 
             : m_thisFrame(thisFrame)
             , m_parent(parentFrame)
             , m_previousSibling(0)
             , m_lastChild(0)
-            , m_childCount(0)
+            , m_scopedChildCount(invalidCount)
         {
         }
+
         ~FrameTree();
 
         const AtomicString& name() const { return m_name; }
@@ -50,7 +55,6 @@ namespace WebCore {
         Frame* previousSibling() const { return m_previousSibling; }
         Frame* firstChild() const { return m_firstChild.get(); }
         Frame* lastChild() const { return m_lastChild; }
-        unsigned childCount() const { return m_childCount; }
 
         bool isDescendantOf(const Frame* ancestor) const;
         Frame* traverseNext(const Frame* stayWithin = 0) const;
@@ -65,15 +69,25 @@ namespace WebCore {
         Frame* child(unsigned index) const;
         Frame* child(const AtomicString& name) const;
         Frame* find(const AtomicString& name) const;
+        unsigned childCount() const;
 
         AtomicString uniqueChildName(const AtomicString& requestedName) const;
 
         Frame* top(bool checkForDisconnectedFrame = false) const;
 
+        Frame* scopedChild(unsigned index) const;
+        Frame* scopedChild(const AtomicString& name) const;
+        unsigned scopedChildCount() const;
+
     private:
         Frame* deepLastChild() const;
         void actuallyAppendChild(PassRefPtr<Frame>);
 
+        bool scopedBy(TreeScope*) const;
+        Frame* scopedChild(unsigned index, TreeScope*) const;
+        Frame* scopedChild(const AtomicString& name, TreeScope*) const;
+        unsigned scopedChildCount(TreeScope*) const;
+
         Frame* m_thisFrame;
 
         Frame* m_parent;
@@ -85,7 +99,7 @@ namespace WebCore {
         Frame* m_previousSibling;
         RefPtr<Frame> m_firstChild;
         Frame* m_lastChild;
-        unsigned m_childCount;
+        mutable unsigned m_scopedChildCount;
     };
 
 } // namespace WebCore