Commit 521f64b8 authored by ggaren@apple.com's avatar ggaren@apple.com

JavaScriptCore: Added the ability to swap vectors with inline capacities, so you can

store a vector with inline capacity in a hash table.

Patch by Geoffrey Garen <ggaren@apple.com> on 2009-09-23
Reviewed by Sam Weinig.

* wtf/Vector.h:
(WTF::swap):
(WTF::VectorBuffer::swap):

WebCore: Bring a little sanity to this crazy EventTarget world of ours
https://bugs.webkit.org/show_bug.cgi?id=29701

Patch by Geoffrey Garen <ggaren@apple.com> on 2009-09-23
Reviewed by Sam Weinig.

Lots of EventTarget refactoring to achieve a single shared implementation
that fixes some of the performance and correctness bugs of the many individual
implementations, and makes reasoning about EventTargets and EventListeners
much easier.
        
The basic design is this:
    - EventTarget manages a set of EventListeners.
    - onXXX EventListener attributes forward to standard EventTarget APIs.
    - Since the onXXX code is repetitive, it is usually done with macros
      of the form DEFINE_ATTRIBUTE_EVENT_LISTENER(attributeName).
    - EventTarget provides a shared implementation of dispatchEvent,
      which subclasses with special event dispatch rules, like Node, override.
    - To support Node, which lazily instantiates its EventTarget data,
      EventTarget has no data members, and instead makes a virtual call
      to get its data from wherever its subclass chose to store it.
              
Code that used to call dispatchEvent, passing an ExceptionCode paratmeter,
even though no exception could be thrown, has been changed not to do so,
to improve clarity and performance.
        
Code that used to call a special dispatchXXXEvent function, which just
turned around and called dispatchEvent, has been changed to call
dispatchEvent, to improve clarity and performance.

* WebCore.base.exp:
* WebCore.xcodeproj/project.pbxproj: Another day in the life of a WebKit
engineer.

* bindings/js/JSDOMBinding.cpp:
(WebCore::isObservableThroughDOM): Updated for Node API change. Added
"is not in the document but is firing event listeners" as a condition
that makes a Node observable in the DOM, so that event listeners firing
on removed nodes are not destroyed midstream. (This was a long-standing
bug that was somewhat hidden by the old implementation's habit of
copying the RegisteredEventListener vector before firing events, which
would keep almost all the relevant objects from being destroyed.)

* bindings/js/JSEventListener.cpp:
(WebCore::JSEventListener::handleEvent): Removed the isWindowEvent flag
because it was one of the most elaborately planned no-ops in the history
of software crime, and one of the reasons clients thought they needed more
than one dispatchEvent function even though they didn't.
* bindings/js/JSEventListener.h:

* bindings/js/JSDOMWindowCustom.cpp:
(WebCore::JSDOMWindow::markChildren):
(WebCore::JSMessagePort::markChildren):
* bindings/js/JSNodeCustom.cpp:
(WebCore::JSNode::markChildren):
* bindings/js/JSAbstractWorkerCustom.cpp:
* bindings/js/JSDOMApplicationCacheCustom.cpp:
* bindings/js/JSDedicatedWorkerContextCustom.cpp:
* bindings/js/JSEventSourceCustom.cpp:
* bindings/js/JSMessagePortCustom.cpp:
* bindings/js/JSSharedWorkerContextCustom.cpp: Removed.
* bindings/js/JSWebSocketCustom.cpp:
* bindings/js/JSWorkerContextCustom.cpp:
(WebCore::JSWorkerContext::markChildren):
* bindings/js/JSWorkerCustom.cpp:
* bindings/js/JSXMLHttpRequestCustom.cpp:
(WebCore::JSXMLHttpRequest::markChildren):
* bindings/js/JSXMLHttpRequestUploadCustom.cpp:
(WebCore::JSXMLHttpRequestUpload::markChildren): EventListener marking is
now autogenerated. Classes that still have custom mark functions for other
reasons now call a shared EventTarget API to mark their EventListeners.

* bindings/objc/ObjCEventListener.h:
* bindings/objc/ObjCEventListener.mm:
(WebCore::ObjCEventListener::handleEvent): Bye bye isWindowEvent.

* bindings/scripts/CodeGeneratorJS.pm: Autogeneration support for
marking and invalidating event listeners.

* dom/CharacterData.cpp:
(WebCore::CharacterData::dispatchModifiedEvent):
* dom/ContainerNode.cpp:
(WebCore::ContainerNode::insertBefore):
(WebCore::ContainerNode::replaceChild):
(WebCore::willRemoveChild):
(WebCore::ContainerNode::appendChild):
(WebCore::dispatchChildInsertionEvents):
(WebCore::dispatchChildRemovalEvents):
* dom/Document.cpp:
(WebCore::Document::removeAllEventListeners):
(WebCore::Document::implicitClose):
(WebCore::Document::setFocusedNode):
(WebCore::Document::dispatchWindowEvent):
(WebCore::Document::dispatchWindowLoadEvent):
(WebCore::Document::finishedParsing):
* dom/Document.h: Use dispatchEvent directly.

* dom/Element.h: Moved a few event listener attributes down from Node,
since they don't apply to all Nodes, only Elements.

* dom/EventListener.h: Removed isWindowEvent parameter.

* dom/EventNames.h: Added the "display" event name, so it works correctly
with attribute macros, and for performance.

* dom/EventTarget.cpp:
(WebCore::forbidEventDispatch):
(WebCore::allowEventDispatch):
(WebCore::eventDispatchForbidden): Made this code (embarrasingly) thread
safe, since it's now called on multiple threads. (Currently, we only forbid
event dispatch on the main thread. If we ever want to forbid event dispatch
on secondary threads, we can improve it then.)

