[Shadow] ShadowRoot should know the existence of elements having ElementShadow.
authorshinyak@chromium.org <shinyak@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 6 Nov 2012 10:15:06 +0000 (10:15 +0000)
committershinyak@chromium.org <shinyak@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 6 Nov 2012 10:15:06 +0000 (10:15 +0000)
https://bugs.webkit.org/show_bug.cgi?id=100922

Reviewed by Hajime Morita.

Source/WebCore:

We count the elements having ElementShadow in ShadowRoot. This is a prepation patch for to solve Bug 100451.
We have a count-up and count-down login in ShadowRoot::insertedInto and ShadowRoot::removedFrom.

For performance reason, we have a flag that an element should be unregistered in ShadowRoot.

Test: fast/dom/shadow/has-elementshadow.html

* dom/ShadowRoot.cpp:
(WebCore::ShadowRoot::ShadowRoot):
(WebCore::ShadowRoot::insertedInto): Count up the number of elements having ElementShadow. ElementShadow
is created only when the oldest ShadowRoot is created, we only count up only when this ShadowRoot is oldest.
(WebCore):
(WebCore::ShadowRoot::removedFrom): Count down if we used this ShadowRoot for count up.
* dom/ShadowRoot.h:
(ShadowRoot):
(WebCore::ShadowRoot::registerElementShadow):
(WebCore::ShadowRoot::unregisterElementShadow):
(WebCore::ShadowRoot::hasElementShadow):
(WebCore::ShadowRoot::countElementShadow):
* testing/Internals.cpp:
(WebCore::Internals::countElementShadow):
(WebCore):
* testing/Internals.h:
(Internals):
* testing/Internals.idl:

LayoutTests:

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

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

LayoutTests/ChangeLog
LayoutTests/fast/dom/shadow/has-elementshadow-expected.txt [new file with mode: 0644]
LayoutTests/fast/dom/shadow/has-elementshadow.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/dom/ShadowRoot.cpp
Source/WebCore/dom/ShadowRoot.h
Source/WebCore/testing/Internals.cpp
Source/WebCore/testing/Internals.h
Source/WebCore/testing/Internals.idl

index 55ff751..649385c 100644 (file)
@@ -1,3 +1,13 @@
+2012-11-06  Shinya Kawanaka  <shinyak@chromium.org>
+
+        [Shadow] ShadowRoot should know the existence of elements having ElementShadow.
+        https://bugs.webkit.org/show_bug.cgi?id=100922
+
+        Reviewed by Hajime Morita.
+
+        * fast/dom/shadow/has-elementshadow-expected.txt: Added.
+        * fast/dom/shadow/has-elementshadow.html: Added.
+
 2012-11-06  Dongwoo Joshua Im  <dw.im@samsung.com>
 
         [QT] [GTK] Remove fast/forms/week-multiple-fields from TestExpectations of gtk and qt.
