Commit 3f29758a authored by rniwa@webkit.org's avatar rniwa@webkit.org

Turn forbidEventDispatch and allowEventDispatch into a RAII object

https://bugs.webkit.org/show_bug.cgi?id=96717

Reviewed by Abhishek Arya.

Replaced forbidEventDispatch and allowEventDispatch by AssertNoEventDispatch.

* dom/ContainerNode.cpp:
(WebCore):
(WebCore::ContainerNode::insertBeforeCommon):
(WebCore::ContainerNode::replaceChild):
(WebCore::ContainerNode::removeBetween):
(WebCore::ContainerNode::removeChildren):
(WebCore::ContainerNode::appendChild):
(WebCore::ContainerNode::parserAddChild):
(WebCore::dispatchChildInsertionEvents):
(WebCore::dispatchChildRemovalEvents):
* dom/ContainerNode.h:
(AssertNoEventDispatch):
(WebCore::AssertNoEventDispatch::AssertNoEventDispatch):
(WebCore::AssertNoEventDispatch::~AssertNoEventDispatch):
(WebCore::AssertNoEventDispatch::isEventDispatchForbidden):
(WebCore):
* dom/ContainerNodeAlgorithms.h:
(WebCore::ChildNodeInsertionNotifier::notifyNodeInsertedIntoTree):
(WebCore::ChildNodeInsertionNotifier::notify):
(WebCore::ChildNodeRemovalNotifier::notifyNodeRemovedFromTree):
* dom/Document.cpp:
(WebCore::Document::dispatchWindowEvent):
(WebCore::Document::dispatchWindowLoadEvent):
* dom/EventDispatcher.cpp:
(WebCore::EventDispatcher::dispatchEvent):
* dom/EventTarget.cpp:
(WebCore):
(WebCore::EventTarget::fireEventListeners):
* dom/EventTarget.h:
(WebCore):
* dom/Node.cpp:
(WebCore::Node::dispatchSubtreeModifiedEvent):
(WebCore::Node::dispatchFocusInEvent):
(WebCore::Node::dispatchFocusOutEvent):
(WebCore::Node::dispatchDOMActivateEvent):
* dom/WebKitNamedFlow.cpp:
(WebCore::WebKitNamedFlow::dispatchRegionLayoutUpdateEvent):
* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::loadInternal):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@128673 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 37842cc9
2012-09-14 Ryosuke Niwa <rniwa@webkit.org>
Turn forbidEventDispatch and allowEventDispatch into a RAII object
https://bugs.webkit.org/show_bug.cgi?id=96717
Reviewed by Abhishek Arya.
Replaced forbidEventDispatch and allowEventDispatch by AssertNoEventDispatch.
* dom/ContainerNode.cpp:
(WebCore):
(WebCore::ContainerNode::insertBeforeCommon):
(WebCore::ContainerNode::replaceChild):
(WebCore::ContainerNode::removeBetween):
(WebCore::ContainerNode::removeChildren):
(WebCore::ContainerNode::appendChild):
(WebCore::ContainerNode::parserAddChild):
(WebCore::dispatchChildInsertionEvents):
(WebCore::dispatchChildRemovalEvents):
* dom/ContainerNode.h:
(AssertNoEventDispatch):
(WebCore::AssertNoEventDispatch::AssertNoEventDispatch):
(WebCore::AssertNoEventDispatch::~AssertNoEventDispatch):
(WebCore::AssertNoEventDispatch::isEventDispatchForbidden):
(WebCore):
* dom/ContainerNodeAlgorithms.h:
(WebCore::ChildNodeInsertionNotifier::notifyNodeInsertedIntoTree):
(WebCore::ChildNodeInsertionNotifier::notify):
(WebCore::ChildNodeRemovalNotifier::notifyNodeRemovedFromTree):
* dom/Document.cpp:
(WebCore::Document::dispatchWindowEvent):
(WebCore::Document::dispatchWindowLoadEvent):
* dom/EventDispatcher.cpp:
(WebCore::EventDispatcher::dispatchEvent):
* dom/EventTarget.cpp:
(WebCore):
(WebCore::EventTarget::fireEventListeners):
* dom/EventTarget.h:
(WebCore):
* dom/Node.cpp:
(WebCore::Node::dispatchSubtreeModifiedEvent):
(WebCore::Node::dispatchFocusInEvent):
(WebCore::Node::dispatchFocusOutEvent):
(WebCore::Node::dispatchDOMActivateEvent):
* dom/WebKitNamedFlow.cpp:
(WebCore::WebKitNamedFlow::dispatchRegionLayoutUpdateEvent):
* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::loadInternal):
2012-09-14 Mike West <mkwst@chromium.org>
JSC should throw a more descriptive exception when blocking 'eval' via CSP.
......@@ -64,6 +64,10 @@ static bool s_shouldReEnableMemoryCacheCallsAfterAttach;
ChildNodesLazySnapshot* ChildNodesLazySnapshot::latestSnapshot = 0;
#ifndef NDEBUG
unsigned AssertNoEventDispatch::s_count = 0;
#endif
static void collectTargetNodes(Node* node, NodeVector& nodes)
{
if (node->nodeType() != Node::DOCUMENT_FRAGMENT_NODE) {
......@@ -186,13 +190,13 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce
void ContainerNode::insertBeforeCommon(Node* nextChild, Node* newChild)
{
AssertNoEventDispatch assertNoEventDispatch;
ASSERT(newChild);
ASSERT(!newChild->parentNode()); // Use insertBefore if you need to handle reparenting (and want DOM mutation events).
ASSERT(!newChild->nextSibling());
ASSERT(!newChild->previousSibling());
ASSERT(!newChild->isShadowRoot());
forbidEventDispatch();
Node* prev = nextChild->previousSibling();
ASSERT(m_lastChild != prev);
nextChild->setPreviousSibling(newChild);
......@@ -207,7 +211,6 @@ void ContainerNode::insertBeforeCommon(Node* nextChild, Node* newChild)
newChild->setParentOrHostNode(this);
newChild->setPreviousSibling(prev);
newChild->setNextSibling(nextChild);
allowEventDispatch();
}
void ContainerNode::parserInsertBefore(PassRefPtr<Node> newChild, Node* nextChild)
......@@ -308,12 +311,13 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce
treeScope()->adoptIfNeeded(child);
// Add child before "next".
forbidEventDispatch();
if (next)
insertBeforeCommon(next.get(), child);
else
appendChildToContainer(child, this);
allowEventDispatch();
{
AssertNoEventDispatch assertNoEventDispatch;
if (next)
insertBeforeCommon(next.get(), child);
else
appendChildToContainer(child, this);
}
updateTreeAfterInsertion(this, child, shouldLazyAttach);
}
......@@ -435,11 +439,10 @@ bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec)
void ContainerNode::removeBetween(Node* previousChild, Node* nextChild, Node* oldChild)
{
AssertNoEventDispatch assertNoEventDispatch;
ASSERT(oldChild);
ASSERT(oldChild->parentNode() == this);
forbidEventDispatch();
// Remove from rendering tree
if (oldChild->attached())
oldChild->detach();
......@@ -458,8 +461,6 @@ void ContainerNode::removeBetween(Node* previousChild, Node* nextChild, Node* ol
oldChild->setParentOrHostNode(0);
document()->adoptIfNeeded(oldChild);
allowEventDispatch();
}
void ContainerNode::parserRemoveChild(Node* oldChild)
......@@ -498,47 +499,48 @@ void ContainerNode::removeChildren()
willRemoveChildren(protect.get());
RenderWidget::suspendWidgetHierarchyUpdates();
forbidEventDispatch();
Vector<RefPtr<Node>, 10> removedChildren;
removedChildren.reserveInitialCapacity(childNodeCount());
while (RefPtr<Node> n = m_firstChild) {
Node* next = n->nextSibling();
// Remove the node from the tree before calling detach or removedFromDocument (4427024, 4129744).
// removeChild() does this after calling detach(). There is no explanation for
// this discrepancy between removeChild() and its optimized version removeChildren().
n->setPreviousSibling(0);
n->setNextSibling(0);
n->setParentOrHostNode(0);
document()->adoptIfNeeded(n.get());
m_firstChild = next;
if (n == m_lastChild)
m_lastChild = 0;
removedChildren.append(n.release());
}
size_t removedChildrenCount = removedChildren.size();
size_t i;
// Detach the nodes only after properly removed from the tree because
// a. detaching requires a proper DOM tree (for counters and quotes for
// example) and during the previous loop the next sibling still points to
// the node being removed while the node being removed does not point back
// and does not point to the same parent as its next sibling.
// b. destroying Renderers of standalone nodes is sometimes faster.
for (i = 0; i < removedChildrenCount; ++i) {
Node* removedChild = removedChildren[i].get();
if (removedChild->attached())
removedChild->detach();
}
{
AssertNoEventDispatch assertNoEventDispatch;
Vector<RefPtr<Node>, 10> removedChildren;
removedChildren.reserveInitialCapacity(childNodeCount());
while (RefPtr<Node> n = m_firstChild) {
Node* next = n->nextSibling();
// Remove the node from the tree before calling detach or removedFromDocument (4427024, 4129744).
// removeChild() does this after calling detach(). There is no explanation for
// this discrepancy between removeChild() and its optimized version removeChildren().
n->setPreviousSibling(0);
n->setNextSibling(0);
n->setParentOrHostNode(0);
document()->adoptIfNeeded(n.get());
m_firstChild = next;
if (n == m_lastChild)
m_lastChild = 0;
removedChildren.append(n.release());
}
childrenChanged(false, 0, 0, -static_cast<int>(removedChildrenCount));
size_t removedChildrenCount = removedChildren.size();
size_t i;
// Detach the nodes only after properly removed from the tree because
// a. detaching requires a proper DOM tree (for counters and quotes for
// example) and during the previous loop the next sibling still points to
// the node being removed while the node being removed does not point back
// and does not point to the same parent as its next sibling.
// b. destroying Renderers of standalone nodes is sometimes faster.
for (i = 0; i < removedChildrenCount; ++i) {
Node* removedChild = removedChildren[i].get();
if (removedChild->attached())
removedChild->detach();
}
for (i = 0; i < removedChildrenCount; ++i)
ChildNodeRemovalNotifier(this).notify(removedChildren[i].get());
childrenChanged(false, 0, 0, -static_cast<int>(removedChildrenCount));
allowEventDispatch();
for (i = 0; i < removedChildrenCount; ++i)
ChildNodeRemovalNotifier(this).notify(removedChildren[i].get());
}
RenderWidget::resumeWidgetHierarchyUpdates();
dispatchSubtreeModifiedEvent();
......@@ -589,9 +591,10 @@ bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bo
treeScope()->adoptIfNeeded(child);
// Append child to the end of the list
forbidEventDispatch();
appendChildToContainer(child, this);
allowEventDispatch();
{
AssertNoEventDispatch assertNoEventDispatch;
appendChildToContainer(child, this);
}
updateTreeAfterInsertion(this, child, shouldLazyAttach);
}
......@@ -605,13 +608,13 @@ void ContainerNode::parserAddChild(PassRefPtr<Node> newChild)
ASSERT(newChild);
ASSERT(!newChild->parentNode()); // Use appendChild if you need to handle reparenting (and want DOM mutation events).
forbidEventDispatch();
Node* last = m_lastChild;
// FIXME: This method should take a PassRefPtr.
appendChildToContainer(newChild.get(), this);
treeScope()->adoptIfNeeded(newChild.get());
allowEventDispatch();
{
AssertNoEventDispatch assertNoEventDispatch;
// FIXME: This method should take a PassRefPtr.
appendChildToContainer(newChild.get(), this);
treeScope()->adoptIfNeeded(newChild.get());
}
childrenChanged(true, last, 0, 1);
ChildNodeInsertionNotifier(this).notify(newChild.get());
......@@ -948,7 +951,7 @@ static void dispatchChildInsertionEvents(Node* child)
if (child->isInShadowTree())
return;
ASSERT(!eventDispatchForbidden());
ASSERT(!AssertNoEventDispatch::isEventDispatchForbidden());
RefPtr<Node> c = child;
RefPtr<Document> document = child->document();
......@@ -968,7 +971,7 @@ static void dispatchChildRemovalEvents(Node* child)
if (child->isInShadowTree())
return;
ASSERT(!eventDispatchForbidden());
ASSERT(!AssertNoEventDispatch::isEventDispatchForbidden());
InspectorInstrumentation::willRemoveDOMNode(child->document(), child);
......
......@@ -41,6 +41,35 @@ namespace Private {
void addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer*);
};
class AssertNoEventDispatch {
public:
AssertNoEventDispatch()
{
ASSERT(isMainThread());
#ifndef NDEBUG
s_count++;
#endif
}
~AssertNoEventDispatch()
{
ASSERT(isMainThread());
ASSERT(s_count);
#ifndef NDEBUG
s_count--;
#endif
}
#ifndef NDEBUG
static bool isEventDispatchForbidden() { return s_count; }
#endif
private:
#ifndef NDEBUG
static unsigned s_count;
#endif
};
class ContainerNode : public Node {
public:
virtual ~ContainerNode();
......
......@@ -201,14 +201,12 @@ inline void ChildNodeInsertionNotifier::notifyNodeInsertedIntoDocument(Node* nod
inline void ChildNodeInsertionNotifier::notifyNodeInsertedIntoTree(ContainerNode* node)
{
AssertNoEventDispatch assertNoEventDispatch;
ASSERT(!m_insertionPoint->inDocument());
forbidEventDispatch();
if (Node::InsertionShouldCallDidNotifySubtreeInsertions == node->insertedInto(m_insertionPoint))
m_postInsertionNotificationTargets.append(node);
notifyDescendantInsertedIntoTree(node);
allowEventDispatch();
}
inline void ChildNodeInsertionNotifier::notifyInsertedIntoDocument(Node* node)
......@@ -218,7 +216,7 @@ inline void ChildNodeInsertionNotifier::notifyInsertedIntoDocument(Node* node)
inline void ChildNodeInsertionNotifier::notify(Node* node)
{
ASSERT(!eventDispatchForbidden());
ASSERT(!AssertNoEventDispatch::isEventDispatchForbidden());
#if ENABLE(INSPECTOR)
InspectorInstrumentation::didInsertDOMNode(node->document(), node);
......@@ -248,13 +246,11 @@ inline void ChildNodeRemovalNotifier::notifyNodeRemovedFromDocument(Node* node)
inline void ChildNodeRemovalNotifier::notifyNodeRemovedFromTree(ContainerNode* node)
{
AssertNoEventDispatch assertNoEventDispatch;
ASSERT(!m_insertionPoint->inDocument());
forbidEventDispatch();
node->removedFrom(m_insertionPoint);
notifyDescendantRemovedFromTree(node);
allowEventDispatch();
}
inline void ChildNodeRemovalNotifier::notify(Node* node)
......
......@@ -4104,7 +4104,7 @@ EventListener* Document::getWindowAttributeEventListener(const AtomicString& eve
void Document::dispatchWindowEvent(PassRefPtr<Event> event, PassRefPtr<EventTarget> target)
{
ASSERT(!eventDispatchForbidden());
ASSERT(!AssertNoEventDispatch::isEventDispatchForbidden());
DOMWindow* domWindow = this->domWindow();
if (!domWindow)
return;
......@@ -4113,7 +4113,7 @@ void Document::dispatchWindowEvent(PassRefPtr<Event> event, PassRefPtr<EventTar
void Document::dispatchWindowLoadEvent()
{
ASSERT(!eventDispatchForbidden());
ASSERT(!AssertNoEventDispatch::isEventDispatchForbidden());
DOMWindow* domWindow = this->domWindow();
if (!domWindow)
return;
......
......@@ -123,7 +123,7 @@ EventTarget* EventRelatedTargetAdjuster::findRelatedTarget(TreeScope* scope)
bool EventDispatcher::dispatchEvent(Node* node, PassRefPtr<EventDispatchMediator> mediator)
{
ASSERT(!eventDispatchForbidden());
ASSERT(!AssertNoEventDispatch::isEventDispatchForbidden());
EventDispatcher dispatcher(node);
return mediator->dispatchEvent(&dispatcher);
......@@ -248,7 +248,7 @@ bool EventDispatcher::dispatchEvent(PassRefPtr<Event> prpEvent)
ChildNodesLazySnapshot::takeChildNodesLazySnapshot();
event->setTarget(eventTargetRespectingSVGTargetRules(m_node.get()));
ASSERT(!eventDispatchForbidden());
ASSERT(!AssertNoEventDispatch::isEventDispatchForbidden());
ASSERT(event->target());
ASSERT(!event->type().isNull()); // JavaScript code can create an event with an empty name, but not null.
ensureEventAncestors(event.get());
......
......@@ -43,32 +43,6 @@ using namespace WTF;
namespace WebCore {
#ifndef NDEBUG
static int gEventDispatchForbidden = 0;
void forbidEventDispatch()
{
if (!isMainThread())
return;
++gEventDispatchForbidden;
}
void allowEventDispatch()
{
if (!isMainThread())
return;
if (gEventDispatchForbidden > 0)
--gEventDispatchForbidden;
}
bool eventDispatchForbidden()
{
if (!isMainThread())
return false;
return gEventDispatchForbidden > 0;
}
#endif // NDEBUG
EventTargetData::EventTargetData()
{
}
......@@ -185,7 +159,7 @@ void EventTarget::uncaughtExceptionInEventHandler()
bool EventTarget::fireEventListeners(Event* event)
{
ASSERT(!eventDispatchForbidden());
ASSERT(!AssertNoEventDispatch::isEventDispatchForbidden());
ASSERT(event && !event->type().isEmpty());
EventTargetData* d = eventTargetData();
......
......@@ -176,15 +176,6 @@ namespace WebCore {
EventListener* on##attribute() { return recipient ? recipient->getAttributeEventListener(eventNames().attribute##Event) : 0; } \
void setOn##attribute(PassRefPtr<EventListener> listener) { if (recipient) recipient->setAttributeEventListener(eventNames().attribute##Event, listener); } \
#ifndef NDEBUG
void forbidEventDispatch();
void allowEventDispatch();
bool eventDispatchForbidden();
#else
inline void forbidEventDispatch() { }
inline void allowEventDispatch() { }
#endif
#if USE(JSC)
inline void EventTarget::visitJSEventListeners(JSC::SlotVisitor& visitor)
{
......
......@@ -2566,7 +2566,7 @@ void Node::dispatchSubtreeModifiedEvent()
if (isInShadowTree())
return;
ASSERT(!eventDispatchForbidden());
ASSERT(!AssertNoEventDispatch::isEventDispatchForbidden());
if (!document()->hasListenerType(Document::DOMSUBTREEMODIFIED_LISTENER))
return;
......@@ -2576,21 +2576,21 @@ void Node::dispatchSubtreeModifiedEvent()
void Node::dispatchFocusInEvent(const AtomicString& eventType, PassRefPtr<Node> oldFocusedNode)
{
ASSERT(!eventDispatchForbidden());
ASSERT(!AssertNoEventDispatch::isEventDispatchForbidden());
ASSERT(eventType == eventNames().focusinEvent || eventType == eventNames().DOMFocusInEvent);
dispatchScopedEventDispatchMediator(FocusInEventDispatchMediator::create(UIEvent::create(eventType, true, false, document()->defaultView(), 0), oldFocusedNode));
}
void Node::dispatchFocusOutEvent(const AtomicString& eventType, PassRefPtr<Node> newFocusedNode)
{
ASSERT(!eventDispatchForbidden());
ASSERT(!AssertNoEventDispatch::isEventDispatchForbidden());
ASSERT(eventType == eventNames().focusoutEvent || eventType == eventNames().DOMFocusOutEvent);
dispatchScopedEventDispatchMediator(FocusOutEventDispatchMediator::create(UIEvent::create(eventType, true, false, document()->defaultView(), 0), newFocusedNode));
}
bool Node::dispatchDOMActivateEvent(int detail, PassRefPtr<Event> underlyingEvent)
{
ASSERT(!eventDispatchForbidden());
ASSERT(!AssertNoEventDispatch::isEventDispatchForbidden());
RefPtr<UIEvent> event = UIEvent::create(eventNames().DOMActivateEvent, true, true, document()->defaultView(), detail);
event->setUnderlyingEvent(underlyingEvent);
dispatchScopedEvent(event);
......
......@@ -195,7 +195,7 @@ EventTargetData* WebKitNamedFlow::ensureEventTargetData()
void WebKitNamedFlow::dispatchRegionLayoutUpdateEvent()
{
ASSERT(!eventDispatchForbidden());
ASSERT(!AssertNoEventDispatch::isEventDispatchForbidden());
ASSERT(m_parentFlowThread);
RefPtr<Event> event = UIEvent::create(eventNames().webkitRegionLayoutUpdateEvent, false, false, m_parentFlowThread->document()->defaultView(), 0);
......
......@@ -756,7 +756,7 @@ void HTMLMediaElement::loadInternal()
// Some of the code paths below this function dispatch the BeforeLoad event. This ASSERT helps
// us catch those bugs more quickly without needing all the branches to align to actually
// trigger the event.
ASSERT(!eventDispatchForbidden());
ASSERT(!AssertNoEventDispatch::isEventDispatchForbidden());
// If we can't start a load right away, start it later.
Page* page = document()->page();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment