From 135e0b012c7fbb05945db97e589a1b7337160427 Mon Sep 17 00:00:00 2001 From: "commit-queue@webkit.org" Date: Wed, 1 Feb 2012 06:39:11 +0000 Subject: [PATCH] Content element should be able to be dynamically added/removed/replaced in a shadow tree. https://bugs.webkit.org/show_bug.cgi?id=76611 Patch by Shinya Kawanaka on 2012-01-31 Reviewed by Hajime Morita. Source/WebCore: When a content element is added/removed/replaced in a shadow tree, we have to recreate the shadow tree to recalculate inclusions of content elements. Currently we didn't recalculate it when content element is removed. (When added, it is recalculated.) This patch enables us to recalcurate the shadow tree when content element is removed. Test: fast/dom/shadow/content-element-move.html * dom/Element.cpp: (WebCore::Element::attach): If a shadow root exists, attaches shadow tree before attaching child elements. * dom/ShadowRoot.cpp: (WebCore::ShadowRoot::recalcShadowTreeStyle): Recalculates light children and shadow tree. (WebCore::ShadowRoot::reattachHostChildrenAndShadow): Detaches shadow tree and host light children, and attaches them again. * dom/ShadowRoot.h: Added a flag to recalculate shadow tree. (WebCore::ShadowRoot::setNeedsShadowTreeStyleRecalc): (WebCore::ShadowRoot::clearNeedsShadowTreeStyleRecalc): (WebCore::ShadowRoot::needsShadowTreeStyleRecalc): * html/shadow/HTMLContentElement.cpp: (WebCore::HTMLContentElement::attach): Does not need to detach included elements, because they are not attached in ContainerNode anymore. (WebCore::HTMLContentElement::detach): When a content element detached, reattaches a shadow tree. LayoutTests: Test cases for appending/removing/replacing content element in a shadow tree. * fast/dom/shadow/content-element-move-expected.txt: Added. * fast/dom/shadow/content-element-move.html: Added. git-svn-id: http://svn.webkit.org/repository/webkit/trunk@106432 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- LayoutTests/ChangeLog | 12 + .../dom/shadow/content-element-move-expected.txt | 24 + .../fast/dom/shadow/content-element-move.html | 504 +++++++++++++++++++++ Source/WebCore/ChangeLog | 33 ++ Source/WebCore/dom/Element.cpp | 19 +- Source/WebCore/dom/ShadowRoot.cpp | 23 +- Source/WebCore/dom/ShadowRoot.h | 23 +- Source/WebCore/html/shadow/HTMLContentElement.cpp | 8 +- 8 files changed, 636 insertions(+), 10 deletions(-) create mode 100644 LayoutTests/fast/dom/shadow/content-element-move-expected.txt create mode 100644 LayoutTests/fast/dom/shadow/content-element-move.html diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog index ad4c367..6ad605f 100644 --- a/LayoutTests/ChangeLog +++ b/LayoutTests/ChangeLog @@ -1,3 +1,15 @@ +2012-01-31 Shinya Kawanaka + + Content element should be able to be dynamically added/removed/replaced in a shadow tree. + https://bugs.webkit.org/show_bug.cgi?id=76611 + + Reviewed by Hajime Morita. + + Test cases for appending/removing/replacing content element in a shadow tree. + + * fast/dom/shadow/content-element-move-expected.txt: Added. + * fast/dom/shadow/content-element-move.html: Added. + 2012-01-31 Ryuan Choi [EFL] Add basic DRT/Efl implementation to support viewport test. diff --git a/LayoutTests/fast/dom/shadow/content-element-move-expected.txt b/LayoutTests/fast/dom/shadow/content-element-move-expected.txt new file mode 100644 index 0000000..49fee1d --- /dev/null +++ b/LayoutTests/fast/dom/shadow/content-element-move-expected.txt @@ -0,0 +1,24 @@ +testRemoveContent +PASS +testRemoveContentToRecalc1 +PASS +testRemoveContentToRecalc2 +PASS +testRemoveContentAndRemoveLightChildren +PASS +testRemoveContentAndRemoveShadowRoot1 +PASS +testRemoveContentAndRemoveShadowRoot2 +PASS +testAppendContent1 +PASS +testAppendContent2 +PASS +testAppendContent3 +PASS +testChangeOrderOfContent +PASS +testMoveLightChildOut +PASS +TEST COMPLETED + diff --git a/LayoutTests/fast/dom/shadow/content-element-move.html b/LayoutTests/fast/dom/shadow/content-element-move.html new file mode 100644 index 0000000..0617b35 --- /dev/null +++ b/LayoutTests/fast/dom/shadow/content-element-move.html @@ -0,0 +1,504 @@ + + + + + + + + +
+
+

