WebCore/dom/ScriptExecutionContext.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2008 Apple 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
       
     6  * are met:
       
     7  * 1. Redistributions of source code must retain the above copyright
       
     8  *    notice, this list of conditions and the following disclaimer.
       
     9  * 2. Redistributions in binary form must reproduce the above copyright
       
    10  *    notice, this list of conditions and the following disclaimer in the
       
    11  *    documentation and/or other materials provided with the distribution.
       
    12  *
       
    13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
       
    14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       
    15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
       
    16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
       
    17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
       
    18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
       
    20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
       
    21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       
    23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
       
    24  *
       
    25  */
       
    26 
       
    27 #include "config.h"
       
    28 #include "ScriptExecutionContext.h"
       
    29 
       
    30 #include "ActiveDOMObject.h"
       
    31 #include "Database.h"
       
    32 #include "DatabaseTask.h"
       
    33 #include "DatabaseThread.h"
       
    34 #if ENABLE(FILE_READER) || ENABLE(FILE_WRITER)
       
    35 #include "FileThread.h"
       
    36 #endif
       
    37 #include "MessagePort.h"
       
    38 #include "SecurityOrigin.h"
       
    39 #include "WorkerContext.h"
       
    40 #include "WorkerThread.h"
       
    41 #include <wtf/MainThread.h>
       
    42 #include <wtf/PassRefPtr.h>
       
    43 
       
    44 #if USE(JSC)
       
    45 #include "JSDOMWindow.h"
       
    46 #endif
       
    47 
       
    48 namespace WebCore {
       
    49 
       
    50 class ProcessMessagesSoonTask : public ScriptExecutionContext::Task {
       
    51 public:
       
    52     static PassOwnPtr<ProcessMessagesSoonTask> create()
       
    53     {
       
    54         return new ProcessMessagesSoonTask;
       
    55     }
       
    56 
       
    57     virtual void performTask(ScriptExecutionContext* context)
       
    58     {
       
    59         context->dispatchMessagePortEvents();
       
    60     }
       
    61 };
       
    62 
       
    63 ScriptExecutionContext::ScriptExecutionContext()
       
    64 #if ENABLE(DATABASE)
       
    65     : m_hasOpenDatabases(false)
       
    66 #endif
       
    67 {
       
    68 }
       
    69 
       
    70 ScriptExecutionContext::~ScriptExecutionContext()
       
    71 {
       
    72     HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
       
    73     for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
       
    74         ASSERT(iter->first->scriptExecutionContext() == this);
       
    75         iter->first->contextDestroyed();
       
    76     }
       
    77 
       
    78     HashSet<MessagePort*>::iterator messagePortsEnd = m_messagePorts.end();
       
    79     for (HashSet<MessagePort*>::iterator iter = m_messagePorts.begin(); iter != messagePortsEnd; ++iter) {
       
    80         ASSERT((*iter)->scriptExecutionContext() == this);
       
    81         (*iter)->contextDestroyed();
       
    82     }
       
    83 #if ENABLE(DATABASE)
       
    84     if (m_databaseThread) {
       
    85         ASSERT(m_databaseThread->terminationRequested());
       
    86         m_databaseThread = 0;
       
    87     }
       
    88 #endif
       
    89 #if ENABLE(FILE_READER) || ENABLE(FILE_WRITER)
       
    90     if (m_fileThread) {
       
    91         m_fileThread->stop();
       
    92         m_fileThread = 0;
       
    93     }
       
    94 #endif
       
    95 }
       
    96 
       
    97 #if ENABLE(DATABASE)
       
    98 
       
    99 DatabaseThread* ScriptExecutionContext::databaseThread()
       
   100 {
       
   101     if (!m_databaseThread && !m_hasOpenDatabases) {
       
   102         // Create the database thread on first request - but not if at least one database was already opened,
       
   103         // because in that case we already had a database thread and terminated it and should not create another.
       
   104         m_databaseThread = DatabaseThread::create();
       
   105         if (!m_databaseThread->start())
       
   106             m_databaseThread = 0;
       
   107     }
       
   108 
       
   109     return m_databaseThread.get();
       
   110 }
       
   111 
       
   112 void ScriptExecutionContext::stopDatabases(DatabaseTaskSynchronizer* cleanupSync)
       
   113 {
       
   114     ASSERT(isContextThread());
       
   115     if (m_databaseThread)
       
   116         m_databaseThread->requestTermination(cleanupSync);
       
   117     else if (cleanupSync)
       
   118         cleanupSync->taskCompleted();
       
   119 }
       
   120 
       
   121 #endif
       
   122 
       
   123 void ScriptExecutionContext::processMessagePortMessagesSoon()
       
   124 {
       
   125     postTask(ProcessMessagesSoonTask::create());
       
   126 }
       
   127 
       
   128 void ScriptExecutionContext::dispatchMessagePortEvents()
       
   129 {
       
   130     RefPtr<ScriptExecutionContext> protect(this);
       
   131 
       
   132     // Make a frozen copy.
       
   133     Vector<MessagePort*> ports;
       
   134     copyToVector(m_messagePorts, ports);
       
   135 
       
   136     unsigned portCount = ports.size();
       
   137     for (unsigned i = 0; i < portCount; ++i) {
       
   138         MessagePort* port = ports[i];
       
   139         // The port may be destroyed, and another one created at the same address, but this is safe, as the worst that can happen
       
   140         // as a result is that dispatchMessages() will be called needlessly.
       
   141         if (m_messagePorts.contains(port) && port->started())
       
   142             port->dispatchMessages();
       
   143     }
       
   144 }
       
   145 
       
   146 void ScriptExecutionContext::createdMessagePort(MessagePort* port)
       
   147 {
       
   148     ASSERT(port);
       
   149 #if ENABLE(WORKERS)
       
   150     ASSERT((isDocument() && isMainThread())
       
   151         || (isWorkerContext() && currentThread() == static_cast<WorkerContext*>(this)->thread()->threadID()));
       
   152 #endif
       
   153 
       
   154     m_messagePorts.add(port);
       
   155 }
       
   156 
       
   157 void ScriptExecutionContext::destroyedMessagePort(MessagePort* port)
       
   158 {
       
   159     ASSERT(port);
       
   160 #if ENABLE(WORKERS)
       
   161     ASSERT((isDocument() && isMainThread())
       
   162         || (isWorkerContext() && currentThread() == static_cast<WorkerContext*>(this)->thread()->threadID()));
       
   163 #endif
       
   164 
       
   165     m_messagePorts.remove(port);
       
   166 }
       
   167 
       
   168 bool ScriptExecutionContext::canSuspendActiveDOMObjects()
       
   169 {
       
   170     // No protection against m_activeDOMObjects changing during iteration: canSuspend() shouldn't execute arbitrary JS.
       
   171     HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
       
   172     for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
       
   173         ASSERT(iter->first->scriptExecutionContext() == this);
       
   174         if (!iter->first->canSuspend())
       
   175             return false;
       
   176     }
       
   177     return true;
       
   178 }
       
   179 
       
   180 void ScriptExecutionContext::suspendActiveDOMObjects()
       
   181 {
       
   182     // No protection against m_activeDOMObjects changing during iteration: suspend() shouldn't execute arbitrary JS.
       
   183     HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
       
   184     for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
       
   185         ASSERT(iter->first->scriptExecutionContext() == this);
       
   186         iter->first->suspend();
       
   187     }
       
   188 }
       
   189 
       
   190 void ScriptExecutionContext::resumeActiveDOMObjects()
       
   191 {
       
   192     // No protection against m_activeDOMObjects changing during iteration: resume() shouldn't execute arbitrary JS.
       
   193     HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
       
   194     for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
       
   195         ASSERT(iter->first->scriptExecutionContext() == this);
       
   196         iter->first->resume();
       
   197     }
       
   198 }
       
   199 
       
   200 void ScriptExecutionContext::stopActiveDOMObjects()
       
   201 {
       
   202     // No protection against m_activeDOMObjects changing during iteration: stop() shouldn't execute arbitrary JS.
       
   203     HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
       
   204     for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
       
   205         ASSERT(iter->first->scriptExecutionContext() == this);
       
   206         iter->first->stop();
       
   207     }
       
   208 }
       
   209 
       
   210 void ScriptExecutionContext::createdActiveDOMObject(ActiveDOMObject* object, void* upcastPointer)
       
   211 {
       
   212     ASSERT(object);
       
   213     ASSERT(upcastPointer);
       
   214     m_activeDOMObjects.add(object, upcastPointer);
       
   215 }
       
   216 
       
   217 void ScriptExecutionContext::destroyedActiveDOMObject(ActiveDOMObject* object)
       
   218 {
       
   219     ASSERT(object);
       
   220     m_activeDOMObjects.remove(object);
       
   221 }
       
   222 
       
   223 void ScriptExecutionContext::setSecurityOrigin(PassRefPtr<SecurityOrigin> securityOrigin)
       
   224 {
       
   225     m_securityOrigin = securityOrigin;
       
   226 }
       
   227 
       
   228 void ScriptExecutionContext::addTimeout(int timeoutId, DOMTimer* timer)
       
   229 {
       
   230     ASSERT(!m_timeouts.contains(timeoutId));
       
   231     m_timeouts.set(timeoutId, timer);
       
   232 }
       
   233 
       
   234 void ScriptExecutionContext::removeTimeout(int timeoutId)
       
   235 {
       
   236     m_timeouts.remove(timeoutId);
       
   237 }
       
   238 
       
   239 DOMTimer* ScriptExecutionContext::findTimeout(int timeoutId)
       
   240 {
       
   241     return m_timeouts.get(timeoutId);
       
   242 }
       
   243 
       
   244 #if ENABLE(FILE_READER) || ENABLE(FILE_WRITER)
       
   245 FileThread* ScriptExecutionContext::fileThread()
       
   246 {
       
   247     if (!m_fileThread) {
       
   248         m_fileThread = FileThread::create();
       
   249         if (!m_fileThread->start())
       
   250             m_fileThread = 0;
       
   251     }
       
   252     return m_fileThread.get();
       
   253 }
       
   254 #endif
       
   255 
       
   256 ScriptExecutionContext::Task::~Task()
       
   257 {
       
   258 }
       
   259 
       
   260 #if USE(JSC)
       
   261 JSC::JSGlobalData* ScriptExecutionContext::globalData()
       
   262 {
       
   263      if (isDocument())
       
   264         return JSDOMWindow::commonJSGlobalData();
       
   265 
       
   266 #if ENABLE(WORKERS)
       
   267     if (isWorkerContext())
       
   268         return static_cast<WorkerContext*>(this)->script()->globalData();
       
   269 #endif
       
   270 
       
   271     ASSERT_NOT_REACHED();
       
   272     return 0;
       
   273 }
       
   274 #endif
       
   275 
       
   276 } // namespace WebCore