diff options
author | Ben Murdoch <benm@google.com> | 2009-08-11 17:01:47 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2009-08-11 18:21:02 +0100 |
commit | 0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5 (patch) | |
tree | 2943df35f62d885c89d01063cc528dd73b480fea /WebKit/mac/WebView | |
parent | 7e7a70bfa49a1122b2597a1e6367d89eb4035eca (diff) | |
download | external_webkit-0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5.zip external_webkit-0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5.tar.gz external_webkit-0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5.tar.bz2 |
Merge in WebKit r47029.
Diffstat (limited to 'WebKit/mac/WebView')
32 files changed, 3464 insertions, 2010 deletions
diff --git a/WebKit/mac/WebView/WebDataSource.mm b/WebKit/mac/WebView/WebDataSource.mm index 57347d3..b83139d 100644 --- a/WebKit/mac/WebView/WebDataSource.mm +++ b/WebKit/mac/WebView/WebDataSource.mm @@ -189,7 +189,7 @@ static inline void addTypesFromClass(NSMutableDictionary *allTypes, Class objCCl - (NSString *)_responseMIMEType { - return [[self response] _webcore_MIMEType]; + return [[self response] MIMEType]; } - (BOOL)_transferApplicationCache:(NSString*)destinationBundleIdentifier @@ -198,14 +198,10 @@ static inline void addTypesFromClass(NSMutableDictionary *allTypes, Class objCCl if (!loader) return NO; - - ApplicationCache* cache = loader->applicationCache(); - if (!cache) - return YES; - + NSString *cacheDir = [NSString _webkit_localCacheDirectoryWithBundleIdentifier:destinationBundleIdentifier]; - return ApplicationCacheStorage::storeCopyOfCache(cacheDir, cache); + return ApplicationCacheStorage::storeCopyOfCache(cacheDir, loader->applicationCacheHost()); } @end @@ -224,7 +220,9 @@ static inline void addTypesFromClass(NSMutableDictionary *allTypes, Class objCCl RetainPtr<WebDataSource*> protect(self); [[self representation] receivedData:data withDataSource:self]; - [[[[self webFrame] frameView] documentView] dataSourceUpdated:self]; + + if ([[self _webView] _usesDocumentViews]) + [[[[self webFrame] frameView] documentView] dataSourceUpdated:self]; } - (void)_setMainDocumentError:(NSError *)error @@ -340,7 +338,7 @@ static inline void addTypesFromClass(NSMutableDictionary *allTypes, Class objCCl return [WebView canShowMIMETypeAsHTML:MIMEType]; } --(void)_makeRepresentation +- (void)_makeRepresentation { Class repClass = [[self class] _representationClassForMIMEType:[self _responseMIMEType]]; @@ -350,7 +348,7 @@ static inline void addTypesFromClass(NSMutableDictionary *allTypes, Class objCCl [self _setRepresentation:(id <WebDocumentRepresentation>)newRep]; [newRep release]; } - + [_private->representation setDataSource:self]; } diff --git a/WebKit/mac/WebView/WebDelegateImplementationCaching.h b/WebKit/mac/WebView/WebDelegateImplementationCaching.h new file mode 100644 index 0000000..41e44e0 --- /dev/null +++ b/WebKit/mac/WebView/WebDelegateImplementationCaching.h @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This header contains WebView declarations that can be used anywhere in WebKit, but are neither SPI nor API. + +#import "WebTypesInternal.h" + +@class WebView; + +struct WebResourceDelegateImplementationCache { + IMP didCancelAuthenticationChallengeFunc; + IMP didReceiveAuthenticationChallengeFunc; + IMP identifierForRequestFunc; + IMP willSendRequestFunc; + IMP didReceiveResponseFunc; + IMP didReceiveContentLengthFunc; + IMP didFinishLoadingFromDataSourceFunc; + IMP didFailLoadingWithErrorFromDataSourceFunc; + IMP didLoadResourceFromMemoryCacheFunc; + IMP willCacheResponseFunc; + IMP plugInFailedWithErrorFunc; + IMP shouldUseCredentialStorageFunc; +}; + +struct WebFrameLoadDelegateImplementationCache { + IMP didClearWindowObjectForFrameFunc; + IMP didClearInspectorWindowObjectForFrameFunc; + IMP windowScriptObjectAvailableFunc; + IMP didHandleOnloadEventsForFrameFunc; + IMP didReceiveServerRedirectForProvisionalLoadForFrameFunc; + IMP didCancelClientRedirectForFrameFunc; + IMP willPerformClientRedirectToURLDelayFireDateForFrameFunc; + IMP didChangeLocationWithinPageForFrameFunc; + IMP willCloseFrameFunc; + IMP didStartProvisionalLoadForFrameFunc; + IMP didReceiveTitleForFrameFunc; + IMP didCommitLoadForFrameFunc; + IMP didFailProvisionalLoadWithErrorForFrameFunc; + IMP didFailLoadWithErrorForFrameFunc; + IMP didFinishLoadForFrameFunc; + IMP didFirstLayoutInFrameFunc; + IMP didFirstVisuallyNonEmptyLayoutInFrameFunc; + IMP didReceiveIconForFrameFunc; + IMP didFinishDocumentLoadForFrameFunc; +}; + +struct WebScriptDebugDelegateImplementationCache { + BOOL didParseSourceExpectsBaseLineNumber; + IMP didParseSourceFunc; + IMP failedToParseSourceFunc; + IMP didEnterCallFrameFunc; + IMP willExecuteStatementFunc; + IMP willLeaveCallFrameFunc; + IMP exceptionWasRaisedFunc; +}; + +WebResourceDelegateImplementationCache* WebViewGetResourceLoadDelegateImplementations(WebView *); +WebFrameLoadDelegateImplementationCache* WebViewGetFrameLoadDelegateImplementations(WebView *); +WebScriptDebugDelegateImplementationCache* WebViewGetScriptDebugDelegateImplementations(WebView *); + +id CallFormDelegate(WebView *, SEL, id, id); +id CallFormDelegate(WebView *self, SEL selector, id object1, id object2, id object3, id object4, id object5); +BOOL CallFormDelegateReturningBoolean(BOOL, WebView *, SEL, id, SEL, id); + +id CallUIDelegate(WebView *, SEL); +id CallUIDelegate(WebView *, SEL, id); +id CallUIDelegate(WebView *, SEL, NSRect); +id CallUIDelegate(WebView *, SEL, id, id); +id CallUIDelegate(WebView *, SEL, id, BOOL); +id CallUIDelegate(WebView *, SEL, id, id, id); +id CallUIDelegate(WebView *, SEL, id, NSUInteger); +float CallUIDelegateReturningFloat(WebView *, SEL); +BOOL CallUIDelegateReturningBoolean(BOOL, WebView *, SEL); +BOOL CallUIDelegateReturningBoolean(BOOL, WebView *, SEL, id); +BOOL CallUIDelegateReturningBoolean(BOOL, WebView *, SEL, id, id); +BOOL CallUIDelegateReturningBoolean(BOOL, WebView *, SEL, id, BOOL); + +id CallFrameLoadDelegate(IMP, WebView *, SEL); +id CallFrameLoadDelegate(IMP, WebView *, SEL, id); +id CallFrameLoadDelegate(IMP, WebView *, SEL, id, id); +id CallFrameLoadDelegate(IMP, WebView *, SEL, id, id, id); +id CallFrameLoadDelegate(IMP, WebView *, SEL, id, id, id, id); +id CallFrameLoadDelegate(IMP, WebView *, SEL, id, NSTimeInterval, id, id); + +id CallResourceLoadDelegate(IMP, WebView *, SEL, id, id); +id CallResourceLoadDelegate(IMP, WebView *, SEL, id, id, id); +id CallResourceLoadDelegate(IMP, WebView *, SEL, id, id, id, id); +id CallResourceLoadDelegate(IMP, WebView *, SEL, id, NSInteger, id); +id CallResourceLoadDelegate(IMP, WebView *, SEL, id, id, NSInteger, id); + +BOOL CallResourceLoadDelegateReturningBoolean(BOOL, IMP, WebView *, SEL, id, id); + +id CallScriptDebugDelegate(IMP, WebView *, SEL, id, id, NSInteger, id); +id CallScriptDebugDelegate(IMP, WebView *, SEL, id, NSInteger, id, NSInteger, id); +id CallScriptDebugDelegate(IMP, WebView *, SEL, id, NSInteger, id, id, id); +id CallScriptDebugDelegate(IMP, WebView *, SEL, id, NSInteger, NSInteger, id); diff --git a/WebKit/mac/WebView/WebDelegateImplementationCaching.mm b/WebKit/mac/WebView/WebDelegateImplementationCaching.mm new file mode 100644 index 0000000..441df92 --- /dev/null +++ b/WebKit/mac/WebView/WebDelegateImplementationCaching.mm @@ -0,0 +1,590 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2006 David Smith (catfish.man@gmail.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "WebDelegateImplementationCaching.h" + +#import "WebKitLogging.h" +#import "WebView.h" +#import "WebViewData.h" +#import <objc/objc-runtime.h> + +@implementation WebView (WebDelegateImplementationCaching) + +WebResourceDelegateImplementationCache* WebViewGetResourceLoadDelegateImplementations(WebView *webView) +{ + static WebResourceDelegateImplementationCache empty; + if (!webView) + return ∅ + return &webView->_private->resourceLoadDelegateImplementations; +} + +WebFrameLoadDelegateImplementationCache* WebViewGetFrameLoadDelegateImplementations(WebView *webView) +{ + static WebFrameLoadDelegateImplementationCache empty; + if (!webView) + return ∅ + return &webView->_private->frameLoadDelegateImplementations; +} + +WebScriptDebugDelegateImplementationCache* WebViewGetScriptDebugDelegateImplementations(WebView *webView) +{ + static WebScriptDebugDelegateImplementationCache empty; + if (!webView) + return ∅ + return &webView->_private->scriptDebugDelegateImplementations; +} + +// We use these functions to call the delegates and block exceptions. These functions are +// declared inside a WebView category to get direct access to the delegate data memebers, +// preventing more ObjC message dispatch and compensating for the expense of the @try/@catch. + +typedef float (*ObjCMsgSendFPRet)(id, SEL, ...); +#if defined(__i386__) +static const ObjCMsgSendFPRet objc_msgSend_float_return = reinterpret_cast<ObjCMsgSendFPRet>(objc_msgSend_fpret); +#else +static const ObjCMsgSendFPRet objc_msgSend_float_return = reinterpret_cast<ObjCMsgSendFPRet>(objc_msgSend); +#endif + +static inline id CallDelegate(WebView *self, id delegate, SEL selector) +{ + if (!delegate || ![delegate respondsToSelector:selector]) + return nil; + if (!self->_private->catchesDelegateExceptions) + return objc_msgSend(delegate, selector, self); + @try { + return objc_msgSend(delegate, selector, self); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return nil; +} + +static inline id CallDelegate(WebView *self, id delegate, SEL selector, id object) +{ + if (!delegate || ![delegate respondsToSelector:selector]) + return nil; + if (!self->_private->catchesDelegateExceptions) + return objc_msgSend(delegate, selector, self, object); + @try { + return objc_msgSend(delegate, selector, self, object); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return nil; +} + +static inline id CallDelegate(WebView *self, id delegate, SEL selector, NSRect rect) +{ + if (!delegate || ![delegate respondsToSelector:selector]) + return nil; + if (!self->_private->catchesDelegateExceptions) + return reinterpret_cast<id (*)(id, SEL, WebView *, NSRect)>(objc_msgSend)(delegate, selector, self, rect); + @try { + return reinterpret_cast<id (*)(id, SEL, WebView *, NSRect)>(objc_msgSend)(delegate, selector, self, rect); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return nil; +} + +static inline id CallDelegate(WebView *self, id delegate, SEL selector, id object1, id object2) +{ + if (!delegate || ![delegate respondsToSelector:selector]) + return nil; + if (!self->_private->catchesDelegateExceptions) + return objc_msgSend(delegate, selector, self, object1, object2); + @try { + return objc_msgSend(delegate, selector, self, object1, object2); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return nil; +} + +static inline id CallDelegate(WebView *self, id delegate, SEL selector, id object, BOOL boolean) +{ + if (!delegate || ![delegate respondsToSelector:selector]) + return nil; + if (!self->_private->catchesDelegateExceptions) + return objc_msgSend(delegate, selector, self, object, boolean); + @try { + return objc_msgSend(delegate, selector, self, object, boolean); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return nil; +} + +static inline id CallDelegate(WebView *self, id delegate, SEL selector, id object1, id object2, id object3) +{ + if (!delegate || ![delegate respondsToSelector:selector]) + return nil; + if (!self->_private->catchesDelegateExceptions) + return objc_msgSend(delegate, selector, self, object1, object2, object3); + @try { + return objc_msgSend(delegate, selector, self, object1, object2, object3); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return nil; +} + +static inline id CallDelegate(WebView *self, id delegate, SEL selector, id object, NSUInteger integer) +{ + if (!delegate || ![delegate respondsToSelector:selector]) + return nil; + if (!self->_private->catchesDelegateExceptions) + return objc_msgSend(delegate, selector, self, object, integer); + @try { + return objc_msgSend(delegate, selector, self, object, integer); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return nil; +} + +static inline float CallDelegateReturningFloat(WebView *self, id delegate, SEL selector) +{ + if (!delegate || ![delegate respondsToSelector:selector]) + return 0.0f; + if (!self->_private->catchesDelegateExceptions) + return objc_msgSend_float_return(delegate, selector, self); + @try { + return objc_msgSend_float_return(delegate, selector, self); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return 0.0f; +} + +static inline BOOL CallDelegateReturningBoolean(BOOL result, WebView *self, id delegate, SEL selector) +{ + if (!delegate || ![delegate respondsToSelector:selector]) + return result; + if (!self->_private->catchesDelegateExceptions) + return reinterpret_cast<BOOL (*)(id, SEL, WebView *)>(objc_msgSend)(delegate, selector, self); + @try { + return reinterpret_cast<BOOL (*)(id, SEL, WebView *)>(objc_msgSend)(delegate, selector, self); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return result; +} + +static inline BOOL CallDelegateReturningBoolean(BOOL result, WebView *self, id delegate, SEL selector, id object) +{ + if (!delegate || ![delegate respondsToSelector:selector]) + return result; + if (!self->_private->catchesDelegateExceptions) + return reinterpret_cast<BOOL (*)(id, SEL, WebView *, id)>(objc_msgSend)(delegate, selector, self, object); + @try { + return reinterpret_cast<BOOL (*)(id, SEL, WebView *, id)>(objc_msgSend)(delegate, selector, self, object); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return result; +} + +static inline BOOL CallDelegateReturningBoolean(BOOL result, WebView *self, id delegate, SEL selector, id object, BOOL boolean) +{ + if (!delegate || ![delegate respondsToSelector:selector]) + return result; + if (!self->_private->catchesDelegateExceptions) + return reinterpret_cast<BOOL (*)(id, SEL, WebView *, id, BOOL)>(objc_msgSend)(delegate, selector, self, object, boolean); + @try { + return reinterpret_cast<BOOL (*)(id, SEL, WebView *, id, BOOL)>(objc_msgSend)(delegate, selector, self, object, boolean); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return result; +} + +static inline BOOL CallDelegateReturningBoolean(BOOL result, WebView *self, id delegate, SEL selector, id object1, id object2) +{ + if (!delegate || ![delegate respondsToSelector:selector]) + return result; + if (!self->_private->catchesDelegateExceptions) + return reinterpret_cast<BOOL (*)(id, SEL, WebView *, id, id)>(objc_msgSend)(delegate, selector, self, object1, object2); + @try { + return reinterpret_cast<BOOL (*)(id, SEL, WebView *, id, id)>(objc_msgSend)(delegate, selector, self, object1, object2); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return result; +} + +static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector) +{ + if (!delegate) + return nil; + if (!self->_private->catchesDelegateExceptions) + return implementation(delegate, selector, self); + @try { + return implementation(delegate, selector, self); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return nil; +} + +static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector, id object) +{ + if (!delegate) + return nil; + if (!self->_private->catchesDelegateExceptions) + return implementation(delegate, selector, self, object); + @try { + return implementation(delegate, selector, self, object); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return nil; +} + +static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector, id object1, id object2) +{ + if (!delegate) + return nil; + if (!self->_private->catchesDelegateExceptions) + return implementation(delegate, selector, self, object1, object2); + @try { + return implementation(delegate, selector, self, object1, object2); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return nil; +} + +static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector, id object1, id object2, id object3) +{ + if (!delegate) + return nil; + if (!self->_private->catchesDelegateExceptions) + return implementation(delegate, selector, self, object1, object2, object3); + @try { + return implementation(delegate, selector, self, object1, object2, object3); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return nil; +} + +static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector, id object1, id object2, id object3, id object4) +{ + if (!delegate) + return nil; + if (!self->_private->catchesDelegateExceptions) + return implementation(delegate, selector, self, object1, object2, object3, object4); + @try { + return implementation(delegate, selector, self, object1, object2, object3, object4); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return nil; +} + +static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector, id object1, NSInteger integer, id object2) +{ + if (!delegate) + return nil; + if (!self->_private->catchesDelegateExceptions) + return implementation(delegate, selector, self, object1, integer, object2); + @try { + return implementation(delegate, selector, self, object1, integer, object2); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return nil; +} + +static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector, id object1, NSInteger integer1, NSInteger integer2, id object2) +{ + if (!delegate) + return nil; + if (!self->_private->catchesDelegateExceptions) + return implementation(delegate, selector, self, object1, integer1, integer2, object2); + @try { + return implementation(delegate, selector, self, object1, integer1, integer2, object2); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return nil; +} + +static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector, id object1, id object2, NSInteger integer, id object3) +{ + if (!delegate) + return nil; + if (!self->_private->catchesDelegateExceptions) + return implementation(delegate, selector, self, object1, object2, integer, object3); + @try { + return implementation(delegate, selector, self, object1, object2, integer, object3); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return nil; +} + +static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector, id object1, NSInteger integer1, id object2, NSInteger integer2, id object3) +{ + if (!delegate) + return nil; + if (!self->_private->catchesDelegateExceptions) + return implementation(delegate, selector, self, object1, integer1, object2, integer2, object3); + @try { + return implementation(delegate, selector, self, object1, integer1, object2, integer2, object3); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return nil; +} + +static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector, id object1, NSInteger integer, id object2, id object3, id object4) +{ + if (!delegate) + return nil; + if (!self->_private->catchesDelegateExceptions) + return implementation(delegate, selector, self, object1, integer, object2, object3, object4); + @try { + return implementation(delegate, selector, self, object1, integer, object2, object3, object4); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return nil; +} + +static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector, id object1, NSTimeInterval interval, id object2, id object3) +{ + if (!delegate) + return nil; + if (!self->_private->catchesDelegateExceptions) + return implementation(delegate, selector, self, object1, interval, object2, object3); + @try { + return implementation(delegate, selector, self, object1, interval, object2, object3); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return nil; +} + +id CallUIDelegate(WebView *self, SEL selector) +{ + return CallDelegate(self, self->_private->UIDelegate, selector); +} + +id CallUIDelegate(WebView *self, SEL selector, id object) +{ + return CallDelegate(self, self->_private->UIDelegate, selector, object); +} + +id CallUIDelegate(WebView *self, SEL selector, id object, BOOL boolean) +{ + return CallDelegate(self, self->_private->UIDelegate, selector, object, boolean); +} + +id CallUIDelegate(WebView *self, SEL selector, NSRect rect) +{ + return CallDelegate(self, self->_private->UIDelegate, selector, rect); +} + +id CallUIDelegate(WebView *self, SEL selector, id object1, id object2) +{ + return CallDelegate(self, self->_private->UIDelegate, selector, object1, object2); +} + +id CallUIDelegate(WebView *self, SEL selector, id object1, id object2, id object3) +{ + return CallDelegate(self, self->_private->UIDelegate, selector, object1, object2, object3); +} + +id CallUIDelegate(WebView *self, SEL selector, id object, NSUInteger integer) +{ + return CallDelegate(self, self->_private->UIDelegate, selector, object, integer); +} + +float CallUIDelegateReturningFloat(WebView *self, SEL selector) +{ + return CallDelegateReturningFloat(self, self->_private->UIDelegate, selector); +} + +BOOL CallUIDelegateReturningBoolean(BOOL result, WebView *self, SEL selector) +{ + return CallDelegateReturningBoolean(result, self, self->_private->UIDelegate, selector); +} + +BOOL CallUIDelegateReturningBoolean(BOOL result, WebView *self, SEL selector, id object) +{ + return CallDelegateReturningBoolean(result, self, self->_private->UIDelegate, selector, object); +} + +BOOL CallUIDelegateReturningBoolean(BOOL result, WebView *self, SEL selector, id object, BOOL boolean) +{ + return CallDelegateReturningBoolean(result, self, self->_private->UIDelegate, selector, object, boolean); +} + +BOOL CallUIDelegateReturningBoolean(BOOL result, WebView *self, SEL selector, id object1, id object2) +{ + return CallDelegateReturningBoolean(result, self, self->_private->UIDelegate, selector, object1, object2); +} + +id CallFrameLoadDelegate(IMP implementation, WebView *self, SEL selector) +{ + return CallDelegate(implementation, self, self->_private->frameLoadDelegate, selector); +} + +id CallFrameLoadDelegate(IMP implementation, WebView *self, SEL selector, id object) +{ + return CallDelegate(implementation, self, self->_private->frameLoadDelegate, selector, object); +} + +id CallFrameLoadDelegate(IMP implementation, WebView *self, SEL selector, id object1, id object2) +{ + return CallDelegate(implementation, self, self->_private->frameLoadDelegate, selector, object1, object2); +} + +id CallFrameLoadDelegate(IMP implementation, WebView *self, SEL selector, id object1, id object2, id object3) +{ + return CallDelegate(implementation, self, self->_private->frameLoadDelegate, selector, object1, object2, object3); +} + +id CallFrameLoadDelegate(IMP implementation, WebView *self, SEL selector, id object1, id object2, id object3, id object4) +{ + return CallDelegate(implementation, self, self->_private->frameLoadDelegate, selector, object1, object2, object3, object4); +} + +id CallFrameLoadDelegate(IMP implementation, WebView *self, SEL selector, id object1, NSTimeInterval interval, id object2, id object3) +{ + return CallDelegate(implementation, self, self->_private->frameLoadDelegate, selector, object1, interval, object2, object3); +} + +id CallResourceLoadDelegate(IMP implementation, WebView *self, SEL selector, id object1, id object2) +{ + return CallDelegate(implementation, self, self->_private->resourceProgressDelegate, selector, object1, object2); +} + +id CallResourceLoadDelegate(IMP implementation, WebView *self, SEL selector, id object1, id object2, id object3) +{ + return CallDelegate(implementation, self, self->_private->resourceProgressDelegate, selector, object1, object2, object3); +} + +id CallResourceLoadDelegate(IMP implementation, WebView *self, SEL selector, id object1, id object2, id object3, id object4) +{ + return CallDelegate(implementation, self, self->_private->resourceProgressDelegate, selector, object1, object2, object3, object4); +} + +id CallResourceLoadDelegate(IMP implementation, WebView *self, SEL selector, id object1, NSInteger integer, id object2) +{ + return CallDelegate(implementation, self, self->_private->resourceProgressDelegate, selector, object1, integer, object2); +} + +id CallResourceLoadDelegate(IMP implementation, WebView *self, SEL selector, id object1, id object2, NSInteger integer, id object3) +{ + return CallDelegate(implementation, self, self->_private->resourceProgressDelegate, selector, object1, object2, integer, object3); +} + +BOOL CallResourceLoadDelegateReturningBoolean(BOOL result, IMP implementation, WebView *self, SEL selector, id object1, id object2) +{ + if (!self->_private->catchesDelegateExceptions) + return reinterpret_cast<BOOL (*)(id, SEL, WebView *, id, id)>(objc_msgSend)(self->_private->resourceProgressDelegate, selector, self, object1, object2); + @try { + return reinterpret_cast<BOOL (*)(id, SEL, WebView *, id, id)>(objc_msgSend)(self->_private->resourceProgressDelegate, selector, self, object1, object2); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return result; +} + +id CallScriptDebugDelegate(IMP implementation, WebView *self, SEL selector, id object1, id object2, NSInteger integer, id object3) +{ + return CallDelegate(implementation, self, self->_private->scriptDebugDelegate, selector, object1, object2, integer, object3); +} + +id CallScriptDebugDelegate(IMP implementation, WebView *self, SEL selector, id object1, NSInteger integer1, id object2, NSInteger integer2, id object3) +{ + return CallDelegate(implementation, self, self->_private->scriptDebugDelegate, selector, object1, integer1, object2, integer2, object3); +} + +id CallScriptDebugDelegate(IMP implementation, WebView *self, SEL selector, id object1, NSInteger integer, id object2, id object3, id object4) +{ + return CallDelegate(implementation, self, self->_private->scriptDebugDelegate, selector, object1, integer, object2, object3, object4); +} + +id CallScriptDebugDelegate(IMP implementation, WebView *self, SEL selector, id object1, NSInteger integer1, NSInteger integer2, id object2) +{ + return CallDelegate(implementation, self, self->_private->scriptDebugDelegate, selector, object1, integer1, integer2, object2); +} + +// The form delegate needs to have it's own implementation, because the first argument is never the WebView + +id CallFormDelegate(WebView *self, SEL selector, id object1, id object2) +{ + id delegate = self->_private->formDelegate; + if (!delegate || ![delegate respondsToSelector:selector]) + return nil; + if (!self->_private->catchesDelegateExceptions) + return objc_msgSend(delegate, selector, object1, object2); + @try { + return objc_msgSend(delegate, selector, object1, object2); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return nil; +} + +id CallFormDelegate(WebView *self, SEL selector, id object1, id object2, id object3, id object4, id object5) +{ + id delegate = self->_private->formDelegate; + if (!delegate || ![delegate respondsToSelector:selector]) + return nil; + if (!self->_private->catchesDelegateExceptions) + return objc_msgSend(delegate, selector, object1, object2, object3, object4, object5); + @try { + return objc_msgSend(delegate, selector, object1, object2, object3, object4, object5); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return nil; +} + +BOOL CallFormDelegateReturningBoolean(BOOL result, WebView *self, SEL selector, id object1, SEL selectorArg, id object2) +{ + id delegate = self->_private->formDelegate; + if (!delegate || ![delegate respondsToSelector:selector]) + return result; + if (!self->_private->catchesDelegateExceptions) + return reinterpret_cast<BOOL (*)(id, SEL, id, SEL, id)>(objc_msgSend)(delegate, selector, object1, selectorArg, object2); + @try { + return reinterpret_cast<BOOL (*)(id, SEL, id, SEL, id)>(objc_msgSend)(delegate, selector, object1, selectorArg, object2); + } @catch(id exception) { + ReportDiscardedDelegateException(selector, exception); + } + return result; +} + +@end diff --git a/WebKit/mac/WebView/WebDynamicScrollBarsView.h b/WebKit/mac/WebView/WebDynamicScrollBarsView.h index a0f8006..ce92b33 100644 --- a/WebKit/mac/WebView/WebDynamicScrollBarsView.h +++ b/WebKit/mac/WebView/WebDynamicScrollBarsView.h @@ -43,6 +43,7 @@ extern const int WebCoreScrollbarAlwaysOn; BOOL suppressLayout; BOOL suppressScrollers; BOOL inUpdateScrollers; + unsigned inUpdateScrollersLayoutPass; } - (void)setAllowsHorizontalScrolling:(BOOL)flag; // This method is used by Safari, so it cannot be removed. @end diff --git a/WebKit/mac/WebView/WebDynamicScrollBarsView.m b/WebKit/mac/WebView/WebDynamicScrollBarsView.mm index de19ef6..0cf2a98 100644 --- a/WebKit/mac/WebView/WebDynamicScrollBarsView.m +++ b/WebKit/mac/WebView/WebDynamicScrollBarsView.mm @@ -29,7 +29,11 @@ #import "WebDynamicScrollBarsViewInternal.h" #import "WebDocument.h" +#import "WebFrameInternal.h" #import "WebFrameView.h" +#import "WebHTMLViewInternal.h" +#import <WebCore/Frame.h> +#import <WebCore/FrameView.h> #import <WebKitSystemInterface.h> using namespace WebCore; @@ -81,80 +85,108 @@ const int WebCoreScrollbarAlwaysOn = ScrollbarAlwaysOn; #endif } +static const unsigned cMaxUpdateScrollbarsPass = 2; + - (void)updateScrollers { - // We need to do the work below twice in the case where a scroll bar disappears, - // making the second layout have a wider width than the first. Doing it more than - // twice would indicate some kind of infinite loop, so we do it at most twice. - // It's quite efficient to do this work twice in the normal case, so we don't bother - // trying to figure out of the second pass is needed or not. - if (inUpdateScrollers) - return; - - inUpdateScrollers = true; - - int pass; BOOL hasVerticalScroller = [self hasVerticalScroller]; BOOL hasHorizontalScroller = [self hasHorizontalScroller]; - BOOL oldHasVertical = hasVerticalScroller; - BOOL oldHasHorizontal = hasHorizontalScroller; - - for (pass = 0; pass < 2; pass++) { - BOOL scrollsVertically; - BOOL scrollsHorizontally; - - if (!suppressLayout && !suppressScrollers && (hScroll == ScrollbarAuto || vScroll == ScrollbarAuto)) { - // Do a layout if pending, before checking if scrollbars are needed. - // This fixes 2969367, although may introduce a slowdown in live resize performance. - NSView *documentView = [self documentView]; - if (!documentView) { - scrollsHorizontally = NO; - scrollsVertically = NO; - } else { - if ((hasVerticalScroller != oldHasVertical || - hasHorizontalScroller != oldHasHorizontal || [documentView inLiveResize]) && [documentView conformsToProtocol:@protocol(WebDocumentView)]) { - [(id <WebDocumentView>)documentView setNeedsLayout: YES]; - [(id <WebDocumentView>)documentView layout]; - } - - NSSize documentSize = [documentView frame].size; - NSSize frameSize = [self frame].size; - - scrollsVertically = (vScroll == ScrollbarAlwaysOn) || - (vScroll == ScrollbarAuto && documentSize.height > frameSize.height); - if (scrollsVertically) - scrollsHorizontally = (hScroll == ScrollbarAlwaysOn) || - (hScroll == ScrollbarAuto && documentSize.width + [NSScroller scrollerWidth] > frameSize.width); - else { - scrollsHorizontally = (hScroll == ScrollbarAlwaysOn) || - (hScroll == ScrollbarAuto && documentSize.width > frameSize.width); - if (scrollsHorizontally) - scrollsVertically = (vScroll == ScrollbarAlwaysOn) || - (vScroll == ScrollbarAuto && documentSize.height + [NSScroller scrollerWidth] > frameSize.height); - } - } - } else { - scrollsHorizontally = (hScroll == ScrollbarAuto) ? hasHorizontalScroller : (hScroll == ScrollbarAlwaysOn); - scrollsVertically = (vScroll == ScrollbarAuto) ? hasVerticalScroller : (vScroll == ScrollbarAlwaysOn); + + BOOL newHasHorizontalScroller = hasHorizontalScroller; + BOOL newHasVerticalScroller = hasVerticalScroller; + + BOOL needsLayout = NO; + + NSView *documentView = [self documentView]; + if (!documentView) { + newHasHorizontalScroller = NO; + newHasVerticalScroller = NO; + } + + if (hScroll != ScrollbarAuto) + newHasHorizontalScroller = (hScroll == ScrollbarAlwaysOn); + if (vScroll != ScrollbarAuto) + newHasVerticalScroller = (vScroll == ScrollbarAlwaysOn); + + if (!documentView || suppressLayout || suppressScrollers || (hScroll != ScrollbarAuto && vScroll != ScrollbarAuto)) { + inUpdateScrollers = YES; + if (hasHorizontalScroller != newHasHorizontalScroller) + [self setHasHorizontalScroller:newHasHorizontalScroller]; + if (hasVerticalScroller != newHasVerticalScroller) + [self setHasVerticalScroller:newHasVerticalScroller]; + if (suppressScrollers) { + [[self verticalScroller] setNeedsDisplay:NO]; + [[self horizontalScroller] setNeedsDisplay:NO]; } + inUpdateScrollers = NO; + return; + } - if (hasVerticalScroller != scrollsVertically) { - [self setHasVerticalScroller:scrollsVertically]; - hasVerticalScroller = scrollsVertically; + needsLayout = NO; + + // If we came in here with the view already needing a layout, then go ahead and do that + // first. (This will be the common case, e.g., when the page changes due to window resizing for example). + // This layout will not re-enter updateScrollers and does not count towards our max layout pass total. + if ([documentView isKindOfClass:[WebHTMLView class]]) { + WebHTMLView* htmlView = (WebHTMLView*)documentView; + if ([htmlView _needsLayout]) { + inUpdateScrollers = YES; + [(id <WebDocumentView>)documentView layout]; + inUpdateScrollers = NO; } + } - if (hasHorizontalScroller != scrollsHorizontally) { - [self setHasHorizontalScroller:scrollsHorizontally]; - hasHorizontalScroller = scrollsHorizontally; - } + NSSize documentSize = [documentView frame].size; + NSSize visibleSize = [self documentVisibleRect].size; + NSSize frameSize = [self frame].size; + + if (hScroll == ScrollbarAuto) { + newHasHorizontalScroller = documentSize.width > visibleSize.width; + if (newHasHorizontalScroller && !inUpdateScrollersLayoutPass && documentSize.height <= frameSize.height && documentSize.width <= frameSize.width) + newHasHorizontalScroller = NO; + } + + if (vScroll == ScrollbarAuto) { + newHasVerticalScroller = documentSize.height > visibleSize.height; + if (newHasVerticalScroller && !inUpdateScrollersLayoutPass && documentSize.height <= frameSize.height && documentSize.width <= frameSize.width) + newHasVerticalScroller = NO; } - if (suppressScrollers) { - [[self verticalScroller] setNeedsDisplay: NO]; - [[self horizontalScroller] setNeedsDisplay: NO]; + // Unless in ScrollbarsAlwaysOn mode, if we ever turn one scrollbar off, always turn the other one off too. + // Never ever try to both gain/lose a scrollbar in the same pass. + if (!newHasHorizontalScroller && hasHorizontalScroller && vScroll != ScrollbarAlwaysOn) + newHasVerticalScroller = NO; + if (!newHasVerticalScroller && hasVerticalScroller && hScroll != ScrollbarAlwaysOn) + newHasHorizontalScroller = NO; + + if (hasHorizontalScroller != newHasHorizontalScroller) { + inUpdateScrollers = YES; + [self setHasHorizontalScroller:newHasHorizontalScroller]; + inUpdateScrollers = NO; + needsLayout = YES; } - inUpdateScrollers = false; + if (hasVerticalScroller != newHasVerticalScroller) { + inUpdateScrollers = YES; + [self setHasVerticalScroller:newHasVerticalScroller]; + inUpdateScrollers = NO; + needsLayout = YES; + } + + if (needsLayout && inUpdateScrollersLayoutPass < cMaxUpdateScrollbarsPass && + [documentView conformsToProtocol:@protocol(WebDocumentView)]) { + inUpdateScrollersLayoutPass++; + [(id <WebDocumentView>)documentView setNeedsLayout:YES]; + [(id <WebDocumentView>)documentView layout]; + NSSize newDocumentSize = [documentView frame].size; + if (NSEqualSizes(documentSize, newDocumentSize)) { + // The layout with the new scroll state had no impact on + // the document's overall size, so updateScrollers didn't get called. + // Recur manually. + [self updateScrollers]; + } + inUpdateScrollersLayoutPass--; + } } // Make the horizontal and vertical scroll bars come and go as needed. @@ -186,6 +218,15 @@ const int WebCoreScrollbarAlwaysOn = ScrollbarAlwaysOn; [[self horizontalScroller] setNeedsDisplay: NO]; } #endif + +#if USE(ACCELERATED_COMPOSITING) && defined(BUILDING_ON_LEOPARD) + NSView *documentView = [self documentView]; + if ([documentView isKindOfClass:[WebHTMLView class]]) { + WebHTMLView *htmlView = (WebHTMLView *)documentView; + if ([htmlView _isUsingAcceleratedCompositing]) + [htmlView _updateLayerHostingViewPosition]; + } +#endif } - (BOOL)allowsHorizontalScrolling diff --git a/WebKit/mac/WebView/WebFrame.mm b/WebKit/mac/WebView/WebFrame.mm index 2aa5fab..c03ef58 100644 --- a/WebKit/mac/WebView/WebFrame.mm +++ b/WebKit/mac/WebView/WebFrame.mm @@ -46,18 +46,21 @@ #import "WebIconFetcherInternal.h" #import "WebKitStatisticsPrivate.h" #import "WebKitVersionChecks.h" +#import "WebNSObjectExtras.h" #import "WebNSURLExtras.h" #import "WebScriptDebugger.h" #import "WebViewInternal.h" #import <JavaScriptCore/APICast.h> +#import <WebCore/AXObjectCache.h> #import <WebCore/AccessibilityObject.h> #import <WebCore/AnimationController.h> -#import <WebCore/AXObjectCache.h> +#import <WebCore/CSSMutableStyleDeclaration.h> #import <WebCore/ColorMac.h> #import <WebCore/DOMImplementation.h> #import <WebCore/DocLoader.h> #import <WebCore/DocumentFragment.h> #import <WebCore/EventHandler.h> +#import <WebCore/EventNames.h> #import <WebCore/Frame.h> #import <WebCore/FrameLoader.h> #import <WebCore/FrameTree.h> @@ -68,21 +71,22 @@ #import <WebCore/LegacyWebArchive.h> #import <WebCore/Page.h> #import <WebCore/PluginData.h> +#import <WebCore/RenderLayer.h> #import <WebCore/RenderPart.h> #import <WebCore/RenderView.h> -#import <WebCore/RenderLayer.h> #import <WebCore/ReplaceSelectionCommand.h> +#import <WebCore/RuntimeApplicationChecks.h> +#import <WebCore/ScriptValue.h> #import <WebCore/SmartReplace.h> #import <WebCore/TextIterator.h> +#import <WebCore/ThreadCheck.h> #import <WebCore/TypingCommand.h> #import <WebCore/htmlediting.h> -#import <WebCore/ScriptController.h> -#import <WebCore/ScriptValue.h> #import <WebCore/markup.h> #import <WebCore/visible_units.h> #import <runtime/JSLock.h> #import <runtime/JSValue.h> -#include <wtf/CurrentTime.h> +#import <wtf/CurrentTime.h> using namespace std; using namespace WebCore; @@ -90,7 +94,8 @@ using namespace HTMLNames; using JSC::JSGlobalObject; using JSC::JSLock; -using JSC::JSValuePtr; +using JSC::JSValue; +using JSC::SilenceAssertionsOnly; /* Here is the current behavior matrix for four types of navigations: @@ -128,6 +133,14 @@ NSString *WebPageCacheEntryDateKey = @"WebPageCacheEntryDateKey"; NSString *WebPageCacheDataSourceKey = @"WebPageCacheDataSourceKey"; NSString *WebPageCacheDocumentViewKey = @"WebPageCacheDocumentViewKey"; +NSString *WebFrameMainDocumentError = @"WebFrameMainDocumentErrorKey"; +NSString *WebFrameHasPlugins = @"WebFrameHasPluginsKey"; +NSString *WebFrameHasUnloadListener = @"WebFrameHasUnloadListenerKey"; +NSString *WebFrameUsesDatabases = @"WebFrameUsesDatabasesKey"; +NSString *WebFrameUsesGeolocation = @"WebFrameUsesGeolocationKey"; +NSString *WebFrameUsesApplicationCache = @"WebFrameUsesApplicationCacheKey"; +NSString *WebFrameCanSuspendActiveDOMObjects = @"WebFrameCanSuspendActiveDOMObjectsKey"; + // FIXME: Remove when this key becomes publicly defined NSString *NSAccessibilityEnhancedUserInterfaceAttribute = @"AXEnhancedUserInterface"; @@ -158,76 +171,6 @@ NSString *NSAccessibilityEnhancedUserInterfaceAttribute = @"AXEnhancedUserInterf @end -CSSStyleDeclaration* core(DOMCSSStyleDeclaration *declaration) -{ - return [declaration _CSSStyleDeclaration]; -} - -DOMCSSStyleDeclaration *kit(WebCore::CSSStyleDeclaration* declaration) -{ - return [DOMCSSStyleDeclaration _wrapCSSStyleDeclaration:declaration]; -} - -Element* core(DOMElement *element) -{ - return [element _element]; -} - -DOMElement *kit(Element* element) -{ - return [DOMElement _wrapElement:element]; -} - -Node* core(DOMNode *node) -{ - return [node _node]; -} - -DOMNode *kit(Node* node) -{ - return [DOMNode _wrapNode:node]; -} - -Document* core(DOMDocument *document) -{ - return [document _document]; -} - -DOMDocument *kit(Document* document) -{ - return [DOMDocument _wrapDocument:document]; -} - -DocumentFragment* core(DOMDocumentFragment *fragment) -{ - return [fragment _documentFragment]; -} - -DOMDocumentFragment *kit(DocumentFragment* fragment) -{ - return [DOMDocumentFragment _wrapDocumentFragment:fragment]; -} - -HTMLElement* core(DOMHTMLElement *element) -{ - return [element _HTMLElement]; -} - -DOMHTMLElement *kit(HTMLElement *element) -{ - return [DOMHTMLElement _wrapHTMLElement:element]; -} - -Range* core(DOMRange *range) -{ - return [range _range]; -} - -DOMRange *kit(Range* range) -{ - return [DOMRange _wrapRange:range]; -} - EditableLinkBehavior core(WebKitEditableLinkBehavior editableLinkBehavior) { switch (editableLinkBehavior) { @@ -385,22 +328,24 @@ WebView *getWebView(WebFrame *webFrame) Frame* coreFrame = _private->coreFrame; for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) { - WebFrame *webFrame = kit(frame); - // Don't call setDrawsBackground:YES here because it may be NO because of a load - // in progress; WebFrameLoaderClient keeps it set to NO during the load process. - if (!drawsBackground) - [[[webFrame frameView] _scrollView] setDrawsBackground:NO]; - [[[webFrame frameView] _scrollView] setBackgroundColor:backgroundColor]; - id documentView = [[webFrame frameView] documentView]; - if ([documentView respondsToSelector:@selector(setDrawsBackground:)]) - [documentView setDrawsBackground:drawsBackground]; - if ([documentView respondsToSelector:@selector(setBackgroundColor:)]) - [documentView setBackgroundColor:backgroundColor]; - if (frame && frame->view()) { - frame->view()->setTransparent(!drawsBackground); - Color color = colorFromNSColor([backgroundColor colorUsingColorSpaceName:NSDeviceRGBColorSpace]); - frame->view()->setBaseBackgroundColor(color); - frame->view()->setShouldUpdateWhileOffscreen([webView shouldUpdateWhileOffscreen]); + if ([webView _usesDocumentViews]) { + // Don't call setDrawsBackground:YES here because it may be NO because of a load + // in progress; WebFrameLoaderClient keeps it set to NO during the load process. + WebFrame *webFrame = kit(frame); + if (!drawsBackground) + [[[webFrame frameView] _scrollView] setDrawsBackground:NO]; + [[[webFrame frameView] _scrollView] setBackgroundColor:backgroundColor]; + id documentView = [[webFrame frameView] documentView]; + if ([documentView respondsToSelector:@selector(setDrawsBackground:)]) + [documentView setDrawsBackground:drawsBackground]; + if ([documentView respondsToSelector:@selector(setBackgroundColor:)]) + [documentView setBackgroundColor:backgroundColor]; + } + + if (FrameView* view = frame->view()) { + view->setTransparent(!drawsBackground); + view->setBaseBackgroundColor(colorFromNSColor([backgroundColor colorUsingColorSpaceName:NSDeviceRGBColorSpace])); + view->setShouldUpdateWhileOffscreen([webView shouldUpdateWhileOffscreen]); } } } @@ -437,21 +382,27 @@ WebView *getWebView(WebFrame *webFrame) - (BOOL)_hasSelection { - id documentView = [_private->webFrameView documentView]; + if ([getWebView(self) _usesDocumentViews]) { + id documentView = [_private->webFrameView documentView]; - // optimization for common case to avoid creating potentially large selection string - if ([documentView isKindOfClass:[WebHTMLView class]]) - if (Frame* coreFrame = _private->coreFrame) - return coreFrame->selection()->isRange(); + // optimization for common case to avoid creating potentially large selection string + if ([documentView isKindOfClass:[WebHTMLView class]]) + if (Frame* coreFrame = _private->coreFrame) + return coreFrame->selection()->isRange(); - if ([documentView conformsToProtocol:@protocol(WebDocumentText)]) - return [[documentView selectedString] length] > 0; - - return NO; + if ([documentView conformsToProtocol:@protocol(WebDocumentText)]) + return [[documentView selectedString] length] > 0; + + return NO; + } + + Frame* coreFrame = _private->coreFrame; + return coreFrame && coreFrame->selection()->isRange(); } - (void)_clearSelection { + ASSERT([getWebView(self) _usesDocumentViews]); id documentView = [_private->webFrameView documentView]; if ([documentView conformsToProtocol:@protocol(WebDocumentText)]) [documentView deselectAll]; @@ -532,7 +483,7 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) size_t size = nodesVector->size(); NSMutableArray *nodes = [NSMutableArray arrayWithCapacity:size]; for (size_t i = 0; i < size; ++i) - [nodes addObject:[DOMNode _wrapNode:(*nodesVector)[i]]]; + [nodes addObject:kit((*nodesVector)[i])]; return nodes; } @@ -540,7 +491,7 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) { // FIXME: This is always "for interchange". Is that right? See the previous method. Vector<Node*> nodeList; - NSString *markupString = createMarkup([range _range], nodes ? &nodeList : 0, AnnotateForInterchange); + NSString *markupString = createMarkup(core(range), nodes ? &nodeList : 0, AnnotateForInterchange); if (nodes) *nodes = [self _nodesFromList:&nodeList]; @@ -556,7 +507,7 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) { // This will give a system malloc'd buffer that can be turned directly into an NSString unsigned length; - UChar* buf = plainTextToMallocAllocatedBuffer([range _range], length, true); + UChar* buf = plainTextToMallocAllocatedBuffer(core(range), length, true); if (!buf) return [NSString string]; @@ -592,7 +543,7 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) } if (!_private->coreFrame || !_private->coreFrame->document() || !_private->coreFrame->view()) return pages; - RenderView* root = static_cast<RenderView *>(_private->coreFrame->document()->renderer()); + RenderView* root = toRenderView(_private->coreFrame->document()->renderer()); if (!root) return pages; FrameView* view = _private->coreFrame->view(); @@ -644,7 +595,7 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) { ASSERT(_private->coreFrame->document()); - JSValuePtr result = _private->coreFrame->loader()->executeScript(string, forceUserGesture).jsValue(); + JSValue result = _private->coreFrame->loader()->executeScript(string, forceUserGesture).jsValue(); if (!_private->coreFrame) // In case the script removed our frame from the page. return @""; @@ -655,25 +606,25 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) if (!result || !result.isBoolean() && !result.isString() && !result.isNumber()) return @""; - JSLock lock(false); + JSLock lock(SilenceAssertionsOnly); return String(result.toString(_private->coreFrame->script()->globalObject()->globalExec())); } - (NSRect)_caretRectAtNode:(DOMNode *)node offset:(int)offset affinity:(NSSelectionAffinity)affinity { - VisiblePosition visiblePosition([node _node], offset, static_cast<EAffinity>(affinity)); + VisiblePosition visiblePosition(core(node), offset, static_cast<EAffinity>(affinity)); return visiblePosition.absoluteCaretBounds(); } - (NSRect)_firstRectForDOMRange:(DOMRange *)range { - return _private->coreFrame->firstRectForRange([range _range]); + return _private->coreFrame->firstRectForRange(core(range)); } - (void)_scrollDOMRangeToVisible:(DOMRange *)range { NSRect rangeRect = [self _firstRectForDOMRange:range]; - Node *startNode = [[range startContainer] _node]; + Node *startNode = core([range startContainer]); if (startNode && startNode->renderer()) { RenderLayer *layer = startNode->renderer()->enclosingLayer(); @@ -698,7 +649,7 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) if (!_private->coreFrame || !_private->coreFrame->document()) return nil; - RenderView* root = static_cast<RenderView *>(_private->coreFrame->document()->renderer()); + RenderView* root = toRenderView(_private->coreFrame->document()->renderer()); if (!root) return nil; return _private->coreFrame->document()->axObjectCache()->getOrCreate(root)->wrapper(); @@ -715,7 +666,7 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) SelectionController selection; selection.setSelection(_private->coreFrame->selection()->selection()); selection.modify(alteration, direction, granularity); - return [DOMRange _wrapRange:selection.toNormalizedRange().get()]; + return kit(selection.toNormalizedRange().get()); } - (TextGranularity)_selectionGranularity @@ -777,7 +728,7 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) - (DOMRange *)_convertNSRangeToDOMRange:(NSRange)nsrange { - return [DOMRange _wrapRange:[self _convertToDOMRange:nsrange].get()]; + return kit([self _convertToDOMRange:nsrange].get()); } - (NSRange)convertDOMRangeToNSRange:(DOMRange *)range @@ -788,12 +739,12 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) - (NSRange)_convertDOMRangeToNSRange:(DOMRange *)range { - return [self _convertToNSRange:[range _range]]; + return [self _convertToNSRange:core(range)]; } - (DOMRange *)_markDOMRange { - return [DOMRange _wrapRange:_private->coreFrame->mark().toNormalizedRange().get()]; + return kit(_private->coreFrame->mark().toNormalizedRange().get()); } // Given proposedRange, returns an extended range that includes adjacent whitespace that should @@ -801,8 +752,8 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) // the text surrounding the deletion. - (DOMRange *)_smartDeleteRangeForProposedRange:(DOMRange *)proposedRange { - Node *startContainer = [[proposedRange startContainer] _node]; - Node *endContainer = [[proposedRange endContainer] _node]; + Node* startContainer = core([proposedRange startContainer]); + Node* endContainer = core([proposedRange endContainer]); if (startContainer == nil || endContainer == nil) return nil; @@ -824,9 +775,9 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) RefPtr<Range> range = _private->coreFrame->document()->createRange(); int exception = 0; - range->setStart(newStart.node(), newStart.m_offset, exception); - range->setEnd(newStart.node(), newStart.m_offset, exception); - return [DOMRange _wrapRange:range.get()]; + range->setStart(newStart.node(), newStart.deprecatedEditingOffset(), exception); + range->setEnd(newStart.node(), newStart.deprecatedEditingOffset(), exception); + return kit(range.get()); } // Determines whether whitespace needs to be added around aString to preserve proper spacing and @@ -842,8 +793,8 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) *afterString = nil; // inspect destination - Node *startContainer = [[rangeToReplace startContainer] _node]; - Node *endContainer = [[rangeToReplace endContainer] _node]; + Node *startContainer = core([rangeToReplace startContainer]); + Node *endContainer = core([rangeToReplace endContainer]); Position startPos(startContainer, [rangeToReplace startOffset]); Position endPos(endContainer, [rangeToReplace endOffset]); @@ -890,28 +841,28 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) - (DOMDocumentFragment *)_documentFragmentWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString { if (!_private->coreFrame || !_private->coreFrame->document()) - return 0; + return nil; - return [DOMDocumentFragment _wrapDocumentFragment:createFragmentFromMarkup(_private->coreFrame->document(), markupString, baseURLString).get()]; + return kit(createFragmentFromMarkup(_private->coreFrame->document(), markupString, baseURLString).get()); } - (DOMDocumentFragment *)_documentFragmentWithNodesAsParagraphs:(NSArray *)nodes { if (!_private->coreFrame || !_private->coreFrame->document()) - return 0; + return nil; NSEnumerator *nodeEnum = [nodes objectEnumerator]; Vector<Node*> nodesVector; DOMNode *node; while ((node = [nodeEnum nextObject])) - nodesVector.append([node _node]); + nodesVector.append(core(node)); - return [DOMDocumentFragment _wrapDocumentFragment:createFragmentFromNodes(_private->coreFrame->document(), nodesVector).get()]; + return kit(createFragmentFromNodes(_private->coreFrame->document(), nodesVector).get()); } - (void)_replaceSelectionWithNode:(DOMNode *)node selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace matchStyle:(BOOL)matchStyle { - DOMDocumentFragment *fragment = [DOMDocumentFragment _wrapDocumentFragment:_private->coreFrame->document()->createDocumentFragment().get()]; + DOMDocumentFragment *fragment = kit(_private->coreFrame->document()->createDocumentFragment().get()); [fragment appendChild:node]; [self _replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:matchStyle]; } @@ -939,7 +890,7 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) VisiblePosition previous = position.previous(); if (previous.isNotNull()) { - DOMRange *previousCharacterRange = [DOMRange _wrapRange:makeRange(previous, position).get()]; + DOMRange *previousCharacterRange = kit(makeRange(previous, position).get()); NSRect rect = [self _firstRectForDOMRange:previousCharacterRange]; if (NSPointInRect(point, rect)) return previousCharacterRange; @@ -947,7 +898,7 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) VisiblePosition next = position.next(); if (next.isNotNull()) { - DOMRange *nextCharacterRange = [DOMRange _wrapRange:makeRange(position, next).get()]; + DOMRange *nextCharacterRange = kit(makeRange(position, next).get()); NSRect rect = [self _firstRectForDOMRange:nextCharacterRange]; if (NSPointInRect(point, rect)) return nextCharacterRange; @@ -960,14 +911,14 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) { if (!_private->coreFrame || !_private->coreFrame->typingStyle()) return nil; - return [DOMCSSStyleDeclaration _wrapCSSStyleDeclaration:_private->coreFrame->typingStyle()->copy().get()]; + return kit(_private->coreFrame->typingStyle()->copy().get()); } - (void)_setTypingStyle:(DOMCSSStyleDeclaration *)style withUndoAction:(EditAction)undoAction { if (!_private->coreFrame) return; - _private->coreFrame->computeAndSetTypingStyle([style _CSSStyleDeclaration], undoAction); + _private->coreFrame->computeAndSetTypingStyle(core(style), undoAction); } - (void)_dragSourceMovedTo:(NSPoint)windowLoc @@ -977,6 +928,7 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) FrameView* view = _private->coreFrame->view(); if (!view) return; + ASSERT([getWebView(self) _usesDocumentViews]); // FIXME: These are fake modifier keys here, but they should be real ones instead. PlatformMouseEvent event(IntPoint(windowLoc), globalPoint(windowLoc, [view->platformWidget() window]), LeftButton, MouseEventMoved, 0, false, false, false, false, currentTime()); @@ -990,6 +942,7 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) FrameView* view = _private->coreFrame->view(); if (!view) return; + ASSERT([getWebView(self) _usesDocumentViews]); // FIXME: These are fake modifier keys here, but they should be real ones instead. PlatformMouseEvent event(IntPoint(windowLoc), globalPoint(windowLoc, [view->platformWidget() window]), LeftButton, MouseEventMoved, 0, false, false, false, false, currentTime()); @@ -1097,7 +1050,7 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) - (unsigned)_pendingFrameUnloadEventCount { - return _private->coreFrame->eventHandler()->pendingFrameUnloadEventCount(); + return _private->coreFrame->domWindow()->pendingUnloadEventListeners(); } - (WebIconFetcher *)fetchApplicationIcon:(id)target @@ -1150,7 +1103,7 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) if (!controller) return false; - Node* coreNode = [node _node]; + Node* coreNode = core(node); if (!coreNode || !coreNode->renderer()) return false; @@ -1167,7 +1120,7 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) if (!controller) return false; - Node* coreNode = [node _node]; + Node* coreNode = core(node); if (!coreNode || !coreNode->renderer()) return false; @@ -1192,7 +1145,7 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) if (_private->coreFrame->selection()->isNone() || !fragment) return; - applyCommand(ReplaceSelectionCommand::create(_private->coreFrame->document(), [fragment _documentFragment], selectReplacement, smartReplace, matchStyle)); + applyCommand(ReplaceSelectionCommand::create(_private->coreFrame->document(), core(fragment), selectReplacement, smartReplace, matchStyle)); _private->coreFrame->revealSelection(ScrollAlignment::alignToEdgeIfNeeded); } @@ -1208,6 +1161,40 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) [self _replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:smartReplace matchStyle:NO]; } +- (NSMutableDictionary *)_cacheabilityDictionary +{ + NSMutableDictionary *result = [NSMutableDictionary dictionary]; + + FrameLoader* frameLoader = _private->coreFrame->loader(); + DocumentLoader* documentLoader = frameLoader->documentLoader(); + if (documentLoader && !documentLoader->mainDocumentError().isNull()) + [result setObject:(NSError *)documentLoader->mainDocumentError() forKey:WebFrameMainDocumentError]; + + if (frameLoader->containsPlugins()) + [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameHasPlugins]; + + if (DOMWindow* domWindow = _private->coreFrame->domWindow()) { + if (domWindow->hasEventListener(eventNames().unloadEvent)) + [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameHasUnloadListener]; + + if (domWindow->optionalApplicationCache()) + [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameUsesApplicationCache]; + } + + if (Document* document = _private->coreFrame->document()) { + if (document->hasOpenDatabases()) + [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameUsesDatabases]; + + if (document->usingGeolocation()) + [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameUsesGeolocation]; + + if (!document->canSuspendActiveDOMObjects()) + [result setObject:[NSNumber numberWithBool:YES] forKey:WebFrameCanSuspendActiveDOMObjects]; + } + + return result; +} + @end @implementation WebFrame @@ -1246,6 +1233,7 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) - (WebFrameView *)frameView { + ASSERT(!getWebView(self) || [getWebView(self) _usesDocumentViews]); return _private->webFrameView; } @@ -1254,8 +1242,17 @@ static inline WebDataSource *dataSource(DocumentLoader* loader) return getWebView(self); } +static bool needsMicrosoftMessengerDOMDocumentWorkaround() +{ + static bool needsWorkaround = applicationIsMicrosoftMessenger() && [[[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey] compare:@"7.1" options:NSNumericSearch] == NSOrderedAscending; + return needsWorkaround; +} + - (DOMDocument *)DOMDocument { + if (needsMicrosoftMessengerDOMDocumentWorkaround() && !pthread_main_np()) + return nil; + Frame* coreFrame = _private->coreFrame; if (!coreFrame) return nil; @@ -1314,6 +1311,9 @@ static NSURL *createUniqueWebDataURL() - (void)_loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL unreachableURL:(NSURL *)unreachableURL { + if (!pthread_main_np()) + return [[self _webkit_invokeOnMainThread] _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:baseURL unreachableURL:unreachableURL]; + KURL responseURL; if (!baseURL) { baseURL = blankURL(); @@ -1333,6 +1333,8 @@ static NSURL *createUniqueWebDataURL() - (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL { + WebCoreThreadViolationCheckRoundTwo(); + if (!MIMEType) MIMEType = @"text/html"; [self _loadData:data MIMEType:MIMEType textEncodingName:encodingName baseURL:baseURL unreachableURL:nil]; @@ -1346,11 +1348,15 @@ static NSURL *createUniqueWebDataURL() - (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL { + WebCoreThreadViolationCheckRoundTwo(); + [self _loadHTMLString:string baseURL:baseURL unreachableURL:nil]; } - (void)loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)baseURL forUnreachableURL:(NSURL *)unreachableURL { + WebCoreThreadViolationCheckRoundTwo(); + [self _loadHTMLString:string baseURL:baseURL unreachableURL:unreachableURL]; } @@ -1369,8 +1375,7 @@ static NSURL *createUniqueWebDataURL() - (void)reload { - if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_RELOAD_FROM_ORIGIN) && - [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Safari"]) + if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_RELOAD_FROM_ORIGIN) && applicationIsSafari()) _private->coreFrame->loader()->reload(GetCurrentKeyModifiers() & shiftKey); else _private->coreFrame->loader()->reload(false); diff --git a/WebKit/mac/WebView/WebFrameInternal.h b/WebKit/mac/WebView/WebFrameInternal.h index 473e691..10a3015 100644 --- a/WebKit/mac/WebView/WebFrameInternal.h +++ b/WebKit/mac/WebView/WebFrameInternal.h @@ -63,30 +63,9 @@ namespace WebCore { typedef WebCore::HistoryItem WebCoreHistoryItem; -WebCore::CSSStyleDeclaration* core(DOMCSSStyleDeclaration *); -DOMCSSStyleDeclaration *kit(WebCore::CSSStyleDeclaration*); - WebCore::Frame* core(WebFrame *); WebFrame *kit(WebCore::Frame *); -WebCore::Element* core(DOMElement *); -DOMElement *kit(WebCore::Element*); - -WebCore::Node* core(DOMNode *); -DOMNode *kit(WebCore::Node*); - -WebCore::Document* core(DOMDocument *); -DOMDocument *kit(WebCore::Document*); - -WebCore::DocumentFragment* core(DOMDocumentFragment *); -DOMDocumentFragment *kit(WebCore::DocumentFragment*); - -WebCore::HTMLElement* core(DOMHTMLElement *); -DOMHTMLElement *kit(WebCore::HTMLElement*); - -WebCore::Range* core(DOMRange *); -DOMRange *kit(WebCore::Range*); - WebCore::Page* core(WebView *); WebView *kit(WebCore::Page*); diff --git a/WebKit/mac/WebView/WebFramePrivate.h b/WebKit/mac/WebView/WebFramePrivate.h index e3e3540..8e7a2ef 100644 --- a/WebKit/mac/WebView/WebFramePrivate.h +++ b/WebKit/mac/WebView/WebFramePrivate.h @@ -45,6 +45,14 @@ extern NSString *WebPageCacheEntryDateKey; extern NSString *WebPageCacheDataSourceKey; extern NSString *WebPageCacheDocumentViewKey; +extern NSString *WebFrameMainDocumentError; +extern NSString *WebFrameHasPlugins; +extern NSString *WebFrameHasUnloadListener; +extern NSString *WebFrameUsesDatabases; +extern NSString *WebFrameUsesGeolocation; +extern NSString *WebFrameUsesApplicationCache; +extern NSString *WebFrameCanSuspendActiveDOMObjects; + typedef enum { WebFrameLoadTypeStandard, WebFrameLoadTypeBack, @@ -55,7 +63,8 @@ typedef enum { WebFrameLoadTypeSame, // user loads same URL again (but not reload button) WebFrameLoadTypeInternal, // maps to WebCore::FrameLoadTypeRedirectWithLockedBackForwardList WebFrameLoadTypeReplace, - WebFrameLoadTypeReloadFromOrigin + WebFrameLoadTypeReloadFromOrigin, + WebFrameLoadTypeBackWMLDeckNotAccessible } WebFrameLoadType; @interface WebFrame (WebPrivate) @@ -100,4 +109,5 @@ typedef enum { - (void)_replaceSelectionWithText:(NSString *)text selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace; - (void)_replaceSelectionWithMarkupString:(NSString *)markupString baseURLString:(NSString *)baseURLString selectReplacement:(BOOL)selectReplacement smartReplace:(BOOL)smartReplace; +- (NSMutableDictionary *)_cacheabilityDictionary; @end diff --git a/WebKit/mac/WebView/WebFrameView.mm b/WebKit/mac/WebView/WebFrameView.mm index bc51bb5..1a460ea 100644 --- a/WebKit/mac/WebView/WebFrameView.mm +++ b/WebKit/mac/WebView/WebFrameView.mm @@ -307,20 +307,21 @@ static inline void addTypesFromClass(NSMutableDictionary *allTypes, Class objCCl [WebViewFactory createSharedFactory]; [WebKeyGenerator createSharedGenerator]; - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - +// FIXME: Remove the NSAppKitVersionNumberWithDeferredWindowDisplaySupport check once +// once AppKit's Deferred Window Display support is available. +#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) || !defined(NSAppKitVersionNumberWithDeferredWindowDisplaySupport) // CoreGraphics deferred updates are disabled if WebKitEnableCoalescedUpdatesPreferenceKey is NO - // or has no value. For compatibility with Mac OS X 10.4.6, deferred updates are off by default. - if (![defaults boolForKey:WebKitEnableDeferredUpdatesPreferenceKey]) + // or has no value. For compatibility with Mac OS X 10.5 and lower, deferred updates are off by default. + if (![[NSUserDefaults standardUserDefaults] boolForKey:WebKitEnableDeferredUpdatesPreferenceKey]) WKDisableCGDeferredUpdates(); - +#endif if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_MAIN_THREAD_EXCEPTIONS)) setDefaultThreadViolationBehavior(LogOnFirstThreadViolation, ThreadViolationRoundOne); bool throwExceptionsForRoundTwo = WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_ROUND_TWO_MAIN_THREAD_EXCEPTIONS); #ifdef MAIL_THREAD_WORKAROUND // Even if old Mail is linked with new WebKit, don't throw exceptions. - if (needMailThreadWorkaround()) + if ([WebResource _needMailThreadWorkaroundIfCalledOffMainThread]) throwExceptionsForRoundTwo = false; #endif if (!throwExceptionsForRoundTwo) @@ -492,9 +493,15 @@ static inline void addTypesFromClass(NSMutableDictionary *allTypes, Class objCCl - (void)setFrameSize:(NSSize)size { - // See WebFrameLoaderClient::provisionalLoadStarted. - if (!NSEqualSizes(size, [self frame].size) && [[[self webFrame] webView] drawsBackground]) - [[self _scrollView] setDrawsBackground:YES]; + if (!NSEqualSizes(size, [self frame].size)) { + // See WebFrameLoaderClient::provisionalLoadStarted. + if ([[[self webFrame] webView] drawsBackground]) + [[self _scrollView] setDrawsBackground:YES]; + if (Frame* coreFrame = [self _web_frame]) { + if (FrameView* coreFrameView = coreFrame->view()) + coreFrameView->setNeedsLayout(); + } + } [super setFrameSize:size]; } @@ -518,31 +525,49 @@ static inline void addTypesFromClass(NSMutableDictionary *allTypes, Class objCCl return frame->eventHandler()->scrollOverflow(direction, granularity); } -- (void)scrollToBeginningOfDocument:(id)sender +- (BOOL)_scrollToBeginningOfDocument { - if (![self _scrollOverflowInDirection:ScrollUp granularity:ScrollByDocument]) { + if ([self _scrollOverflowInDirection:ScrollUp granularity:ScrollByDocument]) + return YES; + if (![self _hasScrollBars]) + return NO; + NSPoint point = [[[self _scrollView] documentView] frame].origin; + return [[self _contentView] _scrollTo:&point animate:YES]; +} - if (![self _hasScrollBars]) { - [[self _largestChildWithScrollBars] scrollToBeginningOfDocument:sender]; - return; - } +- (BOOL)_scrollToEndOfDocument +{ + if ([self _scrollOverflowInDirection:ScrollDown granularity:ScrollByDocument]) + return YES; + if (![self _hasScrollBars]) + return NO; + NSRect frame = [[[self _scrollView] documentView] frame]; + NSPoint point = NSMakePoint(frame.origin.x, NSMaxY(frame)); + return [[self _contentView] _scrollTo:&point animate:YES]; +} - [[self _contentView] scrollPoint:[[[self _scrollView] documentView] frame].origin]; +- (void)scrollToBeginningOfDocument:(id)sender +{ + if ([self _scrollToBeginningOfDocument]) + return; + + if (WebFrameView *child = [self _largestChildWithScrollBars]) { + if ([child _scrollToBeginningOfDocument]) + return; } + [[self nextResponder] tryToPerform:@selector(scrollToBeginningOfDocument:) with:sender]; } - (void)scrollToEndOfDocument:(id)sender { - if (![self _scrollOverflowInDirection:ScrollDown granularity:ScrollByDocument]) { + if ([self _scrollToEndOfDocument]) + return; - if (![self _hasScrollBars]) { - [[self _largestChildWithScrollBars] scrollToEndOfDocument:sender]; + if (WebFrameView *child = [self _largestChildWithScrollBars]) { + if ([child _scrollToEndOfDocument]) return; - } - - NSRect frame = [[[self _scrollView] documentView] frame]; - [[self _contentView] scrollPoint:NSMakePoint(frame.origin.x, NSMaxY(frame))]; } + [[self nextResponder] tryToPerform:@selector(scrollToEndOfDocument:) with:sender]; } - (void)_goBack @@ -653,12 +678,14 @@ static inline void addTypesFromClass(NSMutableDictionary *allTypes, Class objCCl - (void)scrollLineUp:(id)sender { - [self _scrollLineVertically:YES]; + if (![self _scrollLineVertically:YES]) + [[self nextResponder] tryToPerform:@selector(scrollLineUp:) with:sender]; } - (void)scrollLineDown:(id)sender { - [self _scrollLineVertically:NO]; + if (![self _scrollLineVertically:NO]) + [[self nextResponder] tryToPerform:@selector(scrollLineDown:) with:sender]; } - (BOOL)_firstResponderIsFormControl diff --git a/WebKit/mac/WebView/WebHTMLRepresentation.mm b/WebKit/mac/WebView/WebHTMLRepresentation.mm index 3f69870..39489e8 100644 --- a/WebKit/mac/WebView/WebHTMLRepresentation.mm +++ b/WebKit/mac/WebView/WebHTMLRepresentation.mm @@ -28,7 +28,7 @@ #import "WebHTMLRepresentation.h" -#import "DOMNodeInternal.h" +#import "DOMElementInternal.h" #import "DOMRangeInternal.h" #import "WebArchive.h" #import "WebBasePluginPackage.h" @@ -47,6 +47,7 @@ #import <WebCore/FrameLoader.h> #import <WebCore/FrameLoaderClient.h> #import <WebCore/HTMLFormControlElement.h> +#import <WebCore/HTMLFormElement.h> #import <WebCore/HTMLInputElement.h> #import <WebCore/HTMLNames.h> #import <WebCore/MIMETypeRegistry.h> @@ -259,13 +260,13 @@ static NSArray *concatenateArrays(NSArray *first, NSArray *second) - (NSAttributedString *)attributedStringFrom:(DOMNode *)startNode startOffset:(int)startOffset to:(DOMNode *)endNode endOffset:(int)endOffset { - return [NSAttributedString _web_attributedStringFromRange:Range::create([startNode _node]->document(), [startNode _node], startOffset, [endNode _node], endOffset).get()]; + return [NSAttributedString _web_attributedStringFromRange:Range::create(core(startNode)->document(), core(startNode), startOffset, core(endNode), endOffset).get()]; } static HTMLFormElement* formElementFromDOMElement(DOMElement *element) { - Node* node = [element _node]; - return node && node->hasTagName(formTag) ? static_cast<HTMLFormElement *>(node) : 0; + Element* node = core(element); + return node && node->hasTagName(formTag) ? static_cast<HTMLFormElement*>(node) : 0; } - (DOMElement *)elementWithName:(NSString *)name inForm:(DOMElement *)form @@ -277,7 +278,7 @@ static HTMLFormElement* formElementFromDOMElement(DOMElement *element) AtomicString targetName = name; for (unsigned i = 0; i < elements.size(); i++) { HTMLFormControlElement* elt = elements[i]; - if (elt->name() == targetName) + if (elt->formControlName() == targetName) return kit(elt); } return nil; @@ -285,7 +286,7 @@ static HTMLFormElement* formElementFromDOMElement(DOMElement *element) static HTMLInputElement* inputElementFromDOMElement(DOMElement* element) { - Node* node = [element _node]; + Element* node = core(element); return node && node->hasTagName(inputTag) ? static_cast<HTMLInputElement*>(node) : 0; } diff --git a/WebKit/mac/WebView/WebHTMLView.mm b/WebKit/mac/WebView/WebHTMLView.mm index c4ca174..d58c765 100644 --- a/WebKit/mac/WebView/WebHTMLView.mm +++ b/WebKit/mac/WebView/WebHTMLView.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * (C) 2006, 2007 Graham Dennis (graham.dennis@gmail.com) * * Redistribution and use in source and binary forms, with or without @@ -29,14 +29,17 @@ #import "WebHTMLView.h" +#import "DOMCSSStyleDeclarationInternal.h" +#import "DOMDocumentFragmentInternal.h" +#import "DOMDocumentInternal.h" #import "DOMNodeInternal.h" #import "DOMRangeInternal.h" #import "WebArchive.h" -#import "WebNetscapePluginView.h" #import "WebClipView.h" -#import "WebDOMOperationsPrivate.h" +#import "WebDOMOperationsInternal.h" #import "WebDataSourceInternal.h" #import "WebDefaultUIDelegate.h" +#import "WebDelegateImplementationCaching.h" #import "WebDocumentInternal.h" #import "WebDynamicScrollBarsView.h" #import "WebEditingDelegate.h" @@ -50,7 +53,6 @@ #import "WebKitNSStringExtras.h" #import "WebKitVersionChecks.h" #import "WebLocalizableStrings.h" -#import "WebNodeHighlight.h" #import "WebNSAttributedStringExtras.h" #import "WebNSEventExtras.h" #import "WebNSFileManagerExtras.h" @@ -60,17 +62,20 @@ #import "WebNSPrintOperationExtras.h" #import "WebNSURLExtras.h" #import "WebNSViewExtras.h" +#import "WebNetscapePluginView.h" +#import "WebNodeHighlight.h" #import "WebPluginController.h" #import "WebPreferences.h" #import "WebPreferencesPrivate.h" #import "WebResourcePrivate.h" #import "WebStringTruncator.h" +#import "WebTextCompletionController.h" #import "WebTypesInternal.h" #import "WebUIDelegatePrivate.h" #import "WebViewInternal.h" #import <AppKit/NSAccessibility.h> #import <ApplicationServices/ApplicationServices.h> -#import <dlfcn.h> +#import <WebCore/CSSMutableStyleDeclaration.h> #import <WebCore/CachedImage.h> #import <WebCore/CachedResourceClient.h> #import <WebCore/ColorMac.h> @@ -78,38 +83,38 @@ #import <WebCore/ContextMenuController.h> #import <WebCore/Document.h> #import <WebCore/DocumentFragment.h> +#import <WebCore/DragController.h> #import <WebCore/Editor.h> #import <WebCore/EditorDeleteAction.h> #import <WebCore/Element.h> #import <WebCore/EventHandler.h> #import <WebCore/ExceptionHandlers.h> -#import <WebCore/DragController.h> #import <WebCore/FloatRect.h> #import <WebCore/FocusController.h> #import <WebCore/Frame.h> #import <WebCore/FrameLoader.h> #import <WebCore/FrameView.h> -#import <WebCore/HitTestResult.h> #import <WebCore/HTMLNames.h> +#import <WebCore/HitTestResult.h> #import <WebCore/Image.h> #import <WebCore/KeyboardEvent.h> #import <WebCore/LegacyWebArchive.h> #import <WebCore/MIMETypeRegistry.h> #import <WebCore/Page.h> #import <WebCore/PlatformKeyboardEvent.h> -#import <WebCore/PlatformMouseEvent.h> #import <WebCore/Range.h> #import <WebCore/SelectionController.h> #import <WebCore/SharedBuffer.h> #import <WebCore/SimpleFontData.h> #import <WebCore/Text.h> #import <WebCore/WebCoreObjCExtras.h> -#import <WebCore/WebCoreTextRenderer.h> +#import <WebCore/WebFontCache.h> #import <WebCore/markup.h> #import <WebKit/DOM.h> #import <WebKit/DOMExtensions.h> #import <WebKit/DOMPrivate.h> #import <WebKitSystemInterface.h> +#import <dlfcn.h> #import <limits> #import <runtime/InitializeThreading.h> @@ -144,6 +149,7 @@ using namespace WTF; static IMP oldSetCursorIMP = NULL; #ifdef BUILDING_ON_TIGER + static IMP oldResetCursorRectsIMP = NULL; static BOOL canSetCursor = YES; @@ -169,7 +175,9 @@ static void setCursor(NSCursor* self, SEL cmd) if (canSetCursor) oldSetCursorIMP(self, cmd); } + #else + static void setCursor(NSWindow* self, SEL cmd, NSPoint point) { NSView* view = [[self _web_borderView] hitTest:point]; @@ -184,21 +192,8 @@ static void setCursor(NSWindow* self, SEL cmd, NSPoint point) } oldSetCursorIMP(self, cmd, point); } -#endif -#if USE(ACCELERATED_COMPOSITING) -@interface WebLayerHostingView : NSView -@end - -@implementation WebLayerHostingView -// Empty NSViews intercept rightMouseDown: to do context menu handling, but we need the WebLayerHostingView to -// let right mouse clicks through. -- (void)rightMouseDown:(NSEvent *)theEvent -{ - [[self nextResponder] performSelector:_cmd withObject:theEvent]; -} -@end -#endif // USE(ACCELERATED_COMPOSITING) +#endif extern "C" { @@ -206,6 +201,7 @@ extern "C" { extern NSString *NSMarkedClauseSegmentAttributeName; extern NSString *NSTextInputReplacementRangeAttributeName; + } @interface NSView (WebNSViewDetails) @@ -224,7 +220,6 @@ extern NSString *NSTextInputReplacementRangeAttributeName; @interface NSWindow (WebNSWindowDetails) - (id)_newFirstResponderAfterResigning; -- (void)_setForceActiveControls:(BOOL)flag; @end @interface NSAttributedString (WebNSAttributedStringDetails) @@ -335,6 +330,32 @@ static CachedResourceClient* promisedDataClient() - (void)_web_clearPrintingModeRecursive; @end +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + +@interface WebHTMLView (WebHTMLViewTextCheckingInternal) +- (void)orderFrontSubstitutionsPanel:(id)sender; +- (BOOL)smartInsertDeleteEnabled; +- (void)setSmartInsertDeleteEnabled:(BOOL)flag; +- (void)toggleSmartInsertDelete:(id)sender; +- (BOOL)isAutomaticQuoteSubstitutionEnabled; +- (void)setAutomaticQuoteSubstitutionEnabled:(BOOL)flag; +- (void)toggleAutomaticQuoteSubstitution:(id)sender; +- (BOOL)isAutomaticLinkDetectionEnabled; +- (void)setAutomaticLinkDetectionEnabled:(BOOL)flag; +- (void)toggleAutomaticLinkDetection:(id)sender; +- (BOOL)isAutomaticDashSubstitutionEnabled; +- (void)setAutomaticDashSubstitutionEnabled:(BOOL)flag; +- (void)toggleAutomaticDashSubstitution:(id)sender; +- (BOOL)isAutomaticTextReplacementEnabled; +- (void)setAutomaticTextReplacementEnabled:(BOOL)flag; +- (void)toggleAutomaticTextReplacement:(id)sender; +- (BOOL)isAutomaticSpellingCorrectionEnabled; +- (void)setAutomaticSpellingCorrectionEnabled:(BOOL)flag; +- (void)toggleAutomaticSpellingCorrection:(id)sender; +@end + +#endif + @interface WebHTMLView (WebForwardDeclaration) // FIXME: Put this in a normal category and stop doing the forward declaration trick. - (void)_setPrinting:(BOOL)printing minimumPageWidth:(float)minPageWidth maximumPageWidth:(float)maxPageWidth adjustViewSize:(BOOL)adjustViewSize; @end @@ -366,24 +387,6 @@ static CachedResourceClient* promisedDataClient() - (void)_web_setObjectIfNotNil:(id)object forKey:(id)key; @end -// Handles the complete: text command -@interface WebTextCompleteController : NSObject <NSTableViewDelegate, NSTableViewDataSource> { -@private - WebHTMLView *_view; - NSWindow *_popupWindow; - NSTableView *_tableView; - NSArray *_completions; - NSString *_originalString; - int prefixLength; -} -- (id)initWithHTMLView:(WebHTMLView *)view; -- (void)doCompletion; -- (void)endRevertingChange:(BOOL)revertChange moveLeft:(BOOL)goLeft; -- (BOOL)popupWindowIsOpen; -- (BOOL)filterKeyDown:(NSEvent *)event; -- (void)_reflectSelection; -@end - struct WebHTMLViewInterpretKeyEventsParameters { KeyboardEvent* event; BOOL eventWasHandled; @@ -396,7 +399,6 @@ struct WebHTMLViewInterpretKeyEventsParameters { @interface WebHTMLViewPrivate : NSObject { @public BOOL closed; - BOOL needsLayout; BOOL needsToApplyStyles; BOOL ignoringMouseDraggedEvents; BOOL printing; @@ -404,7 +406,6 @@ struct WebHTMLViewInterpretKeyEventsParameters { BOOL observingMouseMovedNotifications; BOOL observingSuperviewNotifications; BOOL observingWindowNotifications; - BOOL resigningFirstResponder; id savedSubviews; BOOL subviewsSetAside; @@ -416,8 +417,10 @@ struct WebHTMLViewInterpretKeyEventsParameters { NSEvent *mouseDownEvent; // Kept after handling the event. BOOL handlingMouseDownEvent; NSEvent *keyDownEvent; // Kept after handling the event. - - NSSize lastLayoutSize; + + // A WebHTMLView has a single input context, but we return nil when in non-editable content to avoid making input methods do their work. + // This state is saved each time selection changes, because computing it causes style recalc, which is not always safe to do. + BOOL exposeInputContext; NSPoint lastScrollPosition; @@ -439,7 +442,7 @@ struct WebHTMLViewInterpretKeyEventsParameters { BOOL nextResponderDisabledOnce; #endif - WebTextCompleteController *compController; + WebTextCompletionController *completionController; BOOL transparentBackground; @@ -449,7 +452,6 @@ struct WebHTMLViewInterpretKeyEventsParameters { WebDataSource *dataSource; WebCore::CachedImage* promisedDragTIFFDataSource; - CFRunLoopTimerRef updateFocusedAndActiveStateTimer; CFRunLoopTimerRef updateMouseoverTimer; SEL selectorForDoCommandBySelector; @@ -514,14 +516,13 @@ static NSCellStateValue kit(TriState state) ASSERT(!autoscrollTimer); ASSERT(!autoscrollTriggerEvent); - ASSERT(!updateFocusedAndActiveStateTimer); ASSERT(!updateMouseoverTimer); [mouseDownEvent release]; [keyDownEvent release]; [pluginController release]; [toolTip release]; - [compController release]; + [completionController release]; [dataSource release]; [highlighters release]; if (promisedDragTIFFDataSource) @@ -546,7 +547,7 @@ static NSCellStateValue kit(TriState state) [keyDownEvent release]; [pluginController release]; [toolTip release]; - [compController release]; + [completionController release]; [dataSource release]; [highlighters release]; if (promisedDragTIFFDataSource) @@ -556,7 +557,7 @@ static NSCellStateValue kit(TriState state) keyDownEvent = nil; pluginController = nil; toolTip = nil; - compController = nil; + completionController = nil; dataSource = nil; highlighters = nil; promisedDragTIFFDataSource = 0; @@ -684,6 +685,13 @@ static NSURL* uniqueURLWithRelativePart(NSString *relativePart) subresources:0])) return fragment; + if ([types containsObject:NSRTFDPboardType] && + (fragment = [self _documentFragmentFromPasteboard:pasteboard + forType:NSRTFDPboardType + inContext:context + subresources:0])) + return fragment; + if ([types containsObject:NSRTFPboardType] && (fragment = [self _documentFragmentFromPasteboard:pasteboard forType:NSRTFPboardType @@ -691,16 +699,16 @@ static NSURL* uniqueURLWithRelativePart(NSString *relativePart) subresources:0])) return fragment; - if ([types containsObject:NSRTFDPboardType] && + if ([types containsObject:NSTIFFPboardType] && (fragment = [self _documentFragmentFromPasteboard:pasteboard - forType:NSRTFDPboardType + forType:NSTIFFPboardType inContext:context subresources:0])) return fragment; - if ([types containsObject:NSTIFFPboardType] && + if ([types containsObject:NSPDFPboardType] && (fragment = [self _documentFragmentFromPasteboard:pasteboard - forType:NSTIFFPboardType + forType:NSPDFPboardType inContext:context subresources:0])) return fragment; @@ -746,7 +754,7 @@ static NSURL* uniqueURLWithRelativePart(NSString *relativePart) NSArray *types = [pasteboard types]; if ([types containsObject:NSStringPboardType]) - return [pasteboard stringForType:NSStringPboardType]; + return [[pasteboard stringForType:NSStringPboardType] precomposedStringWithCanonicalMapping]; NSAttributedString *attributedString = nil; NSString *string; @@ -780,20 +788,29 @@ static NSURL* uniqueURLWithRelativePart(NSString *relativePart) - (void)_pasteWithPasteboard:(NSPasteboard *)pasteboard allowPlainText:(BOOL)allowPlainText { + WebView *webView = [[self _webView] retain]; + [webView _setInsertionPasteboard:pasteboard]; + DOMRange *range = [self _selectedRange]; - DOMDocumentFragment *fragment = [self _documentFragmentFromPasteboard:pasteboard - inContext:range allowPlainText:allowPlainText]; - WebFrame *frame = [self _frame]; - if (fragment && [self _shouldInsertFragment:fragment replacingDOMRange:[self _selectedRange] givenAction:WebViewInsertActionPasted]) { - [frame _replaceSelectionWithFragment:fragment selectReplacement:NO smartReplace:[self _canSmartReplaceWithPasteboard:pasteboard] matchStyle:NO]; - } + DOMDocumentFragment *fragment = [self _documentFragmentFromPasteboard:pasteboard inContext:range allowPlainText:allowPlainText]; + if (fragment && [self _shouldInsertFragment:fragment replacingDOMRange:range givenAction:WebViewInsertActionPasted]) + [[self _frame] _replaceSelectionWithFragment:fragment selectReplacement:NO smartReplace:[self _canSmartReplaceWithPasteboard:pasteboard] matchStyle:NO]; + + [webView _setInsertionPasteboard:nil]; + [webView release]; } - (void)_pasteAsPlainTextWithPasteboard:(NSPasteboard *)pasteboard { + WebView *webView = [[self _webView] retain]; + [webView _setInsertionPasteboard:pasteboard]; + NSString *text = [self _plainTextFromPasteboard:pasteboard]; if ([self _shouldReplaceSelectionWithText:text givenAction:WebViewInsertActionPasted]) [[self _frame] _replaceSelectionWithText:text selectReplacement:NO smartReplace:[self _canSmartReplaceWithPasteboard:pasteboard]]; + + [webView _setInsertionPasteboard:nil]; + [webView release]; } - (void)_removeMouseMovedObserverUnconditionally @@ -834,7 +851,6 @@ static NSURL* uniqueURLWithRelativePart(NSString *relativePart) [notificationCenter removeObserver:self name:NSWindowDidBecomeKeyNotification object:nil]; [notificationCenter removeObserver:self name:NSWindowDidResignKeyNotification object:nil]; [notificationCenter removeObserver:self name:NSWindowWillCloseNotification object:window]; - [notificationCenter removeObserver:self name:WKWindowWillOrderOnScreenNotification() object:window]; _private->observingWindowNotifications = false; } @@ -950,15 +966,6 @@ static NSURL* uniqueURLWithRelativePart(NSString *relativePart) _private->mouseDownEvent = event; } -- (void)_cancelUpdateFocusedAndActiveStateTimer -{ - if (_private->updateFocusedAndActiveStateTimer) { - CFRunLoopTimerInvalidate(_private->updateFocusedAndActiveStateTimer); - CFRelease(_private->updateFocusedAndActiveStateTimer); - _private->updateFocusedAndActiveStateTimer = NULL; - } -} - - (void)_cancelUpdateMouseoverTimer { if (_private->updateMouseoverTimer) { @@ -1139,17 +1146,11 @@ static void _updateMouseoverTimerCallback(CFRunLoopTimerRef timer, void *info) - (void)_frameOrBoundsChanged { - if (!NSEqualSizes(_private->lastLayoutSize, [(NSClipView *)[self superview] documentVisibleRect].size)) { - [self setNeedsLayout:YES]; - [self setNeedsDisplay:YES]; - [_private->compController endRevertingChange:NO moveLeft:NO]; - } - NSPoint origin = [[self superview] bounds].origin; if (!NSEqualPoints(_private->lastScrollPosition, origin)) { if (Frame* coreFrame = core([self _frame])) coreFrame->eventHandler()->sendScrollEvent(); - [_private->compController endRevertingChange:NO moveLeft:NO]; + [_private->completionController endRevertingChange:NO moveLeft:NO]; WebView *webView = [self _webView]; [[webView _UIDelegateForwarder] webView:webView didScrollDocumentInFrameView:[self _frameView]]; @@ -1165,6 +1166,10 @@ static void _updateMouseoverTimerCallback(CFRunLoopTimerRef timer, void *info) _updateMouseoverTimerCallback, &context); CFRunLoopAddTimer(CFRunLoopGetCurrent(), _private->updateMouseoverTimer, kCFRunLoopDefaultMode); } + +#if USE(ACCELERATED_COMPOSITING) && defined(BUILDING_ON_LEOPARD) + [self _updateLayerHostingViewPosition]; +#endif } - (void)_setAsideSubviews @@ -1267,12 +1272,20 @@ static void _updateMouseoverTimerCallback(CFRunLoopTimerRef timer, void *info) } else if (wasInPrintingMode) [self _web_clearPrintingModeRecursive]; -#ifdef BUILDING_ON_TIGER - +#ifndef BUILDING_ON_TIGER + // There are known cases where -viewWillDraw is not called on all views being drawn. + // See <rdar://problem/6964278> for example. Performing layout at this point prevents us from + // trying to paint without layout (which WebCore now refuses to do, instead bailing out without + // drawing at all), but we may still fail to update and regions dirtied by the layout which are + // not already dirty. + if ([self _needsLayout]) { + LOG_ERROR("View needs layout. Either -viewWillDraw wasn't called or layout was invalidated during the display operation. Performing layout now."); + [self _web_layoutIfNeededRecursive]; + } +#else // Because Tiger does not have viewWillDraw we need to do layout here. [self _web_layoutIfNeededRecursive]; [_subviews makeObjectsPerformSelector:@selector(_propagateDirtyRectsToOpaqueAncestors)]; - #endif [self _setAsideSubviews]; @@ -1381,10 +1394,13 @@ static void _updateMouseoverTimerCallback(CFRunLoopTimerRef timer, void *info) // when there is HTML overlapping the view, see bug 4361626) // 4) NSAccessibilityHitTest relies on this for checking the cursor position. // Our check for that is whether the event is NSFlagsChanged. This works - // for VoiceOver's cntl-opt-f5 command (move focus to item under cursor) - // and Dictionary's cmd-cntl-D (open dictionary popup for item under cursor). + // for VoiceOver's Control-Option-F5 command (move focus to item under cursor) + // and Dictionary's Command-Control-D (open dictionary popup for item under cursor). // This is of course a hack. + if (_private->closed) + return nil; + BOOL captureHitsOnSubviews; if (forceNSViewHitTest) captureHitsOnSubviews = NO; @@ -1398,8 +1414,14 @@ static void _updateMouseoverTimerCallback(CFRunLoopTimerRef timer, void *info) || [event type] == NSFlagsChanged); } - if (!captureHitsOnSubviews) - return [super hitTest:point]; + if (!captureHitsOnSubviews) { + NSView* hitView = [super hitTest:point]; +#if USE(ACCELERATED_COMPOSITING) + if (_private && hitView == _private->layerHostingView) + hitView = self; +#endif + return hitView; + } if ([[self superview] mouse:point inRect:[self frame]]) return self; return nil; @@ -1551,18 +1573,18 @@ static void _updateMouseoverTimerCallback(CFRunLoopTimerRef timer, void *info) if (lastHitView != view && lastHitView && [lastHitView _frame]) { // If we are moving out of a view (or frame), let's pretend the mouse moved // all the way out of that view. But we have to account for scrolling, because - // khtml doesn't understand our clipping. + // WebCore doesn't understand our clipping. NSRect visibleRect = [[[[lastHitView _frame] frameView] _scrollView] documentVisibleRect]; float yScroll = visibleRect.origin.y; float xScroll = visibleRect.origin.x; - event = [NSEvent mouseEventWithType:NSMouseMoved - location:NSMakePoint(-1 - xScroll, -1 - yScroll ) - modifierFlags:[[NSApp currentEvent] modifierFlags] - timestamp:[NSDate timeIntervalSinceReferenceDate] - windowNumber:[[view window] windowNumber] - context:[[NSApp currentEvent] context] - eventNumber:0 clickCount:0 pressure:0]; + NSEvent *event = [NSEvent mouseEventWithType:NSMouseMoved + location:NSMakePoint(-1 - xScroll, -1 - yScroll) + modifierFlags:[[NSApp currentEvent] modifierFlags] + timestamp:[NSDate timeIntervalSinceReferenceDate] + windowNumber:[[view window] windowNumber] + context:[[NSApp currentEvent] context] + eventNumber:0 clickCount:0 pressure:0]; if (Frame* lastHitCoreFrame = core([lastHitView _frame])) lastHitCoreFrame->eventHandler()->mouseMoved(event); } @@ -1582,7 +1604,7 @@ static void _updateMouseoverTimerCallback(CFRunLoopTimerRef timer, void *info) { static NSArray *types = nil; if (!types) { - types = [[NSArray alloc] initWithObjects:WebArchivePboardType, NSHTMLPboardType, NSFilenamesPboardType, NSTIFFPboardType, + types = [[NSArray alloc] initWithObjects:WebArchivePboardType, NSHTMLPboardType, NSFilenamesPboardType, NSTIFFPboardType, NSPDFPboardType, #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) NSPICTPboardType, #endif @@ -1736,7 +1758,7 @@ static void _updateMouseoverTimerCallback(CFRunLoopTimerRef timer, void *info) return [[self _webView] smartInsertDeleteEnabled] && [[pasteboard types] containsObject:WebSmartPastePboardType]; } -- (void)_startAutoscrollTimer: (NSEvent *)triggerEvent +- (void)_startAutoscrollTimer:(NSEvent *)triggerEvent { if (_private->autoscrollTimer == nil) { _private->autoscrollTimer = [[NSTimer scheduledTimerWithTimeInterval:AUTOSCROLL_INTERVAL @@ -1910,13 +1932,6 @@ static void _updateMouseoverTimerCallback(CFRunLoopTimerRef timer, void *info) [_private->highlighters removeObjectForKey:type]; } -- (void)_updateFocusedAndActiveState -{ - [self _cancelUpdateFocusedAndActiveStateTimer]; - - [[self _webView] _updateFocusedAndActiveStateForFrame:[self _frame]]; -} - - (void)_writeSelectionToPasteboard:(NSPasteboard *)pasteboard { ASSERT([self _hasSelection]); @@ -1946,7 +1961,6 @@ static void _updateMouseoverTimerCallback(CFRunLoopTimerRef timer, void *info) _private->closed = YES; [self _cancelUpdateMouseoverTimer]; - [self _cancelUpdateFocusedAndActiveStateTimer]; [self _clearLastHitViewIfSelf]; [self _removeMouseMovedObserverUnconditionally]; [self _removeWindowObservers]; @@ -2057,6 +2071,16 @@ static void _updateMouseoverTimerCallback(CFRunLoopTimerRef timer, void *info) [resource release]; return fragment; } + if (pboardType == NSPDFPboardType) { + WebResource *resource = [[WebResource alloc] initWithData:[pasteboard dataForType:NSPDFPboardType] + URL:uniqueURLWithRelativePart(@"application.pdf") + MIMEType:@"application/pdf" + textEncodingName:nil + frameName:nil]; + DOMDocumentFragment *fragment = [[self _dataSource] _documentFragmentWithImageResource:resource]; + [resource release]; + return fragment; + } #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) if (pboardType == NSPICTPboardType) { WebResource *resource = [[WebResource alloc] initWithData:[pasteboard dataForType:NSPICTPboardType] @@ -2173,23 +2197,14 @@ static void _updateMouseoverTimerCallback(CFRunLoopTimerRef timer, void *info) @end -@interface NSString (WebHTMLViewFileInternal) -- (BOOL)matchesExtensionEquivalent:(NSString *)extension; -@end - -@implementation NSString (WebHTMLViewFileInternal) - -- (BOOL)matchesExtensionEquivalent:(NSString *)extension +static bool matchesExtensionOrEquivalent(NSString *filename, NSString *extension) { - if ([self hasSuffix:extension]) - return YES; - else if ([extension isEqualToString:@"jpeg"] && [self hasSuffix:@"jpg"]) - return YES; - return NO; + NSString *extensionAsSuffix = [@"." stringByAppendingString:extension]; + return [filename _webkit_hasCaseInsensitiveSuffix:extensionAsSuffix] + || ([extension _webkit_isCaseInsensitiveEqualToString:@"jpeg"] + && [filename _webkit_hasCaseInsensitiveSuffix:@".jpg"]); } -@end - #ifdef BUILDING_ON_TIGER // The following is a workaround for @@ -2245,7 +2260,6 @@ static void _updateMouseoverTimerCallback(CFRunLoopTimerRef timer, void *info) _private = [[WebHTMLViewPrivate alloc] init]; _private->pluginController = [[WebPluginController alloc] initWithDocumentView:self]; - _private->needsLayout = YES; return self; } @@ -2637,6 +2651,58 @@ WEBCORE_COMMAND(yankAndSelect) return YES; } #endif + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + if (action == @selector(orderFrontSubstitutionsPanel:)) { + NSMenuItem *menuItem = (NSMenuItem *)item; + if ([menuItem isKindOfClass:[NSMenuItem class]]) { + BOOL panelShowing = [[[NSSpellChecker sharedSpellChecker] substitutionsPanel] isVisible]; + [menuItem setTitle:panelShowing + ? UI_STRING("Hide Substitutions", "menu item title") + : UI_STRING("Show Substitutions", "menu item title")]; + } + return [self _canEdit]; + } + // FIXME 4799134: WebView is the bottleneck for this logic, but we must validate + // the selector here because we implement it here, and we must implement it here because the AppKit + // code checks the first responder. + if (action == @selector(toggleSmartInsertDelete:)) { + NSMenuItem *menuItem = (NSMenuItem *)item; + if ([menuItem isKindOfClass:[NSMenuItem class]]) + [menuItem setState:[self smartInsertDeleteEnabled] ? NSOnState : NSOffState]; + return [self _canEdit]; + } + if (action == @selector(toggleAutomaticQuoteSubstitution:)) { + NSMenuItem *menuItem = (NSMenuItem *)item; + if ([menuItem isKindOfClass:[NSMenuItem class]]) + [menuItem setState:[self isAutomaticQuoteSubstitutionEnabled] ? NSOnState : NSOffState]; + return [self _canEdit]; + } + if (action == @selector(toggleAutomaticLinkDetection:)) { + NSMenuItem *menuItem = (NSMenuItem *)item; + if ([menuItem isKindOfClass:[NSMenuItem class]]) + [menuItem setState:[self isAutomaticLinkDetectionEnabled] ? NSOnState : NSOffState]; + return [self _canEdit]; + } + if (action == @selector(toggleAutomaticDashSubstitution:)) { + NSMenuItem *menuItem = (NSMenuItem *)item; + if ([menuItem isKindOfClass:[NSMenuItem class]]) + [menuItem setState:[self isAutomaticDashSubstitutionEnabled] ? NSOnState : NSOffState]; + return [self _canEdit]; + } + if (action == @selector(toggleAutomaticTextReplacement:)) { + NSMenuItem *menuItem = (NSMenuItem *)item; + if ([menuItem isKindOfClass:[NSMenuItem class]]) + [menuItem setState:[self isAutomaticTextReplacementEnabled] ? NSOnState : NSOffState]; + return [self _canEdit]; + } + if (action == @selector(toggleAutomaticSpellingCorrection:)) { + NSMenuItem *menuItem = (NSMenuItem *)item; + if ([menuItem isKindOfClass:[NSMenuItem class]]) + [menuItem setState:[self isAutomaticSpellingCorrectionEnabled] ? NSOnState : NSOffState]; + return [self _canEdit]; + } +#endif Editor::Command command = [self coreCommandBySelector:action]; if (command.isSupported()) { @@ -2745,14 +2811,6 @@ WEBCORE_COMMAND(yankAndSelect) - (void)addSuperviewObservers { - // We watch the bounds of our superview, so that we can do a layout when the size - // of the superview changes. This is different from other scrollable things that don't - // need this kind of thing because their layout doesn't change. - - // We need to pay attention to both height and width because our "layout" has to change - // to extend the background the full height of the space and because some elements have - // sizes that are based on the total size of the view. - if (_private->observingSuperviewNotifications) return; @@ -2765,7 +2823,7 @@ WEBCORE_COMMAND(yankAndSelect) [notificationCenter addObserver:self selector:@selector(_frameOrBoundsChanged) name:NSViewBoundsDidChangeNotification object:superview]; // In addition to registering for frame/bounds change notifications, call -_frameOrBoundsChanged. - // It will check the current size/scroll against the previous layout's size/scroll. We need to + // It will check the current scroll against the previous layout's scroll. We need to // do this here to catch the case where the WebView is laid out at one size, removed from its // window, resized, and inserted into another window. Our frame/bounds changed notifications // will not be sent in that situation, since we only watch for changes while in the view hierarchy. @@ -2787,7 +2845,6 @@ WEBCORE_COMMAND(yankAndSelect) [notificationCenter addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:nil]; [notificationCenter addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:nil]; [notificationCenter addObserver:self selector:@selector(windowWillClose:) name:NSWindowWillCloseNotification object:window]; - [notificationCenter addObserver:self selector:@selector(windowWillOrderOnScreen:) name:WKWindowWillOrderOnScreenNotification() object:window]; _private->observingWindowNotifications = true; } @@ -2803,12 +2860,6 @@ WEBCORE_COMMAND(yankAndSelect) [self addSuperviewObservers]; } -static void _updateFocusedAndActiveStateTimerCallback(CFRunLoopTimerRef timer, void *info) -{ - WebHTMLView *view = (WebHTMLView *)info; - [view _updateFocusedAndActiveState]; -} - - (void)viewWillMoveToWindow:(NSWindow *)window { // Don't do anything if we aren't initialized. This happens @@ -2823,7 +2874,6 @@ static void _updateFocusedAndActiveStateTimerCallback(CFRunLoopTimerRef timer, v [self _removeWindowObservers]; [self _removeSuperviewObservers]; [self _cancelUpdateMouseoverTimer]; - [self _cancelUpdateFocusedAndActiveStateTimer]; [[self _pluginController] stopAllPlugins]; } @@ -2844,19 +2894,6 @@ static void _updateFocusedAndActiveStateTimerCallback(CFRunLoopTimerRef timer, v [self addSuperviewObservers]; [self addMouseMovedObserver]; - // Schedule this update, rather than making the call right now. - // The reason is that placing the caret in the just-installed view requires - // the HTML/XML document to be available on the WebCore side, but it is not - // at the time this code is running. However, it will be there on the next - // crank of the run loop. Doing this helps to make a blinking caret appear - // in a new, empty window "automatic". - if (!_private->updateFocusedAndActiveStateTimer) { - CFRunLoopTimerContext context = { 0, self, NULL, NULL, NULL }; - _private->updateFocusedAndActiveStateTimer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent(), 0, 0, 0, - _updateFocusedAndActiveStateTimerCallback, &context); - CFRunLoopAddTimer(CFRunLoopGetCurrent(), _private->updateFocusedAndActiveStateTimer, kCFRunLoopDefaultMode); - } - [[self _pluginController] startAllPlugins]; _private->lastScrollPosition = NSZeroPoint; @@ -2921,7 +2958,7 @@ static void _updateFocusedAndActiveStateTimerCallback(CFRunLoopTimerRef timer, v { [self reapplyStyles]; - if (!_private->needsLayout && ![[self _frame] _needsLayout]) + if (![self _needsLayout]) return; #ifdef LOG_TIMES @@ -2931,10 +2968,8 @@ static void _updateFocusedAndActiveStateTimerCallback(CFRunLoopTimerRef timer, v LOG(View, "%@ doing layout", self); Frame* coreFrame = core([self _frame]); - if (!coreFrame) { - _private->needsLayout = NO; + if (!coreFrame) return; - } if (FrameView* coreView = coreFrame->view()) { if (minPageWidth > 0.0) @@ -2945,11 +2980,7 @@ static void _updateFocusedAndActiveStateTimerCallback(CFRunLoopTimerRef timer, v coreView->adjustViewSize(); } } - _private->needsLayout = NO; - if (!_private->printing) - _private->lastLayoutSize = [(NSClipView *)[self superview] documentVisibleRect].size; - #ifdef LOG_TIMES double thisTime = CFAbsoluteTimeGetCurrent() - start; LOG(Timing, "%s layout seconds = %f", [self URL], thisTime); @@ -2964,49 +2995,64 @@ static void _updateFocusedAndActiveStateTimerCallback(CFRunLoopTimerRef timer, v // Deliver mouseup events to the DOM for button 2. - (void)rightMouseUp:(NSEvent *)event { + // There's a chance that if we run a nested event loop the event will be released. + // Retaining and then autoreleasing prevents that from causing a problem later here or + // inside AppKit code. + [[event retain] autorelease]; + [super rightMouseUp:event]; + if (Frame* coreframe = core([self _frame])) coreframe->eventHandler()->mouseUp(event); } - (NSMenu *)menuForEvent:(NSEvent *)event { - [_private->compController endRevertingChange:NO moveLeft:NO]; + // There's a chance that if we run a nested event loop the event will be released. + // Retaining and then autoreleasing prevents that from causing a problem later here or + // inside AppKit code. + [[event retain] autorelease]; - _private->handlingMouseDownEvent = YES; - BOOL handledEvent = NO; - Frame* coreFrame = core([self _frame]); + [_private->completionController endRevertingChange:NO moveLeft:NO]; - if (!coreFrame) { - _private->handlingMouseDownEvent = NO; + RefPtr<Frame> coreFrame = core([self _frame]); + if (!coreFrame) return nil; - } Page* page = coreFrame->page(); if (!page) return nil; + // Match behavior of other browsers by sending a mousedown event for right clicks. + _private->handlingMouseDownEvent = YES; page->contextMenuController()->clearContextMenu(); - // Match behavior of other browsers by sending an onmousedown event for right clicks. coreFrame->eventHandler()->mouseDown(event); - handledEvent = coreFrame->eventHandler()->sendContextMenuEvent(PlatformMouseEvent(event)); + BOOL handledEvent = coreFrame->eventHandler()->sendContextMenuEvent(event); _private->handlingMouseDownEvent = NO; if (!handledEvent) return nil; + // Re-get page, since it might have gone away during event handling. + page = coreFrame->page(); + if (!page) + return nil; + ContextMenu* coreMenu = page->contextMenuController()->contextMenu(); if (!coreMenu) return nil; NSArray* menuItems = coreMenu->platformDescription(); - NSMenu* menu = nil; - if (menuItems && [menuItems count] > 0) { - menu = [[[NSMenu alloc] init] autorelease]; - for (unsigned i = 0; i < [menuItems count]; i++) - [menu addItem:[menuItems objectAtIndex:i]]; - } + if (!menuItems) + return nil; + NSUInteger count = [menuItems count]; + if (!count) + return nil; + + NSMenu* menu = [[[NSMenu alloc] init] autorelease]; + for (NSUInteger i = 0; i < count; i++) + [menu addItem:[menuItems objectAtIndex:i]]; return menu; } @@ -3041,7 +3087,14 @@ static void _updateFocusedAndActiveStateTimerCallback(CFRunLoopTimerRef timer, v - (void)setNeedsLayout: (BOOL)flag { LOG(View, "%@ setNeedsLayout:%@", self, flag ? @"YES" : @"NO"); - _private->needsLayout = flag; + if (!flag) + return; // There's no way to say you don't need a layout. + if (Frame* frame = core([self _frame])) { + if (frame->document() && frame->document()->inPageCache()) + return; + if (FrameView* view = frame->view()) + view->setNeedsLayout(); + } } - (void)setNeedsToApplyStyles: (BOOL)flag @@ -3123,9 +3176,13 @@ static void _updateFocusedAndActiveStateTimerCallback(CFRunLoopTimerRef timer, v #if USE(ACCELERATED_COMPOSITING) if ([[self _webView] _needsOneShotDrawingSynchronization]) { - // Disable screen updates so that drawing into the NSView and - // CALayer updates appear on the screen at the same time. + // Disable screen updates so that any layer changes committed here + // don't show up on the screen before the window flush at the end + // of the current window display. [[self window] disableScreenUpdatesUntilFlush]; + + // Make sure any layer changes that happened as a result of layout + // via -viewWillDraw are committed. [CATransaction flush]; [[self _webView] _setNeedsOneShotDrawingSynchronization:NO]; } @@ -3159,47 +3216,54 @@ static void _updateFocusedAndActiveStateTimerCallback(CFRunLoopTimerRef timer, v - (void)windowDidBecomeKey:(NSNotification *)notification { + if (!pthread_main_np()) { + [self performSelectorOnMainThread:_cmd withObject:notification waitUntilDone:NO]; + return; + } + NSWindow *keyWindow = [notification object]; if (keyWindow == [self window]) [self addMouseMovedObserver]; - - if (keyWindow == [self window] || keyWindow == [[self window] attachedSheet]) - [self _updateFocusedAndActiveState]; } - (void)windowDidResignKey:(NSNotification *)notification { + if (!pthread_main_np()) { + [self performSelectorOnMainThread:_cmd withObject:notification waitUntilDone:NO]; + return; + } + NSWindow *formerKeyWindow = [notification object]; if (formerKeyWindow == [self window]) [self removeMouseMovedObserver]; - if (formerKeyWindow == [self window] || formerKeyWindow == [[self window] attachedSheet]) { - [self _updateFocusedAndActiveState]; - [_private->compController endRevertingChange:NO moveLeft:NO]; - } + if (formerKeyWindow == [self window] || formerKeyWindow == [[self window] attachedSheet]) + [_private->completionController endRevertingChange:NO moveLeft:NO]; } - (void)windowWillClose:(NSNotification *)notification { - [_private->compController endRevertingChange:NO moveLeft:NO]; - [[self _pluginController] destroyAllPlugins]; -} + if (!pthread_main_np()) { + [self performSelectorOnMainThread:_cmd withObject:notification waitUntilDone:NO]; + return; + } -- (void)windowWillOrderOnScreen:(NSNotification *)notification -{ - if (![[self _webView] shouldUpdateWhileOffscreen]) - [self setNeedsDisplay:YES]; + [_private->completionController endRevertingChange:NO moveLeft:NO]; + [[self _pluginController] destroyAllPlugins]; } - (void)scrollWheel:(NSEvent *)event { - [self retain]; + // There's a chance that responding to this event will run a nested event loop, and + // fetching a new event might release the old one. Retaining and then autoreleasing + // the current event prevents that from causing a problem inside WebKit or AppKit code. + [[event retain] autorelease]; + Frame* frame = core([self _frame]); if (!frame || !frame->eventHandler()->wheelEvent(event)) [super scrollWheel:event]; - [self release]; } - (BOOL)_isSelectionEvent:(NSEvent *)event @@ -3210,6 +3274,11 @@ static void _updateFocusedAndActiveStateTimerCallback(CFRunLoopTimerRef timer, v - (BOOL)acceptsFirstMouse:(NSEvent *)event { + // There's a chance that responding to this event will run a nested event loop, and + // fetching a new event might release the old one. Retaining and then autoreleasing + // the current event prevents that from causing a problem inside WebKit or AppKit code. + [[event retain] autorelease]; + NSView *hitView = [self _hitViewForEvent:event]; WebHTMLView *hitHTMLView = [hitView isKindOfClass:[self class]] ? (WebHTMLView *)hitView : nil; @@ -3234,16 +3303,22 @@ static void _updateFocusedAndActiveStateTimerCallback(CFRunLoopTimerRef timer, v - (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)event { + // There's a chance that responding to this event will run a nested event loop, and + // fetching a new event might release the old one. Retaining and then autoreleasing + // the current event prevents that from causing a problem inside WebKit or AppKit code. + [[event retain] autorelease]; + NSView *hitView = [self _hitViewForEvent:event]; WebHTMLView *hitHTMLView = [hitView isKindOfClass:[self class]] ? (WebHTMLView *)hitView : nil; if (hitHTMLView) { bool result = false; - if ([hitHTMLView _isSelectionEvent:event]) + if ([hitHTMLView _isSelectionEvent:event]) { if (Frame* coreFrame = core([hitHTMLView _frame])) { [hitHTMLView _setMouseDownEvent:event]; result = coreFrame->eventHandler()->eventMayStartDrag(event); [hitHTMLView _setMouseDownEvent:nil]; } + } return result; } return [hitView shouldDelayWindowOrderingForEvent:event]; @@ -3251,6 +3326,11 @@ static void _updateFocusedAndActiveStateTimerCallback(CFRunLoopTimerRef timer, v - (void)mouseDown:(NSEvent *)event { + // There's a chance that responding to this event will run a nested event loop, and + // fetching a new event might release the old one. Retaining and then autoreleasing + // the current event prevents that from causing a problem inside WebKit or AppKit code. + [[event retain] autorelease]; + RetainPtr<WebHTMLView> protector = self; if ([[self inputContext] wantsToHandleMouseEvents] && [[self inputContext] handleMouseEvent:event]) return; @@ -3264,7 +3344,7 @@ static void _updateFocusedAndActiveStateTimerCallback(CFRunLoopTimerRef timer, v if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:event]) goto done; - [_private->compController endRevertingChange:NO moveLeft:NO]; + [_private->completionController endRevertingChange:NO moveLeft:NO]; // If the web page handles the context menu event and menuForEvent: returns nil, we'll get control click events here. // We don't want to pass them along to KHTML a second time. @@ -3298,15 +3378,23 @@ done: - (void)mouseDragged:(NSEvent *)event { + // There's a chance that responding to this event will run a nested event loop, and + // fetching a new event might release the old one. Retaining and then autoreleasing + // the current event prevents that from causing a problem inside WebKit or AppKit code. + [[event retain] autorelease]; + NSInputManager *currentInputManager = [NSInputManager currentInputManager]; if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:event]) return; [self retain]; - if (!_private->ignoringMouseDraggedEvents) - if (Frame* coreframe = core([self _frame])) - coreframe->eventHandler()->mouseDragged(event); + if (!_private->ignoringMouseDraggedEvents) { + if (Frame* frame = core([self _frame])) { + if (Page* page = frame->page()) + page->mainFrame()->eventHandler()->mouseDragged(event); + } + } [self release]; } @@ -3315,15 +3403,15 @@ done: { ASSERT(![self _webView] || [self _isTopHTMLView]); - Page *page = core([self _webView]); - + Page* page = core([self _webView]); if (!page) return NSDragOperationNone; - - if (page->dragController()->dragOperation() == DragOperationNone) + + // FIXME: Why do we override the source provided operation here? Why not in DragController::startDrag + if (page->dragController()->sourceDragOperation() == DragOperationNone) return NSDragOperationGeneric | NSDragOperationCopy; - - return (NSDragOperation)page->dragController()->dragOperation(); + + return (NSDragOperation)page->dragController()->sourceDragOperation(); } - (void)draggedImage:(NSImage *)image movedTo:(NSPoint)screenLoc @@ -3388,7 +3476,7 @@ done: wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:data] autorelease]; NSString* filename = [response suggestedFilename]; NSString* trueExtension(tiffResource->image()->filenameExtension()); - if (![filename matchesExtensionEquivalent:trueExtension]) + if (!matchesExtensionOrEquivalent(filename, trueExtension)) filename = [[filename stringByAppendingString:@"."] stringByAppendingString:trueExtension]; [wrapper setPreferredFilename:filename]; } @@ -3431,6 +3519,11 @@ noPromisedData: - (void)mouseUp:(NSEvent *)event { + // There's a chance that responding to this event will run a nested event loop, and + // fetching a new event might release the old one. Retaining and then autoreleasing + // the current event prevents that from causing a problem inside WebKit or AppKit code. + [[event retain] autorelease]; + [self _setMouseDownEvent:nil]; NSInputManager *currentInputManager = [NSInputManager currentInputManager]; @@ -3440,8 +3533,10 @@ noPromisedData: [self retain]; [self _stopAutoscrollTimer]; - if (Frame* coreframe = core([self _frame])) - coreframe->eventHandler()->mouseUp(event); + if (Frame* frame = core([self _frame])) { + if (Page* page = frame->page()) + page->mainFrame()->eventHandler()->mouseUp(event); + } [self _updateMouseoverWithFakeEvent]; [self release]; @@ -3459,29 +3554,50 @@ noPromisedData: return YES; } +// Utility function to make sure we don't return anything through the NSTextInput +// API when an editable region is not currently focused. +static BOOL isTextInput(Frame* coreFrame) +{ + return coreFrame && !coreFrame->selection()->isNone() && coreFrame->selection()->isContentEditable(); +} + +static BOOL isInPasswordField(Frame* coreFrame) +{ + return coreFrame && coreFrame->selection()->isInPasswordField(); +} + - (BOOL)becomeFirstResponder { NSSelectionDirection direction = NSDirectSelection; if (![[self _webView] _isPerformingProgrammaticFocus]) direction = [[self window] keyViewSelectionDirection]; - [self _updateFocusedAndActiveState]; [self _updateFontPanel]; Frame* frame = core([self _frame]); if (!frame) return YES; - - frame->editor()->setStartNewKillRingSequence(true); - if (direction == NSDirectSelection) - return YES; + BOOL exposeInputContext = isTextInput(frame) && !isInPasswordField(frame); + if (exposeInputContext != _private->exposeInputContext) { + _private->exposeInputContext = exposeInputContext; + [NSApp updateWindows]; + } + + frame->editor()->setStartNewKillRingSequence(true); Page* page = frame->page(); if (!page) return YES; - page->focusController()->setFocusedFrame(frame); + if (![[self _webView] _isPerformingProgrammaticFocus]) + page->focusController()->setFocusedFrame(frame); + + page->focusController()->setFocused(true); + + if (direction == NSDirectSelection) + return YES; + if (Document* document = frame->document()) document->setFocusedNode(0); page->focusController()->setInitialFocus(direction == NSSelectingNext ? FocusDirectionForward : FocusDirectionBackward, @@ -3493,15 +3609,24 @@ noPromisedData: { BOOL resign = [super resignFirstResponder]; if (resign) { - _private->resigningFirstResponder = YES; - [_private->compController endRevertingChange:NO moveLeft:NO]; + [_private->completionController endRevertingChange:NO moveLeft:NO]; + Frame* coreFrame = core([self _frame]); + if (!coreFrame) + return resign; + Page* page = coreFrame->page(); + if (!page) + return resign; if (![self maintainsInactiveSelection]) { [self deselectAll]; if (![[self _webView] _isPerformingProgrammaticFocus]) [self clearFocus]; } - [self _updateFocusedAndActiveState]; - _private->resigningFirstResponder = NO; + + id nextResponder = [[self window] _newFirstResponderAfterResigning]; + bool nextResponderIsInWebView = [nextResponder isKindOfClass:[NSView class]] + && [nextResponder isDescendantOf:[[[self _webView] mainFrame] frameView]]; + if (!nextResponderIsInWebView) + page->focusController()->setFocused(false); } return resign; } @@ -3582,8 +3707,10 @@ noPromisedData: [self _setPrinting:YES minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:NO]; float newBottomFloat = *newBottom; - if (FrameView* view = core([self _frame])->view()) - view->adjustPageHeight(&newBottomFloat, oldTop, oldBottom, bottomLimit); + if (Frame* frame = core([self _frame])) { + if (FrameView* view = frame->view()) + view->adjustPageHeight(&newBottomFloat, oldTop, oldBottom, bottomLimit); + } #ifdef __LP64__ // If the new bottom is equal to the old bottom (when both are treated as floats), we just copy @@ -3781,6 +3908,11 @@ noPromisedData: - (void)keyDown:(NSEvent *)event { + // There's a chance that responding to this event will run a nested event loop, and + // fetching a new event might release the old one. Retaining and then autoreleasing + // the current event prevents that from causing a problem inside WebKit or AppKit code. + [[event retain] autorelease]; + RetainPtr<WebHTMLView> selfProtector = self; BOOL eventWasSentToWebCore = (_private->keyDownEvent == event); @@ -3789,15 +3921,15 @@ noPromisedData: [_private->keyDownEvent release]; _private->keyDownEvent = [event retain]; - BOOL completionPopupWasOpen = _private->compController && [_private->compController popupWindowIsOpen]; + BOOL completionPopupWasOpen = _private->completionController && [_private->completionController popupWindowIsOpen]; Frame* coreFrame = core([self _frame]); if (!eventWasSentToWebCore && coreFrame && coreFrame->eventHandler()->keyEvent(event)) { // WebCore processed a key event, bail on any preexisting complete: UI if (completionPopupWasOpen) - [_private->compController endRevertingChange:YES moveLeft:NO]; - } else if (!_private->compController || ![_private->compController filterKeyDown:event]) { + [_private->completionController endRevertingChange:YES moveLeft:NO]; + } else if (!_private->completionController || ![_private->completionController filterKeyDown:event]) { // Not consumed by complete: popup window - [_private->compController endRevertingChange:YES moveLeft:NO]; + [_private->completionController endRevertingChange:YES moveLeft:NO]; callSuper = YES; } if (callSuper) @@ -3808,6 +3940,11 @@ noPromisedData: - (void)keyUp:(NSEvent *)event { + // There's a chance that responding to this event will run a nested event loop, and + // fetching a new event might release the old one. Retaining and then autoreleasing + // the current event prevents that from causing a problem inside WebKit or AppKit code. + [[event retain] autorelease]; + BOOL eventWasSentToWebCore = (_private->keyDownEvent == event); RetainPtr<WebHTMLView> selfProtector = self; @@ -3820,6 +3957,11 @@ noPromisedData: - (void)flagsChanged:(NSEvent *)event { + // There's a chance that responding to this event will run a nested event loop, and + // fetching a new event might release the old one. Retaining and then autoreleasing + // the current event prevents that from causing a problem inside WebKit or AppKit code. + [[event retain] autorelease]; + Frame* coreFrame = core([self _frame]); if (coreFrame) coreFrame->eventHandler()->capsLockStateMayHaveChanged(); @@ -4052,6 +4194,11 @@ noPromisedData: - (BOOL)performKeyEquivalent:(NSEvent *)event { + // There's a chance that responding to this event will run a nested event loop, and + // fetching a new event might release the old one. Retaining and then autoreleasing + // the current event prevents that from causing a problem inside WebKit or AppKit code. + [[event retain] autorelease]; + if ([self _handleStyleKeyEquivalent:event]) return YES; @@ -4144,6 +4291,8 @@ noPromisedData: BOOL aIsItalic = ([fm traitsOfFont:a] & NSItalicFontMask) != 0; BOOL bIsItalic = ([fm traitsOfFont:b] & NSItalicFontMask) != 0; + BOOL aIsBold = aWeight > MIN_BOLD_WEIGHT; + if ([aFamilyName isEqualToString:bFamilyName]) { NSString *familyNameForCSS = aFamilyName; @@ -4153,7 +4302,8 @@ noPromisedData: // Find the font the same way the rendering code would later if it encountered this CSS. NSFontTraitMask traits = aIsItalic ? NSFontItalicTrait : 0; - NSFont *foundFont = WebCoreFindFont(aFamilyName, traits, aWeight, aPointSize); + int weight = aIsBold ? STANDARD_BOLD_WEIGHT : STANDARD_WEIGHT; + NSFont *foundFont = [WebFontCache fontWithFamily:aFamilyName traits:traits weight:weight size:aPointSize]; // If we don't find a font with the same Postscript name, then we'll have to use the // Postscript name to make the CSS specific enough. @@ -4173,8 +4323,9 @@ noPromisedData: else if (aPointSize > soa) [style _setFontSizeDelta:@"1px"]; + // FIXME: Map to the entire range of CSS weight values. if (aWeight == bWeight) - [style setFontWeight:aWeight > MIN_BOLD_WEIGHT ? @"bold" : @"normal"]; + [style setFontWeight:aIsBold ? @"bold" : @"normal"]; if (aIsItalic == bIsItalic) [style setFontStyle:aIsItalic ? @"italic" : @"normal"]; @@ -4408,9 +4559,9 @@ NSStrokeColorAttributeName /* NSColor, default nil: same as foreground co if (![self _canEdit]) return; - if (!_private->compController) - _private->compController = [[WebTextCompleteController alloc] initWithHTMLView:self]; - [_private->compController doCompletion]; + if (!_private->completionController) + _private->completionController = [[WebTextCompletionController alloc] initWithWebView:[self _webView] HTMLView:self]; + [_private->completionController doCompletion]; } - (void)checkSpelling:(id)sender @@ -4630,7 +4781,13 @@ static BOOL writingDirectionKeyBindingsEnabled() // support them via the key bindings mechanism. - (BOOL)_wantsKeyDownForEvent:(NSEvent *)event { - return YES; + bool haveWebCoreFrame = core([self _frame]); + + // If we have a frame, our keyDown method will handle key bindings after sending + // the event through the DOM, so ask AppKit not to do its early special key binding + // mapping. If we don't have a frame, just let things work the normal way without + // a keyDown. + return haveWebCoreFrame; } #else @@ -4704,15 +4861,28 @@ static BOOL writingDirectionKeyBindingsEnabled() #endif +- (void)_updateControlTints +{ + Frame* frame = core([self _frame]); + if (!frame) + return; + FrameView* view = frame->view(); + if (!view) + return; + view->updateControlTints(); +} + // Despite its name, this is called at different times than windowDidBecomeKey is. // It takes into account all the other factors that determine when NSCell draws // with different tints, so it's the right call to use for control tints. We'd prefer // to do this with API. <rdar://problem/5136760> - (void)_windowChangedKeyState { - if (Frame* frame = core([self _frame])) - if (FrameView* view = frame->view()) - view->updateControlTints(); + if (pthread_main_np()) + [self _updateControlTints]; + else + [self performSelectorOnMainThread:@selector(_updateControlTints) withObject:nil waitUntilDone:NO]; + [super _windowChangedKeyState]; } @@ -4902,6 +5072,121 @@ static CGPoint coreGraphicsScreenPointForAppKitScreenPoint(NSPoint point) #endif +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + +- (void)orderFrontSubstitutionsPanel:(id)sender +{ + COMMAND_PROLOGUE + + NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker]; + if (!checker) { + LOG_ERROR("No NSSpellChecker"); + return; + } + + NSPanel *substitutionsPanel = [checker substitutionsPanel]; + if ([substitutionsPanel isVisible]) { + [substitutionsPanel orderOut:sender]; + return; + } + [substitutionsPanel orderFront:sender]; +} + +// FIXME 4799134: WebView is the bottleneck for this logic, but we must implement these methods here because +// the AppKit code checks the first responder. + +- (BOOL)smartInsertDeleteEnabled +{ + return [[self _webView] smartInsertDeleteEnabled]; +} + +- (void)setSmartInsertDeleteEnabled:(BOOL)flag +{ + [[self _webView] setSmartInsertDeleteEnabled:flag]; +} + +- (void)toggleSmartInsertDelete:(id)sender +{ + [[self _webView] toggleSmartInsertDelete:sender]; +} + +- (BOOL)isAutomaticQuoteSubstitutionEnabled +{ + return [[self _webView] isAutomaticQuoteSubstitutionEnabled]; +} + +- (void)setAutomaticQuoteSubstitutionEnabled:(BOOL)flag +{ + [[self _webView] setAutomaticQuoteSubstitutionEnabled:flag]; +} + +- (void)toggleAutomaticQuoteSubstitution:(id)sender +{ + [[self _webView] toggleAutomaticQuoteSubstitution:sender]; +} + +- (BOOL)isAutomaticLinkDetectionEnabled +{ + return [[self _webView] isAutomaticLinkDetectionEnabled]; +} + +- (void)setAutomaticLinkDetectionEnabled:(BOOL)flag +{ + [[self _webView] setAutomaticLinkDetectionEnabled:flag]; +} + +- (void)toggleAutomaticLinkDetection:(id)sender +{ + [[self _webView] toggleAutomaticLinkDetection:sender]; +} + +- (BOOL)isAutomaticDashSubstitutionEnabled +{ + return [[self _webView] isAutomaticDashSubstitutionEnabled]; +} + +- (void)setAutomaticDashSubstitutionEnabled:(BOOL)flag +{ + [[self _webView] setAutomaticDashSubstitutionEnabled:flag]; +} + +- (void)toggleAutomaticDashSubstitution:(id)sender +{ + [[self _webView] toggleAutomaticDashSubstitution:sender]; +} + +- (BOOL)isAutomaticTextReplacementEnabled +{ + return [[self _webView] isAutomaticTextReplacementEnabled]; +} + +- (void)setAutomaticTextReplacementEnabled:(BOOL)flag +{ + [[self _webView] setAutomaticTextReplacementEnabled:flag]; +} + +- (void)toggleAutomaticTextReplacement:(id)sender +{ + [[self _webView] toggleAutomaticTextReplacement:sender]; +} + +- (BOOL)isAutomaticSpellingCorrectionEnabled +{ + return [[self _webView] isAutomaticSpellingCorrectionEnabled]; +} + +- (void)setAutomaticSpellingCorrectionEnabled:(BOOL)flag +{ + [[self _webView] setAutomaticSpellingCorrectionEnabled:flag]; +} + +- (void)toggleAutomaticSpellingCorrection:(id)sender +{ + [[self _webView] toggleAutomaticSpellingCorrection:sender]; +} + +#endif + - (void)_lookUpInDictionaryFromMenu:(id)sender { // Dictionary API will accept a whitespace-only string and display UI as if it were real text, @@ -4929,7 +5214,6 @@ static CGPoint coreGraphicsScreenPointForAppKitScreenPoint(NSPoint point) return; #endif - // We soft link to get the function that displays the dictionary (either pop-up window or app) to avoid the performance // penalty of linking to another framework. This function changed signature as well as framework between Tiger and Leopard, // so the two cases are handled separately. @@ -5002,7 +5286,7 @@ static CGPoint coreGraphicsScreenPointForAppKitScreenPoint(NSPoint point) if (const PlatformKeyboardEvent* platformEvent = event->keyEvent()) { NSEvent *macEvent = platformEvent->macEvent(); - if ([macEvent type] == NSKeyDown && [_private->compController filterKeyDown:macEvent]) + if ([macEvent type] == NSKeyDown && [_private->completionController filterKeyDown:macEvent]) return true; if ([macEvent type] == NSFlagsChanged) @@ -5065,9 +5349,7 @@ static CGPoint coreGraphicsScreenPointForAppKitScreenPoint(NSPoint point) { ASSERT(!_private->subviewsSetAside); - if ([[self _frame] _needsLayout]) - _private->needsLayout = YES; - if (_private->needsToApplyStyles || _private->needsLayout) + if (_private->needsToApplyStyles || [self _needsLayout]) [self layout]; } @@ -5099,17 +5381,19 @@ static CGPoint coreGraphicsScreenPointForAppKitScreenPoint(NSPoint point) [[self _pluginController] destroyAllPlugins]; } -- (BOOL)_isResigningFirstResponder +- (BOOL)_needsLayout { - return _private->resigningFirstResponder; + return [[self _frame] _needsLayout]; } #if USE(ACCELERATED_COMPOSITING) - (void)attachRootLayer:(CALayer*)layer { if (!_private->layerHostingView) { - WebLayerHostingView* hostingView = [[WebLayerHostingView alloc] initWithFrame:[self bounds]]; + NSView* hostingView = [[NSView alloc] initWithFrame:[self bounds]]; +#if !defined(BUILDING_ON_LEOPARD) [hostingView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; +#endif [self addSubview:hostingView]; [hostingView release]; // hostingView is owned by being a subview of self @@ -5117,13 +5401,35 @@ static CGPoint coreGraphicsScreenPointForAppKitScreenPoint(NSPoint point) [[self _webView] _startedAcceleratedCompositingForFrame:[self _frame]]; } - // Make a container layer, which will get sized/positioned by AppKit and CA + // Make a container layer, which will get sized/positioned by AppKit and CA. CALayer* viewLayer = [CALayer layer]; + +#if defined(BUILDING_ON_LEOPARD) + // Turn off default animations. + NSNull *nullValue = [NSNull null]; + NSDictionary *actions = [NSDictionary dictionaryWithObjectsAndKeys: + nullValue, @"anchorPoint", + nullValue, @"bounds", + nullValue, @"contents", + nullValue, @"contentsRect", + nullValue, @"opacity", + nullValue, @"position", + nullValue, @"sublayerTransform", + nullValue, @"sublayers", + nullValue, @"transform", + nil]; + [viewLayer setStyle:[NSDictionary dictionaryWithObject:actions forKey:@"actions"]]; +#endif + [_private->layerHostingView setLayer:viewLayer]; [_private->layerHostingView setWantsLayer:YES]; // Parent our root layer in the container layer [viewLayer addSublayer:layer]; + +#if defined(BUILDING_ON_LEOPARD) + [self _updateLayerHostingViewPosition]; +#endif } - (void)detachRootLayer @@ -5136,7 +5442,37 @@ static CGPoint coreGraphicsScreenPointForAppKitScreenPoint(NSPoint point) [[self _webView] _stoppedAcceleratedCompositingForFrame:[self _frame]]; } } -#endif + +#if defined(BUILDING_ON_LEOPARD) +// This method is necessary on Leopard to work around <rdar://problem/7067892>. +- (void)_updateLayerHostingViewPosition +{ + if (!_private->layerHostingView) + return; + + const CGFloat maxHeight = 4096; + NSRect layerViewFrame = [self bounds]; + + if (layerViewFrame.size.height > maxHeight) { + CGFloat documentHeight = layerViewFrame.size.height; + + // Clamp the size of the view to <= 4096px to avoid the bug. + layerViewFrame.size.height = maxHeight; + NSRect visibleRect = [[self enclosingScrollView] documentVisibleRect]; + + // Place the top of the layer-hosting view at the top of the visibleRect. + CGFloat topOffset = NSMinY(visibleRect); + layerViewFrame.origin.y = topOffset; + + // Compensate for the moved view by adjusting the sublayer transform on the view's layer (using flipped coords). + CGFloat bottomOffset = documentHeight - layerViewFrame.size.height - topOffset; + [[_private->layerHostingView layer] setSublayerTransform:CATransform3DMakeTranslation(0, -bottomOffset, 0)]; + } + + [_private->layerHostingView setFrame:layerViewFrame]; +} +#endif // defined(BUILDING_ON_LEOPARD) +#endif // USE(ACCELERATED_COMPOSITING) @end @@ -5160,22 +5496,14 @@ static CGPoint coreGraphicsScreenPointForAppKitScreenPoint(NSPoint point) return validAttributes; } -// Utility function to make sure we don't return anything through the NSTextInput -// API when an editable region is not currently focused. -static BOOL isTextInput(Frame* coreFrame) -{ - return coreFrame && !coreFrame->selection()->isNone() && coreFrame->selection()->isContentEditable(); -} - -static BOOL isInPasswordField(Frame* coreFrame) +- (NSTextInputContext *)inputContext { - return coreFrame && coreFrame->selection()->isInPasswordField(); + return _private->exposeInputContext ? [super inputContext] : nil; } - (NSAttributedString *)textStorage { - Frame* coreFrame = core([self _frame]); - if (!isTextInput(coreFrame) || isInPasswordField(coreFrame)) { + if (!_private->exposeInputContext) { LOG(TextInput, "textStorage -> nil"); return nil; } @@ -5524,6 +5852,15 @@ static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnde if (!coreFrame) return; + BOOL exposeInputContext = isTextInput(coreFrame) && !isInPasswordField(coreFrame); + if (exposeInputContext != _private->exposeInputContext) { + _private->exposeInputContext = exposeInputContext; + // Let AppKit cache a potentially changed input context. + // WebCore routinely sets the selection to None when editing, and IMs become unhappy when an input context suddenly turns nil, see bug 26009. + if (!coreFrame->selection()->isNone()) + [NSApp updateWindows]; + } + if (!coreFrame->editor()->hasComposition()) return; @@ -5542,292 +5879,6 @@ static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnde @end -/* - This class runs the show for handing the complete: NSTextView operation. It counts on its HTML view - to call endRevertingChange: whenever the current completion needs to be aborted. - - The class is in one of two modes: PopupWindow showing, or not. It is shown when a completion yields - more than one match. If a completion yields one or zero matches, it is not shown, and **there is no - state carried across to the next completion**. - */ - -@implementation WebTextCompleteController - -- (id)initWithHTMLView:(WebHTMLView *)view -{ - self = [super init]; - if (!self) - return nil; - _view = view; - return self; -} - -- (void)dealloc -{ - [_popupWindow release]; - [_completions release]; - [_originalString release]; - - [super dealloc]; -} - -- (void)_insertMatch:(NSString *)match -{ - // FIXME: 3769654 - We should preserve case of string being inserted, even in prefix (but then also be - // able to revert that). Mimic NSText. - WebFrame *frame = [_view _frame]; - NSString *newText = [match substringFromIndex:prefixLength]; - [frame _replaceSelectionWithText:newText selectReplacement:YES smartReplace:NO]; -} - -// mostly lifted from NSTextView_KeyBinding.m -- (void)_buildUI -{ - NSRect scrollFrame = NSMakeRect(0, 0, 100, 100); - NSRect tableFrame = NSZeroRect; - tableFrame.size = [NSScrollView contentSizeForFrameSize:scrollFrame.size hasHorizontalScroller:NO hasVerticalScroller:YES borderType:NSNoBorder]; - // Added cast to work around problem with multiple Foundation initWithIdentifier: methods with different parameter types. - NSTableColumn *column = [(NSTableColumn *)[NSTableColumn alloc] initWithIdentifier:[NSNumber numberWithInt:0]]; - [column setWidth:tableFrame.size.width]; - [column setEditable:NO]; - - _tableView = [[NSTableView alloc] initWithFrame:tableFrame]; - [_tableView setAutoresizingMask:NSViewWidthSizable]; - [_tableView addTableColumn:column]; - [column release]; - [_tableView setGridStyleMask:NSTableViewGridNone]; - [_tableView setCornerView:nil]; - [_tableView setHeaderView:nil]; - [_tableView setColumnAutoresizingStyle:NSTableViewUniformColumnAutoresizingStyle]; - [_tableView setDelegate:self]; - [_tableView setDataSource:self]; - [_tableView setTarget:self]; - [_tableView setDoubleAction:@selector(tableAction:)]; - - NSScrollView *scrollView = [[NSScrollView alloc] initWithFrame:scrollFrame]; - [scrollView setBorderType:NSNoBorder]; - [scrollView setHasVerticalScroller:YES]; - [scrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - [scrollView setDocumentView:_tableView]; - [_tableView release]; - - _popupWindow = [[NSWindow alloc] initWithContentRect:scrollFrame styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; - [_popupWindow setAlphaValue:0.88f]; - [_popupWindow setContentView:scrollView]; - [scrollView release]; - [_popupWindow setHasShadow:YES]; - [_popupWindow setOneShot:YES]; - [_popupWindow _setForceActiveControls:YES]; - [_popupWindow setReleasedWhenClosed:NO]; -} - -// mostly lifted from NSTextView_KeyBinding.m -- (void)_placePopupWindow:(NSPoint)topLeft -{ - int numberToShow = [_completions count]; - if (numberToShow > 20) { - numberToShow = 20; - } - - NSRect windowFrame; - NSPoint wordStart = topLeft; - windowFrame.origin = [[_view window] convertBaseToScreen:[_view convertPoint:wordStart toView:nil]]; - windowFrame.size.height = numberToShow * [_tableView rowHeight] + (numberToShow + 1) * [_tableView intercellSpacing].height; - windowFrame.origin.y -= windowFrame.size.height; - NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:[NSFont systemFontOfSize:12.0f], NSFontAttributeName, nil]; - float maxWidth = 0.0f; - int maxIndex = -1; - int i; - for (i = 0; i < numberToShow; i++) { - float width = ceilf([[_completions objectAtIndex:i] sizeWithAttributes:attributes].width); - if (width > maxWidth) { - maxWidth = width; - maxIndex = i; - } - } - windowFrame.size.width = 100; - if (maxIndex >= 0) { - maxWidth = ceilf([NSScrollView frameSizeForContentSize:NSMakeSize(maxWidth, 100.0f) hasHorizontalScroller:NO hasVerticalScroller:YES borderType:NSNoBorder].width); - maxWidth = ceilf([NSWindow frameRectForContentRect:NSMakeRect(0.0f, 0.0f, maxWidth, 100.0f) styleMask:NSBorderlessWindowMask].size.width); - maxWidth += 5.0f; - windowFrame.size.width = MAX(maxWidth, windowFrame.size.width); - maxWidth = MIN(400.0f, windowFrame.size.width); - } - [_popupWindow setFrame:windowFrame display:NO]; - - [_tableView reloadData]; - [_tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO]; - [_tableView scrollRowToVisible:0]; - [self _reflectSelection]; - [_popupWindow setLevel:NSPopUpMenuWindowLevel]; - [_popupWindow orderFront:nil]; - [[_view window] addChildWindow:_popupWindow ordered:NSWindowAbove]; -} - -- (void)doCompletion -{ - if (!_popupWindow) { - NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker]; - if (!checker) { - LOG_ERROR("No NSSpellChecker"); - return; - } - - // Get preceeding word stem - WebFrame *frame = [_view _frame]; - DOMRange *selection = kit(core(frame)->selection()->toNormalizedRange().get()); - DOMRange *wholeWord = [frame _rangeByAlteringCurrentSelection:SelectionController::EXTEND - direction:SelectionController::BACKWARD granularity:WordGranularity]; - DOMRange *prefix = [wholeWord cloneRange]; - [prefix setEnd:[selection startContainer] offset:[selection startOffset]]; - - // Reject some NOP cases - if ([prefix collapsed]) { - NSBeep(); - return; - } - NSString *prefixStr = [frame _stringForRange:prefix]; - NSString *trimmedPrefix = [prefixStr stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; - if ([trimmedPrefix length] == 0) { - NSBeep(); - return; - } - prefixLength = [prefixStr length]; - - // Lookup matches - [_completions release]; - _completions = [checker completionsForPartialWordRange:NSMakeRange(0, [prefixStr length]) inString:prefixStr language:nil inSpellDocumentWithTag:[[_view _webView] spellCheckerDocumentTag]]; - [_completions retain]; - - if (!_completions || [_completions count] == 0) { - NSBeep(); - } else if ([_completions count] == 1) { - [self _insertMatch:[_completions objectAtIndex:0]]; - } else { - ASSERT(!_originalString); // this should only be set IFF we have a popup window - _originalString = [[frame _stringForRange:selection] retain]; - [self _buildUI]; - NSRect wordRect = [frame _caretRectAtNode:[wholeWord startContainer] offset:[wholeWord startOffset] affinity:NSSelectionAffinityDownstream]; - // +1 to be under the word, not the caret - // FIXME - 3769652 - Wrong positioning for right to left languages. We should line up the upper - // right corner with the caret instead of upper left, and the +1 would be a -1. - NSPoint wordLowerLeft = { NSMinX(wordRect)+1, NSMaxY(wordRect) }; - [self _placePopupWindow:wordLowerLeft]; - } - } else { - [self endRevertingChange:YES moveLeft:NO]; - } -} - -- (void)endRevertingChange:(BOOL)revertChange moveLeft:(BOOL)goLeft -{ - if (_popupWindow) { - // tear down UI - [[_view window] removeChildWindow:_popupWindow]; - [_popupWindow orderOut:self]; - // Must autorelease because event tracking code may be on the stack touching UI - [_popupWindow autorelease]; - _popupWindow = nil; - - if (revertChange) { - WebFrame *frame = [_view _frame]; - [frame _replaceSelectionWithText:_originalString selectReplacement:YES smartReplace:NO]; - } else if ([_view _hasSelection]) { - if (goLeft) - [_view moveBackward:nil]; - else - [_view moveForward:nil]; - } - [_originalString release]; - _originalString = nil; - } - // else there is no state to abort if the window was not up -} - -- (BOOL)popupWindowIsOpen -{ - return _popupWindow != nil; -} - -// WebHTMLView gives us a crack at key events it sees. Return whether we consumed the event. -// The features for the various keys mimic NSTextView. -- (BOOL)filterKeyDown:(NSEvent *)event -{ - if (!_popupWindow) - return NO; - NSString *string = [event charactersIgnoringModifiers]; - if (![string length]) - return NO; - unichar c = [string characterAtIndex:0]; - if (c == NSUpArrowFunctionKey) { - int selectedRow = [_tableView selectedRow]; - if (0 < selectedRow) { - [_tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow - 1] byExtendingSelection:NO]; - [_tableView scrollRowToVisible:selectedRow - 1]; - } - return YES; - } - if (c == NSDownArrowFunctionKey) { - int selectedRow = [_tableView selectedRow]; - if (selectedRow < (int)[_completions count] - 1) { - [_tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow + 1] byExtendingSelection:NO]; - [_tableView scrollRowToVisible:selectedRow + 1]; - } - return YES; - } - if (c == NSRightArrowFunctionKey || c == '\n' || c == '\r' || c == '\t') { - // FIXME: What about backtab? - [self endRevertingChange:NO moveLeft:NO]; - return YES; - } - if (c == NSLeftArrowFunctionKey) { - [self endRevertingChange:NO moveLeft:YES]; - return YES; - } - if (c == 0x1B || c == NSF5FunctionKey) { - // FIXME: F5? - [self endRevertingChange:YES moveLeft:NO]; - return YES; - } - if (c == ' ' || c >= 0x21 && c <= 0x2F || c >= 0x3A && c <= 0x40 || c >= 0x5B && c <= 0x60 || c >= 0x7B && c <= 0x7D) { - // FIXME: Is the above list of keys really definitive? - // Originally this code called ispunct; aren't there other punctuation keys on international keyboards? - [self endRevertingChange:NO moveLeft:NO]; - return NO; // let the char get inserted - } - return NO; -} - -- (void)_reflectSelection -{ - int selectedRow = [_tableView selectedRow]; - ASSERT(selectedRow >= 0 && selectedRow < (int)[_completions count]); - [self _insertMatch:[_completions objectAtIndex:selectedRow]]; -} - -- (void)tableAction:(id)sender -{ - [self _reflectSelection]; - [self endRevertingChange:NO moveLeft:NO]; -} - -- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView -{ - return [_completions count]; -} - -- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row -{ - return [_completions objectAtIndex:row]; -} - -- (void)tableViewSelectionDidChange:(NSNotification *)notification -{ - [self _reflectSelection]; -} - -@end - @implementation WebHTMLView (WebDocumentPrivateProtocols) - (NSRect)selectionRect @@ -6082,4 +6133,10 @@ static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnde _receivedUnhandledCommand = YES; } +- (BOOL)tryToPerform:(SEL)action with:(id)object +{ + _receivedUnhandledCommand = YES; + return YES; +} + @end diff --git a/WebKit/mac/WebView/WebHTMLViewInternal.h b/WebKit/mac/WebView/WebHTMLViewInternal.h index a32df02..b5ec1c0 100644 --- a/WebKit/mac/WebView/WebHTMLViewInternal.h +++ b/WebKit/mac/WebView/WebHTMLViewInternal.h @@ -58,11 +58,15 @@ namespace WebCore { - (void)setPromisedDragTIFFDataSource:(WebCore::CachedImage*)source; - (void)_web_layoutIfNeededRecursive; - (void)_destroyAllWebPlugins; -- (BOOL)_isResigningFirstResponder; +- (BOOL)_needsLayout; #if USE(ACCELERATED_COMPOSITING) - (void)attachRootLayer:(CALayer*)layer; - (void)detachRootLayer; #endif +#if USE(ACCELERATED_COMPOSITING) && defined(BUILDING_ON_LEOPARD) +- (void)_updateLayerHostingViewPosition; +#endif + @end diff --git a/WebKit/mac/WebView/WebHTMLViewPrivate.h b/WebKit/mac/WebView/WebHTMLViewPrivate.h index 0d73884..bb59a7b 100644 --- a/WebKit/mac/WebView/WebHTMLViewPrivate.h +++ b/WebKit/mac/WebView/WebHTMLViewPrivate.h @@ -118,7 +118,6 @@ #endif // SPI for DumpRenderTree -- (void)_updateFocusedAndActiveState; - (BOOL)_isUsingAcceleratedCompositing; // SPI for printing (should be converted to API someday). When the WebHTMLView isn't being printed diff --git a/WebKit/mac/WebView/WebPDFView.h b/WebKit/mac/WebView/WebPDFView.h index 55d2a08..bdd2a6e 100644 --- a/WebKit/mac/WebView/WebPDFView.h +++ b/WebKit/mac/WebView/WebPDFView.h @@ -37,7 +37,7 @@ NSView *previewView; PDFView *PDFSubview; NSString *path; - id trackedFirstResponder; + BOOL firstResponderIsPDFDocumentView; BOOL written; BOOL _ignoreScaleAndDisplayModeAndPageNotifications; BOOL _willUpdatePreferencesSoon; diff --git a/WebKit/mac/WebView/WebPDFView.mm b/WebKit/mac/WebView/WebPDFView.mm index 0c872b9..dea3819 100644 --- a/WebKit/mac/WebView/WebPDFView.mm +++ b/WebKit/mac/WebView/WebPDFView.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,6 +29,7 @@ #import "WebPDFView.h" #import "WebDataSourceInternal.h" +#import "WebDelegateImplementationCaching.h" #import "WebDocumentInternal.h" #import "WebDocumentPrivate.h" #import "WebFrame.h" @@ -47,13 +48,16 @@ #import "WebViewInternal.h" #import <PDFKit/PDFKit.h> #import <WebCore/EventNames.h> +#import <WebCore/FormState.h> #import <WebCore/Frame.h> -#import <WebCore/FrameLoader.h> #import <WebCore/FrameLoadRequest.h> +#import <WebCore/FrameLoader.h> +#import <WebCore/HTMLFormElement.h> #import <WebCore/KURL.h> #import <WebCore/KeyboardEvent.h> #import <WebCore/MouseEvent.h> #import <WebCore/PlatformKeyboardEvent.h> +#import <WebCore/RuntimeApplicationChecks.h> #import <wtf/Assertions.h> using namespace WebCore; @@ -182,7 +186,6 @@ static BOOL _PDFSelectionsAreEqual(PDFSelection *selectionA, PDFSelection *selec - (void)dealloc { - ASSERT(!trackedFirstResponder); [dataSource release]; [previewView release]; [PDFSubview release]; @@ -373,7 +376,7 @@ static BOOL _PDFSelectionsAreEqual(PDFSelection *selectionA, PDFSelection *selec // (1) the symptom is fairly minor, and (2) we suspect that non-Safari clients are probably using the entire // set of default items, rather than manually choosing from them. We can remove this code entirely when we // ship a version of Safari that includes the fix for radar 3796579. - if (![self _anyPDFTagsFoundInMenu:menu] && [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Safari"]) { + if (![self _anyPDFTagsFoundInMenu:menu] && applicationIsSafari()) { [menu addItem:[NSMenuItem separatorItem]]; NSEnumerator *e = [items objectEnumerator]; NSMenuItem *menuItem; @@ -468,8 +471,7 @@ static BOOL _PDFSelectionsAreEqual(PDFSelection *selectionA, PDFSelection *selec name:NSViewBoundsDidChangeNotification object:[self _clipViewForPDFDocumentView]]; - [trackedFirstResponder release]; - trackedFirstResponder = nil; + firstResponderIsPDFDocumentView = NO; } #pragma mark NSUserInterfaceValidations PROTOCOL IMPLEMENTATION @@ -941,16 +943,17 @@ static BOOL _PDFSelectionsAreEqual(PDFSelection *selectionA, PDFSelection *selec default: break; } - if (button != noButton) + if (button != noButton) { event = MouseEvent::create(eventNames().clickEvent, true, true, 0, [nsEvent clickCount], 0, 0, 0, 0, [nsEvent modifierFlags] & NSControlKeyMask, [nsEvent modifierFlags] & NSAlternateKeyMask, [nsEvent modifierFlags] & NSShiftKeyMask, [nsEvent modifierFlags] & NSCommandKeyMask, button, 0, 0, true); + } // Call to the frame loader because this is where our security checks are made. - core([dataSource webFrame])->loader()->loadFrameRequestWithFormAndValues(ResourceRequest(URL), false, false, event.get(), 0, HashMap<String, String>()); + core([dataSource webFrame])->loader()->loadFrameRequest(ResourceRequest(URL), false, false, event.get(), 0); } - (void)PDFViewOpenPDFInNativeApplication:(PDFView *)sender @@ -1385,20 +1388,17 @@ static BOOL _PDFSelectionsAreEqual(PDFSelection *selectionA, PDFSelection *selec - (void)_trackFirstResponder { ASSERT([self window]); - - id newFirstResponder = [[self window] firstResponder]; - if (newFirstResponder == trackedFirstResponder) + BOOL newFirstResponderIsPDFDocumentView = [[self window] firstResponder] == [PDFSubview documentView]; + if (newFirstResponderIsPDFDocumentView == firstResponderIsPDFDocumentView) return; // This next clause is the entire purpose of _trackFirstResponder. In other WebDocument // view classes this is done in a resignFirstResponder override, but in this case the // first responder view is a PDFKit class that we can't subclass. - if (trackedFirstResponder == [PDFSubview documentView] && ![[dataSource _webView] maintainsInactiveSelection]) + if (newFirstResponderIsPDFDocumentView && ![[dataSource _webView] maintainsInactiveSelection]) [self deselectAll]; - - [trackedFirstResponder release]; - trackedFirstResponder = [newFirstResponder retain]; + firstResponderIsPDFDocumentView = newFirstResponderIsPDFDocumentView; } - (void)_updatePreferences:(WebPreferences *)prefs diff --git a/WebKit/mac/WebView/WebPreferenceKeysPrivate.h b/WebKit/mac/WebView/WebPreferenceKeysPrivate.h index e22113c..6565c09 100644 --- a/WebKit/mac/WebView/WebPreferenceKeysPrivate.h +++ b/WebKit/mac/WebView/WebPreferenceKeysPrivate.h @@ -61,8 +61,14 @@ #define WebKitBackForwardCacheExpirationIntervalKey @"WebKitBackForwardCacheExpirationIntervalKey" #define WebKitTabToLinksPreferenceKey @"WebKitTabToLinksPreferenceKey" #define WebKitPrivateBrowsingEnabledPreferenceKey @"WebKitPrivateBrowsingEnabled" +#define WebSmartInsertDeleteEnabled @"WebSmartInsertDeleteEnabled" #define WebContinuousSpellCheckingEnabled @"WebContinuousSpellCheckingEnabled" #define WebGrammarCheckingEnabled @"WebGrammarCheckingEnabled" +#define WebAutomaticQuoteSubstitutionEnabled @"WebAutomaticQuoteSubstitutionEnabled" +#define WebAutomaticLinkDetectionEnabled @"WebAutomaticLinkDetectionEnabled" +#define WebAutomaticDashSubstitutionEnabled @"WebAutomaticDashSubstitutionEnabled" +#define WebAutomaticTextReplacementEnabled @"WebAutomaticTextReplacementEnabled" +#define WebAutomaticSpellingCorrectionEnabled @"WebAutomaticSpellingCorrectionEnabled" #define WebKitDOMPasteAllowedPreferenceKey @"WebKitDOMPasteAllowedPreferenceKey" #define WebKitUsesPageCachePreferenceKey @"WebKitUsesPageCachePreferenceKey" #define WebKitFTPDirectoryTemplatePath @"WebKitFTPDirectoryTemplatePath" @@ -71,10 +77,13 @@ #define WebKitAuthorAndUserStylesEnabledPreferenceKey @"WebKitAuthorAndUserStylesEnabledPreferenceKey" #define WebKitApplicationChromeModeEnabledPreferenceKey @"WebKitApplicationChromeModeEnabledPreferenceKey" #define WebKitWebArchiveDebugModeEnabledPreferenceKey @"WebKitWebArchiveDebugModeEnabledPreferenceKey" +#define WebKitLocalFileContentSniffingEnabledPreferenceKey @"WebKitLocalFileContentSniffingEnabledPreferenceKey" #define WebKitLocalStorageDatabasePathPreferenceKey @"WebKitLocalStorageDatabasePathPreferenceKey" #define WebKitEnableFullDocumentTeardownPreferenceKey @"WebKitEnableFullDocumentTeardown" #define WebKitOfflineWebApplicationCacheEnabledPreferenceKey @"WebKitOfflineWebApplicationCacheEnabled" #define WebKitZoomsTextOnlyPreferenceKey @"WebKitZoomsTextOnly" +#define WebKitXSSAuditorEnabledPreferenceKey @"WebKitXSSAuditorEnabled" +#define WebKitAcceleratedCompositingEnabledPreferenceKey @"WebKitAcceleratedCompositingEnabled" // These are private both because callers should be using the cover methods and because the // cover methods themselves are private. diff --git a/WebKit/mac/WebView/WebPreferences.mm b/WebKit/mac/WebView/WebPreferences.mm index 6db14bd..378b280 100644 --- a/WebKit/mac/WebView/WebPreferences.mm +++ b/WebKit/mac/WebView/WebPreferences.mm @@ -345,13 +345,11 @@ static WebCacheModel cacheModelForMainBundle(void) [NSNumber numberWithBool:YES], WebKitAuthorAndUserStylesEnabledPreferenceKey, [NSNumber numberWithBool:NO], WebKitApplicationChromeModeEnabledPreferenceKey, [NSNumber numberWithBool:NO], WebKitWebArchiveDebugModeEnabledPreferenceKey, + [NSNumber numberWithBool:NO], WebKitLocalFileContentSniffingEnabledPreferenceKey, [NSNumber numberWithBool:NO], WebKitOfflineWebApplicationCacheEnabledPreferenceKey, [NSNumber numberWithBool:YES], WebKitZoomsTextOnlyPreferenceKey, -#ifndef NDEBUG - // In Release and Production we skip a lot of object teardown during quit to speed up shutdown time. This breaks - // our RefCount Leak tracking, and so for Debug we will use the full document teardown. - [NSNumber numberWithBool:YES], WebKitEnableFullDocumentTeardownPreferenceKey, -#endif + [NSNumber numberWithBool:YES], WebKitXSSAuditorEnabledPreferenceKey, + [NSNumber numberWithBool:YES], WebKitAcceleratedCompositingEnabledPreferenceKey, nil]; // This value shouldn't ever change, which is assumed in the initialization of WebKitPDFDisplayModePreferenceKey above @@ -795,6 +793,16 @@ static WebCacheModel cacheModelForMainBundle(void) [self _setBoolValue:flag forKey:WebKitWebArchiveDebugModeEnabledPreferenceKey]; } +- (BOOL)localFileContentSniffingEnabled +{ + return [self _boolValueForKey:WebKitLocalFileContentSniffingEnabledPreferenceKey]; +} + +- (void)setLocalFileContentSniffingEnabled:(BOOL)flag +{ + [self _setBoolValue:flag forKey:WebKitLocalFileContentSniffingEnabledPreferenceKey]; +} + - (BOOL)offlineWebApplicationCacheEnabled { return [self _boolValueForKey:WebKitOfflineWebApplicationCacheEnabledPreferenceKey]; @@ -815,6 +823,16 @@ static WebCacheModel cacheModelForMainBundle(void) [self _setBoolValue:flag forKey:WebKitZoomsTextOnlyPreferenceKey]; } +- (BOOL)isXSSAuditorEnabled +{ + return [self _boolValueForKey:WebKitXSSAuditorEnabledPreferenceKey]; +} + +- (void)setXSSAuditorEnabled:(BOOL)flag +{ + [self _setBoolValue:flag forKey:WebKitXSSAuditorEnabledPreferenceKey]; +} + - (BOOL)respectStandardStyleKeyEquivalents { return [self _boolValueForKey:WebKitRespectStandardStyleKeyEquivalentsPreferenceKey]; @@ -1032,6 +1050,11 @@ static WebCacheModel cacheModelForMainBundle(void) - (void)_postPreferencesChangesNotification { + if (!pthread_main_np()) { + [self performSelectorOnMainThread:_cmd withObject:nil waitUntilDone:NO]; + return; + } + [[NSNotificationCenter defaultCenter] postNotificationName:WebPreferencesChangedNotification object:self userInfo:nil]; @@ -1046,10 +1069,11 @@ static WebCacheModel cacheModelForMainBundle(void) { NSString *systemEncodingName = (NSString *)CFStringConvertEncodingToIANACharSetName([self _systemCFStringEncoding]); - // CFStringConvertEncodingToIANACharSetName() returns CP949 for kTextEncodingDOSKorean AKA "extended EUC-KR" AKA windows-939. + // CFStringConvertEncodingToIANACharSetName() returns cp949 for kTextEncodingDOSKorean AKA "extended EUC-KR" AKA windows-939. // ICU uses this name for a different encoding, so we need to change the name to a value that actually gives us windows-939. // In addition, this value must match what is used in Safari, see <rdar://problem/5579292>. - if ([systemEncodingName isEqualToString:@"CP949"]) + // On some OS versions, the result is CP949 (uppercase). + if ([systemEncodingName _webkit_isCaseInsensitiveEqualToString:@"cp949"]) systemEncodingName = @"ks_c_5601-1987"; [[NSUserDefaults standardUserDefaults] registerDefaults: [NSDictionary dictionaryWithObject:systemEncodingName forKey:WebKitDefaultTextEncodingNamePreferenceKey]]; @@ -1074,11 +1098,6 @@ static NSString *classIBCreatorID = nil; [self _setBoolValue:DOMPasteAllowed forKey:WebKitDOMPasteAllowedPreferenceKey]; } -- (void)_setFTPDirectoryTemplatePath:(NSString *)path -{ - [self _setStringValue:[path stringByStandardizingPath] forKey:WebKitFTPDirectoryTemplatePath]; -} - - (NSString *)_localStorageDatabasePath { return [[self _stringValueForKey:WebKitLocalStorageDatabasePathPreferenceKey] stringByStandardizingPath]; @@ -1094,9 +1113,9 @@ static NSString *classIBCreatorID = nil; return [[self _stringValueForKey:WebKitFTPDirectoryTemplatePath] stringByStandardizingPath]; } -- (void)_setForceFTPDirectoryListings:(BOOL)force +- (void)_setFTPDirectoryTemplatePath:(NSString *)path { - [self _setBoolValue:force forKey:WebKitForceFTPDirectoryListings]; + [self _setStringValue:[path stringByStandardizingPath] forKey:WebKitFTPDirectoryTemplatePath]; } - (BOOL)_forceFTPDirectoryListings @@ -1104,6 +1123,21 @@ static NSString *classIBCreatorID = nil; return [self _boolValueForKey:WebKitForceFTPDirectoryListings]; } +- (void)_setForceFTPDirectoryListings:(BOOL)force +{ + [self _setBoolValue:force forKey:WebKitForceFTPDirectoryListings]; +} + +- (BOOL)acceleratedCompositingEnabled +{ + return [self _boolValueForKey:WebKitAcceleratedCompositingEnabledPreferenceKey]; +} + +- (void)setAcceleratedCompositingEnabled:(BOOL)enabled +{ + [self _setBoolValue:enabled forKey:WebKitAcceleratedCompositingEnabledPreferenceKey]; +} + - (void)didRemoveFromWebView { ASSERT(_private->numWebViews); @@ -1118,16 +1152,6 @@ static NSString *classIBCreatorID = nil; { ++_private->numWebViews; } - -- (void)setFullDocumentTeardownEnabled:(BOOL)fullDocumentTeardownEnabled -{ - [self _setBoolValue:fullDocumentTeardownEnabled forKey:WebKitEnableFullDocumentTeardownPreferenceKey]; -} - -- (BOOL)fullDocumentTeardownEnabled -{ - return [self _boolValueForKey:WebKitEnableFullDocumentTeardownPreferenceKey]; -} @end @implementation WebPreferences (WebInternal) diff --git a/WebKit/mac/WebView/WebPreferencesPrivate.h b/WebKit/mac/WebView/WebPreferencesPrivate.h index ae94cce..d571869 100644 --- a/WebKit/mac/WebView/WebPreferencesPrivate.h +++ b/WebKit/mac/WebView/WebPreferencesPrivate.h @@ -83,6 +83,9 @@ extern NSString *WebPreferencesRemovedNotification; - (BOOL)webArchiveDebugModeEnabled; - (void)setWebArchiveDebugModeEnabled:(BOOL)webArchiveDebugModeEnabled; +- (BOOL)localFileContentSniffingEnabled; +- (void)setLocalFileContentSniffingEnabled:(BOOL)localFileContentSniffingEnabled; + - (BOOL)offlineWebApplicationCacheEnabled; - (void)setOfflineWebApplicationCacheEnabled:(BOOL)offlineWebApplicationCacheEnabled; @@ -101,6 +104,9 @@ extern NSString *WebPreferencesRemovedNotification; - (BOOL)zoomsTextOnly; - (void)setZoomsTextOnly:(BOOL)zoomsTextOnly; +- (BOOL)isXSSAuditorEnabled; +- (void)setXSSAuditorEnabled:(BOOL)flag; + // zero means do AutoScale - (float)PDFScaleFactor; - (void)setPDFScaleFactor:(float)scale; @@ -123,11 +129,16 @@ extern NSString *WebPreferencesRemovedNotification; - (NSString *)_ftpDirectoryTemplatePath; - (void)_setFTPDirectoryTemplatePath:(NSString *)path; + - (void)_setForceFTPDirectoryListings:(BOOL)force; - (BOOL)_forceFTPDirectoryListings; + - (NSString *)_localStorageDatabasePath; - (void)_setLocalStorageDatabasePath:(NSString *)path; +- (BOOL)acceleratedCompositingEnabled; +- (void)setAcceleratedCompositingEnabled:(BOOL)enabled; + // Other private methods - (void)_postPreferencesChangesNotification; + (WebPreferences *)_getInstanceForIdentifier:(NSString *)identifier; @@ -141,8 +152,4 @@ extern NSString *WebPreferencesRemovedNotification; // For WebView's use only. - (void)willAddToWebView; - (void)didRemoveFromWebView; - -// Force document tear down at application quit -- (void)setFullDocumentTeardownEnabled:(BOOL)fullDocumentTeardownEnabled; -- (BOOL)fullDocumentTeardownEnabled; @end diff --git a/WebKit/mac/WebView/WebRenderNode.h b/WebKit/mac/WebView/WebRenderNode.h index 8e6b40f..901b2cc 100644 --- a/WebKit/mac/WebView/WebRenderNode.h +++ b/WebKit/mac/WebView/WebRenderNode.h @@ -28,7 +28,7 @@ #import <Foundation/Foundation.h> -@class WebFrameView; +@class WebFrame; @interface WebRenderNode : NSObject { @@ -38,7 +38,7 @@ NSPoint absolutePosition; } -- (id)initWithWebFrameView:(WebFrameView *)view; +- (id)initWithWebFrame:(WebFrame *)frame; - (NSArray *)children; diff --git a/WebKit/mac/WebView/WebRenderNode.mm b/WebKit/mac/WebView/WebRenderNode.mm index 65ee13c..4a839a5 100644 --- a/WebKit/mac/WebView/WebRenderNode.mm +++ b/WebKit/mac/WebView/WebRenderNode.mm @@ -29,9 +29,8 @@ #import "WebRenderNode.h" #import "WebFrameInternal.h" -#import "WebFrameView.h" -#import "WebHTMLView.h" #import <WebCore/Frame.h> +#import <WebCore/FrameLoaderClient.h> #import <WebCore/RenderText.h> #import <WebCore/RenderWidget.h> #import <WebCore/RenderView.h> @@ -39,9 +38,25 @@ using namespace WebCore; +static WebRenderNode *copyRenderNode(RenderObject*); + @implementation WebRenderNode -- (id)initWithName:(NSString *)n position:(NSPoint)p rect:(NSRect)r view:(NSView *)view children:(NSArray *)c +- (id)_initWithCoreFrame:(Frame *)frame +{ + [self release]; + + if (!frame->loader()->client()->hasHTMLView()) + return nil; + + RenderObject* renderer = frame->contentRenderer(); + if (!renderer) + return nil; + + return copyRenderNode(renderer); +} + +- (id)_initWithName:(NSString *)n position:(NSPoint)p rect:(NSRect)r coreFrame:(Frame*)coreFrame children:(NSArray *)c { NSMutableArray *collectChildren; @@ -55,13 +70,8 @@ using namespace WebCore; rect = r; absolutePosition = p; - if ([view isKindOfClass:[NSScrollView class]]) { - NSScrollView *scrollView = (NSScrollView *)view; - view = [scrollView superview]; - } - if ([view isKindOfClass:[WebFrameView class]]) { - WebFrameView *webFrameView = (WebFrameView *)view; - WebRenderNode *node = [[WebRenderNode alloc] initWithWebFrameView:webFrameView]; + if (coreFrame) { + WebRenderNode *node = [[WebRenderNode alloc] _initWithCoreFrame:coreFrame]; [collectChildren addObject:node]; [node release]; } @@ -83,9 +93,10 @@ static WebRenderNode *copyRenderNode(RenderObject* node) NSString *name = [[NSString alloc] initWithUTF8String:node->renderName()]; - RenderWidget* renderWidget = node->isWidget() ? static_cast<RenderWidget*>(node) : 0; + RenderWidget* renderWidget = node->isWidget() ? toRenderWidget(node) : 0; Widget* widget = renderWidget ? renderWidget->widget() : 0; - NSView *view = widget ? widget->platformWidget() : nil; + FrameView* frameView = widget && widget->isFrameView() ? static_cast<FrameView*>(widget) : 0; + Frame* frame = frameView ? frameView->frame() : 0; // FIXME: broken with transforms FloatPoint absPos = node->localToAbsolute(FloatPoint()); @@ -109,9 +120,9 @@ static WebRenderNode *copyRenderNode(RenderObject* node) height = box.height(); } - WebRenderNode *result = [[WebRenderNode alloc] initWithName:name - position:absPos rect:NSMakeRect(x, y, width, height) - view:view children:children]; + WebRenderNode *result = [[WebRenderNode alloc] _initWithName:name + position:absPos rect:NSMakeRect(x, y, width, height) + coreFrame:frame children:children]; [name release]; [children release]; @@ -119,18 +130,9 @@ static WebRenderNode *copyRenderNode(RenderObject* node) return result; } -- (id)initWithWebFrameView:(WebFrameView *)view +- (id)initWithWebFrame:(WebFrame *)frame { - [self release]; - - if (![[view documentView] isMemberOfClass:[WebHTMLView class]]) - return nil; - - RenderObject* renderer = core([view webFrame])->contentRenderer(); - if (!renderer) - return nil; - - return copyRenderNode(renderer); + return [self _initWithCoreFrame:core(frame)]; } - (void)dealloc diff --git a/WebKit/mac/WebView/WebResource.mm b/WebKit/mac/WebView/WebResource.mm index e62ed1e..735e213 100644 --- a/WebKit/mac/WebView/WebResource.mm +++ b/WebKit/mac/WebView/WebResource.mm @@ -38,6 +38,7 @@ #import <JavaScriptCore/PassRefPtr.h> #import <WebCore/ArchiveResource.h> #import <WebCore/LegacyWebArchive.h> +#import <WebCore/RuntimeApplicationChecks.h> #import <WebCore/TextEncoding.h> #import <WebCore/ThreadCheck.h> #import <WebCore/WebCoreObjCExtras.h> @@ -365,7 +366,7 @@ static NSString * const WebResourceResponseKey = @"WebResourceResponse" // Copying it will also cause a performance regression. return [self _initWithData:data URL:URL - MIMEType:[response _webcore_MIMEType] + MIMEType:[response MIMEType] textEncodingName:[response textEncodingName] frameName:nil response:response @@ -441,8 +442,7 @@ static const double newMailBundleVersion = 1050.0; + (BOOL)_needMailThreadWorkaroundIfCalledOffMainThread { - static BOOL isOldMail = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.mail"] - && [[[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey] doubleValue] < newMailBundleVersion; + static BOOL isOldMail = applicationIsAppleMail() && [[[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey] doubleValue] < newMailBundleVersion; return isOldMail; } diff --git a/WebKit/mac/WebView/WebScriptDebugDelegate.mm b/WebKit/mac/WebView/WebScriptDebugDelegate.mm index 0b47e26..8489c9b 100644 --- a/WebKit/mac/WebView/WebScriptDebugDelegate.mm +++ b/WebKit/mac/WebView/WebScriptDebugDelegate.mm @@ -55,7 +55,7 @@ NSString * const WebScriptErrorLineNumberKey = @"WebScriptErrorLineNumber"; @interface WebScriptCallFrame (WebScriptDebugDelegateInternal) -- (id)_convertValueToObjcValue:(JSValuePtr)value; +- (id)_convertValueToObjcValue:(JSValue)value; @end @@ -113,7 +113,7 @@ NSString * const WebScriptErrorLineNumberKey = @"WebScriptErrorLineNumber"; _private->debuggerCallFrame = 0; } -- (id)_convertValueToObjcValue:(JSValuePtr)value +- (id)_convertValueToObjcValue:(JSValue)value { if (!value) return nil; @@ -174,6 +174,8 @@ NSString * const WebScriptErrorLineNumberKey = @"WebScriptErrorLineNumber"; if (!_private->debuggerCallFrame) return [NSArray array]; + JSLock lock(SilenceAssertionsOnly); + const ScopeChainNode* scopeChain = _private->debuggerCallFrame->scopeChain(); if (!scopeChain->next) // global frame return [NSArray arrayWithObject:_private->globalObject]; @@ -212,7 +214,7 @@ NSString * const WebScriptErrorLineNumberKey = @"WebScriptErrorLineNumber"; if (!_private->debuggerCallFrame) return nil; - JSValuePtr exception = _private->debuggerCallFrame->exception(); + JSValue exception = _private->debuggerCallFrame->exception(); return exception ? [self _convertValueToObjcValue:exception] : nil; } @@ -227,7 +229,7 @@ NSString * const WebScriptErrorLineNumberKey = @"WebScriptErrorLineNumber"; if (!_private->debuggerCallFrame) return nil; - JSLock lock(false); + JSLock lock(SilenceAssertionsOnly); // If this is the global call frame and there is no dynamic global object, // Dashcode is attempting to execute JS in the evaluator using a stale @@ -239,15 +241,15 @@ NSString * const WebScriptErrorLineNumberKey = @"WebScriptErrorLineNumber"; DynamicGlobalObjectScope globalObjectScope(globalObject->globalExec(), globalObject); - JSValuePtr exception = noValue(); - JSValuePtr result = evaluateInGlobalCallFrame(String(script), exception, globalObject); + JSValue exception; + JSValue result = evaluateInGlobalCallFrame(String(script), exception, globalObject); if (exception) return [self _convertValueToObjcValue:exception]; return result ? [self _convertValueToObjcValue:result] : nil; } - JSValuePtr exception = noValue(); - JSValuePtr result = _private->debuggerCallFrame->evaluate(String(script), exception); + JSValue exception; + JSValue result = _private->debuggerCallFrame->evaluate(String(script), exception); if (exception) return [self _convertValueToObjcValue:exception]; return result ? [self _convertValueToObjcValue:result] : nil; diff --git a/WebKit/mac/WebView/WebScriptDebugger.mm b/WebKit/mac/WebView/WebScriptDebugger.mm index 384f826..76bdf58 100644 --- a/WebKit/mac/WebView/WebScriptDebugger.mm +++ b/WebKit/mac/WebView/WebScriptDebugger.mm @@ -28,16 +28,17 @@ #import "WebScriptDebugger.h" +#import "WebDelegateImplementationCaching.h" #import "WebFrameInternal.h" -#import "WebViewInternal.h" #import "WebScriptDebugDelegate.h" -#import <runtime/JSGlobalObject.h> -#import <debugger/DebuggerCallFrame.h> +#import "WebViewInternal.h" #import <WebCore/DOMWindow.h> #import <WebCore/Frame.h> #import <WebCore/JSDOMWindow.h> #import <WebCore/KURL.h> #import <WebCore/ScriptController.h> +#import <debugger/DebuggerCallFrame.h> +#import <runtime/JSGlobalObject.h> using namespace JSC; using namespace WebCore; diff --git a/WebKit/mac/WebView/WebTextCompletionController.h b/WebKit/mac/WebView/WebTextCompletionController.h new file mode 100644 index 0000000..158e9b8 --- /dev/null +++ b/WebKit/mac/WebView/WebTextCompletionController.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +@class WebView; +@class WebHTMLView; + +@interface WebTextCompletionController : NSObject <NSTableViewDelegate, NSTableViewDataSource> { +@private + WebView *_view; + WebHTMLView *_htmlView; + NSWindow *_popupWindow; + NSTableView *_tableView; + NSArray *_completions; + NSString *_originalString; + int prefixLength; +} +- (id)initWithWebView:(WebView *)view HTMLView:(WebHTMLView *)htmlView; +- (void)doCompletion; +- (void)endRevertingChange:(BOOL)revertChange moveLeft:(BOOL)goLeft; +- (BOOL)popupWindowIsOpen; +- (BOOL)filterKeyDown:(NSEvent *)event; +- (void)_reflectSelection; +@end diff --git a/WebKit/mac/WebView/WebTextCompletionController.mm b/WebKit/mac/WebView/WebTextCompletionController.mm new file mode 100644 index 0000000..f7c172f --- /dev/null +++ b/WebKit/mac/WebView/WebTextCompletionController.mm @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "WebTextCompletionController.h" + +#import "DOMRangeInternal.h" +#import "WebFrameInternal.h" +#import "WebHTMLViewInternal.h" +#import "WebTypesInternal.h" +#import <WebCore/Frame.h> + +@interface NSWindow (WebNSWindowDetails) +- (void)_setForceActiveControls:(BOOL)flag; +@end + +using namespace WebCore; + +// This class handles the complete: operation. +// It counts on its host view to call endRevertingChange: whenever the current completion needs to be aborted. + +// The class is in one of two modes: Popup window showing, or not. +// It is shown when a completion yields more than one match. +// If a completion yields one or zero matches, it is not shown, and there is no state carried across to the next completion. + +@implementation WebTextCompletionController + +- (id)initWithWebView:(WebView *)view HTMLView:(WebHTMLView *)htmlView +{ + self = [super init]; + if (!self) + return nil; + _view = view; + _htmlView = htmlView; + return self; +} + +- (void)dealloc +{ + [_popupWindow release]; + [_completions release]; + [_originalString release]; + + [super dealloc]; +} + +- (void)_insertMatch:(NSString *)match +{ + // FIXME: 3769654 - We should preserve case of string being inserted, even in prefix (but then also be + // able to revert that). Mimic NSText. + WebFrame *frame = [_htmlView _frame]; + NSString *newText = [match substringFromIndex:prefixLength]; + [frame _replaceSelectionWithText:newText selectReplacement:YES smartReplace:NO]; +} + +// mostly lifted from NSTextView_KeyBinding.m +- (void)_buildUI +{ + NSRect scrollFrame = NSMakeRect(0, 0, 100, 100); + NSRect tableFrame = NSZeroRect; + tableFrame.size = [NSScrollView contentSizeForFrameSize:scrollFrame.size hasHorizontalScroller:NO hasVerticalScroller:YES borderType:NSNoBorder]; + // Added cast to work around problem with multiple Foundation initWithIdentifier: methods with different parameter types. + NSTableColumn *column = [(NSTableColumn *)[NSTableColumn alloc] initWithIdentifier:[NSNumber numberWithInt:0]]; + [column setWidth:tableFrame.size.width]; + [column setEditable:NO]; + + _tableView = [[NSTableView alloc] initWithFrame:tableFrame]; + [_tableView setAutoresizingMask:NSViewWidthSizable]; + [_tableView addTableColumn:column]; + [column release]; + [_tableView setGridStyleMask:NSTableViewGridNone]; + [_tableView setCornerView:nil]; + [_tableView setHeaderView:nil]; + [_tableView setColumnAutoresizingStyle:NSTableViewUniformColumnAutoresizingStyle]; + [_tableView setDelegate:self]; + [_tableView setDataSource:self]; + [_tableView setTarget:self]; + [_tableView setDoubleAction:@selector(tableAction:)]; + + NSScrollView *scrollView = [[NSScrollView alloc] initWithFrame:scrollFrame]; + [scrollView setBorderType:NSNoBorder]; + [scrollView setHasVerticalScroller:YES]; + [scrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + [scrollView setDocumentView:_tableView]; + [_tableView release]; + + _popupWindow = [[NSWindow alloc] initWithContentRect:scrollFrame styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; + [_popupWindow setAlphaValue:0.88f]; + [_popupWindow setContentView:scrollView]; + [scrollView release]; + [_popupWindow setHasShadow:YES]; + [_popupWindow setOneShot:YES]; + [_popupWindow _setForceActiveControls:YES]; + [_popupWindow setReleasedWhenClosed:NO]; +} + +// mostly lifted from NSTextView_KeyBinding.m +- (void)_placePopupWindow:(NSPoint)topLeft +{ + int numberToShow = [_completions count]; + if (numberToShow > 20) + numberToShow = 20; + + NSRect windowFrame; + NSPoint wordStart = topLeft; + windowFrame.origin = [[_view window] convertBaseToScreen:[_htmlView convertPoint:wordStart toView:nil]]; + windowFrame.size.height = numberToShow * [_tableView rowHeight] + (numberToShow + 1) * [_tableView intercellSpacing].height; + windowFrame.origin.y -= windowFrame.size.height; + NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:[NSFont systemFontOfSize:12.0f], NSFontAttributeName, nil]; + float maxWidth = 0.0f; + int maxIndex = -1; + int i; + for (i = 0; i < numberToShow; i++) { + float width = ceilf([[_completions objectAtIndex:i] sizeWithAttributes:attributes].width); + if (width > maxWidth) { + maxWidth = width; + maxIndex = i; + } + } + windowFrame.size.width = 100; + if (maxIndex >= 0) { + maxWidth = ceilf([NSScrollView frameSizeForContentSize:NSMakeSize(maxWidth, 100.0f) hasHorizontalScroller:NO hasVerticalScroller:YES borderType:NSNoBorder].width); + maxWidth = ceilf([NSWindow frameRectForContentRect:NSMakeRect(0.0f, 0.0f, maxWidth, 100.0f) styleMask:NSBorderlessWindowMask].size.width); + maxWidth += 5.0f; + windowFrame.size.width = MAX(maxWidth, windowFrame.size.width); + maxWidth = MIN(400.0f, windowFrame.size.width); + } + [_popupWindow setFrame:windowFrame display:NO]; + + [_tableView reloadData]; + [_tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO]; + [_tableView scrollRowToVisible:0]; + [self _reflectSelection]; + [_popupWindow setLevel:NSPopUpMenuWindowLevel]; + [_popupWindow orderFront:nil]; + [[_view window] addChildWindow:_popupWindow ordered:NSWindowAbove]; +} + +- (void)doCompletion +{ + if (!_popupWindow) { + NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker]; + if (!checker) { + LOG_ERROR("No NSSpellChecker"); + return; + } + + // Get preceeding word stem + WebFrame *frame = [_htmlView _frame]; + DOMRange *selection = kit(core(frame)->selection()->toNormalizedRange().get()); + DOMRange *wholeWord = [frame _rangeByAlteringCurrentSelection:SelectionController::EXTEND + direction:SelectionController::BACKWARD granularity:WordGranularity]; + DOMRange *prefix = [wholeWord cloneRange]; + [prefix setEnd:[selection startContainer] offset:[selection startOffset]]; + + // Reject some NOP cases + if ([prefix collapsed]) { + NSBeep(); + return; + } + NSString *prefixStr = [frame _stringForRange:prefix]; + NSString *trimmedPrefix = [prefixStr stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if ([trimmedPrefix length] == 0) { + NSBeep(); + return; + } + prefixLength = [prefixStr length]; + + // Lookup matches + [_completions release]; + _completions = [checker completionsForPartialWordRange:NSMakeRange(0, [prefixStr length]) inString:prefixStr language:nil inSpellDocumentWithTag:[_view spellCheckerDocumentTag]]; + [_completions retain]; + + if (!_completions || [_completions count] == 0) { + NSBeep(); + } else if ([_completions count] == 1) { + [self _insertMatch:[_completions objectAtIndex:0]]; + } else { + ASSERT(!_originalString); // this should only be set IFF we have a popup window + _originalString = [[frame _stringForRange:selection] retain]; + [self _buildUI]; + NSRect wordRect = [frame _caretRectAtNode:[wholeWord startContainer] offset:[wholeWord startOffset] affinity:NSSelectionAffinityDownstream]; + // +1 to be under the word, not the caret + // FIXME - 3769652 - Wrong positioning for right to left languages. We should line up the upper + // right corner with the caret instead of upper left, and the +1 would be a -1. + NSPoint wordLowerLeft = { NSMinX(wordRect)+1, NSMaxY(wordRect) }; + [self _placePopupWindow:wordLowerLeft]; + } + } else { + [self endRevertingChange:YES moveLeft:NO]; + } +} + +- (void)endRevertingChange:(BOOL)revertChange moveLeft:(BOOL)goLeft +{ + if (_popupWindow) { + // tear down UI + [[_view window] removeChildWindow:_popupWindow]; + [_popupWindow orderOut:self]; + // Must autorelease because event tracking code may be on the stack touching UI + [_popupWindow autorelease]; + _popupWindow = nil; + + if (revertChange) { + WebFrame *frame = [_htmlView _frame]; + [frame _replaceSelectionWithText:_originalString selectReplacement:YES smartReplace:NO]; + } else if ([_htmlView _hasSelection]) { + if (goLeft) + [_htmlView moveBackward:nil]; + else + [_htmlView moveForward:nil]; + } + [_originalString release]; + _originalString = nil; + } + // else there is no state to abort if the window was not up +} + +- (BOOL)popupWindowIsOpen +{ + return _popupWindow != nil; +} + +// WebHTMLView gives us a crack at key events it sees. Return whether we consumed the event. +// The features for the various keys mimic NSTextView. +- (BOOL)filterKeyDown:(NSEvent *)event +{ + if (!_popupWindow) + return NO; + NSString *string = [event charactersIgnoringModifiers]; + if (![string length]) + return NO; + unichar c = [string characterAtIndex:0]; + if (c == NSUpArrowFunctionKey) { + int selectedRow = [_tableView selectedRow]; + if (0 < selectedRow) { + [_tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow - 1] byExtendingSelection:NO]; + [_tableView scrollRowToVisible:selectedRow - 1]; + } + return YES; + } + if (c == NSDownArrowFunctionKey) { + int selectedRow = [_tableView selectedRow]; + if (selectedRow < (int)[_completions count] - 1) { + [_tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow + 1] byExtendingSelection:NO]; + [_tableView scrollRowToVisible:selectedRow + 1]; + } + return YES; + } + if (c == NSRightArrowFunctionKey || c == '\n' || c == '\r' || c == '\t') { + // FIXME: What about backtab? + [self endRevertingChange:NO moveLeft:NO]; + return YES; + } + if (c == NSLeftArrowFunctionKey) { + [self endRevertingChange:NO moveLeft:YES]; + return YES; + } + if (c == 0x1B || c == NSF5FunctionKey) { + // FIXME: F5? + [self endRevertingChange:YES moveLeft:NO]; + return YES; + } + if (c == ' ' || c >= 0x21 && c <= 0x2F || c >= 0x3A && c <= 0x40 || c >= 0x5B && c <= 0x60 || c >= 0x7B && c <= 0x7D) { + // FIXME: Is the above list of keys really definitive? + // Originally this code called ispunct; aren't there other punctuation keys on international keyboards? + [self endRevertingChange:NO moveLeft:NO]; + return NO; // let the char get inserted + } + return NO; +} + +- (void)_reflectSelection +{ + int selectedRow = [_tableView selectedRow]; + ASSERT(selectedRow >= 0 && selectedRow < (int)[_completions count]); + [self _insertMatch:[_completions objectAtIndex:selectedRow]]; +} + +- (void)tableAction:(id)sender +{ + [self _reflectSelection]; + [self endRevertingChange:NO moveLeft:NO]; +} + +- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView +{ + return [_completions count]; +} + +- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row +{ + return [_completions objectAtIndex:row]; +} + +- (void)tableViewSelectionDidChange:(NSNotification *)notification +{ + [self _reflectSelection]; +} + +@end diff --git a/WebKit/mac/WebView/WebTextIterator.mm b/WebKit/mac/WebView/WebTextIterator.mm index 15eeb5f..457bece 100644 --- a/WebKit/mac/WebView/WebTextIterator.mm +++ b/WebKit/mac/WebView/WebTextIterator.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -67,7 +67,7 @@ using namespace WebCore; return self; _private = [[WebTextIteratorPrivate alloc] init]; - _private->_textIterator.set(new TextIterator([range _range], true, false)); + _private->_textIterator.set(new TextIterator(core(range))); return self; } @@ -83,7 +83,7 @@ using namespace WebCore; - (DOMRange *)currentRange { - return [DOMRange _wrapRange:_private->_textIterator->range().get()]; + return kit(_private->_textIterator->range().get()); } - (const unichar *)currentTextPointer @@ -102,7 +102,7 @@ using namespace WebCore; - (DOMNode *)currentNode { - return [DOMNode _wrapNode:_private->_textIterator->node()]; + return kit(_private->_textIterator->node()); } - (NSString *)currentText diff --git a/WebKit/mac/WebView/WebUIDelegatePrivate.h b/WebKit/mac/WebView/WebUIDelegatePrivate.h index 8e67963..717cf01 100644 --- a/WebKit/mac/WebView/WebUIDelegatePrivate.h +++ b/WebKit/mac/WebView/WebUIDelegatePrivate.h @@ -72,6 +72,19 @@ enum { WebMenuItemTagTextDirectionDefault, WebMenuItemTagTextDirectionLeftToRight, WebMenuItemTagTextDirectionRightToLeft, + WebMenuItemTagCorrectSpellingAutomatically, + WebMenuItemTagSubstitutionsMenu, + WebMenuItemTagShowSubstitutions, + WebMenuItemTagSmartCopyPaste, + WebMenuItemTagSmartQuotes, + WebMenuItemTagSmartDashes, + WebMenuItemTagSmartLinks, + WebMenuItemTagTextReplacement, + WebMenuItemTagTransformationsMenu, + WebMenuItemTagMakeUpperCase, + WebMenuItemTagMakeLowerCase, + WebMenuItemTagCapitalize, + WebMenuItemTagChangeBack, WebMenuItemTagBaseApplication = 10000 }; @class WebGeolocation; @@ -113,4 +126,17 @@ enum { - (BOOL)webView:(WebView *)sender frame:(WebFrame *)frame requestGeolocationPermission:(WebGeolocation *)geolocation securityOrigin:(WebSecurityOrigin *)origin; +- (void)webView:(WebView *)sender formStateDidChangeForNode:(DOMNode *)node; +- (void)webView:(WebView *)sender formStateDidFocusNode:(DOMNode *)node; +- (void)webView:(WebView *)sender formStateDidBlurNode:(DOMNode *)node; + +/*! + @method webView:printFrame: + @abstract Informs that a WebFrame needs to be printed + @param webView The WebView sending the delegate method + @param frameView The WebFrame needing to be printed + @discussion This method is called when a script or user requests the page to be printed. +*/ +- (void)webView:(WebView *)sender printFrame:(WebFrame *)frame; + @end diff --git a/WebKit/mac/WebView/WebView.mm b/WebKit/mac/WebView/WebView.mm index eabbc9d..20f2712 100644 --- a/WebKit/mac/WebView/WebView.mm +++ b/WebKit/mac/WebView/WebView.mm @@ -28,7 +28,10 @@ */ #import "WebViewInternal.h" +#import "WebViewData.h" +#import "DOMCSSStyleDeclarationInternal.h" +#import "DOMNodeInternal.h" #import "DOMRangeInternal.h" #import "WebBackForwardListInternal.h" #import "WebCache.h" @@ -40,6 +43,7 @@ #import "WebDefaultEditingDelegate.h" #import "WebDefaultPolicyDelegate.h" #import "WebDefaultUIDelegate.h" +#import "WebDelegateImplementationCaching.h" #import "WebDocument.h" #import "WebDocumentInternal.h" #import "WebDownload.h" @@ -64,7 +68,6 @@ #import "WebKitSystemBits.h" #import "WebKitVersionChecks.h" #import "WebLocalizableStrings.h" -#import "WebNodeHighlight.h" #import "WebNSDataExtras.h" #import "WebNSDataExtrasPrivate.h" #import "WebNSDictionaryExtras.h" @@ -76,6 +79,7 @@ #import "WebNSURLRequestExtras.h" #import "WebNSUserDefaultsExtras.h" #import "WebNSViewExtras.h" +#import "WebNodeHighlight.h" #import "WebPDFView.h" #import "WebPanelAuthenticationHandler.h" #import "WebPasteboardHelper.h" @@ -84,6 +88,8 @@ #import "WebPreferenceKeysPrivate.h" #import "WebPreferencesPrivate.h" #import "WebScriptDebugDelegate.h" +#import "WebSystemInterface.h" +#import "WebTextCompletionController.h" #import "WebTextIterator.h" #import "WebUIDelegate.h" #import "WebUIDelegatePrivate.h" @@ -103,8 +109,8 @@ #import <WebCore/FocusController.h> #import <WebCore/Frame.h> #import <WebCore/FrameLoader.h> -#import <WebCore/FrameView.h> #import <WebCore/FrameTree.h> +#import <WebCore/FrameView.h> #import <WebCore/GCController.h> #import <WebCore/HTMLNames.h> #import <WebCore/HistoryItem.h> @@ -116,15 +122,18 @@ #import <WebCore/PageGroup.h> #import <WebCore/PlatformMouseEvent.h> #import <WebCore/ProgressTracker.h> +#import <WebCore/ResourceHandle.h> +#import <WebCore/RuntimeApplicationChecks.h> #import <WebCore/ScriptController.h> #import <WebCore/ScriptValue.h> +#import <WebCore/SecurityOrigin.h> #import <WebCore/SelectionController.h> #import <WebCore/Settings.h> #import <WebCore/TextResourceDecoder.h> #import <WebCore/ThreadCheck.h> #import <WebCore/WebCoreObjCExtras.h> -#import <WebCore/WebCoreTextRenderer.h> #import <WebCore/WebCoreView.h> +#import <WebCore/Widget.h> #import <WebKit/DOM.h> #import <WebKit/DOMExtensions.h> #import <WebKit/DOMPrivate.h> @@ -147,6 +156,26 @@ #import <WebKit/WebDashboardRegion.h> #endif +@class NSTextInputContext; + +@interface NSResponder (WebNSResponderDetails) +- (NSTextInputContext *)inputContext; +@end + +@interface NSSpellChecker (WebNSSpellCheckerDetails) +- (void)_preflightChosenSpellServer; +@end + +@interface NSView (WebNSViewDetails) +- (NSView *)_hitTest:(NSPoint *)aPoint dragTypes:(NSSet *)types; +- (void)_autoscrollForDraggingInfo:(id)dragInfo timeDelta:(NSTimeInterval)repeatDelta; +- (BOOL)_shouldAutoscrollForDraggingInfo:(id)dragInfo; +@end + +@interface NSWindow (WebNSWindowDetails) +- (id)_oldFirstResponderBeforeBecoming; +@end + using namespace WebCore; using namespace JSC; @@ -247,6 +276,7 @@ macro(moveWordLeftAndModifySelection) \ macro(moveWordRight) \ macro(moveWordRightAndModifySelection) \ macro(outdent) \ +macro(orderFrontSubstitutionsPanel) \ macro(pageDown) \ macro(pageDownAndModifySelection) \ macro(pageUp) \ @@ -295,32 +325,23 @@ macro(yankAndSelect) \ #define UsingAcceleratedCompositingProperty @"_isUsingAcceleratedCompositing" #endif - static BOOL s_didSetCacheModel; static WebCacheModel s_cacheModel = WebCacheModelDocumentViewer; -static BOOL applicationIsTerminating; -static int pluginDatabaseClientCount = 0; +static WebView *lastMouseoverView; #ifndef NDEBUG static const char webViewIsOpen[] = "At least one WebView is still open."; #endif -@interface NSSpellChecker (AppKitSecretsIKnow) -- (void)_preflightChosenSpellServer; -@end - -@interface NSView (AppKitSecretsIKnow) -- (NSView *)_hitTest:(NSPoint *)aPoint dragTypes:(NSSet *)types; -- (void)_autoscrollForDraggingInfo:(id)dragInfo timeDelta:(NSTimeInterval)repeatDelta; -- (BOOL)_shouldAutoscrollForDraggingInfo:(id)dragInfo; -@end - -@interface NSWindow (AppKitSecretsIKnow) -- (id)_oldFirstResponderBeforeBecoming; +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +@interface NSObject (NSTextInputContextDetails) +- (BOOL)wantsToHandleMouseEvents; +- (BOOL)handleMouseEvent:(NSEvent *)event; @end +#endif -@interface NSObject (ValidateWithoutDelegate) +@interface NSObject (WebValidateWithoutDelegate) - (BOOL)validateUserInterfaceItemWithoutDelegate:(id <NSValidatedUserInterfaceItem>)item; @end @@ -333,99 +354,6 @@ static const char webViewIsOpen[] = "At least one WebView is still open."; - (id)initWithTarget:(id)target defaultTarget:(id)defaultTarget catchExceptions:(BOOL)catchExceptions; @end -@interface WebViewPrivate : NSObject { -@public - Page* page; - - id UIDelegate; - id UIDelegateForwarder; - id resourceProgressDelegate; - id downloadDelegate; - id policyDelegate; - id policyDelegateForwarder; - id frameLoadDelegate; - id frameLoadDelegateForwarder; - id <WebFormDelegate> formDelegate; - id editingDelegate; - id editingDelegateForwarder; - id scriptDebugDelegate; - - WebInspector *inspector; - WebNodeHighlight *currentNodeHighlight; - - BOOL allowsUndo; - - float zoomMultiplier; - - NSString *applicationNameForUserAgent; - String userAgent; - BOOL userAgentOverridden; - - WebPreferences *preferences; - BOOL useSiteSpecificSpoofing; - - NSWindow *hostWindow; - - int programmaticFocusCount; - - WebResourceDelegateImplementationCache resourceLoadDelegateImplementations; - WebFrameLoadDelegateImplementationCache frameLoadDelegateImplementations; - WebScriptDebugDelegateImplementationCache scriptDebugDelegateImplementations; - - void *observationInfo; - - BOOL closed; - BOOL shouldCloseWithWindow; - BOOL mainFrameDocumentReady; - BOOL drawsBackground; - BOOL editable; - BOOL tabKeyCyclesThroughElementsChanged; - BOOL becomingFirstResponder; - BOOL becomingFirstResponderFromOutside; - BOOL hoverFeedbackSuspended; - BOOL usesPageCache; - BOOL catchesDelegateExceptions; - - NSColor *backgroundColor; - - NSString *mediaStyle; - - BOOL hasSpellCheckerDocumentTag; - NSInteger spellCheckerDocumentTag; - - BOOL smartInsertDeleteEnabled; - BOOL selectTrailingWhitespaceEnabled; - -#if ENABLE(DASHBOARD_SUPPORT) - BOOL dashboardBehaviorAlwaysSendMouseEventsToAllWindows; - BOOL dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns; - BOOL dashboardBehaviorAlwaysAcceptsFirstMouse; - BOOL dashboardBehaviorAllowWheelScrolling; -#endif - - // WebKit has both a global plug-in database and a separate, per WebView plug-in database. Dashboard uses the per WebView database. - WebPluginDatabase *pluginDatabase; - - HashMap<unsigned long, RetainPtr<id> > identifierMap; - - BOOL _keyboardUIModeAccessed; - KeyboardUIMode _keyboardUIMode; - - BOOL shouldUpdateWhileOffscreen; - - // When this flag is set, we will not make any subviews underneath this WebView. This means no WebFrameViews and no WebHTMLViews. - BOOL useDocumentViews; - -#if USE(ACCELERATED_COMPOSITING) - // When this flag is set, next time a WebHTMLView draws, it needs to temporarily disable screen updates - // so that the NSView drawing is visually synchronized with CALayer updates. - BOOL needsOneShotDrawingSynchronization; - // Number of WebHTMLViews using accelerated compositing. Used to implement _isUsingAcceleratedCompositing. - int acceleratedFramesCount; -#endif -} -@end - @interface WebView (WebFileInternal) - (WebFrame *)_selectedOrMainFrame; - (BOOL)_isLoading; @@ -434,9 +362,9 @@ static const char webViewIsOpen[] = "At least one WebView is still open."; + (void)_preflightSpellChecker; - (BOOL)_continuousCheckingAllowed; - (NSResponder *)_responderForResponderOperations; -@end - -@interface WebView (WebCallDelegateFunctions) +#if USE(ACCELERATED_COMPOSITING) +- (void)_clearLayerSyncLoopObserver; +#endif @end static void patchMailRemoveAttributesMethod(); @@ -497,75 +425,13 @@ static BOOL continuousSpellCheckingEnabled; #ifndef BUILDING_ON_TIGER static BOOL grammarCheckingEnabled; #endif - -@implementation WebViewPrivate - -+ (void)initialize -{ - JSC::initializeThreading(); -#ifndef BUILDING_ON_TIGER - WebCoreObjCFinalizeOnMainThread(self); -#endif -} - -- init -{ - self = [super init]; - if (!self) - return nil; - JSC::initializeThreading(); - allowsUndo = YES; - zoomMultiplier = 1; -#if ENABLE(DASHBOARD_SUPPORT) - dashboardBehaviorAllowWheelScrolling = YES; +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +static BOOL automaticQuoteSubstitutionEnabled; +static BOOL automaticLinkDetectionEnabled; +static BOOL automaticDashSubstitutionEnabled; +static BOOL automaticTextReplacementEnabled; +static BOOL automaticSpellingCorrectionEnabled; #endif - shouldCloseWithWindow = objc_collecting_enabled(); - continuousSpellCheckingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebContinuousSpellCheckingEnabled]; - -#ifndef BUILDING_ON_TIGER - grammarCheckingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebGrammarCheckingEnabled]; -#endif - - usesPageCache = YES; - - pluginDatabaseClientCount++; - - shouldUpdateWhileOffscreen = YES; - - return self; -} - -- (void)dealloc -{ - ASSERT(applicationIsTerminating || !page); - ASSERT(applicationIsTerminating || !preferences); - - [applicationNameForUserAgent release]; - [backgroundColor release]; - - [inspector release]; - [currentNodeHighlight release]; - - [hostWindow release]; - - [policyDelegateForwarder release]; - [UIDelegateForwarder release]; - [frameLoadDelegateForwarder release]; - [editingDelegateForwarder release]; - - [mediaStyle release]; - - [super dealloc]; -} - -- (void)finalize -{ - ASSERT_MAIN_THREAD(); - - [super finalize]; -} - -@end @implementation WebView (AllWebViews) @@ -680,7 +546,7 @@ static void WebKitInitializeApplicationCachePathIfNecessary() static bool runningLeopardMail() { #ifdef BUILDING_ON_LEOPARD - return [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.mail"]; + return applicationIsAppleMail(); #endif return NO; } @@ -688,11 +554,16 @@ static bool runningLeopardMail() static bool runningTigerMail() { #ifdef BUILDING_ON_TIGER - return [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.mail"]; + return applicationIsAppleMail(); #endif return NO; } +- (void)_dispatchPendingLoadRequests +{ + cache()->loader()->servePendingRequests(); +} + - (void)_registerDraggedTypes { NSArray *editableTypes = [WebHTMLView _insertablePasteboardTypes]; @@ -705,7 +576,7 @@ static bool runningTigerMail() - (BOOL)_usesDocumentViews { - return _private->useDocumentViews; + return _private->usesDocumentViews; } - (void)_commonInitializationWithFrameName:(NSString *)frameName groupName:(NSString *)groupName usesDocumentViews:(BOOL)usesDocumentViews @@ -723,12 +594,11 @@ static bool runningTigerMail() _private->catchesDelegateExceptions = YES; _private->mainFrameDocumentReady = NO; _private->drawsBackground = YES; - _private->smartInsertDeleteEnabled = YES; - _private->backgroundColor = [[NSColor whiteColor] retain]; - _private->useDocumentViews = usesDocumentViews; + _private->backgroundColor = [[NSColor colorWithDeviceWhite:1 alpha:1] retain]; + _private->usesDocumentViews = usesDocumentViews; WebFrameView *frameView = nil; - if (_private->useDocumentViews) { + if (_private->usesDocumentViews) { NSRect f = [self frame]; frameView = [[WebFrameView alloc] initWithFrame: NSMakeRect(0,0,f.size.width,f.size.height)]; [frameView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; @@ -797,6 +667,9 @@ static bool runningTigerMail() // with substitute data. FrameLoader::setLocalLoadPolicy(FrameLoader::AllowLocalLoadsForLocalAndSubstituteData); } + + if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_CONTENT_SNIFFING_FOR_FILE_URLS)) + ResourceHandle::forceContentSniffing(); } - (id)_initWithFrame:(NSRect)f frameName:(NSString *)frameName groupName:(NSString *)groupName usesDocumentViews:(BOOL)usesDocumentViews @@ -823,15 +696,6 @@ static bool runningTigerMail() return self; } -- (void)_boundsChanged -{ - Frame* frame = core([self mainFrame]); - IntSize oldSize = frame->view()->frameRect().size(); - frame->view()->resize([self bounds].size.width, [self bounds].size.height); - if (oldSize != frame->view()->frameRect().size()) - [self setNeedsDisplay: YES]; -} - - (BOOL)_mustDrawUnionedRect:(NSRect)rect singleRects:(const NSRect *)rects count:(NSInteger)count { // If count == 0 here, use the rect passed in for drawing. This is a workaround for: @@ -858,7 +722,7 @@ static bool runningTigerMail() - (void)drawSingleRect:(NSRect)rect { - ASSERT(!_private->useDocumentViews); + ASSERT(!_private->usesDocumentViews); [NSGraphicsContext saveGraphicsState]; NSRectClip(rect); @@ -882,18 +746,43 @@ static bool runningTigerMail() - (BOOL)isFlipped { - return _private && !_private->useDocumentViews; + return _private && !_private->usesDocumentViews; +} + +- (void)setFrameSize:(NSSize)size +{ + if (!_private->usesDocumentViews && !NSEqualSizes(_private->lastLayoutSize, size)) { + Frame* frame = [self _mainCoreFrame]; + // FIXME: Viewless WebKit is broken with Safari banners (e.g., the Find banner). We'll have to figure out a way for + // Safari to communicate that this space is being consumed. For WebKit with document views, there's no + // need to do an explicit resize, since WebFrameViews have auto resizing turned on and will handle changing + // their bounds automatically. See <rdar://problem/6835573> for details. + frame->view()->resize(IntSize(size)); + frame->view()->setNeedsLayout(); + [self setNeedsDisplay:YES]; + _private->lastLayoutSize = size; + } + + [super setFrameSize:size]; +} + +#if USE(ACCELERATED_COMPOSITING) || !defined(BUILDING_ON_TIGER) + +- (void)_viewWillDrawInternal +{ + Frame* frame = [self _mainCoreFrame]; + if (frame && frame->view()) + frame->view()->layoutIfNeededRecursive(); } +#endif + #ifndef BUILDING_ON_TIGER - (void)viewWillDraw { - if (!_private->useDocumentViews) { - Frame* frame = core([self mainFrame]); - if (frame && frame->view()) - frame->view()->layoutIfNeededRecursive(); - } + if (!_private->usesDocumentViews) + [self _viewWillDrawInternal]; [super viewWillDraw]; } @@ -902,7 +791,7 @@ static bool runningTigerMail() - (void)drawRect:(NSRect)rect { - if (_private->useDocumentViews) + if (_private->usesDocumentViews) return [super drawRect:rect]; ASSERT_MAIN_THREAD(); @@ -1002,7 +891,22 @@ static bool runningTigerMail() + (void)_setAlwaysUsesComplexTextCodePath:(BOOL)f { - WebCoreSetAlwaysUsesComplexTextCodePath(f); + Font::setCodePath(f ? Font::Complex : Font::Auto); +} + ++ (BOOL)canCloseAllWebViews +{ + return DOMWindow::dispatchAllPendingBeforeUnloadEvents(); +} + ++ (void)closeAllWebViews +{ + DOMWindow::dispatchAllPendingUnloadEvents(); + + // This will close the WebViews in a random order. Change this if close order is important. + NSEnumerator *enumerator = [(NSMutableSet *)allWebViewsSet objectEnumerator]; + while (WebView *webView = [enumerator nextObject]) + [webView close]; } + (BOOL)canShowFile:(NSString *)path @@ -1045,18 +949,33 @@ static bool runningTigerMail() WTF::RefCountedLeakCounter::suppressMessages("At least one WebView was closed with fast teardown."); #endif - // Dispatch unload events. - // FIXME: Shouldn't have to use a RefPtr here -- keeping the frame alive while stopping it - // should be WebCore's responsibility -- but we do as of the time this comment was written. - RefPtr<Frame> mainFrame = core([self mainFrame]); - if (mainFrame && mainFrame->page() && mainFrame->page()->pendingUnloadEventCount()) - mainFrame->loader()->stopLoading(true); - _private->closed = YES; + + [[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; [self _closePluginDatabases]; } +static bool fastDocumentTeardownEnabled() +{ +#ifdef NDEBUG + static bool enabled = ![[NSUserDefaults standardUserDefaults] boolForKey:WebKitEnableFullDocumentTeardownPreferenceKey]; +#else + static bool initialized = false; + static bool enabled = false; + if (!initialized) { + // This allows debug builds to default to not have fast teardown, so leak checking still works. + // But still allow the WebKitEnableFullDocumentTeardown default to override it if present. + NSNumber *setting = [[NSUserDefaults standardUserDefaults] objectForKey:WebKitEnableFullDocumentTeardownPreferenceKey]; + if (setting) + enabled = ![setting boolValue]; + initialized = true; + } +#endif + return enabled; +} + // _close is here only for backward compatibility; clients and subclasses should use // public method -close instead. - (void)_close @@ -1064,22 +983,21 @@ static bool runningTigerMail() if (!_private || _private->closed) return; + if (lastMouseoverView == self) + lastMouseoverView = nil; + #ifndef NDEBUG WTF::RefCountedLeakCounter::cancelMessageSuppression(webViewIsOpen); #endif - - WebPreferences *preferences = _private->preferences; - BOOL fullDocumentTeardown = [preferences fullDocumentTeardownEnabled]; - - // To quit the apps fast we skip document teardown. Two exceptions: - // 1) plugins need to be destroyed and unloaded - // 2) unload events need to be called - if (applicationIsTerminating && !fullDocumentTeardown) { + + // To quit the apps fast we skip document teardown, except plugins + // need to be destroyed and unloaded. + if (applicationIsTerminating && fastDocumentTeardownEnabled()) { [self _closeWithFastTeardown]; return; } - if (Frame* mainFrame = core([self mainFrame])) + if (Frame* mainFrame = [self _mainCoreFrame]) mainFrame->loader()->detachFromParent(); [self _removeFromAllWebViewsSet]; @@ -1111,12 +1029,17 @@ static bool runningTigerMail() [[NSSpellChecker sharedSpellChecker] closeSpellDocumentWithTag:_private->spellCheckerDocumentTag]; _private->hasSpellCheckerDocumentTag = NO; } + +#if USE(ACCELERATED_COMPOSITING) + [self _clearLayerSyncLoopObserver]; +#endif [[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; [[NSNotificationCenter defaultCenter] removeObserver:self]; [WebPreferences _removeReferenceForIdentifier:[self preferencesIdentifier]]; + WebPreferences *preferences = _private->preferences; _private->preferences = nil; [preferences didRemoveFromWebView]; [preferences release]; @@ -1132,6 +1055,13 @@ static bool runningTigerMail() #endif } +// Indicates if the WebView is in the midst of a user gesture. +- (BOOL)_isProcessingUserGesture +{ + WebFrame *frame = [self mainFrame]; + return core(frame)->loader()->isProcessingUserGesture(); +} + + (NSString *)_MIMETypeForFile:(NSString *)path { NSString *extension = [path pathExtension]; @@ -1277,13 +1207,7 @@ static bool runningTigerMail() - (BOOL)_needsAdobeFrameReloadingQuirk { - static BOOL checked = NO; - static BOOL needsQuirk = NO; - - if (checked) - return needsQuirk; - - needsQuirk = WKAppVersionCheckLessThan(@"com.adobe.Acrobat", -1, 9.0) + static BOOL needsQuirk = WKAppVersionCheckLessThan(@"com.adobe.Acrobat", -1, 9.0) || WKAppVersionCheckLessThan(@"com.adobe.Acrobat.Pro", -1, 9.0) || WKAppVersionCheckLessThan(@"com.adobe.Reader", -1, 9.0) || WKAppVersionCheckLessThan(@"com.adobe.distiller", -1, 9.0) @@ -1293,26 +1217,29 @@ static bool runningTigerMail() || WKAppVersionCheckLessThan(@"com.adobe.InCopy", -1, 5.1) || WKAppVersionCheckLessThan(@"com.adobe.InDesign", -1, 5.1) || WKAppVersionCheckLessThan(@"com.adobe.Soundbooth", -1, 2); - checked = YES; return needsQuirk; } -- (BOOL)_needsKeyboardEventDisambiguationQuirks +- (BOOL)_needsLinkElementTextCSSQuirk { - static BOOL checked = NO; - static BOOL needsQuirks = NO; - - if (checked) - return needsQuirks; - - needsQuirks = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_IE_COMPATIBLE_KEYBOARD_EVENT_DISPATCH) - && ![[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Safari"]; - checked = YES; + static BOOL needsQuirk = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_LINK_ELEMENT_TEXT_CSS_QUIRK) + && WKAppVersionCheckLessThan(@"com.e-frontier.shade10", -1, 10.6); + return needsQuirk; +} +- (BOOL)_needsKeyboardEventDisambiguationQuirks +{ + static BOOL needsQuirks = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_IE_COMPATIBLE_KEYBOARD_EVENT_DISPATCH) && !applicationIsSafari(); return needsQuirks; } +- (BOOL)_needsFrameLoadDelegateRetainQuirk +{ + static BOOL needsQuirk = WKAppVersionCheckLessThan(@"com.equinux.iSale5", -1, 5.6); + return needsQuirk; +} + - (void)_preferencesChangedNotification:(NSNotification *)notification { WebPreferences *preferences = (WebPreferences *)[notification object]; @@ -1372,14 +1299,18 @@ static bool runningTigerMail() } else settings->setUserStyleSheetLocation([NSURL URLWithString:@""]); settings->setNeedsAdobeFrameReloadingQuirk([self _needsAdobeFrameReloadingQuirk]); + settings->setTreatsAnyTextCSSLinkAsStylesheet([self _needsLinkElementTextCSSQuirk]); settings->setNeedsKeyboardEventDisambiguationQuirks([self _needsKeyboardEventDisambiguationQuirks]); settings->setNeedsLeopardMailQuirks(runningLeopardMail()); settings->setNeedsTigerMailQuirks(runningTigerMail()); settings->setNeedsSiteSpecificQuirks(_private->useSiteSpecificSpoofing); settings->setWebArchiveDebugModeEnabled([preferences webArchiveDebugModeEnabled]); + settings->setLocalFileContentSniffingEnabled([preferences localFileContentSniffingEnabled]); settings->setOfflineWebApplicationCacheEnabled([preferences offlineWebApplicationCacheEnabled]); settings->setZoomsTextOnly([preferences zoomsTextOnly]); + settings->setXSSAuditorEnabled([preferences isXSSAuditorEnabled]); settings->setEnforceCSSMIMETypeInStrictMode(!WKAppVersionCheckLessThan(@"com.apple.iWeb", -1, 2.1)); + settings->setAcceleratedCompositingEnabled([preferences acceleratedCompositingEnabled]); } static inline IMP getMethod(id o, SEL s) @@ -1411,14 +1342,6 @@ static inline IMP getMethod(id o, SEL s) cache->shouldUseCredentialStorageFunc = getMethod(delegate, @selector(webView:resource:shouldUseCredentialStorageForDataSource:)); } -WebResourceDelegateImplementationCache* WebViewGetResourceLoadDelegateImplementations(WebView *webView) -{ - static WebResourceDelegateImplementationCache empty; - if (!webView) - return ∅ - return &webView->_private->resourceLoadDelegateImplementations; -} - - (void)_cacheFrameLoadDelegateImplementations { WebFrameLoadDelegateImplementationCache *cache = &_private->frameLoadDelegateImplementations; @@ -1432,6 +1355,7 @@ WebResourceDelegateImplementationCache* WebViewGetResourceLoadDelegateImplementa cache->didCancelClientRedirectForFrameFunc = getMethod(delegate, @selector(webView:didCancelClientRedirectForFrame:)); cache->didChangeLocationWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didChangeLocationWithinPageForFrame:)); cache->didClearWindowObjectForFrameFunc = getMethod(delegate, @selector(webView:didClearWindowObject:forFrame:)); + cache->didClearInspectorWindowObjectForFrameFunc = getMethod(delegate, @selector(webView:didClearInspectorWindowObject:forFrame:)); cache->didCommitLoadForFrameFunc = getMethod(delegate, @selector(webView:didCommitLoadForFrame:)); cache->didFailLoadWithErrorForFrameFunc = getMethod(delegate, @selector(webView:didFailLoadWithError:forFrame:)); cache->didFailProvisionalLoadWithErrorForFrameFunc = getMethod(delegate, @selector(webView:didFailProvisionalLoadWithError:forFrame:)); @@ -1449,14 +1373,6 @@ WebResourceDelegateImplementationCache* WebViewGetResourceLoadDelegateImplementa cache->windowScriptObjectAvailableFunc = getMethod(delegate, @selector(webView:windowScriptObjectAvailable:)); } -WebFrameLoadDelegateImplementationCache* WebViewGetFrameLoadDelegateImplementations(WebView *webView) -{ - static WebFrameLoadDelegateImplementationCache empty; - if (!webView) - return ∅ - return &webView->_private->frameLoadDelegateImplementations; -} - - (void)_cacheScriptDebugDelegateImplementations { WebScriptDebugDelegateImplementationCache *cache = &_private->scriptDebugDelegateImplementations; @@ -1480,14 +1396,6 @@ WebFrameLoadDelegateImplementationCache* WebViewGetFrameLoadDelegateImplementati cache->exceptionWasRaisedFunc = getMethod(delegate, @selector(webView:exceptionWasRaised:sourceId:line:forWebFrame:)); } -WebScriptDebugDelegateImplementationCache* WebViewGetScriptDebugDelegateImplementations(WebView *webView) -{ - static WebScriptDebugDelegateImplementationCache empty; - if (!webView) - return ∅ - return &webView->_private->scriptDebugDelegateImplementations; -} - - (id)_policyDelegateForwarder { if (!_private->policyDelegateForwarder) @@ -1758,42 +1666,72 @@ WebScriptDebugDelegateImplementationCache* WebViewGetScriptDebugDelegateImplemen #define DASHBOARD_CONTROL_LABEL @"control" +- (void)_addControlRect:(NSRect)bounds clip:(NSRect)clip fromView:(NSView *)view toDashboardRegions:(NSMutableDictionary *)regions +{ + NSRect adjustedBounds = bounds; + adjustedBounds.origin = [self convertPoint:bounds.origin fromView:view]; + adjustedBounds.origin.y = [self bounds].size.height - adjustedBounds.origin.y; + adjustedBounds.size = bounds.size; + + NSRect adjustedClip; + adjustedClip.origin = [self convertPoint:clip.origin fromView:view]; + adjustedClip.origin.y = [self bounds].size.height - adjustedClip.origin.y; + adjustedClip.size = clip.size; + + WebDashboardRegion *region = [[WebDashboardRegion alloc] initWithRect:adjustedBounds + clip:adjustedClip type:WebDashboardRegionTypeScrollerRectangle]; + NSMutableArray *scrollerRegions = [regions objectForKey:DASHBOARD_CONTROL_LABEL]; + if (!scrollerRegions) { + scrollerRegions = [[NSMutableArray alloc] init]; + [regions setObject:scrollerRegions forKey:DASHBOARD_CONTROL_LABEL]; + [scrollerRegions release]; + } + [scrollerRegions addObject:region]; + [region release]; +} + +- (void)_addScrollerDashboardRegionsForFrameView:(FrameView*)frameView dashboardRegions:(NSMutableDictionary *)regions +{ + NSView *documentView = [[kit(frameView->frame()) frameView] documentView]; + + const HashSet<RefPtr<Widget> >* children = frameView->children(); + HashSet<RefPtr<Widget> >::const_iterator end = children->end(); + for (HashSet<RefPtr<Widget> >::const_iterator it = children->begin(); it != end; ++it) { + Widget* widget = (*it).get(); + if (widget->isFrameView()) { + [self _addScrollerDashboardRegionsForFrameView:static_cast<FrameView*>(widget) dashboardRegions:regions]; + continue; + } + + if (!widget->isScrollbar()) + continue; + + // FIXME: This should really pass an appropriate clip, but our first try got it wrong, and + // it's not common to need this to be correct in Dashboard widgets. + NSRect bounds = widget->frameRect(); + [self _addControlRect:bounds clip:bounds fromView:documentView toDashboardRegions:regions]; + } +} + - (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions from:(NSArray *)views { - // Add scroller regions for NSScroller and KWQScrollBar - int i, count = [views count]; - - for (i = 0; i < count; i++) { - NSView *aView = [views objectAtIndex:i]; + // Add scroller regions for NSScroller and WebCore scrollbars + NSUInteger count = [views count]; + for (NSUInteger i = 0; i < count; i++) { + NSView *view = [views objectAtIndex:i]; - if ([aView isKindOfClass:[NSScroller class]] || - [aView isKindOfClass:NSClassFromString (@"KWQScrollBar")]) { - NSRect bounds = [aView bounds]; - NSRect adjustedBounds; - adjustedBounds.origin = [self convertPoint:bounds.origin fromView:aView]; - adjustedBounds.origin.y = [self bounds].size.height - adjustedBounds.origin.y; - - // AppKit has horrible hack of placing absent scrollers at -100,-100 - if (adjustedBounds.origin.y == -100) - continue; - adjustedBounds.size = bounds.size; - NSRect clip = [aView visibleRect]; - NSRect adjustedClip; - adjustedClip.origin = [self convertPoint:clip.origin fromView:aView]; - adjustedClip.origin.y = [self bounds].size.height - adjustedClip.origin.y; - adjustedClip.size = clip.size; - WebDashboardRegion *aRegion = - [[[WebDashboardRegion alloc] initWithRect:adjustedBounds - clip:adjustedClip type:WebDashboardRegionTypeScrollerRectangle] autorelease]; - NSMutableArray *scrollerRegions; - scrollerRegions = [regions objectForKey:DASHBOARD_CONTROL_LABEL]; - if (!scrollerRegions) { - scrollerRegions = [NSMutableArray array]; - [regions setObject:scrollerRegions forKey:DASHBOARD_CONTROL_LABEL]; + if ([view isKindOfClass:[WebHTMLView class]]) { + if (Frame* coreFrame = core([(WebHTMLView*)view _frame])) { + if (FrameView* coreView = coreFrame->view()) + [self _addScrollerDashboardRegionsForFrameView:coreView dashboardRegions:regions]; } - [scrollerRegions addObject:aRegion]; + } else if ([view isKindOfClass:[NSScroller class]]) { + // AppKit places absent scrollers at -100,-100 + if ([view frame].origin.y < 0) + continue; + [self _addControlRect:[view bounds] clip:[view visibleRect] fromView:view toDashboardRegions:regions]; } - [self _addScrollerDashboardRegions:regions from:[aView subviews]]; + [self _addScrollerDashboardRegions:regions from:[view subviews]]; } } @@ -1805,7 +1743,7 @@ WebScriptDebugDelegateImplementationCache* WebViewGetScriptDebugDelegateImplemen - (NSDictionary *)_dashboardRegions { // Only return regions from main frame. - Frame* mainFrame = core([self mainFrame]); + Frame* mainFrame = [self _mainCoreFrame]; if (!mainFrame) return nil; NSMutableDictionary *regions = mainFrame->dashboardRegionsDictionary(); @@ -1871,12 +1809,12 @@ WebScriptDebugDelegateImplementationCache* WebViewGetScriptDebugDelegateImplemen + (void)_setShouldUseFontSmoothing:(BOOL)f { - WebCoreSetShouldUseFontSmoothing(f); + Font::setShouldUseSmoothing(f); } + (BOOL)_shouldUseFontSmoothing { - return WebCoreShouldUseFontSmoothing(); + return Font::shouldUseSmoothing(); } + (void)_setUsesTestModeFocusRingColor:(BOOL)f @@ -1889,12 +1827,6 @@ WebScriptDebugDelegateImplementationCache* WebViewGetScriptDebugDelegateImplemen return usesTestModeFocusRingColor(); } -// This is only used by versions of Safari up to and including 3.0 and should be removed in a future release. -+ (NSString *)_minimumRequiredSafariBuildNumber -{ - return @"420+"; -} - - (void)setAlwaysShowVerticalScroller:(BOOL)flag { WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView]; @@ -1925,8 +1857,7 @@ WebScriptDebugDelegateImplementationCache* WebViewGetScriptDebugDelegateImplemen - (void)setProhibitsMainFrameScrolling:(BOOL)prohibits { - Frame* mainFrame = core([self mainFrame]); - if (mainFrame) + if (Frame* mainFrame = [self _mainCoreFrame]) mainFrame->view()->setProhibitsScrolling(prohibits); } @@ -1938,14 +1869,13 @@ WebScriptDebugDelegateImplementationCache* WebViewGetScriptDebugDelegateImplemen - (void)_setInViewSourceMode:(BOOL)flag { - Frame* mainFrame = core([self mainFrame]); - if (mainFrame) + if (Frame* mainFrame = [self _mainCoreFrame]) mainFrame->setInViewSourceMode(flag); } - (BOOL)_inViewSourceMode { - Frame* mainFrame = core([self mainFrame]); + Frame* mainFrame = [self _mainCoreFrame]; return mainFrame && mainFrame->inViewSourceMode(); } @@ -1988,13 +1918,13 @@ WebScriptDebugDelegateImplementationCache* WebViewGetScriptDebugDelegateImplemen - (void)_attachScriptDebuggerToAllFrames { - for (Frame* frame = core([self mainFrame]); frame; frame = frame->tree()->traverseNext()) + for (Frame* frame = [self _mainCoreFrame]; frame; frame = frame->tree()->traverseNext()) [kit(frame) _attachScriptDebugger]; } - (void)_detachScriptDebuggerFromAllFrames { - for (Frame* frame = core([self mainFrame]); frame; frame = frame->tree()->traverseNext()) + for (Frame* frame = [self _mainCoreFrame]; frame; frame = frame->tree()->traverseNext()) [kit(frame) _detachScriptDebugger]; } @@ -2057,13 +1987,13 @@ WebScriptDebugDelegateImplementationCache* WebViewGetScriptDebugDelegateImplemen IntPoint rectStart(rect.origin.x, rect.origin.y); IntPoint rectEnd(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height); - Frame* coreFrame = core([self mainFrame]); + Frame* coreFrame = [self _mainCoreFrame]; if (!coreFrame) return nil; VisibleSelection selectionInsideRect(coreFrame->visiblePositionForPoint(rectStart), coreFrame->visiblePositionForPoint(rectEnd)); - return [[[WebTextIterator alloc] initWithRange:[DOMRange _wrapRange:selectionInsideRect.toNormalizedRange().get()]] autorelease]; + return [[[WebTextIterator alloc] initWithRange:kit(selectionInsideRect.toNormalizedRange().get())] autorelease]; } - (void)handleAuthenticationForResource:(id)identifier challenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource @@ -2091,7 +2021,7 @@ WebScriptDebugDelegateImplementationCache* WebViewGetScriptDebugDelegateImplemen - (void)_executeCoreCommandByName:(NSString *)name value:(NSString *)value { - Frame* coreFrame = core([self mainFrame]); + Frame* coreFrame = [self _mainCoreFrame]; if (!coreFrame) return; coreFrame->editor()->command(name).execute(value); @@ -2148,47 +2078,25 @@ WebScriptDebugDelegateImplementationCache* WebViewGetScriptDebugDelegateImplemen return handCursor().impl(); } -#if USE(ACCELERATED_COMPOSITING) -- (BOOL)_needsOneShotDrawingSynchronization -{ - return _private->needsOneShotDrawingSynchronization; -} - -- (void)_setNeedsOneShotDrawingSynchronization:(BOOL)needsSynchronization +- (BOOL)_isUsingAcceleratedCompositing { - _private->needsOneShotDrawingSynchronization = needsSynchronization; +#if USE(ACCELERATED_COMPOSITING) + return _private->acceleratedFramesCount > 0; +#else + return NO; +#endif } -- (void)_startedAcceleratedCompositingForFrame:(WebFrame*)webFrame +- (NSPasteboard *)_insertionPasteboard { - BOOL entering = _private->acceleratedFramesCount == 0; - if (entering) - [self willChangeValueForKey:UsingAcceleratedCompositingProperty]; - ++_private->acceleratedFramesCount; - if (entering) - [self didChangeValueForKey:UsingAcceleratedCompositingProperty]; + return _private ? _private->insertionPasteboard : nil; } -- (void)_stoppedAcceleratedCompositingForFrame:(WebFrame*)webFrame -{ - BOOL leaving = _private->acceleratedFramesCount == 1; - ASSERT(_private->acceleratedFramesCount > 0); - - if (leaving) - [self willChangeValueForKey:UsingAcceleratedCompositingProperty]; - --_private->acceleratedFramesCount; - if (leaving) - [self didChangeValueForKey:UsingAcceleratedCompositingProperty]; -} -#endif -- (BOOL)_isUsingAcceleratedCompositing +- (void)_updateActiveState { -#if USE(ACCELERATED_COMPOSITING) - return _private->acceleratedFramesCount > 0; -#else - return NO; -#endif + if (_private && _private->page) + _private->page->focusController()->setActive([[self window] isKeyWindow]); } @end @@ -2244,14 +2152,33 @@ WebScriptDebugDelegateImplementationCache* WebViewGetScriptDebugDelegateImplemen return; initialized = YES; + InitWebCoreSystemInterface(); + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_applicationWillTerminate) name:NSApplicationWillTerminateNotification object:NSApp]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:) name:WebPreferencesChangedNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesRemovedNotification:) name:WebPreferencesRemovedNotification object:nil]; + + continuousSpellCheckingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebContinuousSpellCheckingEnabled]; +#ifndef BUILDING_ON_TIGER + grammarCheckingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebGrammarCheckingEnabled]; +#endif + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + automaticQuoteSubstitutionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticQuoteSubstitutionEnabled]; + automaticLinkDetectionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticLinkDetectionEnabled]; + automaticDashSubstitutionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticDashSubstitutionEnabled]; + automaticTextReplacementEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticTextReplacementEnabled]; + automaticSpellingCorrectionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticSpellingCorrectionEnabled]; +#endif } + (void)_applicationWillTerminate { applicationIsTerminating = YES; + + if (fastDocumentTeardownEnabled()) + [self closeAllWebViews]; + if (!pluginDatabaseClientCount) [WebPluginDatabase closeSharedDatabase]; @@ -2368,7 +2295,7 @@ WebScriptDebugDelegateImplementationCache* WebViewGetScriptDebugDelegateImplemen + (void)registerURLSchemeAsLocal:(NSString *)protocol { - FrameLoader::registerURLSchemeAsLocal(protocol); + SecurityOrigin::registerURLSchemeAsLocal(protocol); } - (id)_initWithArguments:(NSDictionary *) arguments @@ -2388,11 +2315,41 @@ WebScriptDebugDelegateImplementationCache* WebViewGetScriptDebugDelegateImplemen return self; } +static bool clientNeedsWebViewInitThreadWorkaround() +{ + if (WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_WEBVIEW_INIT_THREAD_WORKAROUND)) + return false; + + NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + + // Installer. + if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.installer"]) + return true; + + // Automator. + if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.Automator"]) + return true; + + // Automator Runner. + if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.AutomatorRunner"]) + return true; + + // Automator workflows. + if ([bundleIdentifier _webkit_hasCaseInsensitivePrefix:@"com.apple.Automator."]) + return true; + +#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) + // Mail. + if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.Mail"]) + return true; +#endif + + return false; +} + static bool needsWebViewInitThreadWorkaround() { - static BOOL isOldClient = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_WEBVIEW_INIT_THREAD_WORKAROUND) - && ([[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.installer"] || - [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Automator"]); + static bool isOldClient = clientNeedsWebViewInitThreadWorkaround(); return isOldClient && !pthread_main_np(); } @@ -2517,6 +2474,9 @@ static bool needsWebViewInitThreadWorkaround() --WebViewCount; + if ([self _needsFrameLoadDelegateRetainQuirk]) + [_private->frameLoadDelegate release]; + [_private release]; // [super dealloc] can end up dispatching against _private (3466082) _private = nil; @@ -2549,31 +2509,9 @@ static bool needsWebViewInitThreadWorkaround() return _private->shouldCloseWithWindow; } -- (void)removeSizeObservers -{ - if (!_private->useDocumentViews && [self window]) { - [[NSNotificationCenter defaultCenter] removeObserver:self - name:NSViewFrameDidChangeNotification object:self]; - [[NSNotificationCenter defaultCenter] removeObserver:self - name:NSViewBoundsDidChangeNotification object:self]; - } -} - -- (void)addSizeObservers +- (void)addWindowObserversForWindow:(NSWindow *)window { - if (!_private->useDocumentViews && [self window]) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_boundsChanged) - name:NSViewFrameDidChangeNotification object:self]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_boundsChanged) - name:NSViewBoundsDidChangeNotification object:self]; - [self _boundsChanged]; - } -} - -- (void)addWindowObservers -{ - NSWindow *window = [self window]; - if (!_private->useDocumentViews && window) { + if (window) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidResignKey:) @@ -2586,7 +2524,7 @@ static bool needsWebViewInitThreadWorkaround() - (void)removeWindowObservers { NSWindow *window = [self window]; - if (!_private->useDocumentViews && window) { + if (window) { [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidBecomeKeyNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self @@ -2601,10 +2539,7 @@ static bool needsWebViewInitThreadWorkaround() // Don't do anything if the WebView isn't initialized. // This happens when decoding a WebView in a nib. // FIXME: What sets up the observer of NSWindowWillCloseNotification in this case? - if (!_private) - return; - - if (_private->closed) + if (!_private || _private->closed) return; if ([self window] && [self window] != [self hostWindow]) @@ -2618,11 +2553,13 @@ static bool needsWebViewInitThreadWorkaround() // and over, so do them when we move into a window. [window setAcceptsMouseMovedEvents:YES]; WKSetNSWindowShouldPostEventNotifications(window, YES); - - [self removeWindowObservers]; - [self removeSizeObservers]; } else _private->page->willMoveOffscreen(); + + if (window != [self window]) { + [self removeWindowObservers]; + [self addWindowObserversForWindow:window]; + } } - (void)viewDidMoveToWindow @@ -2633,66 +2570,29 @@ static bool needsWebViewInitThreadWorkaround() // initialized. The stub views are discarded by WebView. if (!_private || _private->closed) return; - - if ([self window]) { - [self addWindowObservers]; - [self addSizeObservers]; - _private->page->didMoveOnscreen(); - } -} -- (void)_updateFocusedAndActiveState -{ - ASSERT(!_private->useDocumentViews); - [self _updateFocusedAndActiveStateForFrame:[self mainFrame]]; -} - -- (void)_updateFocusedAndActiveStateForFrame:(WebFrame *)webFrame -{ - Frame* frame = core(webFrame); - if (!frame) - return; + if ([self window]) + _private->page->didMoveOnscreen(); - Page* page = frame->page(); - if (!page) - return; - - NSWindow *window = [self window]; - BOOL windowIsKey = [window isKeyWindow]; - BOOL windowOrSheetIsKey = windowIsKey || [[window attachedSheet] isKeyWindow]; - - WebFrameView *mainFrameView = [[self mainFrame] frameView]; - id <WebDocumentView> documentView = [mainFrameView documentView]; - BOOL documentViewIsResigningFirstResponder = [documentView isKindOfClass:[WebHTMLView class]] && [(WebHTMLView *)documentView _isResigningFirstResponder]; - - NSResponder *firstResponder = [window firstResponder]; - if ([firstResponder isKindOfClass:[NSView class]] - && [(NSView *)firstResponder isDescendantOf:mainFrameView]) - page->focusController()->setActive(windowIsKey && !documentViewIsResigningFirstResponder); - - Frame* focusedFrame = page->focusController()->focusedOrMainFrame(); - frame->selection()->setFocused(frame == focusedFrame && windowOrSheetIsKey); + [self _updateActiveState]; } - (void)_windowDidBecomeKey:(NSNotification *)notification { - ASSERT(!_private->useDocumentViews); NSWindow *keyWindow = [notification object]; if (keyWindow == [self window] || keyWindow == [[self window] attachedSheet]) - [self _updateFocusedAndActiveState]; + [self _updateActiveState]; } - (void)_windowDidResignKey:(NSNotification *)notification { - ASSERT(!_private->useDocumentViews); NSWindow *formerKeyWindow = [notification object]; if (formerKeyWindow == [self window] || formerKeyWindow == [[self window] attachedSheet]) - [self _updateFocusedAndActiveState]; + [self _updateActiveState]; } - (void)_windowWillOrderOnScreen:(NSNotification *)notification { - ASSERT(!_private->useDocumentViews); if (![self shouldUpdateWhileOffscreen]) [self setNeedsDisplay:YES]; } @@ -2797,12 +2697,23 @@ static bool needsWebViewInitThreadWorkaround() - (void)setFrameLoadDelegate:delegate { + // <rdar://problem/6950660> - Due to some subtle WebKit changes - presumably to delegate callback behavior - we've + // unconvered a latent bug in at least one WebKit app where the delegate wasn't properly retained by the app and + // was dealloc'ed before being cleared. + // This is an effort to keep such apps working for now. + if ([self _needsFrameLoadDelegateRetainQuirk]) { + [delegate retain]; + [_private->frameLoadDelegate release]; + } + _private->frameLoadDelegate = delegate; [self _cacheFrameLoadDelegateImplementations]; +#if ENABLE(ICONDATABASE) // If this delegate wants callbacks for icons, fire up the icon database. if (_private->frameLoadDelegateImplementations.didReceiveIconForFrameFunc) [WebIconDatabase sharedIconDatabase]; +#endif } - frameLoadDelegate @@ -2813,21 +2724,21 @@ static bool needsWebViewInitThreadWorkaround() - (WebFrame *)mainFrame { // This can be called in initialization, before _private has been set up (3465613) - if (!_private) - return nil; - if (!_private->page) + if (!_private || !_private->page) return nil; return kit(_private->page->mainFrame()); } - (WebFrame *)selectedFrame { - // If the first responder is a view in our tree, we get the frame containing the first responder. - // This is faster than searching the frame hierarchy, and will give us a result even in the case - // where the focused frame doesn't actually contain a selection. - WebFrame *focusedFrame = [self _focusedFrame]; - if (focusedFrame) - return focusedFrame; + if (_private->usesDocumentViews) { + // If the first responder is a view in our tree, we get the frame containing the first responder. + // This is faster than searching the frame hierarchy, and will give us a result even in the case + // where the focused frame doesn't actually contain a selection. + WebFrame *focusedFrame = [self _focusedFrame]; + if (focusedFrame) + return focusedFrame; + } // If the first responder is outside of our view tree, we search for a frame containing a selection. // There should be at most only one of these. @@ -2843,7 +2754,7 @@ static bool needsWebViewInitThreadWorkaround() return kit(_private->page->backForwardList()); } -- (void)setMaintainsBackForwardList: (BOOL)flag +- (void)setMaintainsBackForwardList:(BOOL)flag { if (!_private->page) return; @@ -2895,7 +2806,7 @@ static bool needsWebViewInitThreadWorkaround() // FIXME: it would be nice to rework this code so that _private->zoomMultiplier doesn't exist and callers // all access _private->page->settings(). - Frame* coreFrame = core([self mainFrame]); + Frame* coreFrame = [self _mainCoreFrame]; if (coreFrame) coreFrame->setZoomFactor(m, isTextOnly); } @@ -2990,17 +2901,6 @@ static bool needsWebViewInitThreadWorkaround() [self _setZoomMultiplier:1.0f isTextOnly:isTextOnly]; } -- (void)viewWillMoveToSuperview:(NSView *)newSuperview -{ - [self removeSizeObservers]; -} - -- (void)viewDidMoveToSuperview -{ - if ([self superview] != nil) - [self addSizeObservers]; -} - - (void)setApplicationNameForUserAgent:(NSString *)applicationName { NSString *name = [applicationName copy]; @@ -3053,7 +2953,7 @@ static bool needsWebViewInitThreadWorkaround() NSString *oldEncoding = [self customTextEncodingName]; if (encoding == oldEncoding || [encoding isEqualToString:oldEncoding]) return; - if (Frame* mainFrame = core([self mainFrame])) + if (Frame* mainFrame = [self _mainCoreFrame]) mainFrame->loader()->reloadWithOverrideEncoding(encoding); } @@ -3094,7 +2994,7 @@ static bool needsWebViewInitThreadWorkaround() - (WebScriptObject *)windowScriptObject { - Frame* coreFrame = core([self mainFrame]); + Frame* coreFrame = [self _mainCoreFrame]; if (!coreFrame) return nil; return coreFrame->script()->windowScriptObject(); @@ -3113,17 +3013,21 @@ static bool needsWebViewInitThreadWorkaround() if (hostWindow == _private->hostWindow) return; - Frame* coreFrame = core([self mainFrame]); - for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) - [[[kit(frame) frameView] documentView] viewWillMoveToHostWindow:hostWindow]; + Frame* coreFrame = [self _mainCoreFrame]; + if (_private->usesDocumentViews) { + for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) + [[[kit(frame) frameView] documentView] viewWillMoveToHostWindow:hostWindow]; + } if (_private->hostWindow && [self window] != _private->hostWindow) [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:_private->hostWindow]; if (hostWindow) [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillClose:) name:NSWindowWillCloseNotification object:hostWindow]; [_private->hostWindow release]; _private->hostWindow = [hostWindow retain]; - for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) - [[[kit(frame) frameView] documentView] viewDidMoveToHostWindow]; + if (_private->usesDocumentViews) { + for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) + [[[kit(frame) frameView] documentView] viewDidMoveToHostWindow]; + } } - (NSWindow *)hostWindow @@ -3159,7 +3063,7 @@ static bool needsWebViewInitThreadWorkaround() return [self _elementAtWindowPoint:[self convertPoint:point toView:nil]]; } -// The following 2 internal NSView methods are called on the drag destination by make scrolling while dragging work. +// The following 2 internal NSView methods are called on the drag destination to make scrolling while dragging work. // Scrolling while dragging will only work if the drag destination is in a scroll view. The WebView is the drag destination. // When dragging to a WebView, the document subview should scroll, but it doesn't because it is not the drag destination. // Forward these calls to the document subview to make its scroll view scroll. @@ -3228,87 +3132,98 @@ static bool needsWebViewInitThreadWorkaround() return core(self)->dragController()->performDrag(&dragData); } -- (NSView *)_hitTest:(NSPoint *)aPoint dragTypes:(NSSet *)types +- (NSView *)_hitTest:(NSPoint *)point dragTypes:(NSSet *)types { - NSView *hitView = [super _hitTest:aPoint dragTypes:types]; - if (!hitView && [[self superview] mouse:*aPoint inRect:[self frame]]) { + NSView *hitView = [super _hitTest:point dragTypes:types]; + if (!hitView && [[self superview] mouse:*point inRect:[self frame]]) return self; - } else { - return hitView; - } + return hitView; } - (BOOL)acceptsFirstResponder { - return [[[self mainFrame] frameView] acceptsFirstResponder]; + if (_private->usesDocumentViews) + return [[[self mainFrame] frameView] acceptsFirstResponder]; + + // FIXME (Viewless): Need more code from WebHTMLView here. + return YES; } - (BOOL)becomeFirstResponder { - if (_private->becomingFirstResponder) { - // Fix for unrepro infinite recursion reported in radar 4448181. If we hit this assert on - // a debug build, we should figure out what causes the problem and do a better fix. - ASSERT_NOT_REACHED(); - return NO; - } - - // This works together with setNextKeyView to splice the WebView into - // the key loop similar to the way NSScrollView does this. Note that - // WebFrameView has very similar code. - NSWindow *window = [self window]; - WebFrameView *mainFrameView = [[self mainFrame] frameView]; + if (_private->usesDocumentViews) { + if (_private->becomingFirstResponder) { + // Fix for unrepro infinite recursion reported in Radar 4448181. If we hit this assert on + // a debug build, we should figure out what causes the problem and do a better fix. + ASSERT_NOT_REACHED(); + return NO; + } + + // This works together with setNextKeyView to splice the WebView into + // the key loop similar to the way NSScrollView does this. Note that + // WebFrameView has very similar code. + NSWindow *window = [self window]; + WebFrameView *mainFrameView = [[self mainFrame] frameView]; + + NSResponder *previousFirstResponder = [[self window] _oldFirstResponderBeforeBecoming]; + BOOL fromOutside = ![previousFirstResponder isKindOfClass:[NSView class]] || (![(NSView *)previousFirstResponder isDescendantOf:self] && previousFirstResponder != self); + + if ([window keyViewSelectionDirection] == NSSelectingPrevious) { + NSView *previousValidKeyView = [self previousValidKeyView]; + if (previousValidKeyView != self && previousValidKeyView != mainFrameView) { + _private->becomingFirstResponder = YES; + _private->becomingFirstResponderFromOutside = fromOutside; + [window makeFirstResponder:previousValidKeyView]; + _private->becomingFirstResponderFromOutside = NO; + _private->becomingFirstResponder = NO; + return YES; + } + return NO; + } - NSResponder *previousFirstResponder = [[self window] _oldFirstResponderBeforeBecoming]; - BOOL fromOutside = ![previousFirstResponder isKindOfClass:[NSView class]] || (![(NSView *)previousFirstResponder isDescendantOf:self] && previousFirstResponder != self); - - if ([window keyViewSelectionDirection] == NSSelectingPrevious) { - NSView *previousValidKeyView = [self previousValidKeyView]; - if ((previousValidKeyView != self) && (previousValidKeyView != mainFrameView)) { + if ([mainFrameView acceptsFirstResponder]) { _private->becomingFirstResponder = YES; _private->becomingFirstResponderFromOutside = fromOutside; - [window makeFirstResponder:previousValidKeyView]; + [window makeFirstResponder:mainFrameView]; _private->becomingFirstResponderFromOutside = NO; _private->becomingFirstResponder = NO; return YES; - } else { - return NO; - } + } + + return NO; } - - if ([mainFrameView acceptsFirstResponder]) { - _private->becomingFirstResponder = YES; - _private->becomingFirstResponderFromOutside = fromOutside; - [window makeFirstResponder:mainFrameView]; - _private->becomingFirstResponderFromOutside = NO; - _private->becomingFirstResponder = NO; - return YES; - } - - return NO; + + // FIXME (Viewless): Need more code from WebHTMLView here. + return YES; } - (NSView *)_webcore_effectiveFirstResponder { - WebFrameView *frameView = [[self mainFrame] frameView]; - return frameView ? [frameView _webcore_effectiveFirstResponder] : [super _webcore_effectiveFirstResponder]; + if (_private && _private->usesDocumentViews) { + if (WebFrameView *frameView = [[self mainFrame] frameView]) + return [frameView _webcore_effectiveFirstResponder]; + } + return [super _webcore_effectiveFirstResponder]; } -- (void)setNextKeyView:(NSView *)aView +- (void)setNextKeyView:(NSView *)view { - // This works together with becomeFirstResponder to splice the WebView into - // the key loop similar to the way NSScrollView does this. Note that - // WebFrameView has very similar code. - WebFrameView *mainFrameView = [[self mainFrame] frameView]; - if (mainFrameView != nil) { - [mainFrameView setNextKeyView:aView]; - } else { - [super setNextKeyView:aView]; + if (_private && _private->usesDocumentViews) { + // This works together with becomeFirstResponder to splice the WebView into + // the key loop similar to the way NSScrollView does this. Note that + // WebFrameView has similar code. + if (WebFrameView *mainFrameView = [[self mainFrame] frameView]) { + [mainFrameView setNextKeyView:view]; + return; + } } + + [super setNextKeyView:view]; } -static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag) +static WebFrame *incrementFrame(WebFrame *frame, BOOL forward, BOOL wrapFlag) { - Frame* coreFrame = core(curr); + Frame* coreFrame = core(frame); return kit(forward ? coreFrame->tree()->traverseNextWithWrap(wrapFlag) : coreFrame->tree()->traversePreviousWithWrap(wrapFlag)); @@ -3349,7 +3264,6 @@ static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag) { if (!_private->page) return 0.0; - return _private->page->progress()->estimatedProgress(); } @@ -3487,6 +3401,117 @@ static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag) return _private->currentNodeHighlight; } +- (NSView *)previousValidKeyView +{ + NSView *result = [super previousValidKeyView]; + + // Work around AppKit bug 6905484. If the result is a view that's inside this one, it's + // possible it is the wrong answer, because the fact that it's a descendant causes the + // code that implements key view redirection to fail; this means we won't redirect to + // the toolbar, for example, when we hit the edge of a window. Since the bug is specific + // to cases where the receiver of previousValidKeyView is an ancestor of the last valid + // key view in the loop, we can sidestep it by walking along previous key views until + // we find one that is not a superview, then using that to call previousValidKeyView. + + if (![result isDescendantOf:self]) + return result; + + // Use a visited set so we don't loop indefinitely when walking crazy key loops. + // AppKit uses such sets internally and we want our loop to be as robust as its loops. + RetainPtr<CFMutableSetRef> visitedViews = CFSetCreateMutable(0, 0, 0); + CFSetAddValue(visitedViews.get(), result); + + NSView *previousView = self; + do { + CFSetAddValue(visitedViews.get(), previousView); + previousView = [previousView previousKeyView]; + if (!previousView || CFSetGetValue(visitedViews.get(), previousView)) + return result; + } while ([result isDescendantOf:previousView]); + return [previousView previousValidKeyView]; +} + +- (void)mouseDown:(NSEvent *)event +{ + // FIXME (Viewless): This method should be shared with WebHTMLView, which needs to + // do the same work in the usesDocumentViews case. We don't want to maintain two + // duplicate copies of this method. + + if (_private->usesDocumentViews) { + [super mouseDown:event]; + return; + } + + // There's a chance that responding to this event will run a nested event loop, and + // fetching a new event might release the old one. Retaining and then autoreleasing + // the current event prevents that from causing a problem inside WebKit or AppKit code. + [[event retain] autorelease]; + + RetainPtr<WebView> protector = self; + if ([[self inputContext] wantsToHandleMouseEvents] && [[self inputContext] handleMouseEvent:event]) + return; + + _private->handlingMouseDownEvent = YES; + + // Record the mouse down position so we can determine drag hysteresis. + [self _setMouseDownEvent:event]; + + NSInputManager *currentInputManager = [NSInputManager currentInputManager]; + if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:event]) + goto done; + + [_private->completionController endRevertingChange:NO moveLeft:NO]; + + // If the web page handles the context menu event and menuForEvent: returns nil, we'll get control click events here. + // We don't want to pass them along to KHTML a second time. + if (!([event modifierFlags] & NSControlKeyMask)) { + _private->ignoringMouseDraggedEvents = NO; + + // Don't do any mouseover while the mouse is down. + [self _cancelUpdateMouseoverTimer]; + + // Let WebCore get a chance to deal with the event. This will call back to us + // to start the autoscroll timer if appropriate. + if (Frame* frame = [self _mainCoreFrame]) + frame->eventHandler()->mouseDown(event); + } + +done: + _private->handlingMouseDownEvent = NO; +} + +- (void)mouseUp:(NSEvent *)event +{ + // FIXME (Viewless): This method should be shared with WebHTMLView, which needs to + // do the same work in the usesDocumentViews case. We don't want to maintain two + // duplicate copies of this method. + + if (_private->usesDocumentViews) { + [super mouseUp:event]; + return; + } + + // There's a chance that responding to this event will run a nested event loop, and + // fetching a new event might release the old one. Retaining and then autoreleasing + // the current event prevents that from causing a problem inside WebKit or AppKit code. + [[event retain] autorelease]; + + [self _setMouseDownEvent:nil]; + + NSInputManager *currentInputManager = [NSInputManager currentInputManager]; + if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:event]) + return; + + [self retain]; + + [self _stopAutoscrollTimer]; + if (Frame* frame = [self _mainCoreFrame]) + frame->eventHandler()->mouseUp(event); + [self _updateMouseoverWithFakeEvent]; + + [self release]; +} + @end @implementation WebView (WebIBActions) @@ -3627,6 +3652,13 @@ static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag) [menuItem setState:checkMark ? NSOnState : NSOffState]; } return retVal; + } else if (action == @selector(toggleSmartInsertDelete:)) { + BOOL checkMark = [self smartInsertDeleteEnabled]; + if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { + NSMenuItem *menuItem = (NSMenuItem *)item; + [menuItem setState:checkMark ? NSOnState : NSOffState]; + } + return YES; #ifndef BUILDING_ON_TIGER } else if (action == @selector(toggleGrammarChecking:)) { BOOL checkMark = [self isGrammarCheckingEnabled]; @@ -3636,6 +3668,43 @@ static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag) } return YES; #endif +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + } else if (action == @selector(toggleAutomaticQuoteSubstitution:)) { + BOOL checkMark = [self isAutomaticQuoteSubstitutionEnabled]; + if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { + NSMenuItem *menuItem = (NSMenuItem *)item; + [menuItem setState:checkMark ? NSOnState : NSOffState]; + } + return YES; + } else if (action == @selector(toggleAutomaticLinkDetection:)) { + BOOL checkMark = [self isAutomaticLinkDetectionEnabled]; + if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { + NSMenuItem *menuItem = (NSMenuItem *)item; + [menuItem setState:checkMark ? NSOnState : NSOffState]; + } + return YES; + } else if (action == @selector(toggleAutomaticDashSubstitution:)) { + BOOL checkMark = [self isAutomaticDashSubstitutionEnabled]; + if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { + NSMenuItem *menuItem = (NSMenuItem *)item; + [menuItem setState:checkMark ? NSOnState : NSOffState]; + } + return YES; + } else if (action == @selector(toggleAutomaticTextReplacement:)) { + BOOL checkMark = [self isAutomaticTextReplacementEnabled]; + if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { + NSMenuItem *menuItem = (NSMenuItem *)item; + [menuItem setState:checkMark ? NSOnState : NSOffState]; + } + return YES; + } else if (action == @selector(toggleAutomaticSpellingCorrection:)) { + BOOL checkMark = [self isAutomaticSpellingCorrectionEnabled]; + if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { + NSMenuItem *menuItem = (NSMenuItem *)item; + [menuItem setState:checkMark ? NSOnState : NSOffState]; + } + return YES; +#endif } FOR_EACH_RESPONDER_SELECTOR(VALIDATE) @@ -3737,15 +3806,21 @@ static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag) return; _private->hoverFeedbackSuspended = newValue; - id <WebDocumentView> documentView = [[[self mainFrame] frameView] documentView]; - // FIXME: in a perfect world we'd do this in a general way that worked with any document view, - // such as by calling a protocol method or using respondsToSelector or sending a notification. - // But until there is any need for these more general solutions, we'll just hardwire it to work - // with WebHTMLView. - // Note that _hoverFeedbackSuspendedChanged needs to be called only on the main WebHTMLView, not - // on each subframe separately. - if ([documentView isKindOfClass:[WebHTMLView class]]) - [(WebHTMLView *)documentView _hoverFeedbackSuspendedChanged]; + + if (_private->usesDocumentViews) { + id <WebDocumentView> documentView = [[[self mainFrame] frameView] documentView]; + // FIXME: in a perfect world we'd do this in a general way that worked with any document view, + // such as by calling a protocol method or using respondsToSelector or sending a notification. + // But until there is any need for these more general solutions, we'll just hardwire it to work + // with WebHTMLView. + // Note that _hoverFeedbackSuspendedChanged needs to be called only on the main WebHTMLView, not + // on each subframe separately. + if ([documentView isKindOfClass:[WebHTMLView class]]) + [(WebHTMLView *)documentView _hoverFeedbackSuspendedChanged]; + return; + } + + [self _updateMouseoverWithFakeEvent]; } - (BOOL)isHoverFeedbackSuspended @@ -3803,13 +3878,13 @@ static WebFrame *incrementFrame(WebFrame *curr, BOOL forward, BOOL wrapFlag) - (BOOL)shouldClose { - Frame* coreFrame = core([self mainFrame]); + Frame* coreFrame = [self _mainCoreFrame]; if (!coreFrame) return YES; return coreFrame->shouldClose(); } -static NSAppleEventDescriptor* aeDescFromJSValue(ExecState* exec, JSValuePtr jsValue) +static NSAppleEventDescriptor* aeDescFromJSValue(ExecState* exec, JSValue jsValue) { NSAppleEventDescriptor* aeDesc = 0; if (jsValue.isBoolean()) @@ -3851,7 +3926,7 @@ static NSAppleEventDescriptor* aeDescFromJSValue(ExecState* exec, JSValuePtr jsV return aeDesc; } } - JSValuePtr primitive = object->toPrimitive(exec); + JSValue primitive = object->toPrimitive(exec); if (exec->hadException()) { exec->clearException(); return [NSAppleEventDescriptor nullDescriptor]; @@ -3866,15 +3941,15 @@ static NSAppleEventDescriptor* aeDescFromJSValue(ExecState* exec, JSValuePtr jsV - (NSAppleEventDescriptor *)aeDescByEvaluatingJavaScriptFromString:(NSString *)script { - Frame* coreFrame = core([self mainFrame]); + Frame* coreFrame = [self _mainCoreFrame]; if (!coreFrame) return nil; if (!coreFrame->document()) return nil; - JSValuePtr result = coreFrame->loader()->executeScript(script, true).jsValue(); + JSValue result = coreFrame->loader()->executeScript(script, true).jsValue(); if (!result) // FIXME: pass errors return 0; - JSLock lock(false); + JSLock lock(SilenceAssertionsOnly); return aeDescFromJSValue(coreFrame->script()->globalObject()->globalExec(), result); } @@ -4215,7 +4290,7 @@ static NSAppleEventDescriptor* aeDescFromJSValue(ExecState* exec, JSValuePtr jsV if (!coreFrame) return; - coreFrame->selection()->setSelectedRange([range _range], core(selectionAffinity), true); + coreFrame->selection()->setSelectedRange(core(range), core(selectionAffinity), true); } } @@ -4241,7 +4316,7 @@ static NSAppleEventDescriptor* aeDescFromJSValue(ExecState* exec, JSValuePtr jsV _private->editable = flag; if (!_private->tabKeyCyclesThroughElementsChanged && _private->page) _private->page->setTabKeyCyclesThroughElements(!flag); - Frame* mainFrame = core([self mainFrame]); + Frame* mainFrame = [self _mainCoreFrame]; if (mainFrame) { if (flag) { mainFrame->applyEditingStyleToBodyElement(); @@ -4273,7 +4348,10 @@ static NSAppleEventDescriptor* aeDescFromJSValue(ExecState* exec, JSValuePtr jsV - (void)setSmartInsertDeleteEnabled:(BOOL)flag { - _private->smartInsertDeleteEnabled = flag; + if (_private->smartInsertDeleteEnabled != flag) { + _private->smartInsertDeleteEnabled = flag; + [[NSUserDefaults standardUserDefaults] setBool:_private->smartInsertDeleteEnabled forKey:WebSmartInsertDeleteEnabled]; + } if (flag) [self setSelectTrailingWhitespaceEnabled:false]; } @@ -4393,10 +4471,13 @@ static NSAppleEventDescriptor* aeDescFromJSValue(ExecState* exec, JSValuePtr jsV grammarCheckingEnabled = flag; [[NSUserDefaults standardUserDefaults] setBool:grammarCheckingEnabled forKey:WebGrammarCheckingEnabled]; - // FIXME 4811447: workaround for lack of API +#ifndef BUILDING_ON_LEOPARD + [[NSSpellChecker sharedSpellChecker] updatePanels]; +#else NSSpellChecker *spellChecker = [NSSpellChecker sharedSpellChecker]; if ([spellChecker respondsToSelector:@selector(_updateGrammar)]) [spellChecker performSelector:@selector(_updateGrammar)]; +#endif // We call _preflightSpellChecker when turning continuous spell checking on, but we don't need to do that here // because grammar checking only occurs on code paths that already preflight spell checking appropriately. @@ -4414,6 +4495,129 @@ static NSAppleEventDescriptor* aeDescFromJSValue(ExecState* exec, JSValuePtr jsV @end +@implementation WebView (WebViewTextChecking) + +- (BOOL)isAutomaticQuoteSubstitutionEnabled +{ +#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) + return NO; +#else + return automaticQuoteSubstitutionEnabled; +#endif +} + +- (BOOL)isAutomaticLinkDetectionEnabled +{ +#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) + return NO; +#else + return automaticLinkDetectionEnabled; +#endif +} + +- (BOOL)isAutomaticDashSubstitutionEnabled +{ +#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) + return NO; +#else + return automaticDashSubstitutionEnabled; +#endif +} + +- (BOOL)isAutomaticTextReplacementEnabled +{ +#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) + return NO; +#else + return automaticTextReplacementEnabled; +#endif +} + +- (BOOL)isAutomaticSpellingCorrectionEnabled +{ +#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) + return NO; +#else + return automaticSpellingCorrectionEnabled; +#endif +} + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + +- (void)setAutomaticQuoteSubstitutionEnabled:(BOOL)flag +{ + if (automaticQuoteSubstitutionEnabled == flag) + return; + automaticQuoteSubstitutionEnabled = flag; + [[NSUserDefaults standardUserDefaults] setBool:automaticQuoteSubstitutionEnabled forKey:WebAutomaticQuoteSubstitutionEnabled]; + [[NSSpellChecker sharedSpellChecker] updatePanels]; +} + +- (void)toggleAutomaticQuoteSubstitution:(id)sender +{ + [self setAutomaticQuoteSubstitutionEnabled:![self isAutomaticQuoteSubstitutionEnabled]]; +} + +- (void)setAutomaticLinkDetectionEnabled:(BOOL)flag +{ + if (automaticLinkDetectionEnabled == flag) + return; + automaticLinkDetectionEnabled = flag; + [[NSUserDefaults standardUserDefaults] setBool:automaticLinkDetectionEnabled forKey:WebAutomaticLinkDetectionEnabled]; + [[NSSpellChecker sharedSpellChecker] updatePanels]; +} + +- (void)toggleAutomaticLinkDetection:(id)sender +{ + [self setAutomaticLinkDetectionEnabled:![self isAutomaticLinkDetectionEnabled]]; +} + +- (void)setAutomaticDashSubstitutionEnabled:(BOOL)flag +{ + if (automaticDashSubstitutionEnabled == flag) + return; + automaticDashSubstitutionEnabled = flag; + [[NSUserDefaults standardUserDefaults] setBool:automaticDashSubstitutionEnabled forKey:WebAutomaticDashSubstitutionEnabled]; + [[NSSpellChecker sharedSpellChecker] updatePanels]; +} + +- (void)toggleAutomaticDashSubstitution:(id)sender +{ + [self setAutomaticDashSubstitutionEnabled:![self isAutomaticDashSubstitutionEnabled]]; +} + +- (void)setAutomaticTextReplacementEnabled:(BOOL)flag +{ + if (automaticTextReplacementEnabled == flag) + return; + automaticTextReplacementEnabled = flag; + [[NSUserDefaults standardUserDefaults] setBool:automaticTextReplacementEnabled forKey:WebAutomaticTextReplacementEnabled]; + [[NSSpellChecker sharedSpellChecker] updatePanels]; +} + +- (void)toggleAutomaticTextReplacement:(id)sender +{ + [self setAutomaticTextReplacementEnabled:![self isAutomaticTextReplacementEnabled]]; +} + +- (void)setAutomaticSpellingCorrectionEnabled:(BOOL)flag +{ + if (automaticSpellingCorrectionEnabled == flag) + return; + automaticSpellingCorrectionEnabled = flag; + [[NSUserDefaults standardUserDefaults] setBool:automaticSpellingCorrectionEnabled forKey:WebAutomaticSpellingCorrectionEnabled]; + [[NSSpellChecker sharedSpellChecker] updatePanels]; +} + +- (void)toggleAutomaticSpellingCorrection:(id)sender +{ + [self setAutomaticSpellingCorrectionEnabled:![self isAutomaticSpellingCorrectionEnabled]]; +} + +#endif + +@end + @implementation WebView (WebViewUndoableEditing) - (void)replaceSelectionWithNode:(DOMNode *)node @@ -4508,6 +4712,22 @@ FOR_EACH_RESPONDER_SELECTOR(FORWARD) [[self _selectedOrMainFrame] _replaceSelectionWithNode:node selectReplacement:YES smartReplace:NO matchStyle:matchStyle]; } +- (BOOL)_selectionIsCaret +{ + Frame* coreFrame = core([self _selectedOrMainFrame]); + if (!coreFrame) + return NO; + return coreFrame->selection()->isCaret(); +} + +- (BOOL)_selectionIsAll +{ + Frame* coreFrame = core([self _selectedOrMainFrame]); + if (!coreFrame) + return NO; + return coreFrame->selection()->isAll(MayLeaveEditableContent); +} + @end static WebFrameView *containingFrameView(NSView *view) @@ -4524,7 +4744,7 @@ static WebFrameView *containingFrameView(NSView *view) if (s_didSetCacheModel && cacheModel == s_cacheModel) return; - NSString *nsurlCacheDirectory = [(NSString *)WKCopyFoundationCacheDirectory() autorelease]; + NSString *nsurlCacheDirectory = (NSString *)WebCFAutorelease(WKCopyFoundationCacheDirectory()); if (!nsurlCacheDirectory) nsurlCacheDirectory = NSHomeDirectory(); @@ -4773,6 +4993,7 @@ static WebFrameView *containingFrameView(NSView *view) { if (_private->closed) return nil; + ASSERT(_private->usesDocumentViews); NSView *view = [self hitTest:[[self superview] convertPoint:point fromView:nil]]; if (![view isDescendantOf:[[self mainFrame] frameView]]) return nil; @@ -4878,6 +5099,18 @@ static WebFrameView *containingFrameView(NSView *view) (void)HISearchWindowShow((CFStringRef)selectedString, kNilOptions); } + +#if USE(ACCELERATED_COMPOSITING) +- (void)_clearLayerSyncLoopObserver +{ + if (!_private->layerSyncRunLoopObserver) + return; + + CFRunLoopObserverInvalidate(_private->layerSyncRunLoopObserver); + CFRelease(_private->layerSyncRunLoopObserver); + _private->layerSyncRunLoopObserver = 0; +} +#endif @end @implementation WebView (WebViewInternal) @@ -4887,6 +5120,7 @@ static WebFrameView *containingFrameView(NSView *view) return _private->becomingFirstResponderFromOutside; } +#if ENABLE(ICONDATABASE) - (void)_receivedIconChangedNotification:(NSNotification *)notification { // Get the URL for this notification @@ -4927,6 +5161,7 @@ static WebFrameView *containingFrameView(NSView *view) [self _didChangeValueForKey:_WebMainFrameIconKey]; } +#endif // ENABLE(ICONDATABASE) // Get the appropriate user-agent string for a particular URL. - (WebCore::String)_userAgentForURL:(const WebCore::KURL&)url @@ -5009,536 +5244,230 @@ static WebFrameView *containingFrameView(NSView *view) return _private->_keyboardUIMode; } -@end - -// We use these functions to call the delegates and block exceptions. These functions are -// declared inside a WebView category to get direct access to the delegate data memebers, -// preventing more ObjC message dispatch and compensating for the expense of the @try/@catch. - -@implementation WebView (WebCallDelegateFunctions) - -typedef float (*ObjCMsgSendFPRet)(id, SEL, ...); -#if defined(__i386__) -static const ObjCMsgSendFPRet objc_msgSend_float_return = reinterpret_cast<ObjCMsgSendFPRet>(objc_msgSend_fpret); -#else -static const ObjCMsgSendFPRet objc_msgSend_float_return = reinterpret_cast<ObjCMsgSendFPRet>(objc_msgSend); -#endif - -static inline id CallDelegate(WebView *self, id delegate, SEL selector) -{ - if (!delegate || ![delegate respondsToSelector:selector]) - return nil; - if (!self->_private->catchesDelegateExceptions) - return objc_msgSend(delegate, selector, self); - @try { - return objc_msgSend(delegate, selector, self); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return nil; -} - -static inline id CallDelegate(WebView *self, id delegate, SEL selector, id object) -{ - if (!delegate || ![delegate respondsToSelector:selector]) - return nil; - if (!self->_private->catchesDelegateExceptions) - return objc_msgSend(delegate, selector, self, object); - @try { - return objc_msgSend(delegate, selector, self, object); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return nil; -} - -static inline id CallDelegate(WebView *self, id delegate, SEL selector, NSRect rect) -{ - if (!delegate || ![delegate respondsToSelector:selector]) - return nil; - if (!self->_private->catchesDelegateExceptions) - return reinterpret_cast<id (*)(id, SEL, WebView *, NSRect)>(objc_msgSend)(delegate, selector, self, rect); - @try { - return reinterpret_cast<id (*)(id, SEL, WebView *, NSRect)>(objc_msgSend)(delegate, selector, self, rect); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return nil; -} - -static inline id CallDelegate(WebView *self, id delegate, SEL selector, id object1, id object2) -{ - if (!delegate || ![delegate respondsToSelector:selector]) - return nil; - if (!self->_private->catchesDelegateExceptions) - return objc_msgSend(delegate, selector, self, object1, object2); - @try { - return objc_msgSend(delegate, selector, self, object1, object2); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return nil; -} - -static inline id CallDelegate(WebView *self, id delegate, SEL selector, id object, BOOL boolean) -{ - if (!delegate || ![delegate respondsToSelector:selector]) - return nil; - if (!self->_private->catchesDelegateExceptions) - return objc_msgSend(delegate, selector, self, object, boolean); - @try { - return objc_msgSend(delegate, selector, self, object, boolean); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return nil; -} - -static inline id CallDelegate(WebView *self, id delegate, SEL selector, id object1, id object2, id object3) -{ - if (!delegate || ![delegate respondsToSelector:selector]) - return nil; - if (!self->_private->catchesDelegateExceptions) - return objc_msgSend(delegate, selector, self, object1, object2, object3); - @try { - return objc_msgSend(delegate, selector, self, object1, object2, object3); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return nil; -} - -static inline id CallDelegate(WebView *self, id delegate, SEL selector, id object, NSUInteger integer) -{ - if (!delegate || ![delegate respondsToSelector:selector]) - return nil; - if (!self->_private->catchesDelegateExceptions) - return objc_msgSend(delegate, selector, self, object, integer); - @try { - return objc_msgSend(delegate, selector, self, object, integer); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return nil; -} - -static inline float CallDelegateReturningFloat(WebView *self, id delegate, SEL selector) +- (void)_setInsertionPasteboard:(NSPasteboard *)pasteboard { - if (!delegate || ![delegate respondsToSelector:selector]) - return 0.0f; - if (!self->_private->catchesDelegateExceptions) - return objc_msgSend_float_return(delegate, selector, self); - @try { - return objc_msgSend_float_return(delegate, selector, self); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return 0.0f; + _private->insertionPasteboard = pasteboard; } -static inline BOOL CallDelegateReturningBoolean(BOOL result, WebView *self, id delegate, SEL selector) +- (void)_setMouseDownEvent:(NSEvent *)event { - if (!delegate || ![delegate respondsToSelector:selector]) - return result; - if (!self->_private->catchesDelegateExceptions) - return reinterpret_cast<BOOL (*)(id, SEL, WebView *)>(objc_msgSend)(delegate, selector, self); - @try { - return reinterpret_cast<BOOL (*)(id, SEL, WebView *)>(objc_msgSend)(delegate, selector, self); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return result; -} + ASSERT(!event || [event type] == NSLeftMouseDown || [event type] == NSRightMouseDown || [event type] == NSOtherMouseDown); -static inline BOOL CallDelegateReturningBoolean(BOOL result, WebView *self, id delegate, SEL selector, id object) -{ - if (!delegate || ![delegate respondsToSelector:selector]) - return result; - if (!self->_private->catchesDelegateExceptions) - return reinterpret_cast<BOOL (*)(id, SEL, WebView *, id)>(objc_msgSend)(delegate, selector, self, object); - @try { - return reinterpret_cast<BOOL (*)(id, SEL, WebView *, id)>(objc_msgSend)(delegate, selector, self, object); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return result; -} + if (event == _private->mouseDownEvent) + return; -static inline BOOL CallDelegateReturningBoolean(BOOL result, WebView *self, id delegate, SEL selector, id object, BOOL boolean) -{ - if (!delegate || ![delegate respondsToSelector:selector]) - return result; - if (!self->_private->catchesDelegateExceptions) - return reinterpret_cast<BOOL (*)(id, SEL, WebView *, id, BOOL)>(objc_msgSend)(delegate, selector, self, object, boolean); - @try { - return reinterpret_cast<BOOL (*)(id, SEL, WebView *, id, BOOL)>(objc_msgSend)(delegate, selector, self, object, boolean); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return result; + [event retain]; + [_private->mouseDownEvent release]; + _private->mouseDownEvent = event; } -static inline BOOL CallDelegateReturningBoolean(BOOL result, WebView *self, id delegate, SEL selector, id object1, id object2) +- (void)_cancelUpdateMouseoverTimer { - if (!delegate || ![delegate respondsToSelector:selector]) - return result; - if (!self->_private->catchesDelegateExceptions) - return reinterpret_cast<BOOL (*)(id, SEL, WebView *, id, id)>(objc_msgSend)(delegate, selector, self, object1, object2); - @try { - return reinterpret_cast<BOOL (*)(id, SEL, WebView *, id, id)>(objc_msgSend)(delegate, selector, self, object1, object2); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); + if (_private->updateMouseoverTimer) { + CFRunLoopTimerInvalidate(_private->updateMouseoverTimer); + CFRelease(_private->updateMouseoverTimer); + _private->updateMouseoverTimer = NULL; } - return result; } -static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector) +- (void)_stopAutoscrollTimer { - if (!delegate) - return nil; - if (!self->_private->catchesDelegateExceptions) - return implementation(delegate, selector, self); - @try { - return implementation(delegate, selector, self); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return nil; + NSTimer *timer = _private->autoscrollTimer; + _private->autoscrollTimer = nil; + [_private->autoscrollTriggerEvent release]; + _private->autoscrollTriggerEvent = nil; + [timer invalidate]; + [timer release]; } -static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector, id object) ++ (void)_updateMouseoverWithEvent:(NSEvent *)event { - if (!delegate) - return nil; - if (!self->_private->catchesDelegateExceptions) - return implementation(delegate, selector, self, object); - @try { - return implementation(delegate, selector, self, object); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return nil; -} + WebView *oldView = lastMouseoverView; -static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector, id object1, id object2) -{ - if (!delegate) - return nil; - if (!self->_private->catchesDelegateExceptions) - return implementation(delegate, selector, self, object1, object2); - @try { - return implementation(delegate, selector, self, object1, object2); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return nil; -} + lastMouseoverView = nil; -static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector, id object1, id object2, id object3) -{ - if (!delegate) - return nil; - if (!self->_private->catchesDelegateExceptions) - return implementation(delegate, selector, self, object1, object2, object3); - @try { - return implementation(delegate, selector, self, object1, object2, object3); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); + NSView *contentView = [[event window] contentView]; + NSPoint locationForHitTest = [[contentView superview] convertPoint:[event locationInWindow] fromView:nil]; + for (NSView *hitView = [contentView hitTest:locationForHitTest]; hitView; hitView = [hitView superview]) { + if ([hitView isKindOfClass:[WebView class]]) { + lastMouseoverView = static_cast<WebView *>(hitView); + break; + } } - return nil; -} -static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector, id object1, id object2, id object3, id object4) -{ - if (!delegate) - return nil; - if (!self->_private->catchesDelegateExceptions) - return implementation(delegate, selector, self, object1, object2, object3, object4); - @try { - return implementation(delegate, selector, self, object1, object2, object3, object4); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); + if (lastMouseoverView && lastMouseoverView->_private->hoverFeedbackSuspended) + lastMouseoverView = nil; + + if (lastMouseoverView != oldView) { + if (Frame* oldCoreFrame = [oldView _mainCoreFrame]) { + NSEvent *oldViewEvent = [NSEvent mouseEventWithType:NSMouseMoved + location:NSMakePoint(-1, -1) + modifierFlags:[[NSApp currentEvent] modifierFlags] + timestamp:[NSDate timeIntervalSinceReferenceDate] + windowNumber:[[oldView window] windowNumber] + context:[[NSApp currentEvent] context] + eventNumber:0 clickCount:0 pressure:0]; + oldCoreFrame->eventHandler()->mouseMoved(oldViewEvent); + } } - return nil; -} -static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector, id object1, NSInteger integer, id object2) -{ - if (!delegate) - return nil; - if (!self->_private->catchesDelegateExceptions) - return implementation(delegate, selector, self, object1, integer, object2); - @try { - return implementation(delegate, selector, self, object1, integer, object2); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return nil; -} + if (!lastMouseoverView) + return; -static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector, id object1, NSInteger integer1, NSInteger integer2, id object2) -{ - if (!delegate) - return nil; - if (!self->_private->catchesDelegateExceptions) - return implementation(delegate, selector, self, object1, integer1, integer2, object2); - @try { - return implementation(delegate, selector, self, object1, integer1, integer2, object2); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return nil; + if (Frame* coreFrame = core([lastMouseoverView mainFrame])) + coreFrame->eventHandler()->mouseMoved(event); } -static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector, id object1, id object2, NSInteger integer, id object3) +- (void)_updateMouseoverWithFakeEvent { - if (!delegate) - return nil; - if (!self->_private->catchesDelegateExceptions) - return implementation(delegate, selector, self, object1, object2, integer, object3); - @try { - return implementation(delegate, selector, self, object1, object2, integer, object3); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return nil; + [self _cancelUpdateMouseoverTimer]; + + NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved + location:[[self window] convertScreenToBase:[NSEvent mouseLocation]] + modifierFlags:[[NSApp currentEvent] modifierFlags] + timestamp:[NSDate timeIntervalSinceReferenceDate] + windowNumber:[[self window] windowNumber] + context:[[NSApp currentEvent] context] + eventNumber:0 clickCount:0 pressure:0]; + + [[self class] _updateMouseoverWithEvent:fakeEvent]; } -static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector, id object1, NSInteger integer1, id object2, NSInteger integer2, id object3) +- (void)_setToolTip:(NSString *)toolTip { - if (!delegate) - return nil; - if (!self->_private->catchesDelegateExceptions) - return implementation(delegate, selector, self, object1, integer1, object2, integer2, object3); - @try { - return implementation(delegate, selector, self, object1, integer1, object2, integer2, object3); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); + if (_private->usesDocumentViews) { + id documentView = [[[self _selectedOrMainFrame] frameView] documentView]; + if ([documentView isKindOfClass:[WebHTMLView class]]) + [documentView _setToolTip:toolTip]; + return; } - return nil; -} -static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector, id object1, NSInteger integer, id object2, id object3, id object4) -{ - if (!delegate) - return nil; - if (!self->_private->catchesDelegateExceptions) - return implementation(delegate, selector, self, object1, integer, object2, object3, object4); - @try { - return implementation(delegate, selector, self, object1, integer, object2, object3, object4); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return nil; + // FIXME (Viewless): Code to handle tooltips needs to move into WebView. } -static inline id CallDelegate(IMP implementation, WebView *self, id delegate, SEL selector, id object1, NSTimeInterval interval, id object2, id object3) +- (void)_selectionChanged { - if (!delegate) - return nil; - if (!self->_private->catchesDelegateExceptions) - return implementation(delegate, selector, self, object1, interval, object2, object3); - @try { - return implementation(delegate, selector, self, object1, interval, object2, object3); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); + if (_private->usesDocumentViews) { + id documentView = [[[self _selectedOrMainFrame] frameView] documentView]; + if ([documentView isKindOfClass:[WebHTMLView class]]) + [documentView _selectionChanged]; + return; } - return nil; -} -id CallUIDelegate(WebView *self, SEL selector) -{ - return CallDelegate(self, self->_private->UIDelegate, selector); -} - -id CallUIDelegate(WebView *self, SEL selector, id object) -{ - return CallDelegate(self, self->_private->UIDelegate, selector, object); + // FIXME (Viewless): We'll need code here. } -id CallUIDelegate(WebView *self, SEL selector, id object, BOOL boolean) +- (Frame*)_mainCoreFrame { - return CallDelegate(self, self->_private->UIDelegate, selector, object, boolean); + return (_private && _private->page) ? _private->page->mainFrame() : 0; } -id CallUIDelegate(WebView *self, SEL selector, NSRect rect) -{ - return CallDelegate(self, self->_private->UIDelegate, selector, rect); -} - -id CallUIDelegate(WebView *self, SEL selector, id object1, id object2) -{ - return CallDelegate(self, self->_private->UIDelegate, selector, object1, object2); -} - -id CallUIDelegate(WebView *self, SEL selector, id object1, id object2, id object3) -{ - return CallDelegate(self, self->_private->UIDelegate, selector, object1, object2, object3); -} - -id CallUIDelegate(WebView *self, SEL selector, id object, NSUInteger integer) -{ - return CallDelegate(self, self->_private->UIDelegate, selector, object, integer); -} - -float CallUIDelegateReturningFloat(WebView *self, SEL selector) -{ - return CallDelegateReturningFloat(self, self->_private->UIDelegate, selector); -} - -BOOL CallUIDelegateReturningBoolean(BOOL result, WebView *self, SEL selector) -{ - return CallDelegateReturningBoolean(result, self, self->_private->UIDelegate, selector); -} - -BOOL CallUIDelegateReturningBoolean(BOOL result, WebView *self, SEL selector, id object) -{ - return CallDelegateReturningBoolean(result, self, self->_private->UIDelegate, selector, object); -} - -BOOL CallUIDelegateReturningBoolean(BOOL result, WebView *self, SEL selector, id object, BOOL boolean) -{ - return CallDelegateReturningBoolean(result, self, self->_private->UIDelegate, selector, object, boolean); -} - -BOOL CallUIDelegateReturningBoolean(BOOL result, WebView *self, SEL selector, id object1, id object2) -{ - return CallDelegateReturningBoolean(result, self, self->_private->UIDelegate, selector, object1, object2); -} - -id CallFrameLoadDelegate(IMP implementation, WebView *self, SEL selector) -{ - return CallDelegate(implementation, self, self->_private->frameLoadDelegate, selector); -} - -id CallFrameLoadDelegate(IMP implementation, WebView *self, SEL selector, id object) -{ - return CallDelegate(implementation, self, self->_private->frameLoadDelegate, selector, object); -} - -id CallFrameLoadDelegate(IMP implementation, WebView *self, SEL selector, id object1, id object2) -{ - return CallDelegate(implementation, self, self->_private->frameLoadDelegate, selector, object1, object2); -} - -id CallFrameLoadDelegate(IMP implementation, WebView *self, SEL selector, id object1, id object2, id object3) -{ - return CallDelegate(implementation, self, self->_private->frameLoadDelegate, selector, object1, object2, object3); -} - -id CallFrameLoadDelegate(IMP implementation, WebView *self, SEL selector, id object1, id object2, id object3, id object4) -{ - return CallDelegate(implementation, self, self->_private->frameLoadDelegate, selector, object1, object2, object3, object4); -} - -id CallFrameLoadDelegate(IMP implementation, WebView *self, SEL selector, id object1, NSTimeInterval interval, id object2, id object3) -{ - return CallDelegate(implementation, self, self->_private->frameLoadDelegate, selector, object1, interval, object2, object3); -} +#if USE(ACCELERATED_COMPOSITING) -id CallResourceLoadDelegate(IMP implementation, WebView *self, SEL selector, id object1, id object2) +- (BOOL)_needsOneShotDrawingSynchronization { - return CallDelegate(implementation, self, self->_private->resourceProgressDelegate, selector, object1, object2); + return _private->needsOneShotDrawingSynchronization; } -id CallResourceLoadDelegate(IMP implementation, WebView *self, SEL selector, id object1, id object2, id object3) +- (void)_setNeedsOneShotDrawingSynchronization:(BOOL)needsSynchronization { - return CallDelegate(implementation, self, self->_private->resourceProgressDelegate, selector, object1, object2, object3); + _private->needsOneShotDrawingSynchronization = needsSynchronization; } -id CallResourceLoadDelegate(IMP implementation, WebView *self, SEL selector, id object1, id object2, id object3, id object4) +- (void)_startedAcceleratedCompositingForFrame:(WebFrame*)webFrame { - return CallDelegate(implementation, self, self->_private->resourceProgressDelegate, selector, object1, object2, object3, object4); + BOOL entering = _private->acceleratedFramesCount == 0; + if (entering) + [self willChangeValueForKey:UsingAcceleratedCompositingProperty]; + ++_private->acceleratedFramesCount; + if (entering) + [self didChangeValueForKey:UsingAcceleratedCompositingProperty]; } -id CallResourceLoadDelegate(IMP implementation, WebView *self, SEL selector, id object1, NSInteger integer, id object2) +- (void)_stoppedAcceleratedCompositingForFrame:(WebFrame*)webFrame { - return CallDelegate(implementation, self, self->_private->resourceProgressDelegate, selector, object1, integer, object2); + BOOL leaving = _private->acceleratedFramesCount == 1; + ASSERT(_private->acceleratedFramesCount > 0); + + if (leaving) + [self willChangeValueForKey:UsingAcceleratedCompositingProperty]; + --_private->acceleratedFramesCount; + if (leaving) + [self didChangeValueForKey:UsingAcceleratedCompositingProperty]; } -id CallResourceLoadDelegate(IMP implementation, WebView *self, SEL selector, id object1, id object2, NSInteger integer, id object3) +- (BOOL)_syncCompositingChanges { - return CallDelegate(implementation, self, self->_private->resourceProgressDelegate, selector, object1, object2, integer, object3); -} + Frame* frame = [self _mainCoreFrame]; + if (frame && frame->view()) + return frame->view()->syncCompositingStateRecursive(); -BOOL CallResourceLoadDelegateReturningBoolean(BOOL result, IMP implementation, WebView *self, SEL selector, id object1, id object2) -{ - if (!self->_private->catchesDelegateExceptions) - return reinterpret_cast<BOOL (*)(id, SEL, WebView *, id, id)>(objc_msgSend)(self->_private->resourceProgressDelegate, selector, self, object1, object2); - @try { - return reinterpret_cast<BOOL (*)(id, SEL, WebView *, id, id)>(objc_msgSend)(self->_private->resourceProgressDelegate, selector, self, object1, object2); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return result; + return YES; } -id CallScriptDebugDelegate(IMP implementation, WebView *self, SEL selector, id object1, id object2, NSInteger integer, id object3) -{ - return CallDelegate(implementation, self, self->_private->scriptDebugDelegate, selector, object1, object2, integer, object3); -} +/* + The order of events with compositing updates is this: + + Start of runloop End of runloop + | | + --|-------------------------------------------------------|-- + ^ ^ ^ + | | | + NSWindow update, | CA commit + NSView drawing | + flush | + layerSyncRunLoopObserverCallBack + + To avoid flashing, we have to ensure that compositing changes (rendered via + the CoreAnimation rendering display link) appear on screen at the same time + as content painted into the window via the normal WebCore rendering path. + + CoreAnimation will commit any layer changes at the end of the runloop via + its "CA commit" observer. Those changes can then appear onscreen at any time + when the display link fires, which can result in unsynchronized rendering. + + To fix this, the GraphicsLayerCA code in WebCore does not change the CA + layer tree during style changes and layout; it stores up all changes and + commits them via syncCompositingState(). There are then two situations in + which we can call syncCompositingState(): + + 1. When painting. FrameView::paintContents() makes a call to syncCompositingState(). + + 2. When style changes/layout have made changes to the layer tree which do not + result in painting. In this case we need a run loop observer to do a + syncCompositingState() at an appropriate time. The observer will keep firing + until the time is right (essentially when there are no more pending layouts). + +*/ -id CallScriptDebugDelegate(IMP implementation, WebView *self, SEL selector, id object1, NSInteger integer1, id object2, NSInteger integer2, id object3) +static void layerSyncRunLoopObserverCallBack(CFRunLoopObserverRef, CFRunLoopActivity, void* info) { - return CallDelegate(implementation, self, self->_private->scriptDebugDelegate, selector, object1, integer1, object2, integer2, object3); + WebView* webView = reinterpret_cast<WebView*>(info); + if ([webView _syncCompositingChanges]) + [webView _clearLayerSyncLoopObserver]; } -id CallScriptDebugDelegate(IMP implementation, WebView *self, SEL selector, id object1, NSInteger integer, id object2, id object3, id object4) +- (void)_scheduleCompositingLayerSync { - return CallDelegate(implementation, self, self->_private->scriptDebugDelegate, selector, object1, integer, object2, object3, object4); -} + if (_private->layerSyncRunLoopObserver) + return; -id CallScriptDebugDelegate(IMP implementation, WebView *self, SEL selector, id object1, NSInteger integer1, NSInteger integer2, id object2) -{ - return CallDelegate(implementation, self, self->_private->scriptDebugDelegate, selector, object1, integer1, integer2, object2); -} + // Run after AppKit does its window update. If we do any painting, we'll commit + // layer changes from FrameView::paintContents(), otherwise we'll commit via + // _syncCompositingChanges when this observer fires. + const CFIndex runLoopOrder = NSDisplayWindowRunLoopOrdering + 1; -// The form delegate needs to have it's own implementation, because the first argument is never the WebView + // The WebView always outlives the observer, so no need to retain/release. + CFRunLoopObserverContext context = { 0, self, 0, 0, 0 }; -id CallFormDelegate(WebView *self, SEL selector, id object1, id object2) -{ - id delegate = self->_private->formDelegate; - if (!delegate || ![delegate respondsToSelector:selector]) - return nil; - if (!self->_private->catchesDelegateExceptions) - return objc_msgSend(delegate, selector, object1, object2); - @try { - return objc_msgSend(delegate, selector, object1, object2); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return nil; -} + _private->layerSyncRunLoopObserver = CFRunLoopObserverCreate(NULL, + kCFRunLoopBeforeWaiting | kCFRunLoopExit, true /* repeats */, + runLoopOrder, layerSyncRunLoopObserverCallBack, &context); -id CallFormDelegate(WebView *self, SEL selector, id object1, id object2, id object3, id object4, id object5) -{ - id delegate = self->_private->formDelegate; - if (!delegate || ![delegate respondsToSelector:selector]) - return nil; - if (!self->_private->catchesDelegateExceptions) - return objc_msgSend(delegate, selector, object1, object2, object3, object4, object5); - @try { - return objc_msgSend(delegate, selector, object1, object2, object3, object4, object5); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return nil; + CFRunLoopAddObserver(CFRunLoopGetCurrent(), _private->layerSyncRunLoopObserver, kCFRunLoopCommonModes); } -BOOL CallFormDelegateReturningBoolean(BOOL result, WebView *self, SEL selector, id object1, SEL selectorArg, id object2) -{ - id delegate = self->_private->formDelegate; - if (!delegate || ![delegate respondsToSelector:selector]) - return result; - if (!self->_private->catchesDelegateExceptions) - return reinterpret_cast<BOOL (*)(id, SEL, id, SEL, id)>(objc_msgSend)(delegate, selector, object1, selectorArg, object2); - @try { - return reinterpret_cast<BOOL (*)(id, SEL, id, SEL, id)>(objc_msgSend)(delegate, selector, object1, selectorArg, object2); - } @catch(id exception) { - ReportDiscardedDelegateException(selector, exception); - } - return result; -} +#endif @end diff --git a/WebKit/mac/WebView/WebViewData.h b/WebKit/mac/WebView/WebViewData.h new file mode 100644 index 0000000..91d83a7 --- /dev/null +++ b/WebKit/mac/WebView/WebViewData.h @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "WebTypesInternal.h" +#import "WebDelegateImplementationCaching.h" +#import <WebCore/PlatformString.h> +#import <WebCore/WebCoreKeyboardUIMode.h> +#import <wtf/HashMap.h> +#import <wtf/RetainPtr.h> + +namespace WebCore { + class Page; +} + +@class WebInspector; +@class WebNodeHighlight; +@class WebPluginDatabase; +@class WebPreferences; +@class WebTextCompletionController; +@protocol WebFormDelegate; + +extern BOOL applicationIsTerminating; +extern int pluginDatabaseClientCount; + +// FIXME: This should be renamed to WebViewData. +@interface WebViewPrivate : NSObject { +@public + WebCore::Page* page; + + id UIDelegate; + id UIDelegateForwarder; + id resourceProgressDelegate; + id downloadDelegate; + id policyDelegate; + id policyDelegateForwarder; + id frameLoadDelegate; + id frameLoadDelegateForwarder; + id <WebFormDelegate> formDelegate; + id editingDelegate; + id editingDelegateForwarder; + id scriptDebugDelegate; + + WebInspector *inspector; + WebNodeHighlight *currentNodeHighlight; + + BOOL allowsUndo; + + float zoomMultiplier; + + NSString *applicationNameForUserAgent; + WebCore::String userAgent; + BOOL userAgentOverridden; + + WebPreferences *preferences; + BOOL useSiteSpecificSpoofing; + + NSWindow *hostWindow; + + int programmaticFocusCount; + + WebResourceDelegateImplementationCache resourceLoadDelegateImplementations; + WebFrameLoadDelegateImplementationCache frameLoadDelegateImplementations; + WebScriptDebugDelegateImplementationCache scriptDebugDelegateImplementations; + + void *observationInfo; + + BOOL closed; + BOOL shouldCloseWithWindow; + BOOL mainFrameDocumentReady; + BOOL drawsBackground; + BOOL editable; + BOOL tabKeyCyclesThroughElementsChanged; + BOOL becomingFirstResponder; + BOOL becomingFirstResponderFromOutside; + BOOL hoverFeedbackSuspended; + BOOL usesPageCache; + BOOL catchesDelegateExceptions; + + NSColor *backgroundColor; + + NSString *mediaStyle; + + BOOL hasSpellCheckerDocumentTag; + NSInteger spellCheckerDocumentTag; + + BOOL smartInsertDeleteEnabled; + BOOL selectTrailingWhitespaceEnabled; + +#if ENABLE(DASHBOARD_SUPPORT) + BOOL dashboardBehaviorAlwaysSendMouseEventsToAllWindows; + BOOL dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns; + BOOL dashboardBehaviorAlwaysAcceptsFirstMouse; + BOOL dashboardBehaviorAllowWheelScrolling; +#endif + + // WebKit has both a global plug-in database and a separate, per WebView plug-in database. Dashboard uses the per WebView database. + WebPluginDatabase *pluginDatabase; + + HashMap<unsigned long, RetainPtr<id> > identifierMap; + + BOOL _keyboardUIModeAccessed; + WebCore::KeyboardUIMode _keyboardUIMode; + + BOOL shouldUpdateWhileOffscreen; + + // When this flag is set, we will not make any subviews underneath this WebView. This means no WebFrameViews and no WebHTMLViews. + BOOL usesDocumentViews; + +#if USE(ACCELERATED_COMPOSITING) + // When this flag is set, next time a WebHTMLView draws, it needs to temporarily disable screen updates + // so that the NSView drawing is visually synchronized with CALayer updates. + BOOL needsOneShotDrawingSynchronization; + // Number of WebHTMLViews using accelerated compositing. Used to implement _isUsingAcceleratedCompositing. + int acceleratedFramesCount; + // Run loop observer used to implement the compositing equivalent of -viewWillDraw + CFRunLoopObserverRef layerSyncRunLoopObserver; +#endif + + NSPasteboard *insertionPasteboard; + + NSSize lastLayoutSize; + + BOOL ignoringMouseDraggedEvents; + + NSEvent *mouseDownEvent; // Kept after handling the event. + BOOL handlingMouseDownEvent; + NSEvent *keyDownEvent; // Kept after handling the event. + + WebTextCompletionController *completionController; + + NSTimer *autoscrollTimer; + NSEvent *autoscrollTriggerEvent; + + CFRunLoopTimerRef updateMouseoverTimer; +} +@end diff --git a/WebKit/mac/WebView/WebViewData.mm b/WebKit/mac/WebView/WebViewData.mm new file mode 100644 index 0000000..48e7f6c --- /dev/null +++ b/WebKit/mac/WebView/WebViewData.mm @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2006 David Smith (catfish.man@gmail.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "WebViewData.h" + +#import "WebKitLogging.h" +#import "WebPreferenceKeysPrivate.h" +#import <WebCore/WebCoreObjCExtras.h> +#import <objc/objc-auto.h> +#import <runtime/InitializeThreading.h> + +BOOL applicationIsTerminating = NO; +int pluginDatabaseClientCount = 0; + +@implementation WebViewPrivate + ++ (void)initialize +{ + JSC::initializeThreading(); +#ifndef BUILDING_ON_TIGER + WebCoreObjCFinalizeOnMainThread(self); +#endif +} + +- (id)init +{ + self = [super init]; + if (!self) + return nil; + + allowsUndo = YES; + usesPageCache = YES; + shouldUpdateWhileOffscreen = YES; + + zoomMultiplier = 1; + +#if ENABLE(DASHBOARD_SUPPORT) + dashboardBehaviorAllowWheelScrolling = YES; +#endif + + shouldCloseWithWindow = objc_collecting_enabled(); + + smartInsertDeleteEnabled = ![[NSUserDefaults standardUserDefaults] objectForKey:WebSmartInsertDeleteEnabled] + || [[NSUserDefaults standardUserDefaults] boolForKey:WebSmartInsertDeleteEnabled]; + + + pluginDatabaseClientCount++; + + return self; +} + +- (void)dealloc +{ + ASSERT(applicationIsTerminating || !page); + ASSERT(applicationIsTerminating || !preferences); + ASSERT(!insertionPasteboard); + + [applicationNameForUserAgent release]; + [backgroundColor release]; + [inspector release]; + [currentNodeHighlight release]; + [hostWindow release]; + [policyDelegateForwarder release]; + [UIDelegateForwarder release]; + [frameLoadDelegateForwarder release]; + [editingDelegateForwarder release]; + [mediaStyle release]; + + [super dealloc]; +} + +- (void)finalize +{ + ASSERT_MAIN_THREAD(); + ASSERT(!insertionPasteboard); + + [super finalize]; +} + +@end diff --git a/WebKit/mac/WebView/WebViewInternal.h b/WebKit/mac/WebView/WebViewInternal.h index ad4f19c..b8266c5 100644 --- a/WebKit/mac/WebView/WebViewInternal.h +++ b/WebKit/mac/WebView/WebViewInternal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,28 +34,24 @@ #ifdef __cplusplus #import <WebCore/WebCoreKeyboardUIMode.h> -#endif -#ifdef __cplusplus namespace WebCore { - class KeyboardEvent; + class String; + class Frame; class KURL; + class KeyboardEvent; class Page; - class String; } -typedef WebCore::KeyboardEvent WebCoreKeyboardEvent; -typedef WebCore::Page WebCorePage; -#else -@class WebCoreKeyboardEvent; -@class WebCorePage; #endif @class WebBasePluginPackage; @class WebDownload; @class WebNodeHighlight; +#ifdef __cplusplus + @interface WebView (WebViewEditingExtras) -- (BOOL)_interceptEditingKeyEvent:(WebCoreKeyboardEvent *)event shouldSaveCommand:(BOOL)shouldSave; +- (BOOL)_interceptEditingKeyEvent:(WebCore::KeyboardEvent*)event shouldSaveCommand:(BOOL)shouldSave; - (BOOL)_shouldChangeSelectedDOMRange:(DOMRange *)currentRange toDOMRange:(DOMRange *)proposedRange affinity:(NSSelectionAffinity)selectionAffinity stillSelecting:(BOOL)flag; @end @@ -66,17 +62,48 @@ typedef WebCore::Page WebCorePage; @end @interface WebView (WebViewInternal) -#ifdef __cplusplus + +- (WebCore::Frame*)_mainCoreFrame; + - (WebCore::String)_userAgentForURL:(const WebCore::KURL&)url; - (WebCore::KeyboardUIMode)_keyboardUIMode; + +- (BOOL)_becomingFirstResponderFromOutside; + +#if ENABLE(ICONDATABASE) +- (void)_registerForIconNotification:(BOOL)listen; +- (void)_dispatchDidReceiveIconFromWebFrame:(WebFrame *)webFrame; +#endif + +- (void)_setMouseDownEvent:(NSEvent *)event; +- (void)_cancelUpdateMouseoverTimer; +- (void)_stopAutoscrollTimer; +- (void)_updateMouseoverWithFakeEvent; +- (void)_selectionChanged; +- (void)_setToolTip:(NSString *)toolTip; + +#if USE(ACCELERATED_COMPOSITING) +- (BOOL)_needsOneShotDrawingSynchronization; +- (void)_setNeedsOneShotDrawingSynchronization:(BOOL)needsSynchronization; +- (void)_startedAcceleratedCompositingForFrame:(WebFrame*)webFrame; +- (void)_stoppedAcceleratedCompositingForFrame:(WebFrame*)webFrame; +- (void)_scheduleCompositingLayerSync; #endif + @end -@interface WebView (WebViewMiscInternal) +#endif + +// FIXME: Temporary way to expose methods that are in the wrong category inside WebView. +@interface WebView (WebViewOtherInternal) + (void)_setCacheModel:(WebCacheModel)cacheModel; + (WebCacheModel)_cacheModel; -- (WebCorePage*)page; + +#ifdef __cplusplus +- (WebCore::Page*)page; +#endif + - (NSMenu *)_menuForElement:(NSDictionary *)element defaultItems:(NSArray *)items; - (id)_UIDelegateForwarder; - (id)_editingDelegateForwarder; @@ -123,12 +150,8 @@ typedef WebCore::Page WebCorePage; - (void)_addObject:(id)object forIdentifier:(unsigned long)identifier; - (id)_objectForIdentifier:(unsigned long)identifier; - (void)_removeObjectForIdentifier:(unsigned long)identifier; -- (BOOL)_becomingFirstResponderFromOutside; - -- (void)_registerForIconNotification:(BOOL)listen; -- (void)_dispatchDidReceiveIconFromWebFrame:(WebFrame *)webFrame; -- (void)_setZoomMultiplier:(float)m isTextOnly:(BOOL)isTextOnly; +- (void)_setZoomMultiplier:(float)multiplier isTextOnly:(BOOL)isTextOnly; - (float)_zoomMultiplier:(BOOL)isTextOnly; - (float)_realZoomMultiplier; - (BOOL)_realZoomMultiplierIsTextOnly; @@ -140,106 +163,9 @@ typedef WebCore::Page WebCorePage; - (IBAction)_resetZoom:(id)sender isTextOnly:(BOOL)isTextOnly; - (BOOL)_mustDrawUnionedRect:(NSRect)rect singleRects:(const NSRect *)rects count:(NSInteger)count; -- (void)_updateFocusedAndActiveStateForFrame:(WebFrame *)webFrame; + (BOOL)_canHandleRequest:(NSURLRequest *)request forMainFrame:(BOOL)forMainFrame; -#if USE(ACCELERATED_COMPOSITING) -- (BOOL)_needsOneShotDrawingSynchronization; -- (void)_setNeedsOneShotDrawingSynchronization:(BOOL)needsSynchronization; -- (void)_startedAcceleratedCompositingForFrame:(WebFrame*)webFrame; -- (void)_stoppedAcceleratedCompositingForFrame:(WebFrame*)webFrame; -#endif +- (void)_setInsertionPasteboard:(NSPasteboard *)pasteboard; @end - -typedef struct _WebResourceDelegateImplementationCache { - IMP didCancelAuthenticationChallengeFunc; - IMP didReceiveAuthenticationChallengeFunc; - IMP identifierForRequestFunc; - IMP willSendRequestFunc; - IMP didReceiveResponseFunc; - IMP didReceiveContentLengthFunc; - IMP didFinishLoadingFromDataSourceFunc; - IMP didFailLoadingWithErrorFromDataSourceFunc; - IMP didLoadResourceFromMemoryCacheFunc; - IMP willCacheResponseFunc; - IMP plugInFailedWithErrorFunc; - IMP shouldUseCredentialStorageFunc; -} WebResourceDelegateImplementationCache; - -typedef struct _WebFrameLoadDelegateImplementationCache { - IMP didClearWindowObjectForFrameFunc; - IMP windowScriptObjectAvailableFunc; - IMP didHandleOnloadEventsForFrameFunc; - IMP didReceiveServerRedirectForProvisionalLoadForFrameFunc; - IMP didCancelClientRedirectForFrameFunc; - IMP willPerformClientRedirectToURLDelayFireDateForFrameFunc; - IMP didChangeLocationWithinPageForFrameFunc; - IMP willCloseFrameFunc; - IMP didStartProvisionalLoadForFrameFunc; - IMP didReceiveTitleForFrameFunc; - IMP didCommitLoadForFrameFunc; - IMP didFailProvisionalLoadWithErrorForFrameFunc; - IMP didFailLoadWithErrorForFrameFunc; - IMP didFinishLoadForFrameFunc; - IMP didFirstLayoutInFrameFunc; - IMP didFirstVisuallyNonEmptyLayoutInFrameFunc; - IMP didReceiveIconForFrameFunc; - IMP didFinishDocumentLoadForFrameFunc; -} WebFrameLoadDelegateImplementationCache; - -typedef struct _WebScriptDebugDelegateImplementationCache { - BOOL didParseSourceExpectsBaseLineNumber; - IMP didParseSourceFunc; - IMP failedToParseSourceFunc; - IMP didEnterCallFrameFunc; - IMP willExecuteStatementFunc; - IMP willLeaveCallFrameFunc; - IMP exceptionWasRaisedFunc; -} WebScriptDebugDelegateImplementationCache; - -WebResourceDelegateImplementationCache* WebViewGetResourceLoadDelegateImplementations(WebView *webView); -WebFrameLoadDelegateImplementationCache* WebViewGetFrameLoadDelegateImplementations(WebView *webView); -WebScriptDebugDelegateImplementationCache* WebViewGetScriptDebugDelegateImplementations(WebView *webView); - -#ifdef __cplusplus - -id CallFormDelegate(WebView *, SEL, id, id); -id CallFormDelegate(WebView *self, SEL selector, id object1, id object2, id object3, id object4, id object5); -BOOL CallFormDelegateReturningBoolean(BOOL, WebView *, SEL, id, SEL, id); - -id CallUIDelegate(WebView *, SEL); -id CallUIDelegate(WebView *, SEL, id); -id CallUIDelegate(WebView *, SEL, NSRect); -id CallUIDelegate(WebView *, SEL, id, id); -id CallUIDelegate(WebView *, SEL, id, BOOL); -id CallUIDelegate(WebView *, SEL, id, id, id); -id CallUIDelegate(WebView *, SEL, id, NSUInteger); -float CallUIDelegateReturningFloat(WebView *, SEL); -BOOL CallUIDelegateReturningBoolean(BOOL, WebView *, SEL); -BOOL CallUIDelegateReturningBoolean(BOOL, WebView *, SEL, id); -BOOL CallUIDelegateReturningBoolean(BOOL, WebView *, SEL, id, id); -BOOL CallUIDelegateReturningBoolean(BOOL, WebView *, SEL, id, BOOL); - -id CallFrameLoadDelegate(IMP, WebView *, SEL); -id CallFrameLoadDelegate(IMP, WebView *, SEL, id); -id CallFrameLoadDelegate(IMP, WebView *, SEL, id, id); -id CallFrameLoadDelegate(IMP, WebView *, SEL, id, id, id); -id CallFrameLoadDelegate(IMP, WebView *, SEL, id, id, id, id); -id CallFrameLoadDelegate(IMP, WebView *, SEL, id, NSTimeInterval, id, id); - -id CallResourceLoadDelegate(IMP, WebView *, SEL, id, id); -id CallResourceLoadDelegate(IMP, WebView *, SEL, id, id, id); -id CallResourceLoadDelegate(IMP, WebView *, SEL, id, id, id, id); -id CallResourceLoadDelegate(IMP, WebView *, SEL, id, NSInteger, id); -id CallResourceLoadDelegate(IMP, WebView *, SEL, id, id, NSInteger, id); - -BOOL CallResourceLoadDelegateReturningBoolean(BOOL, IMP, WebView *, SEL, id, id); - -id CallScriptDebugDelegate(IMP, WebView *, SEL, id, id, NSInteger, id); -id CallScriptDebugDelegate(IMP, WebView *, SEL, id, NSInteger, id, NSInteger, id); -id CallScriptDebugDelegate(IMP, WebView *, SEL, id, NSInteger, id, id, id); -id CallScriptDebugDelegate(IMP, WebView *, SEL, id, NSInteger, NSInteger, id); - -#endif diff --git a/WebKit/mac/WebView/WebViewPrivate.h b/WebKit/mac/WebView/WebViewPrivate.h index ada0e01..362b2e6 100644 --- a/WebKit/mac/WebView/WebViewPrivate.h +++ b/WebKit/mac/WebView/WebViewPrivate.h @@ -206,12 +206,21 @@ typedef enum { /*! Could be worth adding to the API. - @method loadItemsFromOtherView: + @method _loadBackForwardListFromOtherView: @abstract Loads the view with the contents of the other view, including its backforward list. @param otherView The WebView from which to copy contents. */ - (void)_loadBackForwardListFromOtherView:(WebView *)otherView; + +/*! + @method _dispatchPendingLoadRequests: + @abstract Dispatches any pending load requests that have been scheduled because of recent DOM additions or style changes. + @discussion You only need to call this method if you require synchronous notification of loads through the resource load delegate. + Otherwise the resource load delegate will be notified about loads during a future run loop iteration. + */ +- (void)_dispatchPendingLoadRequests; + + (NSArray *)_supportedFileExtensions; /*! @@ -231,6 +240,13 @@ Could be worth adding to the API. + (NSString *)_standardUserAgentWithApplicationName:(NSString *)applicationName; +/*! + @method canCloseAllWebViews + @abstract Checks if all the open WebViews can be closed (by dispatching the beforeUnload event to the pages). + @result YES if all the WebViews can be closed. +*/ ++ (BOOL)canCloseAllWebViews; + // May well become public - (void)_setFormDelegate:(id<WebFormDelegate>)delegate; - (id<WebFormDelegate>)_formDelegate; @@ -241,6 +257,12 @@ Could be worth adding to the API. // until callers can be weaned off of it. - (void)_close; +// Indicates if the WebView is in the midst of a user gesture. +- (BOOL)_isProcessingUserGesture; + +// SPI for DumpRenderTree +- (void)_updateActiveState; + /*! @method _registerViewClass:representationClass:forURLScheme: @discussion Register classes that implement WebDocumentView and WebDocumentRepresentation respectively. @@ -295,8 +317,6 @@ Could be worth adding to the API. + (void)_setUsesTestModeFocusRingColor:(BOOL)f; + (BOOL)_usesTestModeFocusRingColor; -+ (NSString *)_minimumRequiredSafariBuildNumber; - /*! @method setAlwaysShowVerticalScroller: @result Forces the vertical scroller to be visible if flag is YES, otherwise @@ -369,15 +389,22 @@ Could be worth adding to the API. - (WebHistoryItem *)_globalHistoryItem; /*! - @method textIteratorForRect: - @param rectangle from which we want the WebTextIterator to load text from - @result a WebtextIterator object. + @method textIteratorForRect: + @param rect The rectangle of the document that we're interested in text from. + @result WebTextIterator object, initialized with a range that corresponds to + the passed-in rectangle. + @abstract This method gives the text for the approximate range of the document + corresponding to the rectangle. The range is determined by using hit testing at + the top left and bottom right of the rectangle. Because of that, there can be + text visible in the rectangle that is not included in the iterator. If you need + a guarantee of iterating all text that is visible, then you need to instead make + a WebTextIterator with a DOMRange that covers the entire document. */ - (WebTextIterator *)textIteratorForRect:(NSRect)rect; #if ENABLE_DASHBOARD_SUPPORT -// <rdar://problem/5217124> Clients other than dashboard, don't use this. -// Do not remove until Dashboard has moved off it +// <rdar://problem/5217124> Clients other than Dashboard, don't use this. +// As of this writing, Dashboard uses this on Tiger, but not on Leopard or newer. - (void)handleAuthenticationForResource:(id)identifier challenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource; #endif @@ -413,6 +440,9 @@ Could be worth adding to the API. // SPI for DumpRenderTree - (BOOL)_isUsingAcceleratedCompositing; +// Which pasteboard text is coming from in editing delegate methods such as shouldInsertNode. +- (NSPasteboard *)_insertionPasteboard; + @end @interface WebView (WebViewPrintingPrivate) @@ -447,11 +477,36 @@ Could be worth adding to the API. // FIXME: This method should be merged into WebIBActions when we're not in API freeze - (void)toggleGrammarChecking:(id)sender; #endif + +@end + +@interface WebView (WebViewTextChecking) + +- (BOOL)isAutomaticQuoteSubstitutionEnabled; +- (BOOL)isAutomaticLinkDetectionEnabled; +- (BOOL)isAutomaticDashSubstitutionEnabled; +- (BOOL)isAutomaticTextReplacementEnabled; +- (BOOL)isAutomaticSpellingCorrectionEnabled; +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +- (void)setAutomaticQuoteSubstitutionEnabled:(BOOL)flag; +- (void)toggleAutomaticQuoteSubstitution:(id)sender; +- (void)setAutomaticLinkDetectionEnabled:(BOOL)flag; +- (void)toggleAutomaticLinkDetection:(id)sender; +- (void)setAutomaticDashSubstitutionEnabled:(BOOL)flag; +- (void)toggleAutomaticDashSubstitution:(id)sender; +- (void)setAutomaticTextReplacementEnabled:(BOOL)flag; +- (void)toggleAutomaticTextReplacement:(id)sender; +- (void)setAutomaticSpellingCorrectionEnabled:(BOOL)flag; +- (void)toggleAutomaticSpellingCorrection:(id)sender; +#endif + @end @interface WebView (WebViewEditingInMail) - (void)_insertNewlineInQuotedContent; - (void)_replaceSelectionWithNode:(DOMNode *)node matchStyle:(BOOL)matchStyle; +- (BOOL)_selectionIsCaret; +- (BOOL)_selectionIsAll; @end @interface NSObject (WebFrameLoadDelegatePrivate) @@ -467,6 +522,9 @@ Could be worth adding to the API. - (void)webView:(WebView *)sender didFirstVisuallyNonEmptyLayoutInFrame:(WebFrame *)frame; +// For implementing the WebInspector's test harness +- (void)webView:(WebView *)webView didClearInspectorWindowObject:(WebScriptObject *)windowObject forFrame:(WebFrame *)frame; + @end @interface NSObject (WebResourceLoadDelegatePrivate) |