- 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()