+
+
+
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 4285894..8f16e5a 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,36 @@
+2012-01-31  Shinya Kawanaka  
+
+        Content element should be able to be dynamically added/removed/replaced in a shadow tree.
+        https://bugs.webkit.org/show_bug.cgi?id=76611
+
+        Reviewed by Hajime Morita.
+
+        When a content element is added/removed/replaced in a shadow tree, we have to recreate
+        the shadow tree to recalculate inclusions of content elements. Currently we didn't recalculate it
+        when content element is removed. (When added, it is recalculated.)
+        This patch enables us to recalcurate the shadow tree when content element is removed.
+
+        Test: fast/dom/shadow/content-element-move.html
+
+        * dom/Element.cpp:
+        (WebCore::Element::attach):
+          If a shadow root exists, attaches shadow tree before attaching child elements.
+        * dom/ShadowRoot.cpp:
+        (WebCore::ShadowRoot::recalcShadowTreeStyle):
+          Recalculates light children and shadow tree.
+        (WebCore::ShadowRoot::reattachHostChildrenAndShadow):
+          Detaches shadow tree and host light children, and attaches them again.
+        * dom/ShadowRoot.h:
+          Added a flag to recalculate shadow tree.
+        (WebCore::ShadowRoot::setNeedsShadowTreeStyleRecalc):
+        (WebCore::ShadowRoot::clearNeedsShadowTreeStyleRecalc):
+        (WebCore::ShadowRoot::needsShadowTreeStyleRecalc):
+        * html/shadow/HTMLContentElement.cpp:
+        (WebCore::HTMLContentElement::attach):
+          Does not need to detach included elements, because they are not attached in ContainerNode anymore.
+        (WebCore::HTMLContentElement::detach):
+          When a content element detached, reattaches a shadow tree.
+
 2012-01-31  Joe Thomas  
 
         https://bugs.webkit.org/show_bug.cgi?id=76801
diff --git a/Source/WebCore/dom/Element.cpp b/Source/WebCore/dom/Element.cpp
index e1a6376..43673a6 100644
--- a/Source/WebCore/dom/Element.cpp
+++ b/Source/WebCore/dom/Element.cpp
@@ -940,16 +940,25 @@ void Element::attach()
     RenderWidget::suspendWidgetHierarchyUpdates();
 
     createRendererIfNeeded();
-    
     StyleSelectorParentPusher parentPusher(this);
 
-    if (firstChild())
-        parentPusher.push();
-    ContainerNode::attach();
-
+    // When a shadow root exists, it does the work of attaching the children.
     if (ShadowRoot* shadow = shadowRoot()) {
+        Node::attach();
         parentPusher.push();
         shadow->attach();
+
+        // In a shadow tree, some of light children may be attached by 'content' element.
+        // However, when there is no content element or content element does not select
+        // all light children, we have to attach the rest of light children here.
+        for (Node* child = firstChild(); child; child = child->nextSibling()) {
+            if (!child->attached())
+                child->attach();
+        }
+    } else {
+        if (firstChild())
+            parentPusher.push();
+        ContainerNode::attach();
     }
 
     if (hasRareData()) {   
diff --git a/Source/WebCore/dom/ShadowRoot.cpp b/Source/WebCore/dom/ShadowRoot.cpp
index 4022e9a..316bc28 100644
--- a/Source/WebCore/dom/ShadowRoot.cpp
+++ b/Source/WebCore/dom/ShadowRoot.cpp
@@ -99,8 +99,8 @@ bool ShadowRoot::childTypeAllowed(NodeType type) const
 
 void ShadowRoot::recalcShadowTreeStyle(StyleChange change)
 {
-    if (hasContentElement())
-        reattach();
+    if (needsShadowTreeStyleRecalc() || hasContentElement())
+        reattachHostChildrenAndShadow();
     else {
         for (Node* n = firstChild(); n; n = n->nextSibling()) {
             if (n->isElementNode())
@@ -110,6 +110,7 @@ void ShadowRoot::recalcShadowTreeStyle(StyleChange change)
         }
     }
 
+    clearNeedsShadowTreeStyleRecalc();
     clearNeedsStyleRecalc();
     clearChildNeedsStyleRecalc();
 }
@@ -168,6 +169,24 @@ void ShadowRoot::attach()
         m_inclusions->didSelect();
 }
 
