2006-10-31 Mark Rowe <bdash@webkit.org>
[WebKit-https.git] / WebKit / Misc / WebElementDictionary.m
1 /*
2  * Copyright (C) 2006 Apple Computer, 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #import "WebElementDictionary.h"
30
31 #import "WebDOMOperations.h"
32 #import "WebFrame.h"
33 #import "WebFrameBridge.h"
34 #import "WebFrameInternal.h"
35 #import "WebView.h"
36 #import "WebViewPrivate.h"
37
38 #import <WebKit/DOMCore.h>
39 #import <WebKit/DOMExtensions.h>
40 #import <WebCore/FrameMac.h>
41 #import <WebCore/HitTestResult.h>
42 #import <WebCore/Image.h>
43 #import <WebCore/KURL.h>
44
45 using namespace WebCore;
46
47 static CFMutableDictionaryRef lookupTable = NULL;
48
49 static void addLookupKey(NSString *key, SEL selector)
50 {
51     CFDictionaryAddValue(lookupTable, key, selector);
52 }
53
54 static void cacheValueForKey(const void *key, const void *value, void *self)
55 {
56     // calling objectForKey will cache the value in our _cache dictionary
57     [(WebElementDictionary *)self objectForKey:(NSString *)key];
58 }
59
60 @implementation WebElementDictionary
61 + (void)initializeLookupTable
62 {
63     if (lookupTable)
64         return;
65
66     lookupTable = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, NULL);
67
68     addLookupKey(WebElementDOMNodeKey, @selector(_domNode));
69     addLookupKey(WebElementFrameKey, @selector(_webFrame));
70     addLookupKey(WebElementImageAltStringKey, @selector(_altDisplayString));
71     addLookupKey(WebElementImageKey, @selector(_image));
72     addLookupKey(WebElementImageRectKey, @selector(_imageRect));
73     addLookupKey(WebElementImageURLKey, @selector(_absoluteImageURL));
74     addLookupKey(WebElementIsSelectedKey, @selector(_isSelected));
75     addLookupKey(WebElementSpellingToolTipKey, @selector(_spellingToolTip));
76     addLookupKey(WebElementTitleKey, @selector(_title));
77     addLookupKey(WebElementLinkURLKey, @selector(_absoluteLinkURL));
78     addLookupKey(WebElementLinkTargetFrameKey, @selector(_targetWebFrame));
79     addLookupKey(WebElementLinkTitleKey, @selector(_titleDisplayString));
80     addLookupKey(WebElementLinkLabelKey, @selector(_textContent));
81 }
82
83 - (id)initWithHitTestResult:(const HitTestResult&)result
84 {
85     [[self class] initializeLookupTable];
86     [super init];
87     _result = new HitTestResult(result);
88     return self;
89 }
90
91 - (void)dealloc
92 {
93     delete _result;
94     [_cache release];
95     [_nilValues release];
96     [super dealloc];
97 }
98
99 - (void)finalize
100 {
101     delete _result;
102     [super finalize];
103 }
104
105 - (void)_fillCache
106 {
107     CFDictionaryApplyFunction(lookupTable, cacheValueForKey, self);
108     _cacheComplete = YES;
109 }
110
111 - (unsigned)count
112 {
113     if (!_cacheComplete)
114         [self _fillCache];
115     return [_cache count];
116 }
117
118 - (NSEnumerator *)keyEnumerator
119 {
120     if (!_cacheComplete)
121         [self _fillCache];
122     return [_cache keyEnumerator];
123 }
124
125 - (id)objectForKey:(id)key
126 {
127     id value = [_cache objectForKey:key];
128     if (value || _cacheComplete || [_nilValues containsObject:key])
129         return value;
130
131     SEL selector = (SEL)CFDictionaryGetValue(lookupTable, key);
132     if (!selector)
133         return nil;
134     value = [self performSelector:selector];
135
136     unsigned lookupTableCount = CFDictionaryGetCount(lookupTable);
137     if (value) {
138         if (!_cache)
139             _cache = [[NSMutableDictionary alloc] initWithCapacity:lookupTableCount];
140         [_cache setObject:value forKey:key];
141     } else {
142         if (!_nilValues)
143             _nilValues = [[NSMutableSet alloc] initWithCapacity:lookupTableCount];
144         [_nilValues addObject:key];
145     }
146
147     _cacheComplete = ([_cache count] + [_nilValues count]) == lookupTableCount;
148
149     return value;
150 }
151
152 - (DOMNode *)_domNode
153 {
154     return kit(_result->innerNonSharedNode());
155 }
156
157 - (WebFrame *)_webFrame
158 {
159     return [[[self _domNode] ownerDocument] webFrame];
160 }
161
162 - (NSString *)_altDisplayString
163 {
164     return _result->altDisplayString();
165 }
166
167 - (NSString *)_spellingToolTip
168 {
169     return _result->spellingToolTip();
170 }
171
172 - (NSImage *)_image
173 {
174     Image *image = _result->image();
175     return image ? image->getNSImage() : nil;
176 }
177
178 - (NSValue *)_imageRect
179 {
180     if ([self objectForKey:WebElementImageURLKey])
181         return [NSValue valueWithRect:_result->boundingBox()];
182     return nil;
183 }
184
185 - (NSURL *)_absoluteImageURL
186 {
187     return _result->absoluteImageURL().getNSURL();
188 }
189
190 - (NSNumber *)_isSelected
191 {
192     return [NSNumber numberWithBool:_result->isSelected()];
193 }
194
195 - (NSString *)_title
196 {
197     return _result->title();
198 }
199
200 - (NSURL *)_absoluteLinkURL
201 {
202     return _result->absoluteLinkURL().getNSURL();
203 }
204
205 - (WebFrame *)_targetWebFrame
206 {
207     FrameMac* webCoreFrame = Mac(_result->targetFrame());
208     return kit(webCoreFrame);
209 }
210
211 - (NSString *)_titleDisplayString
212 {
213     return _result->titleDisplayString();
214 }
215
216 - (NSString *)_textContent
217 {
218     return _result->textContent();
219 }
220
221 @end