From 0999ab5dc2aa28fbbb414c73738ba4014127f6cb Mon Sep 17 00:00:00 2001 From: "morrita@google.com" Date: Fri, 24 Feb 2012 00:54:45 +0000 Subject: [PATCH] This test checks select attribute of content element is valid. 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 --- LayoutTests/ChangeLog | 10 +++ .../fast/dom/shadow/iframe-shadow-expected.txt | 23 +++++++ LayoutTests/fast/dom/shadow/iframe-shadow.html | 71 ++++++++++++++++++++++ Source/WebCore/ChangeLog | 49 +++++++++++++++ Source/WebCore/WebCore.exp.in | 1 + Source/WebCore/bindings/js/JSDOMWindowCustom.cpp | 12 ++-- .../bindings/v8/custom/V8DOMWindowCustom.cpp | 14 +++-- Source/WebCore/page/DOMWindow.cpp | 2 +- Source/WebCore/page/Frame.cpp | 9 +++ Source/WebCore/page/Frame.h | 3 + Source/WebCore/page/FrameTree.cpp | 62 ++++++++++++++++++- Source/WebCore/page/FrameTree.h | 20 +++++- 12 files changed, 258 insertions(+), 18 deletions(-) create mode 100644 LayoutTests/fast/dom/shadow/iframe-shadow-expected.txt create mode 100644 LayoutTests/fast/dom/shadow/iframe-shadow.html diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog index 580dc91..8383851 100644 --- a/LayoutTests/ChangeLog +++ b/LayoutTests/ChangeLog @@ -1,3 +1,13 @@ +2012-02-23 MORITA Hajime + + 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 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 index 0000000..1576d16 --- /dev/null +++ b/LayoutTests/fast/dom/shadow/iframe-shadow-expected.txt @@ -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 index 0000000..177df4f --- /dev/null +++ b/LayoutTests/fast/dom/shadow/iframe-shadow.html @@ -0,0 +1,71 @@ + + + + + + +

+
+
+
+
+
+
+ + + + + + diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog index a52a66c..ba21d23 100644 --- a/Source/WebCore/ChangeLog +++ b/Source/WebCore/ChangeLog @@ -1,3 +1,52 @@ +2012-02-23 MORITA Hajime + + 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 Recompute font metrics on scale changes diff --git a/Source/WebCore/WebCore.exp.in b/Source/WebCore/WebCore.exp.in index 12a4b98..e812fff 100644 --- a/Source/WebCore/WebCore.exp.in +++ b/Source/WebCore/WebCore.exp.in @@ -1481,6 +1481,7 @@ __ZNK7WebCore9FrameTree20traverseNextWithWrapEb __ZNK7WebCore9FrameTree24traversePreviousWithWrapEb __ZNK7WebCore9FrameTree4findERKN3WTF12AtomicStringE __ZNK7WebCore9FrameTree6parentEb +__ZNK7WebCore9FrameTree10childCountEv __ZNK7WebCore9FrameView11needsLayoutEv __ZNK7WebCore9FrameView13isTransparentEv __ZNK7WebCore9FrameView13paintBehaviorEv diff --git a/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp b/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp index baf80d3..0ba259e 100644 --- a/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp +++ b/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp @@ -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(asObject(slotBase))->impl()->frame()->tree()->child(identifierToAtomicString(propertyName))->domWindow()); + return toJS(exec, static_cast(asObject(slotBase))->impl()->frame()->tree()->scopedChild(identifierToAtomicString(propertyName))->domWindow()); } static JSValue indexGetter(ExecState* exec, JSValue slotBase, unsigned index) { - return toJS(exec, static_cast(asObject(slotBase))->impl()->frame()->tree()->child(index)->domWindow()); + return toJS(exec, static_cast(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); diff --git a/Source/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp b/Source/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp index fb7628e..cbae113 100644 --- a/Source/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp +++ b/Source/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp @@ -476,7 +476,7 @@ v8::Handle 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 V8DOMWindow::namedPropertyGetter(v8::Local 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 host, v8::Localtree()->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 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); diff --git a/Source/WebCore/page/DOMWindow.cpp b/Source/WebCore/page/DOMWindow.cpp index 9ff0af8..051bbf0 100644 --- a/Source/WebCore/page/DOMWindow.cpp +++ b/Source/WebCore/page/DOMWindow.cpp @@ -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 diff --git a/Source/WebCore/page/Frame.cpp b/Source/WebCore/page/Frame.cpp index 9344e12..ee3c068 100644 --- a/Source/WebCore/page/Frame.cpp +++ b/Source/WebCore/page/Frame.cpp @@ -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); diff --git a/Source/WebCore/page/Frame.h b/Source/WebCore/page/Frame.h index 2832cb0..e06c0df 100644 --- a/Source/WebCore/page/Frame.h +++ b/Source/WebCore/page/Frame.h @@ -74,6 +74,8 @@ namespace WebCore { class TiledBackingStoreClient { }; #endif + class TreeScope; + class Frame : public RefCounted, public TiledBackingStoreClient { public: static PassRefPtr 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); diff --git a/Source/WebCore/page/FrameTree.cpp b/Source/WebCore/page/FrameTree.cpp index fa4982c..ced6200 100644 --- a/Source/WebCore/page/FrameTree.cpp +++ b/Source/WebCore/page/FrameTree.cpp @@ -103,7 +103,7 @@ void FrameTree::actuallyAppendChild(PassRefPtr 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(); diff --git a/Source/WebCore/page/FrameTree.h b/Source/WebCore/page/FrameTree.h index d8291f7..5f9e317 100644 --- a/Source/WebCore/page/FrameTree.h +++ b/Source/WebCore/page/FrameTree.h @@ -20,23 +20,28 @@ #ifndef FrameTree_h #define FrameTree_h +#include #include namespace WebCore { class Frame; + class TreeScope; class FrameTree { WTF_MAKE_NONCOPYABLE(FrameTree); public: + const static unsigned invalidCount = static_cast(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); + 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 m_firstChild; Frame* m_lastChild; - unsigned m_childCount; + mutable unsigned m_scopedChildCount; }; } // namespace WebCore -- 2.7.4