diff --git a/LayoutTests/fast/dom/shadow/has-elementshadow-expected.txt b/LayoutTests/fast/dom/shadow/has-elementshadow-expected.txt
new file mode 100644 (file)
index 0000000..e2fd5a5
--- /dev/null
@@ -0,0 +1,49 @@
+This test confirms that the number of elements having Shadow in a shadow subtree is correctly counted. See Bug 100922 also.
+
+Initial count should be 0
+PASS internals.countElementShadow(shadowRoot) is 0
+
+Inserted into / removed from an element having shadow
+PASS internals.countElementShadow(shadowRoot) is 1
+PASS internals.countElementShadow(shadowRoot) is 0
+
+Inserted into / removed from an element having multiple shadow roots
+PASS internals.countElementShadow(shadowRoot) is 1
+PASS internals.countElementShadow(shadowRoot) is 0
+
+ShadowRoot is added
+PASS internals.countElementShadow(shadowRoot) is 0
+PASS internals.countElementShadow(shadowRoot) is 1
+PASS internals.countElementShadow(shadowRoot) is 1
+
+Should be counted by each shadow root (multiple shadow root case)
+PASS internals.countElementShadow(shadowRoot) is 1
+PASS internals.countElementShadow(youngerShadowRoot) is 0
+PASS internals.countElementShadow(shadowRoot) is 0
+PASS internals.countElementShadow(youngerShadowRoot) is 1
+
+Should be counted by each shadow root (nested shadow root case)
+PASS internals.countElementShadow(shadowRoot) is 1
+PASS internals.countElementShadow(nestedShadowRoot) is 0
+PASS internals.countElementShadow(shadowRoot) is 1
+PASS internals.countElementShadow(nestedShadowRoot) is 1
+PASS internals.countElementShadow(shadowRoot) is 2
+PASS internals.countElementShadow(nestedShadowRoot) is 1
+PASS internals.countElementShadow(shadowRoot) is 2
+PASS internals.countElementShadow(nestedShadowRoot) is 2
+
+Should be counted by each shadow root (deep nested shadow root case)
+PASS internals.countElementShadow(shadowRoot) is 1
+PASS internals.countElementShadow(nestedShadowRoot) is 0
+PASS internals.countElementShadow(deepNestedShadowRoot) is 0
+PASS internals.countElementShadow(shadowRoot) is 1
+PASS internals.countElementShadow(nestedShadowRoot) is 1
+PASS internals.countElementShadow(deepNestedShadowRoot) is 1
+PASS internals.countElementShadow(shadowRoot) is 0
+PASS internals.countElementShadow(nestedShadowRoot) is 0
+PASS internals.countElementShadow(deepNestedShadowRoot) is 0
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/dom/shadow/has-elementshadow.html b/LayoutTests/fast/dom/shadow/has-elementshadow.html
new file mode 100644 (file)
index 0000000..67f5d1a
--- /dev/null
@@ -0,0 +1,150 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../js/resources/js-test-pre.js"></script>
+<script src="resources/polyfill.js"></script>
+<script src="resources/shadow-dom.js"></script>
+</head>
+<body>
+
+<p>This test confirms that the number of elements having Shadow in a shadow subtree is correctly counted.
+See <a href="https://bugs.webkit.org/show_bug.cgi?id=100922">Bug 100922</a> also.</p>
+
+<div id="container"></div>
+<pre id="console"></pre>
+
+<script>
+function testCase(f)
+{
+    container.innerHTML = '';
+    container.appendChild(createDOM('div', {'id': 'host'},
+                                    createShadowRoot()));
+    shadowRoot = internals.shadowRoot(host);
+
+    f();
+    debug('');
+}
+
+testCase(function()
+{
+    debug('Initial count should be 0');
+    shouldBe('internals.countElementShadow(shadowRoot)', '0');
+});
+
+testCase(function()
+{
+    debug('Inserted into / removed from an element having shadow');
+
+    var div = createDOM('div', {}, createShadowRoot());
+    shadowRoot.appendChild(div);
+    shouldBe('internals.countElementShadow(shadowRoot)', '1');
+
+    shadowRoot.removeChild(div);
+    shouldBe('internals.countElementShadow(shadowRoot)', '0');
+});
+
+testCase(function()
+{
+    debug('Inserted into / removed from an element having multiple shadow roots');
+
+    var div = createDOM('div', {}, createShadowRoot(), createShadowRoot());
+
+    shadowRoot.appendChild(div);
+    shouldBe('internals.countElementShadow(shadowRoot)', '1');
+
+    shadowRoot.removeChild(div);
+    shouldBe('internals.countElementShadow(shadowRoot)', '0');
+});
+
+testCase(function()
+{
+    debug('ShadowRoot is added');
+    var div = createDOM('div', {});
+    shadowRoot.appendChild(div);
+    shouldBe('internals.countElementShadow(shadowRoot)', '0');
+
+    new WebKitShadowRoot(div);
+    shouldBe('internals.countElementShadow(shadowRoot)', '1');
+
+    new WebKitShadowRoot(div);
+    shouldBe('internals.countElementShadow(shadowRoot)', '1');
+});
+
+testCase(function()
+{
+    debug('Should be counted by each shadow root (multiple shadow root case)');
+    youngerShadowRoot = new WebKitShadowRoot(host);
+
+    var div = createDOM('div', {}, createShadowRoot());
+
+    shadowRoot.appendChild(div);
+    shouldBe('internals.countElementShadow(shadowRoot)', '1');
+    shouldBe('internals.countElementShadow(youngerShadowRoot)', '0');
+
+    youngerShadowRoot.appendChild(div);
+    shouldBe('internals.countElementShadow(shadowRoot)', '0');
+    shouldBe('internals.countElementShadow(youngerShadowRoot)', '1');
+});
+
+testCase(function()
+{
+    debug('Should be counted by each shadow root (nested shadow root case)');
+    var div = createDOM('div', {}, createShadowRoot());
+    nestedShadowRoot = internals.shadowRoot(div);
+    shadowRoot.appendChild(div);
+
+    shouldBe('internals.countElementShadow(shadowRoot)', '1');
+    shouldBe('internals.countElementShadow(nestedShadowRoot)', '0');
+
+    nestedShadowRoot.appendChild(createDOM('div', {}, createShadowRoot()));
+
+    shouldBe('internals.countElementShadow(shadowRoot)', '1');
+    shouldBe('internals.countElementShadow(nestedShadowRoot)', '1');
+
+    shadowRoot.appendChild(createDOM('div', {}, createShadowRoot()));
+
+    shouldBe('internals.countElementShadow(shadowRoot)', '2');
+    shouldBe('internals.countElementShadow(nestedShadowRoot)', '1');
+
+    nestedShadowRoot.appendChild(createDOM('div', {}, createShadowRoot()));
+
+    shouldBe('internals.countElementShadow(shadowRoot)', '2');
+    shouldBe('internals.countElementShadow(nestedShadowRoot)', '2');
+});
+
+testCase(function()
+{
+    debug('Should be counted by each shadow root (deep nested shadow root case)');
+    var div = createDOM('div', {}, createShadowRoot());
+    nestedShadowRoot = internals.shadowRoot(div);
+    shadowRoot.appendChild(div);
+
+    shouldBe('internals.countElementShadow(shadowRoot)', '1');
+    shouldBe('internals.countElementShadow(nestedShadowRoot)', '0');
+
+    var div1 = createDOM('div', {}, createShadowRoot());
+    div1.setAttribute('title', 'debugstop');
+    deepNestedShadowRoot = internals.shadowRoot(div1);
+    var div2 = createDOM('div', {}, createShadowRoot());
+    var shadowRoot2 = internals.shadowRoot(div2);
+
+    deepNestedShadowRoot.appendChild(div2);
+    // When not in document, we don't count it.
+    shouldBe('internals.countElementShadow(deepNestedShadowRoot)', '0');
+
+    nestedShadowRoot.appendChild(div1);
+    shouldBe('internals.countElementShadow(shadowRoot)', '1');
+    shouldBe('internals.countElementShadow(nestedShadowRoot)', '1');
+    shouldBe('internals.countElementShadow(deepNestedShadowRoot)', '1');
+
+    container.innerHTML = "";
+    shouldBe('internals.countElementShadow(shadowRoot)', '0');
+    shouldBe('internals.countElementShadow(nestedShadowRoot)', '0');
+    shouldBe('internals.countElementShadow(deepNestedShadowRoot)', '0');
+});
+
+finishJSTest();
+</script>
+<script src="../../js/resources/js-test-post.js"></script>
+</body>
+</html>
index 1563158..351b378 100644 (file)
@@ -1,3 +1,36 @@
+2012-11-06  Shinya Kawanaka  <shinyak@chromium.org>
+
+        [Shadow] ShadowRoot should know the existence of elements having ElementShadow.
+        https://bugs.webkit.org/show_bug.cgi?id=100922
+
+        Reviewed by Hajime Morita.
+
+        We count the elements having ElementShadow in ShadowRoot. This is a prepation patch for to solve Bug 100451.
+        We have a count-up and count-down login in ShadowRoot::insertedInto and ShadowRoot::removedFrom.
+
+        For performance reason, we have a flag that an element should be unregistered in ShadowRoot.
+
+        Test: fast/dom/shadow/has-elementshadow.html
+
+        * dom/ShadowRoot.cpp:
+        (WebCore::ShadowRoot::ShadowRoot):
+        (WebCore::ShadowRoot::insertedInto): Count up the number of elements having ElementShadow. ElementShadow
+        is created only when the oldest ShadowRoot is created, we only count up only when this ShadowRoot is oldest.
+        (WebCore):
+        (WebCore::ShadowRoot::removedFrom): Count down if we used this ShadowRoot for count up.
+        * dom/ShadowRoot.h:
+        (ShadowRoot):
+        (WebCore::ShadowRoot::registerElementShadow):
+        (WebCore::ShadowRoot::unregisterElementShadow):
+        (WebCore::ShadowRoot::hasElementShadow):
+        (WebCore::ShadowRoot::countElementShadow):
+        * testing/Internals.cpp:
+        (WebCore::Internals::countElementShadow):
+        (WebCore):
+        * testing/Internals.h:
+        (Internals):
+        * testing/Internals.idl:
+
 2012-11-06  Pavel Feldman  <pfeldman@chromium.org>
 
         Web Inspector: show "debugging session terminated" message when remote debuggign connection is closed unexpectedly.
