Home | History | Annotate | Download | only in dom
      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 #include "MessagePort.h"
     35 #include "SecurityOrigin.h"
     36 #include "WorkerContext.h"
     37 #include "WorkerThread.h"
     38 #include <wtf/MainThread.h>
     39 #include <wtf/PassRefPtr.h>
     40 
     41 #if USE(JSC)
     42 #include "JSDOMWindow.h"
     43 #endif
     44 
     45 namespace WebCore {
     46 
     47 class ProcessMessagesSoonTask : public ScriptExecutionContext::Task {
     48 public:
     49     static PassOwnPtr<ProcessMessagesSoonTask> create()
     50     {
     51         return new ProcessMessagesSoonTask;
     52     }
     53 
     54     virtual void performTask(ScriptExecutionContext* context)
     55     {
     56         context->dispatchMessagePortEvents();
     57     }
     58 };
     59 
     60 ScriptExecutionContext::ScriptExecutionContext()
     61 #if ENABLE(DATABASE)
     62     : m_hasOpenDatabases(false)
     63 #endif
     64 {
     65 }
     66 
     67 ScriptExecutionContext::~ScriptExecutionContext()
     68 {
     69     HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
     70     for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
     71         ASSERT(iter->first->scriptExecutionContext() == this);
     72         iter->first->contextDestroyed();
     73     }
     74 
     75     HashSet<MessagePort*>::iterator messagePortsEnd = m_messagePorts.end();
     76     for (HashSet<MessagePort*>::iterator iter = m_messagePorts.begin(); iter != messagePortsEnd; ++iter) {
     77         ASSERT((*iter)->scriptExecutionContext() == this);
     78         (*iter)->contextDestroyed();
     79     }
     80 #if ENABLE(DATABASE)
     81     if (m_databaseThread) {
     82         ASSERT(m_databaseThread->terminationRequested());
     83         m_databaseThread = 0;
     84     }
     85 #endif
     86 }
     87 
     88 #if ENABLE(DATABASE)
     89 
     90 DatabaseThread* ScriptExecutionContext::databaseThread()
     91 {
     92     if (!m_databaseThread && !m_hasOpenDatabases) {
     93         // Create the database thread on first request - but not if at least one database was already opened,
     94         // because in that case we already had a database thread and terminated it and should not create another.
     95         m_databaseThread = DatabaseThread::create();
     96         if (!m_databaseThread->start())
     97             m_databaseThread = 0;
     98     }
     99 
    100     return m_databaseThread.get();
    101 }
    102 
    103 void ScriptExecutionContext::addOpenDatabase(Database* database)
    104 {
    105     ASSERT(isContextThread());
    106     if (!m_openDatabaseSet)
    107         m_openDatabaseSet.set(new DatabaseSet());
    108 
    109     ASSERT(!m_openDatabaseSet->contains(database));
    110     m_openDatabaseSet->add(database);
    111 }
    112 
    113 void ScriptExecutionContext::removeOpenDatabase(Database* database)
    114 {
    115     ASSERT(isContextThread());
    116     ASSERT(m_openDatabaseSet && m_openDatabaseSet->contains(database));
    117     if (!m_openDatabaseSet)
    118         return;
    119     m_openDatabaseSet->remove(database);
    120 }
    121 
    122 void ScriptExecutionContext::stopDatabases(DatabaseTaskSynchronizer* cleanupSync)
    123 {
    124     ASSERT(isContextThread());
    125     if (m_openDatabaseSet) {
    126         DatabaseSet::iterator i = m_openDatabaseSet->begin();
    127         DatabaseSet::iterator end = m_openDatabaseSet->end();
    128         for (; i != end; ++i) {
    129             (*i)->stop();
    130             if (m_databaseThread)
    131                 m_databaseThread->unscheduleDatabaseTasks(*i);
    132         }
    133     }
    134 
    135     if (m_databaseThread)
    136         m_databaseThread->requestTermination(cleanupSync);
    137     else if (cleanupSync)
    138         cleanupSync->taskCompleted();
    139 }
    140 
    141 #endif
    142 
    143 void ScriptExecutionContext::processMessagePortMessagesSoon()
    144 {
    145     postTask(ProcessMessagesSoonTask::create());
    146 }
    147 
    148 void ScriptExecutionContext::dispatchMessagePortEvents()
    149 {
    150     RefPtr<ScriptExecutionContext> protect(this);
    151 
    152     // Make a frozen copy.
    153     Vector<MessagePort*> ports;
    154     copyToVector(m_messagePorts, ports);
    155 
    156     unsigned portCount = ports.size();
    157     for (unsigned i = 0; i < portCount; ++i) {
    158         MessagePort* port = ports[i];
    159         // The port may be destroyed, and another one created at the same address, but this is safe, as the worst that can happen
    160         // as a result is that dispatchMessages() will be called needlessly.
    161         if (m_messagePorts.contains(port) && port->started())
    162             port->dispatchMessages();
    163     }
    164 }
    165 
    166 void ScriptExecutionContext::createdMessagePort(MessagePort* port)
    167 {
    168     ASSERT(port);
    169 #if ENABLE(WORKERS)
    170     ASSERT((isDocument() && isMainThread())
    171         || (isWorkerContext() && currentThread() == static_cast<WorkerContext*>(this)->thread()->threadID()));
    172 #endif
    173 
    174     m_messagePorts.add(port);
    175 }
    176 
    177 void ScriptExecutionContext::destroyedMessagePort(MessagePort* port)
    178 {
    179     ASSERT(port);
    180 #if ENABLE(WORKERS)
    181     ASSERT((isDocument() && isMainThread())
    182         || (isWorkerContext() && currentThread() == static_cast<WorkerContext*>(this)->thread()->threadID()));
    183 #endif
    184 
    185     m_messagePorts.remove(port);
    186 }
    187 
    188 bool ScriptExecutionContext::canSuspendActiveDOMObjects()
    189 {
    190     // No protection against m_activeDOMObjects changing during iteration: canSuspend() shouldn't execute arbitrary JS.
    191     HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
    192     for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
    193         ASSERT(iter->first->scriptExecutionContext() == this);
    194         if (!iter->first->canSuspend())
    195             return false;
    196     }
    197     return true;
    198 }
    199 
    200 void ScriptExecutionContext::suspendActiveDOMObjects()
    201 {
    202     // No protection against m_activeDOMObjects changing during iteration: suspend() 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->suspend();
    207     }
    208 }
    209 
    210 void ScriptExecutionContext::resumeActiveDOMObjects()
    211 {
    212     // No protection against m_activeDOMObjects changing during iteration: resume() shouldn't execute arbitrary JS.
    213     HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
    214     for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
    215         ASSERT(iter->first->scriptExecutionContext() == this);
    216         iter->first->resume();
    217     }
    218 }
    219 
    220 void ScriptExecutionContext::stopActiveDOMObjects()
    221 {
    222     // No protection against m_activeDOMObjects changing during iteration: stop() shouldn't execute arbitrary JS.
    223     HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end();
    224     for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) {
    225         ASSERT(iter->first->scriptExecutionContext() == this);
    226         iter->first->stop();
    227     }
    228 }
    229 
    230 void ScriptExecutionContext::createdActiveDOMObject(ActiveDOMObject* object, void* upcastPointer)
    231 {
    232     ASSERT(object);
    233     ASSERT(upcastPointer);
    234     m_activeDOMObjects.add(object, upcastPointer);
    235 }
    236 
    237 void ScriptExecutionContext::destroyedActiveDOMObject(ActiveDOMObject* object)
    238 {
    239     ASSERT(object);
    240     m_activeDOMObjects.remove(object);
    241 }
    242 
    243 void ScriptExecutionContext::setSecurityOrigin(PassRefPtr<SecurityOrigin> securityOrigin)
    244 {
    245     m_securityOrigin = securityOrigin;
    246 }
    247 
    248 void ScriptExecutionContext::addTimeout(int timeoutId, DOMTimer* timer)
    249 {
    250     ASSERT(!m_timeouts.contains(timeoutId));
    251     m_timeouts.set(timeoutId, timer);
    252 }
    253 
    254 void ScriptExecutionContext::removeTimeout(int timeoutId)
    255 {
    256     m_timeouts.remove(timeoutId);
    257 }
    258 
    259 DOMTimer* ScriptExecutionContext::findTimeout(int timeoutId)
    260 {
    261     return m_timeouts.get(timeoutId);
    262 }
    263 
    264 ScriptExecutionContext::Task::~Task()
    265 {
    266 }
    267 
    268 #if USE(JSC)
    269 JSC::JSGlobalData* ScriptExecutionContext::globalData()
    270 {
    271      if (isDocument())
    272         return JSDOMWindow::commonJSGlobalData();
    273 
    274 #if ENABLE(WORKERS)
    275     if (isWorkerContext())
    276         return static_cast<WorkerContext*>(this)->script()->globalData();
    277 #endif
    278 
    279     ASSERT_NOT_REACHED();
    280     return 0;
    281 }
    282 #endif
    283 
    284 } // namespace WebCore
    285