Title: [110935] trunk
Revision
110935
Author
[email protected]
Date
2012-03-15 20:20:26 -0700 (Thu, 15 Mar 2012)

Log Message

[Crash] Adding <content> into a ShadowRoot causes crash.
https://bugs.webkit.org/show_bug.cgi?id=80020

Reviewed by Hajime Morita.

Source/WebCore:

The problem is <content> tries to select host children though it is not prepared.
Since populating host children for insertion points is performed just before
attaching a shadow tree, we should recalculate whole shadow tree if <content> is
appended as a child.

However, element->appendChild() does not know the element is in a shadow tree or not.
We have to ensure reattaching whole shadow tree here.

So this patch adds some phases to HTMLContentSelector so that we can check node
distribution algorihm is begin processed or not. If not we cannot select anything,
but we have to enable a flag to reattach whole shadow tree.

Tests: fast/dom/shadow/shadow-content-crash-expected.html
       fast/dom/shadow/shadow-content-crash.html

* dom/ShadowTree.cpp:
(WebCore::ShadowTree::attach):
(WebCore::ShadowTree::insertionPointFor):
* dom/ShadowTree.h:
(WebCore):
(ShadowTree):
(WebCore::ShadowTree::selector):
* html/shadow/HTMLContentSelector.cpp:
(WebCore::HTMLContentSelector::HTMLContentSelector):
(WebCore::HTMLContentSelector::select):
(WebCore::HTMLContentSelector::willSelect):
(WebCore):
(WebCore::HTMLContentSelector::didSelect):
(WebCore::HTMLContentSelector::populateIfNecessary):
* html/shadow/HTMLContentSelector.h:
(HTMLContentSelector):
(WebCore::HTMLContentSelector::isSelecting):
(WebCore):
(WebCore::HTMLContentSelector::hasPopulated):
* html/shadow/InsertionPoint.cpp:
(WebCore::InsertionPoint::distributeHostChildren):
(WebCore::InsertionPoint::clearDistribution):

LayoutTests:

* fast/dom/shadow/shadow-content-crash-expected.html: Added.
* fast/dom/shadow/shadow-content-crash.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (110934 => 110935)


--- trunk/LayoutTests/ChangeLog	2012-03-16 03:14:35 UTC (rev 110934)
+++ trunk/LayoutTests/ChangeLog	2012-03-16 03:20:26 UTC (rev 110935)
@@ -1,3 +1,13 @@
+2012-03-15  Shinya Kawanaka  <[email protected]>
+
+        [Crash] Adding <content> into a ShadowRoot causes crash.
+        https://bugs.webkit.org/show_bug.cgi?id=80020
+
+        Reviewed by Hajime Morita.
+
+        * fast/dom/shadow/shadow-content-crash-expected.html: Added.
+        * fast/dom/shadow/shadow-content-crash.html: Added.
+
 2012-03-15  Mike Lawther  <[email protected]>
 
         CSS3 calc: mixed percent/absolute expressions for gradients

Added: trunk/LayoutTests/fast/dom/shadow/shadow-content-crash-expected.html (0 => 110935)


--- trunk/LayoutTests/fast/dom/shadow/shadow-content-crash-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/dom/shadow/shadow-content-crash-expected.html	2012-03-16 03:20:26 UTC (rev 110935)
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Shadow Content Element Crash</title>
+</head>
+<body>
+<p>This test confirms adding a content element into a shadow root does not cause crash.</p>
+
+<div>PASS<div>
+</body>
+</html>

Added: trunk/LayoutTests/fast/dom/shadow/shadow-content-crash.html (0 => 110935)


--- trunk/LayoutTests/fast/dom/shadow/shadow-content-crash.html	                        (rev 0)
+++ trunk/LayoutTests/fast/dom/shadow/shadow-content-crash.html	2012-03-16 03:20:26 UTC (rev 110935)
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Shadow Content Element Crash</title>
+</head>
+<body>
+<p>This test confirms adding a content element into a shadow root does not cause crash.</p>
+
+<div id='container'>FAIL</div>
+
+<script>
+var div = document.getElementById('container');
+var root = new WebKitShadowRoot(div);
+root.innerHTML = "<content select='span'>PASS</content>";
+</script>
+
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (110934 => 110935)


