Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(83)

Side by Side Diff: third_party/WebKit/Source/core/events/EventTarget.cpp

Issue 1949793002: Emit a console warning when blocking event listener is delayed for too long (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebased Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | third_party/WebKit/Source/core/events/RegisteredEventListener.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org) 4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. 5 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
6 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) 6 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
7 * (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org> 7 * (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
8 * 8 *
9 * Redistribution and use in source and binary forms, with or without 9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions 10 * modification, are permitted provided that the following conditions
(...skipping 14 matching lines...) Expand all
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * 29 *
30 */ 30 */
31 31
32 #include "core/events/EventTarget.h" 32 #include "core/events/EventTarget.h"
33 33
34 #include "bindings/core/v8/ExceptionState.h" 34 #include "bindings/core/v8/ExceptionState.h"
35 #include "bindings/core/v8/V8AbstractEventListener.h" 35 #include "bindings/core/v8/ScriptEventListener.h"
36 #include "bindings/core/v8/V8DOMActivityLogger.h" 36 #include "bindings/core/v8/V8DOMActivityLogger.h"
37 #include "core/dom/ExceptionCode.h" 37 #include "core/dom/ExceptionCode.h"
38 #include "core/editing/Editor.h" 38 #include "core/editing/Editor.h"
39 #include "core/events/Event.h" 39 #include "core/events/Event.h"
40 #include "core/events/EventUtil.h" 40 #include "core/events/EventUtil.h"
41 #include "core/frame/FrameHost.h"
42 #include "core/frame/LocalDOMWindow.h"
43 #include "core/frame/Settings.h"
44 #include "core/frame/UseCounter.h"
45 #include "core/inspector/ConsoleMessage.h"
41 #include "core/inspector/InspectorInstrumentation.h" 46 #include "core/inspector/InspectorInstrumentation.h"
42 #include "core/frame/LocalDOMWindow.h"
43 #include "core/frame/UseCounter.h"
44 #include "platform/EventDispatchForbiddenScope.h" 47 #include "platform/EventDispatchForbiddenScope.h"
45 #include "wtf/StdLibExtras.h" 48 #include "wtf/StdLibExtras.h"
46 #include "wtf/Threading.h" 49 #include "wtf/Threading.h"
47 #include "wtf/Vector.h" 50 #include "wtf/Vector.h"
48 51
49 using namespace WTF; 52 using namespace WTF;
50 53
51 namespace blink { 54 namespace blink {
52 namespace { 55 namespace {
53 56
54 void setDefaultEventListenerOptionsLegacy(EventListenerOptions& options, bool us eCapture) 57 void setDefaultEventListenerOptionsLegacy(EventListenerOptions& options, bool us eCapture)
55 { 58 {
56 options.setCapture(useCapture); 59 options.setCapture(useCapture);
57 } 60 }
58 61
59 void setDefaultAddEventListenerOptionsLegacy(AddEventListenerOptions& options, b ool useCapture) 62 void setDefaultAddEventListenerOptionsLegacy(AddEventListenerOptions& options, b ool useCapture)
60 { 63 {
61 setDefaultEventListenerOptionsLegacy(options, useCapture); 64 setDefaultEventListenerOptionsLegacy(options, useCapture);
62 options.setPassive(false); 65 options.setPassive(false);
63 } 66 }
64 67
65 void setDefaultAddEventListenerOptions(AddEventListenerOptions& options) 68 void setDefaultAddEventListenerOptions(AddEventListenerOptions& options)
66 { 69 {
67 if (!options.hasPassive()) 70 if (!options.hasPassive())
68 options.setPassive(false); 71 options.setPassive(false);
69 } 72 }
70 73
74 double blockedEventsWarningThreshold(const ExecutionContext* context, const Even t* event)
75 {
76 if (!event->cancelable())
77 return 0.0;
78 const AtomicString& eventType = event->type();
79 if (eventType != EventTypeNames::touchstart
80 && eventType != EventTypeNames::touchmove
81 && eventType != EventTypeNames::touchend
82 && eventType != EventTypeNames::mousewheel
83 && eventType != EventTypeNames::wheel) {
84 return 0.0;
85 }
86
87 if (!context->isDocument())
88 return 0.0;
89 FrameHost* frameHost = toDocument(context)->frameHost();
90 if (!frameHost)
91 return 0.0;
92 return frameHost->settings().blockedMainThreadEventsWarningThreshold();
93 }
94
95 void reportBlockedEvent(ExecutionContext* context, const Event* event, Registere dEventListener* registeredListener, double delayedSeconds)
96 {
97 if (registeredListener->listener()->type() != EventListener::JSEventListener Type)
98 return;
99
100 V8AbstractEventListener* v8Listener = V8AbstractEventListener::cast(register edListener->listener());
101 v8::HandleScope handles(v8Listener->isolate());
102 v8::Local<v8::Object> handler = v8Listener->getListenerObject(context);
103
104 String messageText = String::format(
105 "Handling of '%s' input event was delayed for %ld ms due to main thread being busy. "
106 "Consider marking event handler as 'passive' to make the page more respo nive.",
107 event->type().characters8(), lround(delayedSeconds * 1000));
108 ConsoleMessage* message = ConsoleMessage::create(JSMessageSource, WarningMes sageLevel, messageText);
109
110 v8::Local<v8::Function> function = eventListenerEffectiveFunction(v8Listener ->isolate(), handler);
111 if (!function.IsEmpty()) {
112 message->setLineNumber(function->GetScriptLineNumber() + 1);
113 message->setColumnNumber(function->GetScriptColumnNumber());
114 message->setScriptId(function->ScriptId());
115 }
116 context->addConsoleMessage(message);
117 registeredListener->setBlockedEventWarningEmitted();
118 }
119
120
71 } // namespace 121 } // namespace
72 122
73 EventTargetData::EventTargetData() 123 EventTargetData::EventTargetData()
74 { 124 {
75 } 125 }
76 126
77 EventTargetData::~EventTargetData() 127 EventTargetData::~EventTargetData()
78 { 128 {
79 } 129 }
80 130
(...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after
442 if (LocalDOMWindow* executingWindow = this->executingWindow()) 492 if (LocalDOMWindow* executingWindow = this->executingWindow())
443 UseCounter::count(executingWindow->document(), UseCounter::DOMFocusI nOutEvent); 493 UseCounter::count(executingWindow->document(), UseCounter::DOMFocusI nOutEvent);
444 } else if (event->type() == EventTypeNames::focusin || event->type() == Even tTypeNames::focusout) { 494 } else if (event->type() == EventTypeNames::focusin || event->type() == Even tTypeNames::focusout) {
445 if (LocalDOMWindow* executingWindow = this->executingWindow()) 495 if (LocalDOMWindow* executingWindow = this->executingWindow())
446 UseCounter::count(executingWindow->document(), UseCounter::FocusInOu tEvent); 496 UseCounter::count(executingWindow->document(), UseCounter::FocusInOu tEvent);
447 } else if (event->type() == EventTypeNames::textInput) { 497 } else if (event->type() == EventTypeNames::textInput) {
448 if (LocalDOMWindow* executingWindow = this->executingWindow()) 498 if (LocalDOMWindow* executingWindow = this->executingWindow())
449 UseCounter::count(executingWindow->document(), UseCounter::TextInput Fired); 499 UseCounter::count(executingWindow->document(), UseCounter::TextInput Fired);
450 } 500 }
451 501
502 ExecutionContext* context = getExecutionContext();
503 if (!context)
504 return;
505
452 size_t i = 0; 506 size_t i = 0;
453 size_t size = entry.size(); 507 size_t size = entry.size();
454 if (!d->firingEventIterators) 508 if (!d->firingEventIterators)
455 d->firingEventIterators = adoptPtr(new FiringEventIteratorVector); 509 d->firingEventIterators = adoptPtr(new FiringEventIteratorVector);
456 d->firingEventIterators->append(FiringEventIterator(event->type(), i, size)) ; 510 d->firingEventIterators->append(FiringEventIterator(event->type(), i, size)) ;
511
512 double blockedEventThreshold = blockedEventsWarningThreshold(context, event) ;
513 double now = 0.0;
514 bool shouldReportBlockedEvent = false;
515 if (blockedEventThreshold) {
516 now = WTF::monotonicallyIncreasingTime();
517 shouldReportBlockedEvent = now - event->platformTimeStamp() > blockedEve ntThreshold;
518 }
519
457 while (i < size) { 520 while (i < size) {
458 RegisteredEventListener& registeredListener = entry[i]; 521 RegisteredEventListener& registeredListener = entry[i];
459 522
460 // Move the iterator past this event listener. This must match 523 // Move the iterator past this event listener. This must match
461 // the handling of the FiringEventIterator::iterator in 524 // the handling of the FiringEventIterator::iterator in
462 // EventTarget::removeEventListener. 525 // EventTarget::removeEventListener.
463 ++i; 526 ++i;
464 527
465 if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener .capture()) 528 if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener .capture())
466 continue; 529 continue;
467 if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.c apture()) 530 if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.c apture())
468 continue; 531 continue;
469 532
470 // If stopImmediatePropagation has been called, we just break out immedi ately, without 533 // If stopImmediatePropagation has been called, we just break out immedi ately, without
471 // handling any more events on this target. 534 // handling any more events on this target.
472 if (event->immediatePropagationStopped()) 535 if (event->immediatePropagationStopped())
473 break; 536 break;
474 537
475 ExecutionContext* context = getExecutionContext();
476 if (!context)
477 break;
478
479 event->setHandlingPassive(registeredListener.passive()); 538 event->setHandlingPassive(registeredListener.passive());
480 539
481 InspectorInstrumentation::NativeBreakpoint nativeBreakpoint(context, thi s, event); 540 InspectorInstrumentation::NativeBreakpoint nativeBreakpoint(context, thi s, event);
482 541
483 // To match Mozilla, the AT_TARGET phase fires both capturing and bubbli ng 542 // To match Mozilla, the AT_TARGET phase fires both capturing and bubbli ng
484 // event listeners, even though that violates some versions of the DOM s pec. 543 // event listeners, even though that violates some versions of the DOM s pec.
485 registeredListener.listener()->handleEvent(context, event); 544 registeredListener.listener()->handleEvent(context, event);
545
546 if (shouldReportBlockedEvent && !registeredListener.passive() && !regist eredListener.blockedEventWarningEmitted() && !event->defaultPrevented())
547 reportBlockedEvent(context, event, &registeredListener, now - event- >platformTimeStamp());
548
486 event->setHandlingPassive(false); 549 event->setHandlingPassive(false);
487 550
488 RELEASE_ASSERT(i <= size); 551 RELEASE_ASSERT(i <= size);
489 } 552 }
490 d->firingEventIterators->removeLast(); 553 d->firingEventIterators->removeLast();
491 } 554 }
492 555
493 DispatchEventResult EventTarget::dispatchEventResult(const Event& event) 556 DispatchEventResult EventTarget::dispatchEventResult(const Event& event)
494 { 557 {
495 if (event.defaultPrevented()) 558 if (event.defaultPrevented())
(...skipping 28 matching lines...) Expand all
524 // they have one less listener to invoke. 587 // they have one less listener to invoke.
525 if (d->firingEventIterators) { 588 if (d->firingEventIterators) {
526 for (size_t i = 0; i < d->firingEventIterators->size(); ++i) { 589 for (size_t i = 0; i < d->firingEventIterators->size(); ++i) {
527 d->firingEventIterators->at(i).iterator = 0; 590 d->firingEventIterators->at(i).iterator = 0;
528 d->firingEventIterators->at(i).end = 0; 591 d->firingEventIterators->at(i).end = 0;
529 } 592 }
530 } 593 }
531 } 594 }
532 595
533 } // namespace blink 596 } // namespace blink
OLDNEW
« no previous file with comments | « no previous file | third_party/WebKit/Source/core/events/RegisteredEventListener.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698