WebKit/mac/Misc/WebElementDictionary.mm
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2006, 2007, 2008, 2010 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  *
       
     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 "DOMNodeInternal.h"
       
    32 #import "WebDOMOperations.h"
       
    33 #import "WebFrame.h"
       
    34 #import "WebFrameInternal.h"
       
    35 #import "WebKitLogging.h"
       
    36 #import "WebTypesInternal.h"
       
    37 #import "WebView.h"
       
    38 #import "WebViewPrivate.h"
       
    39 #import <WebCore/Frame.h>
       
    40 #import <WebCore/HitTestResult.h>
       
    41 #import <WebCore/Image.h>
       
    42 #import <WebCore/WebCoreObjCExtras.h>
       
    43 #import <WebKit/DOMCore.h>
       
    44 #import <WebKit/DOMExtensions.h>
       
    45 #import <runtime/InitializeThreading.h>
       
    46 #import <wtf/Threading.h>
       
    47 
       
    48 using namespace WebCore;
       
    49 
       
    50 static CFMutableDictionaryRef lookupTable = NULL;
       
    51 
       
    52 static void addLookupKey(NSString *key, SEL selector)
       
    53 {
       
    54     CFDictionaryAddValue(lookupTable, key, selector);
       
    55 }
       
    56 
       
    57 static void cacheValueForKey(const void *key, const void *value, void *self)
       
    58 {
       
    59     // calling objectForKey will cache the value in our _cache dictionary
       
    60     [(WebElementDictionary *)self objectForKey:(NSString *)key];
       
    61 }
       
    62 
       
    63 @implementation WebElementDictionary
       
    64 
       
    65 + (void)initialize
       
    66 {
       
    67     JSC::initializeThreading();
       
    68     WTF::initializeMainThreadToProcessMainThread();
       
    69 #ifndef BUILDING_ON_TIGER
       
    70     WebCoreObjCFinalizeOnMainThread(self);
       
    71 #endif
       
    72 }
       
    73 
       
    74 + (void)initializeLookupTable
       
    75 {
       
    76     if (lookupTable)
       
    77         return;
       
    78 
       
    79     lookupTable = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, NULL);
       
    80 
       
    81     addLookupKey(WebElementDOMNodeKey, @selector(_domNode));
       
    82     addLookupKey(WebElementFrameKey, @selector(_webFrame));
       
    83     addLookupKey(WebElementImageAltStringKey, @selector(_altDisplayString));
       
    84     addLookupKey(WebElementImageKey, @selector(_image));
       
    85     addLookupKey(WebElementImageRectKey, @selector(_imageRect));
       
    86     addLookupKey(WebElementImageURLKey, @selector(_absoluteImageURL));
       
    87     addLookupKey(WebElementIsSelectedKey, @selector(_isSelected));
       
    88     addLookupKey(WebElementSpellingToolTipKey, @selector(_spellingToolTip));
       
    89     addLookupKey(WebElementTitleKey, @selector(_title));
       
    90     addLookupKey(WebElementLinkURLKey, @selector(_absoluteLinkURL));
       
    91     addLookupKey(WebElementLinkTargetFrameKey, @selector(_targetWebFrame));
       
    92     addLookupKey(WebElementLinkTitleKey, @selector(_titleDisplayString));
       
    93     addLookupKey(WebElementLinkLabelKey, @selector(_textContent));
       
    94     addLookupKey(WebElementLinkIsLiveKey, @selector(_isLiveLink));
       
    95     addLookupKey(WebElementIsContentEditableKey, @selector(_isContentEditable));
       
    96     addLookupKey(WebElementIsInScrollBarKey, @selector(_isInScrollBar));
       
    97 }
       
    98 
       
    99 - (id)initWithHitTestResult:(const HitTestResult&)result
       
   100 {
       
   101     [[self class] initializeLookupTable];
       
   102     [super init];
       
   103     _result = new HitTestResult(result);
       
   104     return self;
       
   105 }
       
   106 
       
   107 - (void)dealloc
       
   108 {
       
   109     if (WebCoreObjCScheduleDeallocateOnMainThread([WebElementDictionary class], self))
       
   110         return;
       
   111 
       
   112     delete _result;
       
   113     [_cache release];
       
   114     [_nilValues release];
       
   115     [super dealloc];
       
   116 }
       
   117 
       
   118 - (void)finalize
       
   119 {
       
   120     ASSERT_MAIN_THREAD();
       
   121     delete _result;
       
   122     [super finalize];
       
   123 }
       
   124 
       
   125 - (void)_fillCache
       
   126 {
       
   127     CFDictionaryApplyFunction(lookupTable, cacheValueForKey, self);
       
   128     _cacheComplete = YES;
       
   129 }
       
   130 
       
   131 - (NSUInteger)count
       
   132 {
       
   133     if (!_cacheComplete)
       
   134         [self _fillCache];
       
   135     return [_cache count];
       
   136 }
       
   137 
       
   138 - (NSEnumerator *)keyEnumerator
       
   139 {
       
   140     if (!_cacheComplete)
       
   141         [self _fillCache];
       
   142     return [_cache keyEnumerator];
       
   143 }
       
   144 
       
   145 - (id)objectForKey:(id)key
       
   146 {
       
   147     id value = [_cache objectForKey:key];
       
   148     if (value || _cacheComplete || [_nilValues containsObject:key])
       
   149         return value;
       
   150 
       
   151     SEL selector = (SEL)CFDictionaryGetValue(lookupTable, key);
       
   152     if (!selector)
       
   153         return nil;
       
   154     value = [self performSelector:selector];
       
   155 
       
   156     unsigned lookupTableCount = CFDictionaryGetCount(lookupTable);
       
   157     if (value) {
       
   158         if (!_cache)
       
   159             _cache = [[NSMutableDictionary alloc] initWithCapacity:lookupTableCount];
       
   160         [_cache setObject:value forKey:key];
       
   161     } else {
       
   162         if (!_nilValues)
       
   163             _nilValues = [[NSMutableSet alloc] initWithCapacity:lookupTableCount];
       
   164         [_nilValues addObject:key];
       
   165     }
       
   166 
       
   167     _cacheComplete = ([_cache count] + [_nilValues count]) == lookupTableCount;
       
   168 
       
   169     return value;
       
   170 }
       
   171 
       
   172 - (DOMNode *)_domNode
       
   173 {
       
   174     return kit(_result->innerNonSharedNode());
       
   175 }
       
   176 
       
   177 - (WebFrame *)_webFrame
       
   178 {
       
   179     return [[[self _domNode] ownerDocument] webFrame];
       
   180 }
       
   181 
       
   182 // String's NSString* operator converts null Strings to empty NSStrings for compatibility
       
   183 // with AppKit. We need to work around that here.
       
   184 static NSString* NSStringOrNil(String coreString)
       
   185 {
       
   186     if (coreString.isNull())
       
   187         return nil;
       
   188     return coreString;
       
   189 }
       
   190 
       
   191 - (NSString *)_altDisplayString
       
   192 {
       
   193     return NSStringOrNil(_result->altDisplayString());
       
   194 }
       
   195 
       
   196 - (NSString *)_spellingToolTip
       
   197 {
       
   198     TextDirection dir;
       
   199     return NSStringOrNil(_result->spellingToolTip(dir));
       
   200 }
       
   201 
       
   202 - (NSImage *)_image
       
   203 {
       
   204     Image* image = _result->image();
       
   205     return image ? image->getNSImage() : nil;
       
   206 }
       
   207 
       
   208 - (NSValue *)_imageRect
       
   209 {
       
   210     IntRect rect = _result->imageRect();
       
   211     return rect.isEmpty() ? nil : [NSValue valueWithRect:rect];
       
   212 }
       
   213 
       
   214 - (NSURL *)_absoluteImageURL
       
   215 {
       
   216     return _result->absoluteImageURL();
       
   217 }
       
   218 
       
   219 - (NSNumber *)_isSelected
       
   220 {
       
   221     return [NSNumber numberWithBool:_result->isSelected()];
       
   222 }
       
   223 
       
   224 - (NSString *)_title
       
   225 {
       
   226     TextDirection dir;
       
   227     return NSStringOrNil(_result->title(dir));
       
   228 }
       
   229 
       
   230 - (NSURL *)_absoluteLinkURL
       
   231 {
       
   232     return _result->absoluteLinkURL();
       
   233 }
       
   234 
       
   235 - (WebFrame *)_targetWebFrame
       
   236 {
       
   237     return kit(_result->targetFrame());
       
   238 }
       
   239 
       
   240 - (NSString *)_titleDisplayString
       
   241 {
       
   242     return NSStringOrNil(_result->titleDisplayString());
       
   243 }
       
   244 
       
   245 - (NSString *)_textContent
       
   246 {
       
   247     return NSStringOrNil(_result->textContent());
       
   248 }
       
   249 
       
   250 - (NSNumber *)_isLiveLink
       
   251 {
       
   252     return [NSNumber numberWithBool:_result->isLiveLink()];
       
   253 }
       
   254 
       
   255 - (NSNumber *)_isContentEditable
       
   256 {
       
   257     return [NSNumber numberWithBool:_result->isContentEditable()];
       
   258 }
       
   259 
       
   260 - (NSNumber *)_isInScrollBar
       
   261 {
       
   262     return [NSNumber numberWithBool:_result->scrollbar() != 0];
       
   263 }
       
   264 
       
   265 @end