Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Refactor EventDispatcher::dispatchEvent() so that we can call each ph…
…ase (Caputure, Target and Bubbling) of event dispatching separately.

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

Reviewed by Dimitri Glazkov.

This is one of the required refactorings to support event
propagation for seamless iframes.  I've removed 'goto' statements
from EventDispatcher::dispatchEvent() as a result.

I've verified that all separated functions are successfully
inlined. I could not see any performance regression.  The
benchmark result is:

Before this patch:
% ./Tools/Scripts/run-perf-tests PerformanceTests/DOM/Events.html
Running 1 tests
Running DOM/Events.html (1 of 1)
RESULT DOM: Events= 243.986607143 ms
median= 242.297619048 ms, stdev= 5.74748351315 ms, min= 239.80952381 ms, max= 268.0 ms

After this patch:
% ./Tools/Scripts/run-perf-tests PerformanceTests/DOM/Events.html
Running 1 tests
Running DOM/Events.html (1 of 1)
RESULT DOM: Events= 242.291666667 ms
median= 240.452380952 ms, stdev= 5.8718643632 ms, min= 238.214285714 ms, max= 266.5 ms

No new tests, no behavior change.

* dom/EventDispatcher.cpp:
(WebCore::EventDispatcher::dispatchEvent):
(WebCore::EventDispatcher::dispatchEventPreProcess):
(WebCore):
(WebCore::EventDispatcher::dispatchEventAtCapturing):
(WebCore::EventDispatcher::dispatchEventAtTarget):
(WebCore::EventDispatcher::dispatchEventAtBubbling):
(WebCore::EventDispatcher::dispatchEventPostProcess):
(WebCore::EventDispatcher::topEventContext):
* dom/EventDispatcher.h:
(WebCore):
(EventDispatcher):


Canonical link: https://commits.webkit.org/110666@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@124291 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
hayatoito committed Aug 1, 2012
1 parent a639a25 commit 256eac9
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 30 deletions.
44 changes: 44 additions & 0 deletions Source/WebCore/ChangeLog
@@ -1,3 +1,47 @@
2012-07-31 Hayato Ito <hayato@chromium.org>

Refactor EventDispatcher::dispatchEvent() so that we can call each phase (Caputure, Target and Bubbling) of event dispatching separately.
https://bugs.webkit.org/show_bug.cgi?id=92621

Reviewed by Dimitri Glazkov.

This is one of the required refactorings to support event
propagation for seamless iframes. I've removed 'goto' statements
from EventDispatcher::dispatchEvent() as a result.

I've verified that all separated functions are successfully
inlined. I could not see any performance regression. The
benchmark result is:

Before this patch:
% ./Tools/Scripts/run-perf-tests PerformanceTests/DOM/Events.html
Running 1 tests
Running DOM/Events.html (1 of 1)
RESULT DOM: Events= 243.986607143 ms
median= 242.297619048 ms, stdev= 5.74748351315 ms, min= 239.80952381 ms, max= 268.0 ms

After this patch:
% ./Tools/Scripts/run-perf-tests PerformanceTests/DOM/Events.html
Running 1 tests
Running DOM/Events.html (1 of 1)
RESULT DOM: Events= 242.291666667 ms
median= 240.452380952 ms, stdev= 5.8718643632 ms, min= 238.214285714 ms, max= 266.5 ms

No new tests, no behavior change.

* dom/EventDispatcher.cpp:
(WebCore::EventDispatcher::dispatchEvent):
(WebCore::EventDispatcher::dispatchEventPreProcess):
(WebCore):
(WebCore::EventDispatcher::dispatchEventAtCapturing):
(WebCore::EventDispatcher::dispatchEventAtTarget):
(WebCore::EventDispatcher::dispatchEventAtBubbling):
(WebCore::EventDispatcher::dispatchEventPostProcess):
(WebCore::EventDispatcher::topEventContext):
* dom/EventDispatcher.h:
(WebCore):
(EventDispatcher):

2012-07-31 Yoshifumi Inoue <yosin@chromium.org>