+void ShadowRoot::reattachHostChildrenAndShadow()
+{
+    if (!host())
+        return;
+
+    for (Node* child = host()->firstChild(); child; child = child->nextSibling()) {
+        if (child->attached())
+            child->detach();
+    }
+
+    reattach();
+
+    for (Node* child = host()->firstChild(); child; child = child->nextSibling()) {
+        if (!child->attached())
+            child->attach();
+    }
+}
+
 ContentInclusionSelector* ShadowRoot::inclusions() const
 {
     return m_inclusions.get();
diff --git a/Source/WebCore/dom/ShadowRoot.h b/Source/WebCore/dom/ShadowRoot.h
index 836e4aa..f711e56 100644
--- a/Source/WebCore/dom/ShadowRoot.h
+++ b/Source/WebCore/dom/ShadowRoot.h
@@ -43,11 +43,16 @@ public:
 
     void recalcShadowTreeStyle(StyleChange);
 
+    void setNeedsShadowTreeStyleRecalc();
+    void clearNeedsShadowTreeStyleRecalc();
+    bool needsShadowTreeStyleRecalc();
+
     HTMLContentElement* includerFor(Node*) const;
     void hostChildrenChanged();
     bool isInclusionSelectorActive() const;
 
     virtual void attach();
+    void reattachHostChildrenAndShadow();
 
     virtual bool applyAuthorSheets() const;
     void setApplyAuthorSheets(bool);
@@ -68,7 +73,8 @@ private:
 
     bool hasContentElement() const;
 
-    bool m_applyAuthorSheets;
+    bool m_applyAuthorSheets : 1;
+    bool m_needsShadowTreeStyleRecalc : 1;
     OwnPtr m_inclusions;
 };
 
@@ -77,6 +83,21 @@ inline PassRefPtr ShadowRoot::create(Document* document)
     return adoptRef(new ShadowRoot(document));
 }
 
+inline void ShadowRoot::setNeedsShadowTreeStyleRecalc()
+{
+    m_needsShadowTreeStyleRecalc = true;
+}
+
+inline void ShadowRoot::clearNeedsShadowTreeStyleRecalc()
+{
+    m_needsShadowTreeStyleRecalc = false;
+}
+
+inline bool ShadowRoot::needsShadowTreeStyleRecalc()
+{
+    return m_needsShadowTreeStyleRecalc;
+}
+
 inline ShadowRoot* toShadowRoot(Node* node)
 {
     ASSERT(!node || node->nodeType() == Node::SHADOW_ROOT_NODE);
diff --git a/Source/WebCore/html/shadow/HTMLContentElement.cpp b/Source/WebCore/html/shadow/HTMLContentElement.cpp
index 8c6edb6..aef5760 100644
--- a/Source/WebCore/html/shadow/HTMLContentElement.cpp
+++ b/Source/WebCore/html/shadow/HTMLContentElement.cpp
@@ -83,8 +83,6 @@ void HTMLContentElement::attach()
 
     if (root) {
         for (ShadowInclusion* inclusion = m_inclusions->first(); inclusion; inclusion = inclusion->next())
-            inclusion->content()->detach();
-        for (ShadowInclusion* inclusion = m_inclusions->first(); inclusion; inclusion = inclusion->next())
             inclusion->content()->attach();
     }
 }
@@ -94,6 +92,12 @@ void HTMLContentElement::detach()
     if (ShadowRoot* root = toShadowRoot(shadowTreeRootNode())) {
         if (ContentInclusionSelector* selector = root->inclusions())
             selector->unselect(m_inclusions.get());
+
+        // When content element is detached, shadow tree should be recreated to re-calculate inclusions for
+        // other content elements.
+        root->setNeedsShadowTreeStyleRecalc();
+        if (root->shadowHost())
+            root->shadowHost()->setNeedsStyleRecalc();
     }
 
     ASSERT(m_inclusions->isEmpty());
-- 
2.7.4