1/*
2 * Copyright (C) 2004, 2006, 2007, 2008, 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. ``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 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#import "config.h"
27#import "DOMInternal.h"
28
29#import "DOMNodeInternal.h"
30#import "Frame.h"
31#import "JSNode.h"
32#import "ScriptController.h"
33#import "WebScriptObjectPrivate.h"
34#import "runtime_root.h"
35
36#if PLATFORM(IOS)
37#define NEEDS_WRAPPER_CACHE_LOCK 1
38#endif
39
40//------------------------------------------------------------------------------------------
41// Wrapping WebCore implementation objects
42
43static NSMapTable* DOMWrapperCache;
44
45#ifdef NEEDS_WRAPPER_CACHE_LOCK
46static Mutex& wrapperCacheLock()
47{
48    DEPRECATED_DEFINE_STATIC_LOCAL(Mutex, wrapperCacheMutex, ());
49    return wrapperCacheMutex;
50}
51#endif
52
53#if COMPILER(CLANG)
54#pragma clang diagnostic push
55#pragma clang diagnostic ignored "-Wdeprecated-declarations"
56#endif
57
58NSMapTable* createWrapperCache()
59{
60    // NSMapTable with zeroing weak pointers is the recommended way to build caches like this under garbage collection.
61    NSPointerFunctionsOptions keyOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality;
62    NSPointerFunctionsOptions valueOptions = NSPointerFunctionsZeroingWeakMemory | NSPointerFunctionsObjectPersonality;
63    return [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0];
64}
65
66#if COMPILER(CLANG)
67#pragma clang diagnostic pop
68#endif
69
70NSObject* getDOMWrapper(DOMObjectInternal* impl)
71{
72#ifdef NEEDS_WRAPPER_CACHE_LOCK
73    MutexLocker locker(wrapperCacheLock());
74#endif
75    if (!DOMWrapperCache)
76        return nil;
77    return static_cast<NSObject*>(NSMapGet(DOMWrapperCache, impl));
78}
79
80void addDOMWrapper(NSObject* wrapper, DOMObjectInternal* impl)
81{
82#ifdef NEEDS_WRAPPER_CACHE_LOCK
83    MutexLocker locker(wrapperCacheLock());
84#endif
85    if (!DOMWrapperCache)
86        DOMWrapperCache = createWrapperCache();
87    NSMapInsert(DOMWrapperCache, impl, wrapper);
88}
89
90void removeDOMWrapper(DOMObjectInternal* impl)
91{
92#ifdef NEEDS_WRAPPER_CACHE_LOCK
93    MutexLocker locker(wrapperCacheLock());
94#endif
95    if (!DOMWrapperCache)
96        return;
97    NSMapRemove(DOMWrapperCache, impl);
98}
99
100//------------------------------------------------------------------------------------------
101
102@implementation WebScriptObject (WebScriptObjectInternal)
103
104// Only called by DOMObject subclass.
105- (id)_init
106{
107    self = [super init];
108
109    if (![self isKindOfClass:[DOMObject class]]) {
110        [NSException raise:NSGenericException format:@"+%@: _init is an internal initializer", [self class]];
111        return nil;
112    }
113
114    _private = [[WebScriptObjectPrivate alloc] init];
115    _private->isCreatedByDOMWrapper = YES;
116
117    return self;
118}
119
120- (void)_initializeScriptDOMNodeImp
121{
122    ASSERT(_private->isCreatedByDOMWrapper);
123
124    if (![self isKindOfClass:[DOMNode class]]) {
125        // DOMObject can't map back to a document, and thus an interpreter,
126        // so for now only create wrappers for DOMNodes.
127        NSLog(@"%s:%d:  We don't know how to create ObjC JS wrappers from DOMObjects yet.", __FILE__, __LINE__);
128        return;
129    }
130
131    // Extract the WebCore::Node from the ObjectiveC wrapper.
132    DOMNode *n = (DOMNode *)self;
133    WebCore::Node *nodeImpl = core(n);
134
135    // Dig up Interpreter and ExecState.
136    WebCore::Frame *frame = nodeImpl->document().frame();
137    if (!frame)
138        return;
139
140    // The global object which should own this node - FIXME: does this need to be isolated-world aware?
141    WebCore::JSDOMGlobalObject* globalObject = frame->script().globalObject(WebCore::mainThreadNormalWorld());
142    JSC::ExecState *exec = globalObject->globalExec();
143
144    // Get (or create) a cached JS object for the DOM node.
145    JSC::JSObject *scriptImp = asObject(WebCore::toJS(exec, globalObject, nodeImpl));
146
147    JSC::Bindings::RootObject* rootObject = frame->script().bindingRootObject();
148
149    [self _setImp:scriptImp originRootObject:rootObject rootObject:rootObject];
150}
151
152@end
153