[Chromium] Enable ENABLE_INPUT_TYPE_TIME_MULTIPLE_FIELDS
Expand Down
76 changes: 46 additions & 30 deletions Source/WebCore/dom/EventDispatcher.cpp
Expand Up @@ -236,31 +236,47 @@ void EventDispatcher::ensureEventAncestors(Event* event)
}
}

bool EventDispatcher::dispatchEvent(PassRefPtr<Event> event)
bool EventDispatcher::dispatchEvent(PassRefPtr<Event> prpEvent)
{
RefPtr<Event> event = prpEvent;
event->setTarget(eventTargetRespectingSVGTargetRules(m_node.get()));

ASSERT(!eventDispatchForbidden());
ASSERT(event->target());
ASSERT(!event->type().isNull()); // JavaScript code can create an event with an empty name, but not null.

RefPtr<EventTarget> originalTarget = event->target();
ensureEventAncestors(event.get());
WindowEventContext windowEventContext(event.get(), m_node.get(), topEventContext());
InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchEvent(m_node->document(), *event, windowEventContext.window(), m_node.get(), m_ancestors);

WindowEventContext windowContext(event.get(), m_node.get(), topEventContext());
void* preDispatchEventHandlerResult;
if (dispatchEventPreProcess(event, preDispatchEventHandlerResult) == ContinueDispatching)
if (dispatchEventAtCapturing(event, windowEventContext) == ContinueDispatching)
if (dispatchEventAtTarget(event) == ContinueDispatching)
dispatchEventAtBubbling(event, windowEventContext);
dispatchEventPostProcess(event, preDispatchEventHandlerResult);

InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchEvent(m_node->document(), *event, windowContext.window(), m_node.get(), m_ancestors);
// Ensure that after event dispatch, the event's target object is the
// outermost shadow DOM boundary.
event->setTarget(windowEventContext.target());
event->setCurrentTarget(0);
InspectorInstrumentation::didDispatchEvent(cookie);

return !event->defaultPrevented();
}

inline EventDispatchContinuation EventDispatcher::dispatchEventPreProcess(PassRefPtr<Event> event, void*& preDispatchEventHandlerResult)
{
// Give the target node a chance to do some work before DOM event handlers get a crack.
void* data = m_node->preDispatchEventHandler(event.get());
if (m_ancestors.isEmpty() || event->propagationStopped())
goto doneDispatching;
preDispatchEventHandlerResult = m_node->preDispatchEventHandler(event.get());
return (m_ancestors.isEmpty() || event->propagationStopped()) ? DoneDispatching : ContinueDispatching;
}

inline EventDispatchContinuation EventDispatcher::dispatchEventAtCapturing(PassRefPtr<Event> event, WindowEventContext& windowEventContext)
{
// Trigger capturing event handlers, starting at the top and working our way down.
event->setEventPhase(Event::CAPTURING_PHASE);

if (windowContext.handleLocalEvents(event.get()) && event->propagationStopped())
goto doneDispatching;
if (windowEventContext.handleLocalEvents(event.get()) && event->propagationStopped())
return DoneDispatching;

for (size_t i = m_ancestors.size() - 1; i > 0; --i) {
const EventContext& eventContext = m_ancestors[i];
Expand All @@ -272,14 +288,21 @@ bool EventDispatcher::dispatchEvent(PassRefPtr<Event> event)
event->setEventPhase(Event::CAPTURING_PHASE);
eventContext.handleLocalEvents(event.get());
if (event->propagationStopped())
goto doneDispatching;
return DoneDispatching;
}

return ContinueDispatching;
}

inline EventDispatchContinuation EventDispatcher::dispatchEventAtTarget(PassRefPtr<Event> event)
{
event->setEventPhase(Event::AT_TARGET);
m_ancestors[0].handleLocalEvents(event.get());
if (event->propagationStopped())
goto doneDispatching;
return event->propagationStopped() ? DoneDispatching : ContinueDispatching;
}

