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
+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
--- /dev/null
+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
+
+
--- /dev/null
+<!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>
+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
__ZNK7WebCore9FrameTree24traversePreviousWithWrapEb
__ZNK7WebCore9FrameTree4findERKN3WTF12AtomicStringE
__ZNK7WebCore9FrameTree6parentEb
+__ZNK7WebCore9FrameTree10childCountEv
__ZNK7WebCore9FrameView11needsLayoutEv
__ZNK7WebCore9FrameView13isTransparentEv
__ZNK7WebCore9FrameView13paintBehaviorEv
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)
// 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;
}
// 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;
}
// 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);
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);
if (!frame)
return notHandledByInterceptor();
- Frame* child = frame->tree()->child(index);
+ Frame* child = frame->tree()->scopedChild(index);
if (child)
return toV8(child->domWindow());
// 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());
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;
}
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);
if (!isCurrentlyDisplayedInFrame())
return 0;
- return m_frame->tree()->childCount();
+ return m_frame->tree()->scopedChildCount();
}
String DOMWindow::name() const
}
}
+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);
class TiledBackingStoreClient { };
#endif
+ class TreeScope;
+
class Frame : public RefCounted<Frame>, public TiledBackingStoreClient {
public:
static PassRefPtr<Frame> create(Page*, HTMLFrameOwnerElement*, FrameLoaderClient*);
void setIsDisconnected(bool);
bool excludeFromTextSearch() const;
void setExcludeFromTextSearch(bool);
+ bool inScope(TreeScope*) const;
void injectUserScripts(UserScriptInjectionTime);
} else
m_firstChild = child;
- m_childCount++;
+ m_scopedChildCount = invalidCount;
ASSERT(!m_lastChild->tree()->m_nextSibling);
}
child->tree()->m_previousSibling = 0;
child->tree()->m_nextSibling = 0;
- m_childCount--;
+ m_scopedChildCount = invalidCount;
}
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();
#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; }
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;
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;
Frame* m_previousSibling;
RefPtr<Frame> m_firstChild;
Frame* m_lastChild;
- unsigned m_childCount;
+ mutable unsigned m_scopedChildCount;
};
} // namespace WebCore