index 85a0027..c62396a 100644 (file)
@@ -55,9 +55,11 @@ ShadowRoot::ShadowRoot(Document* document)
     , m_next(0)
     , m_applyAuthorStyles(false)
     , m_resetStyleInheritance(false)
+    , m_registeredWithParentShadowRoot(false)
     , m_insertionPointAssignedTo(0)
     , m_numberOfShadowElementChildren(0)
     , m_numberOfContentElementChildren(0)
+    , m_numberOfElementShadowChildren(0)
     , m_numberOfStyles(0)
 {
     ASSERT(document);
@@ -235,6 +237,42 @@ void ShadowRoot::attach()
     styleResolver->popParentShadowRoot(this);
 }
 
+Node::InsertionNotificationRequest ShadowRoot::insertedInto(ContainerNode* insertionPoint)
+{
+    DocumentFragment::insertedInto(insertionPoint);
+
+    if (!insertionPoint->inDocument() || !isOldest())
+        return InsertionDone;
+
+    // FIXME: When parsing <video controls>, insertedInto() is called many times without invoking removedFrom.
+    // For now, we check m_registeredWithParentShadowroot. We would like to ASSERT(!m_registeredShadowRoot) here.
+    // https://bugs.webkit.org/show_bug.cig?id=101316
+    if (m_registeredWithParentShadowRoot)
+        return InsertionDone;
+
+    if (ShadowRoot* root = host()->shadowRoot()) {
+        root->registerElementShadow();
+        m_registeredWithParentShadowRoot = true;
+    }
+
+    return InsertionDone;
+}
+
+void ShadowRoot::removedFrom(ContainerNode* insertionPoint)
+{
+    if (insertionPoint->inDocument() && m_registeredWithParentShadowRoot) {
+        ShadowRoot* root = host()->shadowRoot();
+        if (!root)
+            root = insertionPoint->shadowRoot();
+
+        if (root)
+            root->unregisterElementShadow();
+        m_registeredWithParentShadowRoot = false;
+    }
+
+    DocumentFragment::removedFrom(insertionPoint);
+}
+
 void ShadowRoot::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
 {
     ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
index 0cc0a84..0675427 100644 (file)
@@ -83,6 +83,9 @@ public:
 
     virtual void attach();
 
+    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
+    virtual void removedFrom(ContainerNode*) OVERRIDE;
+
     bool isUsedForRendering() const;
     InsertionPoint* assignedTo() const;
     void setAssignedTo(InsertionPoint*);
@@ -95,6 +98,11 @@ public:
     void unregisterContentElement() { --m_numberOfContentElementChildren; }
     bool hasContentElement() const { return m_numberOfContentElementChildren > 0; }
 
+    void registerElementShadow() { ++m_numberOfElementShadowChildren; }
+    void unregisterElementShadow() { ASSERT(hasElementShadow()); --m_numberOfElementShadowChildren; }
+    bool hasElementShadow() const { return m_numberOfElementShadowChildren > 0; }
+    size_t countElementShadow() const { return m_numberOfElementShadowChildren; }
+
     virtual void registerScopedHTMLStyleChild() OVERRIDE;
     virtual void unregisterScopedHTMLStyleChild() OVERRIDE;
 
@@ -119,9 +127,11 @@ private:
     bool m_applyAuthorStyles : 1;
     bool m_resetStyleInheritance : 1;
     bool m_isAuthorShadowRoot : 1;
+    bool m_registeredWithParentShadowRoot : 1;
     InsertionPoint* m_insertionPointAssignedTo;
     size_t m_numberOfShadowElementChildren;
     size_t m_numberOfContentElementChildren;
+    size_t m_numberOfElementShadowChildren;
     size_t m_numberOfStyles;
 };
 