--- trunk/Source/WebCore/ChangeLog	2012-03-16 03:14:35 UTC (rev 110934)
+++ trunk/Source/WebCore/ChangeLog	2012-03-16 03:20:26 UTC (rev 110935)
@@ -1,3 +1,48 @@
+2012-03-15  Shinya Kawanaka  <[email protected]>
+
+        [Crash] Adding <content> into a ShadowRoot causes crash.
+        https://bugs.webkit.org/show_bug.cgi?id=80020
+
+        Reviewed by Hajime Morita.
+
+        The problem is <content> tries to select host children though it is not prepared.
+        Since populating host children for insertion points is performed just before
+        attaching a shadow tree, we should recalculate whole shadow tree if <content> is
+        appended as a child.
+
+        However, element->appendChild() does not know the element is in a shadow tree or not.
+        We have to ensure reattaching whole shadow tree here.
+
+        So this patch adds some phases to HTMLContentSelector so that we can check node
+        distribution algorihm is begin processed or not. If not we cannot select anything,
+        but we have to enable a flag to reattach whole shadow tree.
+
+        Tests: fast/dom/shadow/shadow-content-crash-expected.html
+               fast/dom/shadow/shadow-content-crash.html
+
+        * dom/ShadowTree.cpp:
+        (WebCore::ShadowTree::attach):
+        (WebCore::ShadowTree::insertionPointFor):
+        * dom/ShadowTree.h:
+        (WebCore):
+        (ShadowTree):
+        (WebCore::ShadowTree::selector):
+        * html/shadow/HTMLContentSelector.cpp:
+        (WebCore::HTMLContentSelector::HTMLContentSelector):
+        (WebCore::HTMLContentSelector::select):
+        (WebCore::HTMLContentSelector::willSelect):
+        (WebCore):
+        (WebCore::HTMLContentSelector::didSelect):
+        (WebCore::HTMLContentSelector::populateIfNecessary):
+        * html/shadow/HTMLContentSelector.h:
+        (HTMLContentSelector):
+        (WebCore::HTMLContentSelector::isSelecting):
+        (WebCore):
+        (WebCore::HTMLContentSelector::hasPopulated):
+        * html/shadow/InsertionPoint.cpp:
+        (WebCore::InsertionPoint::distributeHostChildren):
+        (WebCore::InsertionPoint::clearDistribution):
+
 2012-03-15  Mike Lawther  <[email protected]>
 
         CSS3 calc: mixed percent/absolute expressions for gradients

Modified: trunk/Source/WebCore/dom/ShadowTree.cpp (110934 => 110935)


--- trunk/Source/WebCore/dom/ShadowTree.cpp	2012-03-16 03:14:35 UTC (rev 110934)
+++ trunk/Source/WebCore/dom/ShadowTree.cpp	2012-03-16 03:20:26 UTC (rev 110935)
@@ -30,7 +30,6 @@
 #include "CSSStyleSelector.h"
 #include "Document.h"
 #include "Element.h"
-#include "HTMLContentSelector.h"
 #include "HTMLShadowElement.h"
 #include "InspectorInstrumentation.h"
 #include "RuntimeEnabledFeatures.h"
@@ -178,15 +177,14 @@
 {
     // Children of m_selector is populated lazily in
     // ensureSelector(), and here we just ensure that it is in clean state.
-    ASSERT(!selector() || !selector()->hasCandidates());
+    ASSERT(!selector().hasPopulated());
 
+    selector().willSelect();
     for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
         if (!root->attached())
             root->attach();
     }
-
-    if (HTMLContentSelector* contentSelector = selector())
-        contentSelector->didSelect();
+    selector().didSelect();
 }
 
 void ShadowTree::attachHost(Element* host)
