/platform/external/webkit/WebCore/bindings/v8/V8AbstractEventListener.cpp

https://github.com/aharish/totoro-gb-opensource-update2 · C++ · 193 lines · 117 code · 33 blank · 43 comment · 27 complexity · 8998babe967c3b1e6491cec3dd9ff2d2 MD5 · raw file

  1. /*
  2. * Copyright (C) 2006, 2007, 2008, 2009 Google Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are
  6. * met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above
  11. * copyright notice, this list of conditions and the following disclaimer
  12. * in the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Google Inc. nor the names of its
  15. * contributors may be used to endorse or promote products derived from
  16. * this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  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.
  29. */
  30. #include "config.h"
  31. #include "V8AbstractEventListener.h"
  32. #include "DateExtension.h"
  33. #include "Document.h"
  34. #include "Event.h"
  35. #include "Frame.h"
  36. #include "V8Binding.h"
  37. #include "V8Event.h"
  38. #include "V8EventListenerList.h"
  39. #include "V8Proxy.h"
  40. #include "V8Utilities.h"
  41. #include "WorkerContext.h"
  42. #include "WorkerContextExecutionProxy.h"
  43. namespace WebCore {
  44. static void weakEventListenerCallback(v8::Persistent<v8::Value>, void* parameter)
  45. {
  46. V8AbstractEventListener* listener = static_cast<V8AbstractEventListener*>(parameter);
  47. listener->disposeListenerObject();
  48. }
  49. V8AbstractEventListener::V8AbstractEventListener(bool isAttribute, const WorldContextHandle& worldContext)
  50. : EventListener(JSEventListenerType)
  51. , m_isWeak(true)
  52. , m_isAttribute(isAttribute)
  53. , m_worldContext(worldContext)
  54. {
  55. }
  56. V8AbstractEventListener::~V8AbstractEventListener()
  57. {
  58. if (!m_listener.IsEmpty()) {
  59. v8::HandleScope scope;
  60. v8::Local<v8::Object> listener = v8::Local<v8::Object>::New(m_listener);
  61. V8EventListenerList::clearWrapper(listener, m_isAttribute);
  62. }
  63. disposeListenerObject();
  64. }
  65. void V8AbstractEventListener::handleEvent(ScriptExecutionContext* context, Event* event)
  66. {
  67. // The callback function on XMLHttpRequest can clear the event listener and destroys 'this' object. Keep a local reference to it.
  68. // See issue 889829.
  69. RefPtr<V8AbstractEventListener> protect(this);
  70. v8::HandleScope handleScope;
  71. v8::Local<v8::Context> v8Context = toV8Context(context, worldContext());
  72. if (v8Context.IsEmpty())
  73. return;
  74. // Enter the V8 context in which to perform the event handling.
  75. v8::Context::Scope scope(v8Context);
  76. // Get the V8 wrapper for the event object.
  77. v8::Handle<v8::Value> jsEvent = toV8(event);
  78. invokeEventHandler(context, event, jsEvent);
  79. Document::updateStyleForAllDocuments();
  80. }
  81. void V8AbstractEventListener::disposeListenerObject()
  82. {
  83. if (!m_listener.IsEmpty()) {
  84. #ifndef NDEBUG
  85. V8GCController::unregisterGlobalHandle(this, m_listener);
  86. #endif
  87. m_listener.Dispose();
  88. m_listener.Clear();
  89. }
  90. }
  91. void V8AbstractEventListener::setListenerObject(v8::Handle<v8::Object> listener)
  92. {
  93. disposeListenerObject();
  94. m_listener = v8::Persistent<v8::Object>::New(listener);
  95. #ifndef NDEBUG
  96. V8GCController::registerGlobalHandle(EVENT_LISTENER, this, m_listener);
  97. #endif
  98. if (m_isWeak)
  99. m_listener.MakeWeak(this, &weakEventListenerCallback);
  100. }
  101. void V8AbstractEventListener::invokeEventHandler(ScriptExecutionContext* context, Event* event, v8::Handle<v8::Value> jsEvent)
  102. {
  103. v8::Local<v8::Context> v8Context = toV8Context(context, worldContext());
  104. if (v8Context.IsEmpty())
  105. return;
  106. // We push the event being processed into the global object, so that it can be exposed by DOMWindow's bindings.
  107. v8::Local<v8::String> eventSymbol = v8::String::NewSymbol("event");
  108. v8::Local<v8::Value> returnValue;
  109. // In beforeunload/unload handlers, we want to avoid sleeps which do tight loops of calling Date.getTime().
  110. if (event->type() == "beforeunload" || event->type() == "unload")
  111. DateExtension::get()->setAllowSleep(false);
  112. {
  113. // Catch exceptions thrown in the event handler so they do not propagate to javascript code that caused the event to fire.
  114. v8::TryCatch tryCatch;
  115. tryCatch.SetVerbose(true);
  116. // Save the old 'event' property so we can restore it later.
  117. v8::Local<v8::Value> savedEvent = v8Context->Global()->GetHiddenValue(eventSymbol);
  118. tryCatch.Reset();
  119. // Make the event available in the global object, so DOMWindow can expose it.
  120. v8Context->Global()->SetHiddenValue(eventSymbol, jsEvent);
  121. tryCatch.Reset();
  122. // Call the event handler.
  123. returnValue = callListenerFunction(context, jsEvent, event);
  124. if (!tryCatch.CanContinue())
  125. return;
  126. // If an error occurs while handling the event, it should be reported.
  127. if (tryCatch.HasCaught()) {
  128. reportException(0, tryCatch);
  129. tryCatch.Reset();
  130. }
  131. // Restore the old event. This must be done for all exit paths through this method.
  132. if (savedEvent.IsEmpty())
  133. v8Context->Global()->SetHiddenValue(eventSymbol, v8::Undefined());
  134. else
  135. v8Context->Global()->SetHiddenValue(eventSymbol, savedEvent);
  136. tryCatch.Reset();
  137. }
  138. if (event->type() == "beforeunload" || event->type() == "unload")
  139. DateExtension::get()->setAllowSleep(true);
  140. ASSERT(!V8Proxy::handleOutOfMemory() || returnValue.IsEmpty());
  141. if (returnValue.IsEmpty())
  142. return;
  143. if (!returnValue->IsNull() && !returnValue->IsUndefined() && event->storesResultAsString())
  144. event->storeResult(toWebCoreString(returnValue));
  145. // Prevent default action if the return value is false;
  146. // FIXME: Add example, and reference to bug entry.
  147. if (m_isAttribute && returnValue->IsBoolean() && !returnValue->BooleanValue())
  148. event->preventDefault();
  149. }
  150. v8::Local<v8::Object> V8AbstractEventListener::getReceiverObject(Event* event)
  151. {
  152. if (!m_listener.IsEmpty() && !m_listener->IsFunction())
  153. return v8::Local<v8::Object>::New(m_listener);
  154. EventTarget* target = event->currentTarget();
  155. v8::Handle<v8::Value> value = V8DOMWrapper::convertEventTargetToV8Object(target);
  156. if (value.IsEmpty())
  157. return v8::Local<v8::Object>();
  158. return v8::Local<v8::Object>::New(v8::Handle<v8::Object>::Cast(value));
  159. }
  160. } // namespace WebCore