inline EventDispatchContinuation EventDispatcher::dispatchEventAtBubbling(PassRefPtr<Event> event, WindowEventContext& windowContext)
{
if (event->bubbles() && !event->cancelBubble()) {
// Trigger bubbling event handlers, starting at the bottom and working our way up.
event->setEventPhase(Event::BUBBLING_PHASE);
Expand All @@ -293,18 +316,21 @@ bool EventDispatcher::dispatchEvent(PassRefPtr<Event> event)
event->setEventPhase(Event::BUBBLING_PHASE);
eventContext.handleLocalEvents(event.get());
if (event->propagationStopped() || event->cancelBubble())
goto doneDispatching;
return DoneDispatching;
}
windowContext.handleLocalEvents(event.get());
}
return ContinueDispatching;
}

doneDispatching:
event->setTarget(originalTarget.get());
inline void EventDispatcher::dispatchEventPostProcess(PassRefPtr<Event> event, void* preDispatchEventHandlerResult)
{
event->setTarget(eventTargetRespectingSVGTargetRules(m_node.get()));
event->setCurrentTarget(0);
event->setEventPhase(0);

// Pass the data from the preDispatchEventHandler to the postDispatchEventHandler.
m_node->postDispatchEventHandler(event.get(), data);
m_node->postDispatchEventHandler(event.get(), preDispatchEventHandlerResult);

// Call default event handlers. While the DOM does have a concept of preventing
// default handling, the detail of which handlers are called is an internal
Expand All @@ -314,7 +340,7 @@ bool EventDispatcher::dispatchEvent(PassRefPtr<Event> event)
m_node->defaultEventHandler(event.get());
ASSERT(!event->defaultPrevented());
if (event->defaultHandled())
goto doneWithDefault;
return;
// For bubbling events, call default event handlers on the same targets in the
// same order as the bubbling phase.
if (event->bubbles()) {
Expand All @@ -323,20 +349,10 @@ bool EventDispatcher::dispatchEvent(PassRefPtr<Event> event)
m_ancestors[i].node()->defaultEventHandler(event.get());
ASSERT(!event->defaultPrevented());
if (event->defaultHandled())
goto doneWithDefault;
return;
}
}
}

doneWithDefault:

// Ensure that after event dispatch, the event's target object is the
// outermost shadow DOM boundary.
event->setTarget(windowContext.target());
event->setCurrentTarget(0);
InspectorInstrumentation::didDispatchEvent(cookie);

return !event->defaultPrevented();
}

const EventContext* EventDispatcher::topEventContext()
Expand Down
12 changes: 12 additions & 0 deletions Source/WebCore/dom/EventDispatcher.h
Expand Up @@ -42,12 +42,18 @@ class PlatformKeyboardEvent;
class PlatformMouseEvent;
class ShadowRoot;
class TreeScope;
class WindowEventContext;

enum EventDispatchBehavior {
RetargetEvent,
StayInsideShadowDOM
};

enum EventDispatchContinuation {
ContinueDispatching,
DoneDispatching
};

class EventRelatedTargetAdjuster {
public:
EventRelatedTargetAdjuster(PassRefPtr<Node>, PassRefPtr<Node> relatedTarget);
Expand Down Expand Up @@ -80,6 +86,12 @@ class EventDispatcher {
void ensureEventAncestors(Event*);
const EventContext* topEventContext();

EventDispatchContinuation dispatchEventPreProcess(PassRefPtr<Event>, void*& preDispatchEventHandlerResult);
EventDispatchContinuation dispatchEventAtCapturing(PassRefPtr<Event>, WindowEventContext&);
EventDispatchContinuation dispatchEventAtTarget(PassRefPtr<Event>);
EventDispatchContinuation dispatchEventAtBubbling(PassRefPtr<Event>, WindowEventContext&);
void dispatchEventPostProcess(PassRefPtr<Event>, void* preDispatchEventHandlerResult);

Vector<EventContext> m_ancestors;
RefPtr<Node> m_node;
RefPtr<FrameView> m_view;
Expand Down

0 comments on commit 256eac9

Please sign in to comment.