index 2af455d..b453fb7 100644 (file)
@@ -324,6 +324,16 @@ bool Internals::hasContentElement(const Node* root, ExceptionCode& ec) const
     return 0;
 }
 
+size_t Internals::countElementShadow(const Node* root, ExceptionCode& ec) const
+{
+    if (!root || !root->isShadowRoot()) {
+        ec = INVALID_ACCESS_ERR;
+        return 0;
+    }
+
+    return toShadowRoot(root)->countElementShadow();
+}
+
 bool Internals::attached(Node* node, ExceptionCode& ec)
 {
     if (!node) {
index f94aad6..2111739 100644 (file)
@@ -86,6 +86,7 @@ public:
     String shadowRootType(const Node*, ExceptionCode&) const;
     bool hasShadowInsertionPoint(const Node*, ExceptionCode&) const;
     bool hasContentElement(const Node*, ExceptionCode&) const;
+    size_t countElementShadow(const Node*, ExceptionCode&) const;
     Element* includerFor(Node*, ExceptionCode&);
     String shadowPseudoId(Element*, ExceptionCode&);
     void setShadowPseudoId(Element*, const String&, ExceptionCode&);
index 5edc5bf..7a5ab7b 100644 (file)
@@ -50,6 +50,7 @@
     DOMString shadowRootType(in Node root) raises (DOMException);
     boolean hasShadowInsertionPoint(in Node root) raises (DOMException);
     boolean hasContentElement(in Node root) raises (DOMException);
+    unsigned long countElementShadow(in Node Root) raises (DOMException);
     Element includerFor(in Node node) raises (DOMException);
     DOMString shadowPseudoId(in Element element) raises (DOMException);
     void setShadowPseudoId(in Element element, in DOMString id) raises (DOMException);