(WebCore::EventTarget::addEventListener):
(WebCore::EventTarget::removeEventListener):
(WebCore::EventTarget::setAttributeEventListener):
(WebCore::EventTarget::getAttributeEventListener):
(WebCore::EventTarget::clearAttributeEventListener):
(WebCore::EventTarget::dispatchEvent):
(WebCore::EventTarget::fireEventListeners):
(WebCore::EventTarget::getEventListeners):
(WebCore::EventTarget::removeAllEventListeners):
* dom/EventTarget.h:
(WebCore::FiringEventEndIterator::FiringEventEndIterator):
(WebCore::EventTarget::ref):
(WebCore::EventTarget::deref):
(WebCore::EventTarget::markEventListeners):
(WebCore::EventTarget::invalidateEventListeners):
(WebCore::EventTarget::isFiringEventListeners):
(WebCore::EventTarget::hasEventListeners): The ONE TRUE IMPLEMENTATION of
EventTarget APIs, crafted from an amalgam of all the different versions
we used to have. The most significant change here is that we no longer
make a copy of an EventListener vector before firing the events in the
vector -- instead, we use a reference to the original vector, along with
a notification mechanism for the unlikely case when an EventListener is
removed from the vector. This substantially reduces malloc, copying, and
refcount overhead, and complexity.

* dom/InputElement.cpp:
(WebCore::InputElement::setValueFromRenderer):
* dom/MessageEvent.h:
(WebCore::MessageEvent::create): Use dispatchEvent directly.

* dom/MessagePort.cpp:
(WebCore::MessagePort::dispatchMessages):
(WebCore::MessagePort::eventTargetData):
(WebCore::MessagePort::ensureEventTargetData):
* dom/MessagePort.h:
(WebCore::MessagePort::setOnmessage):
(WebCore::MessagePort::onmessage):
* dom/MessagePort.idl: Removed custom EventTarget implementation.

* dom/MutationEvent.h:
(WebCore::MutationEvent::create): Added some default values so callers
can construct MutationEvents more easily, without calling a custom dispatch
function.

* dom/Node.cpp:
(WebCore::Node::addEventListener):
(WebCore::Node::removeEventListener):
(WebCore::Node::eventTargetData):
(WebCore::Node::ensureEventTargetData):
(WebCore::Node::handleLocalEvents):
(WebCore::Node::dispatchEvent):
(WebCore::Node::dispatchGenericEvent):
(WebCore::Node::dispatchSubtreeModifiedEvent):
(WebCore::Node::dispatchUIEvent):
(WebCore::Node::dispatchKeyEvent):
(WebCore::Node::dispatchMouseEvent):
(WebCore::Node::dispatchWheelEvent):
(WebCore::Node::dispatchFocusEvent):
(WebCore::Node::dispatchBlurEvent):
* dom/Node.h:
(WebCore::Node::preDispatchEventHandler):
(WebCore::Node::postDispatchEventHandler):
* dom/Node.idl:
* dom/NodeRareData.h:
(WebCore::NodeRareData::eventTargetData):
(WebCore::NodeRareData::ensureEventTargetData): Use the shared EventTarget
interface, and call dispatchEvent directly instead of custom dispatchXXXEvent
functions that just forwarded to dispatchEvent.

* dom/RegisteredEventListener.cpp:
* dom/RegisteredEventListener.h:
(WebCore::RegisteredEventListener::RegisteredEventListener):
(WebCore::operator==): This is just a simple struct now, since we no longer
do a complicated copy / refCount / isRemoved dance just to honor the rule
that an EventListener can be removed during event dispatch.

* history/CachedFrame.cpp:
(WebCore::CachedFrameBase::restore): Removed another custom dispatchEvent.

* html/HTMLBodyElement.cpp:
* html/HTMLBodyElement.h: Use the shared EventTarget API.

* html/HTMLFormControlElement.cpp:
(WebCore::HTMLFormControlElement::dispatchFormControlChangeEvent):
(WebCore::HTMLFormControlElement::checkValidity):
* html/HTMLFormElement.cpp:
(WebCore::HTMLFormElement::handleLocalEvents):
(WebCore::HTMLFormElement::prepareSubmit):
(WebCore::HTMLFormElement::reset):
* html/HTMLFormElement.h: Use the standard dispatchEvent API.

* html/HTMLFrameSetElement.cpp:
* html/HTMLFrameSetElement.h: Use the shared EventTarget API.

* html/HTMLImageLoader.cpp:
(WebCore::HTMLImageLoader::dispatchLoadEvent):
* html/HTMLInputElement.cpp:
(WebCore::HTMLInputElement::onSearch):
* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::loadInternal):
* html/HTMLScriptElement.cpp:
(WebCore::HTMLScriptElement::dispatchLoadEvent):
(WebCore::HTMLScriptElement::dispatchErrorEvent):
* html/HTMLSourceElement.cpp:
(WebCore::HTMLSourceElement::errorEventTimerFired):
* html/HTMLTokenizer.cpp:
(WebCore::HTMLTokenizer::notifyFinished): Use the standard dispatchEvent API.

* inspector/InspectorDOMAgent.cpp:
(WebCore::InspectorDOMAgent::handleEvent):
* inspector/InspectorDOMAgent.h:
* inspector/InspectorDOMStorageResource.cpp:
(WebCore::InspectorDOMStorageResource::handleEvent):
* inspector/InspectorDOMStorageResource.h:
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::stopLoading):
(WebCore::FrameLoader::canCachePageContainingThisFrame):
(WebCore::FrameLoader::logCanCacheFrameDecision):
(WebCore::HashChangeEventTask::performTask):
(WebCore::FrameLoader::pageHidden): No more isWindowEvent.