@@ -222,9 +220,7 @@
         return 0;
     }
 
-    if (!m_selector)
-        return 0;
-    HTMLContentSelection* found = m_selector->findFor(node);
+    HTMLContentSelection* found = selector().findFor(node);
     if (!found)
         return 0;
     return found->insertionPoint();
@@ -317,12 +313,4 @@
     hostNode->attachChildrenIfNeeded();
 }
 
-HTMLContentSelector* ShadowTree::ensureSelector()
-{
-    if (!m_selector)
-        m_selector = adoptPtr(new HTMLContentSelector());
-    m_selector->willSelectOver(host());
-    return m_selector.get();
-}
-
 } // namespace

Modified: trunk/Source/WebCore/dom/ShadowTree.h (110934 => 110935)


--- trunk/Source/WebCore/dom/ShadowTree.h	2012-03-16 03:14:35 UTC (rev 110934)
+++ trunk/Source/WebCore/dom/ShadowTree.h	2012-03-16 03:20:26 UTC (rev 110935)
@@ -28,6 +28,7 @@
 #define ShadowTree_h
 
 #include "ExceptionCode.h"
+#include "HTMLContentSelector.h"
 #include "ShadowRoot.h"
 #include <wtf/DoublyLinkedList.h>
 #include <wtf/Noncopyable.h>
@@ -38,7 +39,6 @@
 
 class Node;
 class Element;
-class HTMLContentSelector;
 class InsertionPoint;
 class TreeScope;
 
@@ -47,6 +47,8 @@
     ShadowTree();
     ~ShadowTree();
 
+    Element* host() const;
+
     bool hasShadowRoot() const;
     ShadowRoot* youngestShadowRoot() const;
     ShadowRoot* oldestShadowRoot() const;
@@ -79,14 +81,13 @@
 
     InsertionPoint* insertionPointFor(Node*) const;
 
-    HTMLContentSelector* selector() const;
-    HTMLContentSelector* ensureSelector();
+    HTMLContentSelector& selector();
+    const HTMLContentSelector& selector() const;
 
 private:
-    Element* host() const;
 
     DoublyLinkedList<ShadowRoot> m_shadowRoots;
-    OwnPtr<HTMLContentSelector> m_selector;
+    HTMLContentSelector m_selector;
     bool m_needsRecalculateContent : 1;
     WTF_MAKE_NONCOPYABLE(ShadowTree);
 };
@@ -106,11 +107,16 @@
     return m_shadowRoots.tail();
 }
 
-inline HTMLContentSelector* ShadowTree::selector() const
+inline HTMLContentSelector& ShadowTree::selector()
 {
-    return m_selector.get();
+    return m_selector;
 }
 
+inline const HTMLContentSelector& ShadowTree::selector() const
+{
+    return m_selector;
+}
+
 inline void ShadowTree::clearNeedsReattachHostChildrenAndShadow()
 {
     m_needsRecalculateContent = false;

Modified: trunk/Source/WebCore/html/shadow/HTMLContentSelector.cpp (110934 => 110935)


--- trunk/Source/WebCore/html/shadow/HTMLContentSelector.cpp	2012-03-16 03:14:35 UTC (rev 110934)
+++ trunk/Source/WebCore/html/shadow/HTMLContentSelector.cpp	2012-03-16 03:20:26 UTC (rev 110935)
@@ -100,6 +100,7 @@
 }
 
 HTMLContentSelector::HTMLContentSelector()
+    : m_phase(SelectionPrevented)
 {
 }
 
@@ -110,6 +111,7 @@
 
 void HTMLContentSelector::select(InsertionPoint* insertionPoint, HTMLContentSelectionList* selections)
 {
+    ASSERT(m_phase == HostChildrenPopulated);
     ASSERT(selections->isEmpty());
 
     ContentSelectorQuery query(insertionPoint);
@@ -141,16 +143,28 @@
     return m_selectionSet.find(key);
 }
 
