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