* loader/ImageDocument.cpp:
(WebCore::ImageEventListener::handleEvent):
* loader/appcache/ApplicationCacheGroup.cpp:
(WebCore::CallCacheListenerTask::performTask):
* loader/appcache/ApplicationCacheHost.cpp:
(WebCore::ApplicationCacheHost::notifyDOMApplicationCache):
* loader/appcache/ApplicationCacheHost.h:
* loader/appcache/DOMApplicationCache.cpp:
(WebCore::DOMApplicationCache::eventTargetData):
(WebCore::DOMApplicationCache::ensureEventTargetData):
* loader/appcache/DOMApplicationCache.h:
* loader/appcache/DOMApplicationCache.idl: Switched to the standard
EventTarget API. As a part of this, I switched this class from using a
custom internal event name enumeration to using the standard EventNames.

* notifications/Notification.cpp:
(WebCore::Notification::eventTargetData):
(WebCore::Notification::ensureEventTargetData):
* notifications/Notification.h:
(WebCore::Notification::scriptExecutionContext):
* notifications/Notification.idl: Switched to the standard EventTarget API.

* page/DOMWindow.cpp:
(WebCore::PostMessageTimer::event):
(WebCore::windowsWithUnloadEventListeners):
(WebCore::windowsWithBeforeUnloadEventListeners):
(WebCore::allowsBeforeUnloadListeners):
(WebCore::DOMWindow::dispatchAllPendingBeforeUnloadEvents):
(WebCore::DOMWindow::pendingUnloadEventListeners):
(WebCore::DOMWindow::dispatchAllPendingUnloadEvents): Changed the "pending"
unload / beforeunload listener tracker just to track which windows had
such listeners, instead of actually keeping a copy of the listeners. Now,
this code can use the standard EventTarget API.

(WebCore::DOMWindow::~DOMWindow):
(WebCore::DOMWindow::postMessageTimerFired):
(WebCore::DOMWindow::addEventListener):
(WebCore::DOMWindow::removeEventListener):
(WebCore::DOMWindow::dispatchLoadEvent):
(WebCore::DOMWindow::dispatchEvent):
(WebCore::DOMWindow::removeAllEventListeners):
(WebCore::DOMWindow::captureEvents):
(WebCore::DOMWindow::releaseEvents):
(WebCore::DOMWindow::eventTargetData):
(WebCore::DOMWindow::ensureEventTargetData):
* page/DOMWindow.h:
* page/DOMWindow.idl: Use the standard EventTarget APIs.

* page/EventHandler.cpp:
(WebCore::EventHandler::canMouseDownStartSelect):
(WebCore::EventHandler::canMouseDragExtendSelect):
(WebCore::EventHandler::sendResizeEvent):
(WebCore::EventHandler::sendScrollEvent): Use dispatchEvent directly.

* page/EventSource.cpp:
(WebCore::EventSource::endRequest):
(WebCore::EventSource::didReceiveResponse):
(WebCore::EventSource::parseEventStreamLine):
(WebCore::EventSource::stop):
(WebCore::EventSource::createMessageEvent):
(WebCore::EventSource::eventTargetData):
(WebCore::EventSource::ensureEventTargetData):
* page/EventSource.h:
* page/EventSource.idl: Use the standard EventTarget APIs.

* page/FocusController.cpp:
(WebCore::dispatchEventsOnWindowAndFocusedNode):
(WebCore::FocusController::setFocusedFrame):
* page/Frame.cpp:
(WebCore::Frame::shouldClose):
* page/Frame.h:
* page/Page.cpp:
(WebCore::networkStateChanged):
* page/animation/AnimationController.cpp:
(WebCore::AnimationControllerPrivate::updateStyleIfNeededDispatcherFired):
* rendering/RenderListBox.cpp:
(WebCore::RenderListBox::valueChanged):
* rendering/RenderTextControl.cpp:
(WebCore::RenderTextControl::selectionChanged):
* rendering/RenderTextControlMultiLine.cpp:
(WebCore::RenderTextControlMultiLine::subtreeHasChanged): Use dispatchEvent.

* svg/SVGElement.cpp:
(WebCore::hasLoadListener): Rewritten for new EventTarget API.

* svg/SVGElementInstance.cpp:
(WebCore::dummyEventTargetData):
(WebCore::SVGElementInstance::addEventListener):
(WebCore::SVGElementInstance::removeEventListener):
(WebCore::SVGElementInstance::removeAllEventListeners):
(WebCore::SVGElementInstance::dispatchEvent):
(WebCore::SVGElementInstance::eventTargetData):
(WebCore::SVGElementInstance::ensureEventTargetData): Use the EventTarget API.

* svg/SVGElementInstance.h:
* svg/SVGImageLoader.cpp:
(WebCore::SVGImageLoader::dispatchLoadEvent):
* svg/SVGScriptElement.cpp:
(WebCore::SVGScriptElement::dispatchErrorEvent): Use dispatchEvent directly.

* svg/SVGUseElement.cpp:
(WebCore::SVGUseElement::transferEventListenersToShadowTree): Updated for
new EventTarget API.

* svg/animation/SVGSMILElement.cpp:
(WebCore::ConditionEventListener::handleEvent): No more isWindowEvent.