+void HTMLContentSelector::willSelect()
+{
+    m_phase = SelectionStarted;
+}
+
 void HTMLContentSelector::didSelect()
 {
+    ASSERT(m_phase != SelectionPrevented);
+    m_phase = SelectionPrevented;
     m_candidates.clear();
 }
 
-void HTMLContentSelector::willSelectOver(Element* shadowHost)
+void HTMLContentSelector::populateIfNecessary(Element* shadowHost)
 {
-    if (!m_candidates.isEmpty())
+    if (hasPopulated())
         return;
+
+    ASSERT(m_candidates.isEmpty());
     ASSERT(shadowHost);
+    ASSERT(m_phase == SelectionStarted);
+
+    m_phase = HostChildrenPopulated;
     for (Node* node = shadowHost->firstChild(); node; node = node->nextSibling())
         m_candidates.append(node);
 }

Modified: trunk/Source/WebCore/html/shadow/HTMLContentSelector.h (110934 => 110935)


--- trunk/Source/WebCore/html/shadow/HTMLContentSelector.h	2012-03-16 03:14:35 UTC (rev 110934)
+++ trunk/Source/WebCore/html/shadow/HTMLContentSelector.h	2012-03-16 03:20:26 UTC (rev 110935)
@@ -134,18 +134,38 @@
     void unselect(HTMLContentSelectionList*);
     HTMLContentSelection* findFor(Node* key) const;
 
-    void willSelectOver(Element* shadowHost);
+    void willSelect();
+    bool isSelecting() const;
     void didSelect();
-    bool hasCandidates() const { return !m_candidates.isEmpty(); }
 
+    void populateIfNecessary(Element* shadowHost);
+    bool hasPopulated() const;
+
 private:
+    enum SelectingPhase {
+        SelectionPrevented,
+        SelectionStarted,
+        HostChildrenPopulated,
+    };
+
     void removeFromSet(HTMLContentSelectionList*);
     void addToSet(HTMLContentSelectionList*);
 
     Vector<RefPtr<Node> > m_candidates;
     HTMLContentSelectionSet m_selectionSet;
+    SelectingPhase m_phase;
 };
 
+inline bool HTMLContentSelector::isSelecting() const
+{
+    return m_phase != SelectionPrevented;
 }
 
+inline bool HTMLContentSelector::hasPopulated() const
+{
+    return m_phase == HostChildrenPopulated;
+}
+
+}
+
 #endif

Modified: trunk/Source/WebCore/html/shadow/InsertionPoint.cpp (110934 => 110935)


--- trunk/Source/WebCore/html/shadow/InsertionPoint.cpp	2012-03-16 03:14:35 UTC (rev 110934)
+++ trunk/Source/WebCore/html/shadow/InsertionPoint.cpp	2012-03-16 03:20:26 UTC (rev 110935)
@@ -109,15 +109,21 @@
 
 inline void InsertionPoint::distributeHostChildren(ShadowTree* tree)
 {
-    HTMLContentSelector* selector = tree->ensureSelector();
-    selector->unselect(&m_selections);
-    selector->select(this, &m_selections);
+    if (!tree->selector().isSelecting()) {
+        // If HTMLContentSelector is not int selecting phase, it means InsertionPoint is attached from
+        // non-ShadowTree node. To run distribute algorithm, we have to reattach ShadowTree.
+        tree->setNeedsReattachHostChildrenAndShadow();
+        return;
+    }
+
+    tree->selector().populateIfNecessary(tree->host());
+    tree->selector().unselect(&m_selections);
+    tree->selector().select(this, &m_selections);
 }
 
 inline void InsertionPoint::clearDistribution(ShadowTree* tree)
 {
-    if (HTMLContentSelector* selector = tree->selector())
-        selector->unselect(&m_selections);
+    tree->selector().unselect(&m_selections);
 }
 
 inline void InsertionPoint::attachDistributedNode()
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to