1/*
2 * Copyright (C) 2009 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 INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "config.h"
26#include "WebKitDLL.h"
27#include "WebScriptWorld.h"
28
29#include <JavaScriptCore/APICast.h>
30#include <WebCore/JSDOMBinding.h>
31#include <WebCore/ScriptController.h>
32
33using namespace WebCore;
34
35typedef HashMap<DOMWrapperWorld*, WebScriptWorld*> WorldMap;
36static WorldMap& allWorlds()
37{
38    static WorldMap& map = *new WorldMap;
39    return map;
40}
41
42inline WebScriptWorld::WebScriptWorld(PassRefPtr<DOMWrapperWorld> world)
43    : m_refCount(0)
44    , m_world(world)
45{
46    ASSERT_ARG(world, m_world);
47
48    ASSERT_ARG(world, !allWorlds().contains(m_world.get()));
49    allWorlds().add(m_world.get(), this);
50
51    ++gClassCount;
52    gClassNameCount.add("WebScriptWorld");
53}
54
55WebScriptWorld::~WebScriptWorld()
56{
57    ASSERT(allWorlds().contains(m_world.get()));
58    allWorlds().remove(m_world.get());
59
60    --gClassCount;
61    gClassNameCount.remove("WebScriptWorld");
62}
63
64WebScriptWorld* WebScriptWorld::standardWorld()
65{
66    static WebScriptWorld* standardWorld = createInstance(mainThreadNormalWorld()).releaseRef();
67    return standardWorld;
68}
69
70COMPtr<WebScriptWorld> WebScriptWorld::createInstance()
71{
72    return createInstance(ScriptController::createWorld());
73}
74
75COMPtr<WebScriptWorld> WebScriptWorld::createInstance(PassRefPtr<DOMWrapperWorld> world)
76{
77    return new WebScriptWorld(world);
78}
79
80COMPtr<WebScriptWorld> WebScriptWorld::findOrCreateWorld(DOMWrapperWorld* world)
81{
82    if (world == mainThreadNormalWorld())
83        return standardWorld();
84
85    if (WebScriptWorld* existingWorld = allWorlds().get(world))
86        return existingWorld;
87
88    return createInstance(world);
89}
90
91ULONG WebScriptWorld::AddRef()
92{
93    return ++m_refCount;
94}
95
96ULONG WebScriptWorld::Release()
97{
98    ULONG newRefCount = --m_refCount;
99    if (!newRefCount)
100        delete this;
101    return newRefCount;
102}
103
104HRESULT WebScriptWorld::QueryInterface(REFIID riid, void** ppvObject)
105{
106    if (!ppvObject)
107        return E_POINTER;
108    *ppvObject = 0;
109
110    if (IsEqualIID(riid, __uuidof(WebScriptWorld)))
111        *ppvObject = this;
112    else if (IsEqualIID(riid, __uuidof(IWebScriptWorld)))
113        *ppvObject = static_cast<IWebScriptWorld*>(this);
114    else if (IsEqualIID(riid, IID_IUnknown))
115        *ppvObject = static_cast<IUnknown*>(this);
116    else
117        return E_NOINTERFACE;
118
119    AddRef();
120    return S_OK;
121}
122
123HRESULT WebScriptWorld::standardWorld(IWebScriptWorld** outWorld)
124{
125    if (!outWorld)
126        return E_POINTER;
127
128    *outWorld = standardWorld();
129    (*outWorld)->AddRef();
130    return S_OK;
131}
132
133HRESULT WebScriptWorld::scriptWorldForGlobalContext(JSGlobalContextRef context, IWebScriptWorld** outWorld)
134{
135    if (!outWorld)
136        return E_POINTER;
137    return findOrCreateWorld(currentWorld(toJS(context))).copyRefTo(outWorld);
138}
139
140HRESULT WebScriptWorld::unregisterWorld()
141{
142    m_world->clearWrappers();
143    return S_OK;
144}
145