* websockets/WebSocket.cpp:
(WebCore::ProcessWebSocketEventTask::create):
(WebCore::ProcessWebSocketEventTask::performTask):
(WebCore::ProcessWebSocketEventTask::ProcessWebSocketEventTask):
(WebCore::WebSocket::didConnect):
(WebCore::WebSocket::didReceiveMessage):
(WebCore::WebSocket::didClose):
(WebCore::WebSocket::eventTargetData):
(WebCore::WebSocket::ensureEventTargetData):
* websockets/WebSocket.h:
* websockets/WebSocket.idl:
* workers/AbstractWorker.cpp:
(WebCore::AbstractWorker::eventTargetData):
(WebCore::AbstractWorker::ensureEventTargetData):
* workers/AbstractWorker.h:
* workers/AbstractWorker.idl:
* workers/DedicatedWorkerContext.cpp:
* workers/DedicatedWorkerContext.h:
* workers/DedicatedWorkerContext.idl:
* workers/DefaultSharedWorkerRepository.cpp:
(WebCore::SharedWorkerConnectTask::performTask):
(WebCore::SharedWorkerScriptLoader::load):
(WebCore::SharedWorkerScriptLoader::notifyFinished):
* workers/SharedWorker.idl:
* workers/SharedWorkerContext.cpp:
(WebCore::createConnectEvent):
* workers/SharedWorkerContext.h:
* workers/SharedWorkerContext.idl:
* workers/Worker.cpp:
(WebCore::Worker::notifyFinished):
* workers/Worker.h:
* workers/Worker.idl:
* workers/WorkerContext.cpp:
(WebCore::WorkerContext::eventTargetData):
(WebCore::WorkerContext::ensureEventTargetData):
* workers/WorkerContext.h:
* workers/WorkerContext.idl:
* workers/WorkerMessagingProxy.cpp:
(WebCore::MessageWorkerContextTask::performTask):
(WebCore::MessageWorkerTask::performTask):
(WebCore::WorkerExceptionTask::performTask):
* xml/XMLHttpRequest.cpp:
(WebCore::XMLHttpRequest::callReadyStateChangeListener):
(WebCore::XMLHttpRequest::createRequest):
(WebCore::XMLHttpRequest::abort):
(WebCore::XMLHttpRequest::networkError):
(WebCore::XMLHttpRequest::abortError):
(WebCore::XMLHttpRequest::didSendData):
(WebCore::XMLHttpRequest::didReceiveData):
(WebCore::XMLHttpRequest::eventTargetData):
(WebCore::XMLHttpRequest::ensureEventTargetData):
* xml/XMLHttpRequest.h:
* xml/XMLHttpRequest.idl:
* xml/XMLHttpRequestProgressEvent.h:
(WebCore::XMLHttpRequestProgressEvent::create):
* xml/XMLHttpRequestUpload.cpp:
(WebCore::XMLHttpRequestUpload::eventTargetData):
(WebCore::XMLHttpRequestUpload::ensureEventTargetData):
* xml/XMLHttpRequestUpload.h:
* xml/XMLHttpRequestUpload.idl: Use new EventTarget API.

WebKit/mac: Updated for a WebCore rename.

Patch by Geoffrey Garen <ggaren@apple.com> on 2009-09-23
Reviewed by Sam Weinig.

* WebView/WebFrame.mm:
(-[WebFrame _cacheabilityDictionary]):

LayoutTests: Layout tests for event target sanitization.
        
Patch by Geoffrey Garen <ggaren@apple.com> on 2009-09-23
Reviewed by Sam Weinig.

New tests for event dispatch:

* fast/events/event-attributes-after-exception-expected.txt: Added.
* fast/events/event-attributes-after-exception.html: Added.
* fast/events/event-fire-order-expected.txt: Added.
* fast/events/event-fire-order.html: Added.
* fast/events/event-fired-after-removal-expected.txt: Added.
* fast/events/event-fired-after-removal.html: Added.
        
Fixed these tests:

* fast/xmlhttprequest/xmlhttprequest-get-expected.txt: eventPhase should
be AT_TARGET (2) when firing an event on an XHR, not INVALID (0).
* http/tests/xmlhttprequest/infoOnProgressEvent-expected.txt: ditto

* http/tests/xmlhttprequest/event-target-expected.txt:
* http/tests/xmlhttprequest/event-target.html: Removing an event listener
during event dispatch should prevent it from firing. (This test was backwards.)
        
* svg/custom/loadevents-capturing.svg: Enhanced this test to tell you
why it fails when it fails. Changed it to register runTest() (now named 
reportResults()) using addEventListener() instead of the 'onload' attribute.
The test relies on reportResults() running after handler(), so it needs
to register reportResults() after handler().



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@48701 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 2209a0b6
2009-09-23 Geoffrey Garen <ggaren@apple.com>
Reviewed by Sam Weinig.
Added the ability to swap vectors with inline capacities, so you can
store a vector with inline capacity in a hash table.
* wtf/Vector.h:
(WTF::swap):
(WTF::VectorBuffer::swap):
2009-09-23 David Kilzer <ddkilzer@apple.com>
Move definition of USE(PLUGIN_HOST_PROCESS) from WebKitPrefix.h to Platform.h
......
......@@ -63,6 +63,13 @@ namespace WTF {
template <size_t size> struct AlignedBuffer<size, 32> { WTF_ALIGNED(AlignedBufferChar, buffer[size], 32); };
template <size_t size> struct AlignedBuffer<size, 64> { WTF_ALIGNED(AlignedBufferChar, buffer[size], 64); };
template <size_t size, size_t alignment>
void swap(AlignedBuffer<size, alignment>& a, AlignedBuffer<size, alignment>& b)
{
for (size_t i = 0; i < size; ++i)
std::swap(a.buffer[i], b.buffer[i]);
}
template <bool needsDestruction, typename T>
class VectorDestructor;
......@@ -404,6 +411,27 @@ namespace WTF {
Base::deallocateBuffer(bufferToDeallocate);
}
void swap(VectorBuffer<T, inlineCapacity>& other)
{
if (buffer() == inlineBuffer() && other.buffer() == other.inlineBuffer()) {
WTF::swap(m_inlineBuffer, other.m_inlineBuffer);
std::swap(m_capacity, other.m_capacity);
} else if (buffer() == inlineBuffer()) {
m_buffer = other.m_buffer;
other.m_buffer = other.inlineBuffer();
WTF::swap(m_inlineBuffer, other.m_inlineBuffer);
std::swap(m_capacity, other.m_capacity);
} else if (other.buffer() == other.inlineBuffer()) {
other.m_buffer = m_buffer;
m_buffer = inlineBuffer();
WTF::swap(m_inlineBuffer, other.m_inlineBuffer);
std::swap(m_capacity, other.m_capacity);
} else {
std::swap(m_buffer, other.m_buffer);
std::swap(m_capacity, other.m_capacity);
}
}
void restoreInlineBufferIfNeeded()
{
if (m_buffer)
......
2009-09-23 Geoffrey Garen <ggaren@apple.com>
Reviewed by Sam Weinig.
Layout tests for event target sanitization.
New tests for event dispatch:
* fast/events/event-attributes-after-exception-expected.txt: Added.
* fast/events/event-attributes-after-exception.html: Added.
* fast/events/event-fire-order-expected.txt: Added.
* fast/events/event-fire-order.html: Added.
* fast/events/event-fired-after-removal-expected.txt: Added.
* fast/events/event-fired-after-removal.html: Added.
Fixed these tests:
* fast/xmlhttprequest/xmlhttprequest-get-expected.txt: eventPhase should
be AT_TARGET (2) when firing an event on an XHR, not INVALID (0).
* http/tests/xmlhttprequest/infoOnProgressEvent-expected.txt: ditto
* http/tests/xmlhttprequest/event-target-expected.txt:
* http/tests/xmlhttprequest/event-target.html: Removing an event listener
during event dispatch should prevent it from firing. (This test was backwards.)
* svg/custom/loadevents-capturing.svg: Enhanced this test to tell you
why it fails when it fails. Changed it to register runTest() (now named
reportResults()) using addEventListener() instead of the 'onload' attribute.
The test relies on reportResults() running after handler(), so it needs
to register reportResults() after handler().
2009-09-23 Karen Grünberg <karen+webkit@chromium.org>
Reviewed by Eric Seidel.
......
This page tests various event attributes after dispatchEvent throws an exception.
If the test passes, you'll see a series of PASS messages below.
PASS: event.target should be null and is.
PASS: event.currentTarget should be null and is.
PASS: event.relatedTarget should be null and is.
PASS: event.eventPhase should be 0 and is.
<p>This page tests various event attributes after dispatchEvent throws an exception.</p>
<p>If the test passes, you'll see a series of PASS messages below.</p>
<pre id="console"></pre>
<script>
if (window.layoutTestController)
layoutTestController.dumpAsText();
function log(s)
{
document.getElementById("console").appendChild(document.createTextNode(s + "\n"));
}
function shouldBe(aDescription, a, b)
{
if (a == b) {
log("PASS: " + aDescription + " should be " + b + " and is.");
return;
}
log("FAIL: " + aDescription + " should be " + b + " but instead is " + a + ".");
}
window.onload = function()
{
var event = document.createEvent("MouseEvent");
try {
document.getElementById("console").dispatchEvent(event);
} catch (e) {
} finally {
shouldBe("event.target", event.target, null);
shouldBe("event.currentTarget", event.currentTarget, null);
shouldBe("event.relatedTarget", event.relatedTarget, null);
shouldBe("event.eventPhase", event.eventPhase, 0);
}
};
</script>
This page tests event listener fire order for a few objects that had it wrong in the past.
If the test passes, you'll see a series of PASS messages below.
PASS: result should be f1,f2 and is.
PASS: result should be f1,f2 and is.
PASS: result should be f1,f2 and is.
<p>This page tests event listener fire order for a few objects that had it wrong in the past.</p>
<p>If the test passes, you'll see a series of PASS messages below.</p>
<pre id="console"></pre>
<div id="div"></div>
<script>
if (window.layoutTestController)
layoutTestController.dumpAsText();
function log(s)
{
document.getElementById("console").appendChild(document.createTextNode(s + "\n"));
}
var result;
function reset()
{
result = [ ];
}
function f1()
{
result.push("f1");
}
function f2(event)
{
result.push("f2");
event.target.removeEventListener(event.type, f3, false); // Removed: should not fire.
event.target.addEventListener(event.type, f4, false); // Added after dispatch began: should not fire.
}
function f3()
{
result.push("f3");
}
function f4()
{
result.push("f4");
}
function reportResult(name, expected)
{
var passed = true;
var end = result.length > expected.length ? result.length : expected.length;
for (var i = 0; i < end; ++i) {
if (result[i] != expected[i]) {
log("FAIL: " + name + " result[" + i + "] should be " + expected[i] + " but instead is " + result[i] + ".");
passed = false;
}
}
if (passed)
log("PASS: result should be " + expected + " and is.");
}
var tests = [
function testDiv()
{
reset();
var x = document.getElementById("div");
x.addEventListener("click", f1, false);
x.onclick = f2;
x.addEventListener("click", f3, false);
var event = document.createEvent("MouseEvent");
event.initMouseEvent("click", true, true, document.defaultView, 1, 0, 0, 0, 0, false, false, false, false, 0, document);
x.dispatchEvent(event);
reportResult(arguments.callee.name, [ "f1", "f2" ]);
},
function testXHR()
{
reset();
var x = new XMLHttpRequest;
x.addEventListener("readystatechange", f1, false);
x.onreadystatechange = f2;
x.addEventListener("readystatechange", f3, false);
x.open("GET", "resources/does-not-exist");
reportResult(arguments.callee.name, [ "f1", "f2" ]);
},
function testXHRUpload()
{
reset();
var x = new XMLHttpRequest;
x.upload.addEventListener("abort", f1, false);
x.upload.onabort = f2;
x.upload.addEventListener("abort", f3, false);
x.open("POST", "resources/does-not-exist");
x.abort();
reportResult(arguments.callee.name, [ "f1", "f2" ]);
}
];
for (var i = 0; i < tests.length; ++i)
tests[i]();
</script>
This page verifies that queued event listeners keep firing even after a node has been removed from the document.
If the test passes, you'll see a PASS message below.
PASS: result should be f1,f2 and is.
<p>This page verifies that queued event listeners keep firing even after a node has been removed from the document.</p>
<p>If the test passes, you'll see a PASS message below.</p>
<pre id="console"></pre>
<div id="div"></div>
<script>
if (window.layoutTestController)
layoutTestController.dumpAsText();
function log(s)
{
document.getElementById("console").appendChild(document.createTextNode(s + "\n"));
}
var result = [ ];
function reportResult(expected)
{
var passed = true;
var end = result.length > expected.length ? result.length : expected.length;
for (var i = 0; i < end; ++i) {
if (result[i] != expected[i]) {
log("FAIL: " + name + " result[" + i + "] should be " + expected[i] + " but instead is " + result[i] + ".");
passed = false;
}
}
if (passed)
log("PASS: result should be " + expected + " and is.");
}
var div = document.getElementById("div");
div.addEventListener("click", function f1() {
result.push(arguments.callee.name);
div.parentNode.removeChild(div);
}, false);
div.addEventListener("click", function f2() {
result.push(arguments.callee.name);
}, false);
var event = document.createEvent("MouseEvent");
event.initMouseEvent("click", true, true, document.defaultView, 1, 0, 0, 0, 0, false, false, false, false, 0, document);
div.dispatchEvent(event);
reportResult([ "f1", "f2" ]);
</script>
......@@ -47,7 +47,7 @@ cancelBubble : 'false'
cancelable : 'true'
clipboardData : 'undefined'
currentTarget : '[object XMLHttpRequest]'
eventPhase : '0'
eventPhase : '2'
initEvent : 'function initEvent() {
[native code]
}'
......
......@@ -4,7 +4,6 @@ fooListener: this = [object XMLHttpRequest]
onload: this = [object XMLHttpRequest]
eventListener: this = [object XMLHttpRequest]
eventListener2: this = [object XMLHttpRequest]
eventListener3: this = [object XMLHttpRequest]
onload: this = [object XMLHttpRequest]
eventListener: this = [object XMLHttpRequest]
eventListener2: this = [object XMLHttpRequest]
......@@ -26,13 +26,13 @@ XMLHttpRequest should be an EventTarget.</p>
function eventListener2() {
log("eventListener2: this = " + this);
// It is too late to remove this listener, so it will still fire.
// Removing this event listener should prevent it from firing.
req.removeEventListener("load", eventListener3, false);
}
function eventListener3() { log("eventListener3: this = " + this); }
// This one is removed just in time to be really removed.
// This listener is removed before it gets a chance to fire.
function eventListener4() { log("eventListener4: this = " + this); }
function fooListener() { log("fooListener: this = " + this); }
......
......@@ -6,7 +6,7 @@ Synchronous case:
Type: progress
Bubble: false
Cancelable: true
EventPhase: 0
EventPhase: 2
Target: [object XMLHttpRequest]
Current target: [object XMLHttpRequest]
......@@ -14,7 +14,7 @@ Asynchronous case:
Type: progress
Bubble: false
Cancelable: true
EventPhase: 0
EventPhase: 2
Target: [object XMLHttpRequest]
Current target: [object XMLHttpRequest]
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="runTest();">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<script>
<![CDATA[
if (window.layoutTestController)
layoutTestController.dumpAsText();
function handler(event) {
var results = [ ];
function handler(event)
{
results.push(event.target.localName);
}
document.documentElement.addEventListener('load', handler, true);
var results = new Array();
var test = document.documentElement;
test.addEventListener('load', handler, true);
function runTest()
function reportResults()
{
var test = document.getElementById("console");
if ( results.length != 6 || results[0] != "image" ||
results[1] != "text" || results[2] != "text" ||
results[3] != "text" || results[4] != "g" ||
results[5] != "svg") {
test.appendChild(document.createTextNode("Failed"));
} else {
test.appendChild(document.createTextNode("Passed"));
var console = document.getElementById("console");
var expected = [ "image", "text", "text", "text", "g", "svg" ];
for (var i = 0; i < expected.length; ++i) {
if (results[i] != expected[i]) {
console.appendChild(document.createTextNode("FAIL: " + i + " should be " + expected[i] + " but instead is " + results[i] + ".\n"));
return;
}
}
console.appendChild(document.createTextNode("Passed"));
}
document.documentElement.addEventListener('load', reportResults);
]]>
</script>
<g>
......
This diff is collapsed.
......@@ -494,7 +494,7 @@ __ZN7WebCore5Cache11setDisabledEb
__ZN7WebCore5Cache13getStatisticsEv
__ZN7WebCore5Cache13setCapacitiesEjjj
__ZN7WebCore5Frame10findStringERKNS_6StringEbbbb
__ZN7WebCore5Frame11shouldCloseEPN3WTF6VectorINS1_6RefPtrINS_23RegisteredEventListenerEEELm0EEE
__ZN7WebCore5Frame11shouldCloseEv
__ZN7WebCore5Frame13reapplyStylesEv
__ZN7WebCore5Frame13setZoomFactorEfb
__ZN7WebCore5Frame14frameForWidgetEPKNS_6WidgetE
......@@ -656,7 +656,6 @@ __ZN7WebCore8Settings40setTextDirectionSubmenuInclusionBehaviorENS_37TextDirecti
__ZN7WebCore8Settings41setNeedsKeyboardEventDisambiguationQuirksEb
__ZN7WebCore8blankURLEv
__ZN7WebCore8makeRGBAEiiii
__ZN7WebCore9DOMWindow16hasEventListenerERKNS_12AtomicStringE
__ZN7WebCore9DOMWindow30dispatchAllPendingUnloadEventsEv
__ZN7WebCore9DOMWindow36dispatchAllPendingBeforeUnloadEventsEv
__ZN7WebCore9FloatRectC1ERK7_NSRect
......
......@@ -680,7 +680,6 @@
412A68470F6B03DD000EA66E /* ScriptObjectQuarantine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 412A68460F6B03DD000EA66E /* ScriptObjectQuarantine.cpp */; };
415B7C570FF598E6006770F7 /* JSAbstractWorkerCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 415B7C540FF598E6006770F7 /* JSAbstractWorkerCustom.cpp */; };
415B7C580FF598E6006770F7 /* JSSharedWorkerConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 415B7C550FF598E6006770F7 /* JSSharedWorkerConstructor.cpp */; };
415B7C590FF598E6006770F7 /* JSSharedWorkerCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 415B7C560FF598E6006770F7 /* JSSharedWorkerCustom.cpp */; };
415B7C630FF5A767006770F7 /* JSSharedWorkerConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 415B7C620FF5A767006770F7 /* JSSharedWorkerConstructor.h */; };
4162A450101145AE00DFF3ED /* DedicatedWorkerContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4162A44D101145AE00DFF3ED /* DedicatedWorkerContext.cpp */; };
4162A451101145AE00DFF3ED /* DedicatedWorkerContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 4162A44E101145AE00DFF3ED /* DedicatedWorkerContext.h */; };
......@@ -714,7 +713,6 @@
41D168EA10226E89009BC827 /* SharedWorkerRepository.h in Headers */ = {isa = PBXBuildFile; fileRef = 41D168E210226E89009BC827 /* SharedWorkerRepository.h */; };
41D168ED10226E89009BC827 /* SharedWorkerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41D168E510226E89009BC827 /* SharedWorkerThread.cpp */; };
41D168EE10226E89009BC827 /* SharedWorkerThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 41D168E610226E89009BC827 /* SharedWorkerThread.h */; };
41D168F010226EC4009BC827 /* JSSharedWorkerContextCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41D168EF10226EC4009BC827 /* JSSharedWorkerContextCustom.cpp */; };
41D1690510238B66009BC827 /* JSSharedWorkerContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41D1690310238B66009BC827 /* JSSharedWorkerContext.cpp */; };
41D1690610238B66009BC827 /* JSSharedWorkerContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 41D1690410238B66009BC827 /* JSSharedWorkerContext.h */; };
41E1B1D00FF5986900576B3B /* AbstractWorker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41E1B1CA0FF5986900576B3B /* AbstractWorker.cpp */; };
......@@ -5840,7 +5838,6 @@
412A68460F6B03DD000EA66E /* ScriptObjectQuarantine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScriptObjectQuarantine.cpp; sourceTree = "<group>"; };
415B7C540FF598E6006770F7 /* JSAbstractWorkerCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSAbstractWorkerCustom.cpp; sourceTree = "<group>"; };
415B7C550FF598E6006770F7 /* JSSharedWorkerConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSharedWorkerConstructor.cpp; sourceTree = "<group>"; };
415B7C560FF598E6006770F7 /* JSSharedWorkerCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSharedWorkerCustom.cpp; sourceTree = "<group>"; };
415B7C620FF5A767006770F7 /* JSSharedWorkerConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSSharedWorkerConstructor.h; sourceTree = "<group>"; };
4162A44D101145AE00DFF3ED /* DedicatedWorkerContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DedicatedWorkerContext.cpp; path = workers/DedicatedWorkerContext.cpp; sourceTree = "<group>"; };
4162A44E101145AE00DFF3ED /* DedicatedWorkerContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DedicatedWorkerContext.h; path = workers/DedicatedWorkerContext.h; sourceTree = "<group>"; };
......@@ -5876,7 +5873,6 @@
41D168E210226E89009BC827 /* SharedWorkerRepository.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SharedWorkerRepository.h; path = workers/SharedWorkerRepository.h; sourceTree = "<group>"; };
41D168E510226E89009BC827 /* SharedWorkerThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SharedWorkerThread.cpp; path = workers/SharedWorkerThread.cpp; sourceTree = "<group>"; };
41D168E610226E89009BC827 /* SharedWorkerThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SharedWorkerThread.h; path = workers/SharedWorkerThread.h; sourceTree = "<group>"; };
41D168EF10226EC4009BC827 /* JSSharedWorkerContextCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSharedWorkerContextCustom.cpp; sourceTree = "<group>"; };
41D1690310238B66009BC827 /* JSSharedWorkerContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSharedWorkerContext.cpp; sourceTree = "<group>"; };
41D1690410238B66009BC827 /* JSSharedWorkerContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSSharedWorkerContext.h; sourceTree = "<group>"; };
41E1B1CA0FF5986900576B3B /* AbstractWorker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AbstractWorker.cpp; path = workers/AbstractWorker.cpp; sourceTree = "<group>"; };
......@@ -14137,6 +14133,8 @@
93B70D5009EB0C7C009D8468 /* JSPluginElementFunctions.h */,
C09158880DB4209200E55AF4 /* JSQuarantinedObjectWrapper.cpp */,
C09158890DB4209200E55AF4 /* JSQuarantinedObjectWrapper.h */,
415B7C550FF598E6006770F7 /* JSSharedWorkerConstructor.cpp */,
415B7C620FF5A767006770F7 /* JSSharedWorkerConstructor.h */,
B21127A50B3186770009BE53 /* JSSVGPODTypeWrapper.h */,
E1C36D320EB0A094007410BC /* JSWorkerContextBase.cpp */,
E1C36D330EB0A094007410BC /* JSWorkerContextBase.h */,
......@@ -14245,6 +14243,28 @@
9392262E10321084006E7D5D /* JSCSSRuleListCustom.cpp */,
BC5825F20C0B89380053F1B5 /* JSCSSStyleDeclarationCustom.cpp */,
BC20FB7E0C0E8E6C00D1447F /* JSCSSValueCustom.cpp */,
FE80D7A20E9C1ED2000D6F75 /* JSCustomPositionCallback.cpp */,
FE80D7A30E9C1ED2000D6F75 /* JSCustomPositionCallback.h */,
FE80D7A40E9C1ED2000D6F75 /* JSCustomPositionErrorCallback.cpp */,
FE80D7A50E9C1ED2000D6F75 /* JSCustomPositionErrorCallback.h */,
51EC925B0CE90DD400F90308 /* JSCustomSQLStatementCallback.cpp */,
51EC925C0CE90DD400F90308 /* JSCustomSQLStatementCallback.h */,
51EC925D0CE90DD400F90308 /* JSCustomSQLStatementErrorCallback.cpp */,
51EC925E0CE90DD400F90308 /* JSCustomSQLStatementErrorCallback.h */,
51EC925F0CE90DD400F90308 /* JSCustomSQLTransactionCallback.cpp */,
51EC92600CE90DD400F90308 /* JSCustomSQLTransactionCallback.h */,
51EC92610CE90DD400F90308 /* JSCustomSQLTransactionErrorCallback.cpp */,
51EC92620CE90DD400F90308 /* JSCustomSQLTransactionErrorCallback.h */,
1A3417C80CECFF250049CBDE /* JSCustomVoidCallback.cpp */,
1A3417C70CECFF250049CBDE /* JSCustomVoidCallback.h */,
93BA59B10F2AA5FE008E8E99 /* JSCDATASectionCustom.cpp */,
BCA83E510D7CE205003421A8 /* JSClipboardCustom.cpp */,
C0DFC86F0DB6841A003EAE7C /* JSConsoleCustom.cpp */,
FE700DD00F92D81A008E2BFE /* JSCoordinatesCustom.cpp */,
BC46C1ED0C0DDBDF0020CFC3 /* JSCSSRuleCustom.cpp */,
9392262E10321084006E7D5D /* JSCSSRuleListCustom.cpp */,
BC5825F20C0B89380053F1B5 /* JSCSSStyleDeclarationCustom.cpp */,
BC20FB7E0C0E8E6C00D1447F /* JSCSSValueCustom.cpp */,
BCCE58AB1061E8CF008FB35A /* JSDatabaseCustom.cpp */,
BC77D1510FF19C730070887B /* JSDataGridColumnListCustom.cpp */,
4162A453101145E300DFF3ED /* JSDedicatedWorkerContextCustom.cpp */,
......@@ -14292,8 +14312,6 @@
BCD9C2610C17AA67005C90A2 /* JSNodeListCustom.cpp */,
A9C6E64A0D7465E7006442E9 /* JSPluginArrayCustom.cpp */,
A9C6E64B0D7465E7006442E9 /* JSPluginCustom.cpp */,
41D168EF10226EC4009BC827 /* JSSharedWorkerContextCustom.cpp */,
415B7C560FF598E6006770F7 /* JSSharedWorkerCustom.cpp */,
51DCE8010CAC9F1C00488358 /* JSSQLResultSetRowListCustom.cpp */,
1AD2316D0CD269E700C1F194 /* JSSQLTransactionCustom.cpp */,
51D0C5150DAA90B7003B3831 /* JSStorageCustom.cpp */,
......@@ -19031,8 +19049,6 @@
41D07A7E0FF935CA0095EDCE /* JSSharedWorker.cpp in Sources */,
415B7C580FF598E6006770F7 /* JSSharedWorkerConstructor.cpp in Sources */,
41D1690510238B66009BC827 /* JSSharedWorkerContext.cpp in Sources */,
41D168F010226EC4009BC827 /* JSSharedWorkerContextCustom.cpp in Sources */,
415B7C590FF598E6006770F7 /* JSSharedWorkerCustom.cpp in Sources */,
514C76370CE9225E007EF3CD /* JSSQLError.cpp in Sources */,
1AE82FEC0CAB07EE002237AE /* JSSQLResultSet.cpp in Sources */,
1AFE11990CBFFCC4003017FA /* JSSQLResultSetRowList.cpp in Sources */,
......@@ -44,21 +44,6 @@ using namespace JSC;
namespace WebCore {
void JSAbstractWorker::markChildren(MarkStack& markStack)
{
Base::markChildren(markStack);
markIfNotNull(markStack, m_impl->onerror());
typedef AbstractWorker::EventListenersMap EventListenersMap;
typedef AbstractWorker::ListenerVector ListenerVector;
EventListenersMap& eventListeners = m_impl->eventListeners();
for (EventListenersMap::iterator mapIter = eventListeners.begin(); mapIter != eventListeners.end(); ++mapIter) {
for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter)
(*vecIter)->markJSFunction(markStack);
}
}
JSValue JSAbstractWorker::addEventListener(ExecState* exec, const ArgList& args)
{
JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(impl()->scriptExecutionContext());
......
......@@ -42,28 +42,6 @@ using namespace JSC;
namespace WebCore {
void JSDOMApplicationCache::markChildren(MarkStack& markStack)
{
Base::markChildren(markStack);
markIfNotNull(markStack, m_impl->onchecking());
markIfNotNull(markStack, m_impl->onerror());
markIfNotNull(markStack, m_impl->onnoupdate());
markIfNotNull(markStack, m_impl->ondownloading());
markIfNotNull(markStack, m_impl->onprogress());
markIfNotNull(markStack, m_impl->onupdateready());
markIfNotNull(markStack, m_impl->oncached());
markIfNotNull(markStack, m_impl->onobsolete());
typedef DOMApplicationCache::EventListenersMap EventListenersMap;
typedef DOMApplicationCache::ListenerVector ListenerVector;
EventListenersMap& eventListeners = m_impl->eventListeners();
for (EventListenersMap::iterator mapIter = eventListeners.begin(); mapIter != eventListeners.end(); ++mapIter) {
for (ListenerVector::iterator vecIter = mapIter->second.begin(); vecIter != mapIter->second.end(); ++vecIter)