1/* 2 * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. 3 * Copyright (C) 2006 David Smith (catfish.man@gmail.com) 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30#import "WebViewInternal.h" 31#import "WebViewData.h" 32 33#import "DOMCSSStyleDeclarationInternal.h" 34#import "DOMNodeInternal.h" 35#import "DOMRangeInternal.h" 36#import "WebBackForwardListInternal.h" 37#import "WebBaseNetscapePluginView.h" 38#import "WebCache.h" 39#import "WebChromeClient.h" 40#import "WebContextMenuClient.h" 41#import "WebDOMOperationsPrivate.h" 42#import "WebDataSourceInternal.h" 43#import "WebDatabaseManagerInternal.h" 44#import "WebDefaultEditingDelegate.h" 45#import "WebDefaultPolicyDelegate.h" 46#import "WebDefaultUIDelegate.h" 47#import "WebDelegateImplementationCaching.h" 48#import "WebDocument.h" 49#import "WebDocumentInternal.h" 50#import "WebDownload.h" 51#import "WebDownloadInternal.h" 52#import "WebDragClient.h" 53#import "WebDynamicScrollBarsViewInternal.h" 54#import "WebEditingDelegate.h" 55#import "WebEditorClient.h" 56#import "WebFormDelegatePrivate.h" 57#import "WebFrameInternal.h" 58#import "WebFrameViewInternal.h" 59#import "WebGeolocationControllerClient.h" 60#import "WebGeolocationPositionInternal.h" 61#import "WebHTMLRepresentation.h" 62#import "WebHTMLViewInternal.h" 63#import "WebHistoryItemInternal.h" 64#import "WebIconDatabaseInternal.h" 65#import "WebInspector.h" 66#import "WebInspectorClient.h" 67#import "WebKitErrors.h" 68#import "WebKitLogging.h" 69#import "WebKitNSStringExtras.h" 70#import "WebKitStatisticsPrivate.h" 71#import "WebKitSystemBits.h" 72#import "WebKitVersionChecks.h" 73#import "WebLocalizableStrings.h" 74#import "WebNSDataExtras.h" 75#import "WebNSDataExtrasPrivate.h" 76#import "WebNSDictionaryExtras.h" 77#import "WebNSEventExtras.h" 78#import "WebNSObjectExtras.h" 79#import "WebNSPasteboardExtras.h" 80#import "WebNSPrintOperationExtras.h" 81#import "WebNSURLExtras.h" 82#import "WebNSURLRequestExtras.h" 83#import "WebNSUserDefaultsExtras.h" 84#import "WebNSViewExtras.h" 85#import "WebNodeHighlight.h" 86#import "WebPDFView.h" 87#import "WebPanelAuthenticationHandler.h" 88#import "WebPasteboardHelper.h" 89#import "WebPluginDatabase.h" 90#import "WebPluginHalterClient.h" 91#import "WebPolicyDelegate.h" 92#import "WebPreferenceKeysPrivate.h" 93#import "WebPreferencesPrivate.h" 94#import "WebScriptDebugDelegate.h" 95#import "WebScriptWorldInternal.h" 96#import "WebSystemInterface.h" 97#import "WebTextCompletionController.h" 98#import "WebTextIterator.h" 99#import "WebUIDelegate.h" 100#import "WebUIDelegatePrivate.h" 101#import "WebVideoFullscreenController.h" 102#import <CoreFoundation/CFSet.h> 103#import <Foundation/NSURLConnection.h> 104#import <WebCore/ApplicationCacheStorage.h> 105#import <WebCore/BackForwardList.h> 106#import <WebCore/Cache.h> 107#import <WebCore/ColorMac.h> 108#import <WebCore/Cursor.h> 109#import <WebCore/Document.h> 110#import <WebCore/DocumentLoader.h> 111#import <WebCore/DragController.h> 112#import <WebCore/DragData.h> 113#import <WebCore/Editor.h> 114#import <WebCore/EventHandler.h> 115#import <WebCore/ExceptionHandlers.h> 116#import <WebCore/FocusController.h> 117#import <WebCore/Frame.h> 118#import <WebCore/FrameLoader.h> 119#import <WebCore/FrameTree.h> 120#import <WebCore/FrameView.h> 121#import <WebCore/GCController.h> 122#import <WebCore/HTMLMediaElement.h> 123#import <WebCore/HTMLNames.h> 124#import <WebCore/HistoryItem.h> 125#import <WebCore/IconDatabase.h> 126#import <WebCore/Logging.h> 127#import <WebCore/MIMETypeRegistry.h> 128#import <WebCore/Page.h> 129#import <WebCore/PageCache.h> 130#import <WebCore/PageGroup.h> 131#import <WebCore/PlatformMouseEvent.h> 132#import <WebCore/ProgressTracker.h> 133#import <WebCore/RenderWidget.h> 134#import <WebCore/ResourceHandle.h> 135#import <WebCore/RuntimeApplicationChecks.h> 136#import <WebCore/ScriptController.h> 137#import <WebCore/ScriptValue.h> 138#import <WebCore/SecurityOrigin.h> 139#import <WebCore/SelectionController.h> 140#import <WebCore/Settings.h> 141#import <WebCore/TextResourceDecoder.h> 142#import <WebCore/ThreadCheck.h> 143#import <WebCore/WebCoreObjCExtras.h> 144#import <WebCore/WebCoreView.h> 145#import <WebCore/Widget.h> 146#import <WebKit/DOM.h> 147#import <WebKit/DOMExtensions.h> 148#import <WebKit/DOMPrivate.h> 149#import <WebKitSystemInterface.h> 150#import <mach-o/dyld.h> 151#import <objc/objc-auto.h> 152#import <objc/objc-runtime.h> 153#import <runtime/ArrayPrototype.h> 154#import <runtime/DateInstance.h> 155#import <runtime/InitializeThreading.h> 156#import <runtime/JSLock.h> 157#import <runtime/JSValue.h> 158#import <wtf/Assertions.h> 159#import <wtf/HashTraits.h> 160#import <wtf/RefCountedLeakCounter.h> 161#import <wtf/RefPtr.h> 162#import <wtf/StdLibExtras.h> 163 164#if ENABLE(DASHBOARD_SUPPORT) 165#import <WebKit/WebDashboardRegion.h> 166#endif 167 168#if ENABLE(CLIENT_BASED_GEOLOCATION) 169#import <WebCore/GeolocationController.h> 170#import <WebCore/GeolocationError.h> 171#endif 172 173@interface NSSpellChecker (WebNSSpellCheckerDetails) 174- (void)_preflightChosenSpellServer; 175@end 176 177@interface NSView (WebNSViewDetails) 178- (NSView *)_hitTest:(NSPoint *)aPoint dragTypes:(NSSet *)types; 179- (void)_autoscrollForDraggingInfo:(id)dragInfo timeDelta:(NSTimeInterval)repeatDelta; 180- (BOOL)_shouldAutoscrollForDraggingInfo:(id)dragInfo; 181@end 182 183@interface NSWindow (WebNSWindowDetails) 184- (id)_oldFirstResponderBeforeBecoming; 185@end 186 187using namespace WebCore; 188using namespace JSC; 189 190#if defined(__ppc__) || defined(__ppc64__) 191#define PROCESSOR "PPC" 192#elif defined(__i386__) || defined(__x86_64__) 193#define PROCESSOR "Intel" 194#else 195#error Unknown architecture 196#endif 197 198#define FOR_EACH_RESPONDER_SELECTOR(macro) \ 199macro(alignCenter) \ 200macro(alignJustified) \ 201macro(alignLeft) \ 202macro(alignRight) \ 203macro(capitalizeWord) \ 204macro(centerSelectionInVisibleArea) \ 205macro(changeAttributes) \ 206macro(changeBaseWritingDirection) \ 207macro(changeBaseWritingDirectionToLTR) \ 208macro(changeBaseWritingDirectionToRTL) \ 209macro(changeColor) \ 210macro(changeDocumentBackgroundColor) \ 211macro(changeFont) \ 212macro(changeSpelling) \ 213macro(checkSpelling) \ 214macro(complete) \ 215macro(copy) \ 216macro(copyFont) \ 217macro(cut) \ 218macro(delete) \ 219macro(deleteBackward) \ 220macro(deleteBackwardByDecomposingPreviousCharacter) \ 221macro(deleteForward) \ 222macro(deleteToBeginningOfLine) \ 223macro(deleteToBeginningOfParagraph) \ 224macro(deleteToEndOfLine) \ 225macro(deleteToEndOfParagraph) \ 226macro(deleteToMark) \ 227macro(deleteWordBackward) \ 228macro(deleteWordForward) \ 229macro(ignoreSpelling) \ 230macro(indent) \ 231macro(insertBacktab) \ 232macro(insertLineBreak) \ 233macro(insertNewline) \ 234macro(insertNewlineIgnoringFieldEditor) \ 235macro(insertParagraphSeparator) \ 236macro(insertTab) \ 237macro(insertTabIgnoringFieldEditor) \ 238macro(lowercaseWord) \ 239macro(makeBaseWritingDirectionLeftToRight) \ 240macro(makeBaseWritingDirectionRightToLeft) \ 241macro(makeTextWritingDirectionLeftToRight) \ 242macro(makeTextWritingDirectionNatural) \ 243macro(makeTextWritingDirectionRightToLeft) \ 244macro(moveBackward) \ 245macro(moveBackwardAndModifySelection) \ 246macro(moveDown) \ 247macro(moveDownAndModifySelection) \ 248macro(moveForward) \ 249macro(moveForwardAndModifySelection) \ 250macro(moveLeft) \ 251macro(moveLeftAndModifySelection) \ 252macro(moveParagraphBackwardAndModifySelection) \ 253macro(moveParagraphForwardAndModifySelection) \ 254macro(moveRight) \ 255macro(moveRightAndModifySelection) \ 256macro(moveToBeginningOfDocument) \ 257macro(moveToBeginningOfDocumentAndModifySelection) \ 258macro(moveToBeginningOfLine) \ 259macro(moveToBeginningOfLineAndModifySelection) \ 260macro(moveToBeginningOfParagraph) \ 261macro(moveToBeginningOfParagraphAndModifySelection) \ 262macro(moveToBeginningOfSentence) \ 263macro(moveToBeginningOfSentenceAndModifySelection) \ 264macro(moveToEndOfDocument) \ 265macro(moveToEndOfDocumentAndModifySelection) \ 266macro(moveToEndOfLine) \ 267macro(moveToEndOfLineAndModifySelection) \ 268macro(moveToEndOfParagraph) \ 269macro(moveToEndOfParagraphAndModifySelection) \ 270macro(moveToEndOfSentence) \ 271macro(moveToEndOfSentenceAndModifySelection) \ 272macro(moveToLeftEndOfLine) \ 273macro(moveToLeftEndOfLineAndModifySelection) \ 274macro(moveToRightEndOfLine) \ 275macro(moveToRightEndOfLineAndModifySelection) \ 276macro(moveUp) \ 277macro(moveUpAndModifySelection) \ 278macro(moveWordBackward) \ 279macro(moveWordBackwardAndModifySelection) \ 280macro(moveWordForward) \ 281macro(moveWordForwardAndModifySelection) \ 282macro(moveWordLeft) \ 283macro(moveWordLeftAndModifySelection) \ 284macro(moveWordRight) \ 285macro(moveWordRightAndModifySelection) \ 286macro(outdent) \ 287macro(orderFrontSubstitutionsPanel) \ 288macro(pageDown) \ 289macro(pageDownAndModifySelection) \ 290macro(pageUp) \ 291macro(pageUpAndModifySelection) \ 292macro(paste) \ 293macro(pasteAsPlainText) \ 294macro(pasteAsRichText) \ 295macro(pasteFont) \ 296macro(performFindPanelAction) \ 297macro(scrollLineDown) \ 298macro(scrollLineUp) \ 299macro(scrollPageDown) \ 300macro(scrollPageUp) \ 301macro(scrollToBeginningOfDocument) \ 302macro(scrollToEndOfDocument) \ 303macro(selectAll) \ 304macro(selectLine) \ 305macro(selectParagraph) \ 306macro(selectSentence) \ 307macro(selectToMark) \ 308macro(selectWord) \ 309macro(setMark) \ 310macro(showGuessPanel) \ 311macro(startSpeaking) \ 312macro(stopSpeaking) \ 313macro(subscript) \ 314macro(superscript) \ 315macro(swapWithMark) \ 316macro(takeFindStringFromSelection) \ 317macro(toggleBaseWritingDirection) \ 318macro(transpose) \ 319macro(underline) \ 320macro(unscript) \ 321macro(uppercaseWord) \ 322macro(yank) \ 323macro(yankAndSelect) \ 324 325#define WebKitOriginalTopPrintingMarginKey @"WebKitOriginalTopMargin" 326#define WebKitOriginalBottomPrintingMarginKey @"WebKitOriginalBottomMargin" 327 328#define KeyboardUIModeDidChangeNotification @"com.apple.KeyboardUIModeDidChange" 329#define AppleKeyboardUIMode CFSTR("AppleKeyboardUIMode") 330#define UniversalAccessDomain CFSTR("com.apple.universalaccess") 331 332static BOOL s_didSetCacheModel; 333static WebCacheModel s_cacheModel = WebCacheModelDocumentViewer; 334 335#ifndef NDEBUG 336static const char webViewIsOpen[] = "At least one WebView is still open."; 337#endif 338 339@interface NSObject (WebValidateWithoutDelegate) 340- (BOOL)validateUserInterfaceItemWithoutDelegate:(id <NSValidatedUserInterfaceItem>)item; 341@end 342 343@interface _WebSafeForwarder : NSObject 344{ 345 id target; // Non-retained. Don't retain delegates. 346 id defaultTarget; 347 BOOL catchExceptions; 348} 349- (id)initWithTarget:(id)target defaultTarget:(id)defaultTarget catchExceptions:(BOOL)catchExceptions; 350@end 351 352@interface WebView (WebFileInternal) 353- (BOOL)_isLoading; 354- (WebFrameView *)_frameViewAtWindowPoint:(NSPoint)point; 355- (WebFrame *)_focusedFrame; 356+ (void)_preflightSpellChecker; 357- (BOOL)_continuousCheckingAllowed; 358- (NSResponder *)_responderForResponderOperations; 359#if USE(ACCELERATED_COMPOSITING) 360- (void)_clearLayerSyncLoopObserver; 361#endif 362@end 363 364static void patchMailRemoveAttributesMethod(); 365 366NSString *WebElementDOMNodeKey = @"WebElementDOMNode"; 367NSString *WebElementFrameKey = @"WebElementFrame"; 368NSString *WebElementImageKey = @"WebElementImage"; 369NSString *WebElementImageAltStringKey = @"WebElementImageAltString"; 370NSString *WebElementImageRectKey = @"WebElementImageRect"; 371NSString *WebElementImageURLKey = @"WebElementImageURL"; 372NSString *WebElementIsSelectedKey = @"WebElementIsSelected"; 373NSString *WebElementLinkLabelKey = @"WebElementLinkLabel"; 374NSString *WebElementLinkTargetFrameKey = @"WebElementTargetFrame"; 375NSString *WebElementLinkTitleKey = @"WebElementLinkTitle"; 376NSString *WebElementLinkURLKey = @"WebElementLinkURL"; 377NSString *WebElementSpellingToolTipKey = @"WebElementSpellingToolTip"; 378NSString *WebElementTitleKey = @"WebElementTitle"; 379NSString *WebElementLinkIsLiveKey = @"WebElementLinkIsLive"; 380NSString *WebElementIsInScrollBarKey = @"WebElementIsInScrollBar"; 381NSString *WebElementIsContentEditableKey = @"WebElementIsContentEditableKey"; 382 383NSString *WebViewProgressStartedNotification = @"WebProgressStartedNotification"; 384NSString *WebViewProgressEstimateChangedNotification = @"WebProgressEstimateChangedNotification"; 385NSString *WebViewProgressFinishedNotification = @"WebProgressFinishedNotification"; 386 387NSString * const WebViewDidBeginEditingNotification = @"WebViewDidBeginEditingNotification"; 388NSString * const WebViewDidChangeNotification = @"WebViewDidChangeNotification"; 389NSString * const WebViewDidEndEditingNotification = @"WebViewDidEndEditingNotification"; 390NSString * const WebViewDidChangeTypingStyleNotification = @"WebViewDidChangeTypingStyleNotification"; 391NSString * const WebViewDidChangeSelectionNotification = @"WebViewDidChangeSelectionNotification"; 392 393enum { WebViewVersion = 4 }; 394 395#define timedLayoutSize 4096 396 397static NSMutableSet *schemesWithRepresentationsSet; 398 399NSString *_WebCanGoBackKey = @"canGoBack"; 400NSString *_WebCanGoForwardKey = @"canGoForward"; 401NSString *_WebEstimatedProgressKey = @"estimatedProgress"; 402NSString *_WebIsLoadingKey = @"isLoading"; 403NSString *_WebMainFrameIconKey = @"mainFrameIcon"; 404NSString *_WebMainFrameTitleKey = @"mainFrameTitle"; 405NSString *_WebMainFrameURLKey = @"mainFrameURL"; 406NSString *_WebMainFrameDocumentKey = @"mainFrameDocument"; 407 408NSString *_WebViewDidStartAcceleratedCompositingNotification = @"_WebViewDidStartAcceleratedCompositing"; 409 410@interface WebProgressItem : NSObject 411{ 412@public 413 long long bytesReceived; 414 long long estimatedLength; 415} 416@end 417 418@implementation WebProgressItem 419@end 420 421static BOOL continuousSpellCheckingEnabled; 422#ifndef BUILDING_ON_TIGER 423static BOOL grammarCheckingEnabled; 424#endif 425#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 426static BOOL automaticQuoteSubstitutionEnabled; 427static BOOL automaticLinkDetectionEnabled; 428static BOOL automaticDashSubstitutionEnabled; 429static BOOL automaticTextReplacementEnabled; 430static BOOL automaticSpellingCorrectionEnabled; 431#endif 432 433@implementation WebView (AllWebViews) 434 435static CFSetCallBacks NonRetainingSetCallbacks = { 436 0, 437 NULL, 438 NULL, 439 CFCopyDescription, 440 CFEqual, 441 CFHash 442}; 443 444static CFMutableSetRef allWebViewsSet; 445 446+ (void)_makeAllWebViewsPerformSelector:(SEL)selector 447{ 448 if (!allWebViewsSet) 449 return; 450 451 [(NSMutableSet *)allWebViewsSet makeObjectsPerformSelector:selector]; 452} 453 454- (void)_removeFromAllWebViewsSet 455{ 456 if (allWebViewsSet) 457 CFSetRemoveValue(allWebViewsSet, self); 458} 459 460- (void)_addToAllWebViewsSet 461{ 462 if (!allWebViewsSet) 463 allWebViewsSet = CFSetCreateMutable(NULL, 0, &NonRetainingSetCallbacks); 464 465 CFSetSetValue(allWebViewsSet, self); 466} 467 468@end 469 470@implementation WebView (WebPrivate) 471 472static inline int callGestalt(OSType selector) 473{ 474 SInt32 value = 0; 475 Gestalt(selector, &value); 476 return value; 477} 478 479// Uses underscores instead of dots because if "4." ever appears in a user agent string, old DHTML libraries treat it as Netscape 4. 480static NSString *createMacOSXVersionString() 481{ 482 // Can't use -[NSProcessInfo operatingSystemVersionString] because it has too much stuff we don't want. 483 int major = callGestalt(gestaltSystemVersionMajor); 484 ASSERT(major); 485 486 int minor = callGestalt(gestaltSystemVersionMinor); 487 int bugFix = callGestalt(gestaltSystemVersionBugFix); 488 if (bugFix) 489 return [[NSString alloc] initWithFormat:@"%d_%d_%d", major, minor, bugFix]; 490 if (minor) 491 return [[NSString alloc] initWithFormat:@"%d_%d", major, minor]; 492 return [[NSString alloc] initWithFormat:@"%d", major]; 493} 494 495static NSString *createUserVisibleWebKitVersionString() 496{ 497 // If the version is 4 digits long or longer, then the first digit represents 498 // the version of the OS. Our user agent string should not include this first digit, 499 // so strip it off and report the rest as the version. <rdar://problem/4997547> 500 NSString *fullVersion = [[NSBundle bundleForClass:[WebView class]] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey]; 501 NSRange nonDigitRange = [fullVersion rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]; 502 if (nonDigitRange.location == NSNotFound && [fullVersion length] >= 4) 503 return [[fullVersion substringFromIndex:1] copy]; 504 if (nonDigitRange.location != NSNotFound && nonDigitRange.location >= 4) 505 return [[fullVersion substringFromIndex:1] copy]; 506 return [fullVersion copy]; 507} 508 509+ (NSString *)_standardUserAgentWithApplicationName:(NSString *)applicationName 510{ 511 // Note: Do *not* move the initialization of osVersion nor webKitVersion into the declaration. 512 // Garbage collection won't correctly mark the global variable in that case <rdar://problem/5733674>. 513 static NSString *osVersion; 514 static NSString *webKitVersion; 515 if (!osVersion) 516 osVersion = createMacOSXVersionString(); 517 if (!webKitVersion) 518 webKitVersion = createUserVisibleWebKitVersionString(); 519 NSString *language = [NSUserDefaults _webkit_preferredLanguageCode]; 520 if ([applicationName length]) 521 return [NSString stringWithFormat:@"Mozilla/5.0 (Macintosh; U; " PROCESSOR " Mac OS X %@; %@) AppleWebKit/%@ (KHTML, like Gecko) %@", osVersion, language, webKitVersion, applicationName]; 522 return [NSString stringWithFormat:@"Mozilla/5.0 (Macintosh; U; " PROCESSOR " Mac OS X %@; %@) AppleWebKit/%@ (KHTML, like Gecko)", osVersion, language, webKitVersion]; 523} 524 525static void WebKitInitializeApplicationCachePathIfNecessary() 526{ 527#if ENABLE(OFFLINE_WEB_APPLICATIONS) 528 static BOOL initialized = NO; 529 if (initialized) 530 return; 531 532 NSString *appName = [[NSBundle mainBundle] bundleIdentifier]; 533 if (!appName) 534 appName = [[NSProcessInfo processInfo] processName]; 535 536 ASSERT(appName); 537 538 NSString* cacheDir = [NSString _webkit_localCacheDirectoryWithBundleIdentifier:appName]; 539 540 cacheStorage().setCacheDirectory(cacheDir); 541 initialized = YES; 542#endif 543} 544 545static bool runningLeopardMail() 546{ 547#ifdef BUILDING_ON_LEOPARD 548 return applicationIsAppleMail(); 549#endif 550 return NO; 551} 552 553static bool runningTigerMail() 554{ 555#ifdef BUILDING_ON_TIGER 556 return applicationIsAppleMail(); 557#endif 558 return NO; 559} 560 561static bool shouldEnableLoadDeferring() 562{ 563 return !applicationIsAdobeInstaller(); 564} 565 566- (void)_dispatchPendingLoadRequests 567{ 568 cache()->loader()->servePendingRequests(); 569} 570 571- (void)_registerDraggedTypes 572{ 573 NSArray *editableTypes = [WebHTMLView _insertablePasteboardTypes]; 574 NSArray *URLTypes = [NSPasteboard _web_dragTypesForURL]; 575 NSMutableSet *types = [[NSMutableSet alloc] initWithArray:editableTypes]; 576 [types addObjectsFromArray:URLTypes]; 577 [self registerForDraggedTypes:[types allObjects]]; 578 [types release]; 579} 580 581- (BOOL)_usesDocumentViews 582{ 583 return _private->usesDocumentViews; 584} 585 586- (void)_commonInitializationWithFrameName:(NSString *)frameName groupName:(NSString *)groupName usesDocumentViews:(BOOL)usesDocumentViews 587{ 588 WebCoreThreadViolationCheckRoundTwo(); 589 590#ifndef NDEBUG 591 WTF::RefCountedLeakCounter::suppressMessages(webViewIsOpen); 592#endif 593 594 WebPreferences *standardPreferences = [WebPreferences standardPreferences]; 595 [standardPreferences willAddToWebView]; 596 597 _private->preferences = [standardPreferences retain]; 598 _private->catchesDelegateExceptions = YES; 599 _private->mainFrameDocumentReady = NO; 600 _private->drawsBackground = YES; 601 _private->backgroundColor = [[NSColor colorWithDeviceWhite:1 alpha:1] retain]; 602 _private->usesDocumentViews = usesDocumentViews; 603 604 WebFrameView *frameView = nil; 605 if (_private->usesDocumentViews) { 606 NSRect f = [self frame]; 607 frameView = [[WebFrameView alloc] initWithFrame: NSMakeRect(0,0,f.size.width,f.size.height)]; 608 [frameView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; 609 [self addSubview:frameView]; 610 [frameView release]; 611 } 612 613 static bool didOneTimeInitialization = false; 614 if (!didOneTimeInitialization) { 615 WebKitInitializeLoggingChannelsIfNecessary(); 616 WebCore::InitializeLoggingChannelsIfNecessary(); 617 [WebHistoryItem initWindowWatcherIfNecessary]; 618#if ENABLE(DATABASE) 619 WebKitInitializeDatabasesIfNecessary(); 620#endif 621 WebKitInitializeApplicationCachePathIfNecessary(); 622 patchMailRemoveAttributesMethod(); 623 didOneTimeInitialization = true; 624 } 625 626#if ENABLE(CLIENT_BASED_GEOLOCATION) 627 WebGeolocationControllerClient* geolocationControllerClient = new WebGeolocationControllerClient(self); 628#else 629 WebGeolocationControllerClient* geolocationControllerClient = 0; 630#endif 631 _private->page = new Page(new WebChromeClient(self), new WebContextMenuClient(self), new WebEditorClient(self), new WebDragClient(self), new WebInspectorClient(self), new WebPluginHalterClient(self), geolocationControllerClient); 632 633 _private->page->settings()->setLocalStorageDatabasePath([[self preferences] _localStorageDatabasePath]); 634 635 [WebFrame _createMainFrameWithPage:_private->page frameName:frameName frameView:frameView]; 636 637#ifndef BUILDING_ON_TIGER 638 NSRunLoop *runLoop = [NSRunLoop mainRunLoop]; 639#else 640 NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; 641#endif 642 643 if (WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_LOADING_DURING_COMMON_RUNLOOP_MODES)) 644 [self scheduleInRunLoop:runLoop forMode:(NSString *)kCFRunLoopCommonModes]; 645 else 646 [self scheduleInRunLoop:runLoop forMode:NSDefaultRunLoopMode]; 647 648 [self _addToAllWebViewsSet]; 649 [self setGroupName:groupName]; 650 651 // If there's already a next key view (e.g., from a nib), wire it up to our 652 // contained frame view. In any case, wire our next key view up to the our 653 // contained frame view. This works together with our becomeFirstResponder 654 // and setNextKeyView overrides. 655 NSView *nextKeyView = [self nextKeyView]; 656 if (nextKeyView && nextKeyView != frameView) 657 [frameView setNextKeyView:nextKeyView]; 658 [super setNextKeyView:frameView]; 659 660 ++WebViewCount; 661 662 [self _registerDraggedTypes]; 663 664 WebPreferences *prefs = [self preferences]; 665 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:) 666 name:WebPreferencesChangedNotification object:prefs]; 667 668 // Post a notification so the WebCore settings update. 669 [[self preferences] _postPreferencesChangesNotification]; 670 671 if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_LOCAL_RESOURCE_SECURITY_RESTRICTION)) { 672 // Originally, we allowed all local loads. 673 SecurityOrigin::setLocalLoadPolicy(SecurityOrigin::AllowLocalLoadsForAll); 674 } else if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_MORE_STRICT_LOCAL_RESOURCE_SECURITY_RESTRICTION)) { 675 // Later, we allowed local loads for local URLs and documents loaded 676 // with substitute data. 677 SecurityOrigin::setLocalLoadPolicy(SecurityOrigin::AllowLocalLoadsForLocalAndSubstituteData); 678 } 679 680 if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_CONTENT_SNIFFING_FOR_FILE_URLS)) 681 ResourceHandle::forceContentSniffing(); 682} 683 684- (id)_initWithFrame:(NSRect)f frameName:(NSString *)frameName groupName:(NSString *)groupName usesDocumentViews:(BOOL)usesDocumentViews 685{ 686 self = [super initWithFrame:f]; 687 if (!self) 688 return nil; 689 690#ifdef ENABLE_WEBKIT_UNSET_DYLD_FRAMEWORK_PATH 691 // DYLD_FRAMEWORK_PATH is used so Safari will load the development version of WebKit, which 692 // may not work with other WebKit applications. Unsetting DYLD_FRAMEWORK_PATH removes the 693 // need for Safari to unset it to prevent it from being passed to applications it launches. 694 // Unsetting it when a WebView is first created is as good a place as any. 695 // See <http://bugs.webkit.org/show_bug.cgi?id=4286> for more details. 696 if (getenv("WEBKIT_UNSET_DYLD_FRAMEWORK_PATH")) { 697 unsetenv("DYLD_FRAMEWORK_PATH"); 698 unsetenv("WEBKIT_UNSET_DYLD_FRAMEWORK_PATH"); 699 } 700#endif 701 702 _private = [[WebViewPrivate alloc] init]; 703 [self _commonInitializationWithFrameName:frameName groupName:groupName usesDocumentViews:usesDocumentViews]; 704 [self setMaintainsBackForwardList: YES]; 705 return self; 706} 707 708- (BOOL)_mustDrawUnionedRect:(NSRect)rect singleRects:(const NSRect *)rects count:(NSInteger)count 709{ 710 // If count == 0 here, use the rect passed in for drawing. This is a workaround for: 711 // <rdar://problem/3908282> REGRESSION (Mail): No drag image dragging selected text in Blot and Mail 712 // The reason for the workaround is that this method is called explicitly from the code 713 // to generate a drag image, and at that time, getRectsBeingDrawn:count: will return a zero count. 714 const int cRectThreshold = 10; 715 const float cWastedSpaceThreshold = 0.75f; 716 BOOL useUnionedRect = (count <= 1) || (count > cRectThreshold); 717 if (!useUnionedRect) { 718 // Attempt to guess whether or not we should use the unioned rect or the individual rects. 719 // We do this by computing the percentage of "wasted space" in the union. If that wasted space 720 // is too large, then we will do individual rect painting instead. 721 float unionPixels = (rect.size.width * rect.size.height); 722 float singlePixels = 0; 723 for (int i = 0; i < count; ++i) 724 singlePixels += rects[i].size.width * rects[i].size.height; 725 float wastedSpace = 1 - (singlePixels / unionPixels); 726 if (wastedSpace <= cWastedSpaceThreshold) 727 useUnionedRect = YES; 728 } 729 return useUnionedRect; 730} 731 732- (void)drawSingleRect:(NSRect)rect 733{ 734 ASSERT(!_private->usesDocumentViews); 735 736 [NSGraphicsContext saveGraphicsState]; 737 NSRectClip(rect); 738 739 @try { 740 [[self mainFrame] _drawRect:rect contentsOnly:NO]; 741 742 WebView *webView = [self _webView]; 743 [[webView _UIDelegateForwarder] webView:webView didDrawRect:rect]; 744 745 if (WebNodeHighlight *currentHighlight = [webView currentNodeHighlight]) 746 [currentHighlight setNeedsUpdateInTargetViewRect:rect]; 747 748 [NSGraphicsContext restoreGraphicsState]; 749 } @catch (NSException *localException) { 750 [NSGraphicsContext restoreGraphicsState]; 751 LOG_ERROR("Exception caught while drawing: %@", localException); 752 [localException raise]; 753 } 754} 755 756- (BOOL)isFlipped 757{ 758 return _private && !_private->usesDocumentViews; 759} 760 761- (void)setFrameSize:(NSSize)size 762{ 763 if (!_private->usesDocumentViews && !NSEqualSizes(_private->lastLayoutSize, size)) { 764 Frame* frame = [self _mainCoreFrame]; 765 // FIXME: Viewless WebKit is broken with Safari banners (e.g., the Find banner). We'll have to figure out a way for 766 // Safari to communicate that this space is being consumed. For WebKit with document views, there's no 767 // need to do an explicit resize, since WebFrameViews have auto resizing turned on and will handle changing 768 // their bounds automatically. See <rdar://problem/6835573> for details. 769 frame->view()->resize(IntSize(size)); 770 frame->view()->setNeedsLayout(); 771 [self setNeedsDisplay:YES]; 772 _private->lastLayoutSize = size; 773 } 774 775 [super setFrameSize:size]; 776} 777 778#if USE(ACCELERATED_COMPOSITING) || !defined(BUILDING_ON_TIGER) 779 780- (void)_viewWillDrawInternal 781{ 782 Frame* frame = [self _mainCoreFrame]; 783 if (frame && frame->view()) 784 frame->view()->layoutIfNeededRecursive(); 785} 786 787#endif 788 789#ifndef BUILDING_ON_TIGER 790 791- (void)viewWillDraw 792{ 793 if (!_private->usesDocumentViews) 794 [self _viewWillDrawInternal]; 795 [super viewWillDraw]; 796} 797 798#endif 799 800 801- (void)drawRect:(NSRect)rect 802{ 803 if (_private->usesDocumentViews) 804 return [super drawRect:rect]; 805 806 ASSERT_MAIN_THREAD(); 807 808 const NSRect *rects; 809 NSInteger count; 810 [self getRectsBeingDrawn:&rects count:&count]; 811 812 813 if ([self _mustDrawUnionedRect:rect singleRects:rects count:count]) 814 [self drawSingleRect:rect]; 815 else 816 for (int i = 0; i < count; ++i) 817 [self drawSingleRect:rects[i]]; 818} 819 820+ (NSArray *)_supportedMIMETypes 821{ 822 // Load the plug-in DB allowing plug-ins to install types. 823 [WebPluginDatabase sharedDatabase]; 824 return [[WebFrameView _viewTypesAllowImageTypeOmission:NO] allKeys]; 825} 826 827+ (NSArray *)_supportedFileExtensions 828{ 829 NSMutableSet *extensions = [[NSMutableSet alloc] init]; 830 NSArray *MIMETypes = [self _supportedMIMETypes]; 831 NSEnumerator *enumerator = [MIMETypes objectEnumerator]; 832 NSString *MIMEType; 833 while ((MIMEType = [enumerator nextObject]) != nil) { 834 NSArray *extensionsForType = WKGetExtensionsForMIMEType(MIMEType); 835 if (extensionsForType) { 836 [extensions addObjectsFromArray:extensionsForType]; 837 } 838 } 839 NSArray *uniqueExtensions = [extensions allObjects]; 840 [extensions release]; 841 return uniqueExtensions; 842} 843 844+ (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType allowingPlugins:(BOOL)allowPlugins 845{ 846 MIMEType = [MIMEType lowercaseString]; 847 Class viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType]; 848 Class repClass = [[WebDataSource _repTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType]; 849 850 if (!viewClass || !repClass || [[WebPDFView supportedMIMETypes] containsObject:MIMEType]) { 851 // Our optimization to avoid loading the plug-in DB and image types for the HTML case failed. 852 853 if (allowPlugins) { 854 // Load the plug-in DB allowing plug-ins to install types. 855 [WebPluginDatabase sharedDatabase]; 856 } 857 858 // Load the image types and get the view class and rep class. This should be the fullest picture of all handled types. 859 viewClass = [[WebFrameView _viewTypesAllowImageTypeOmission:NO] _webkit_objectForMIMEType:MIMEType]; 860 repClass = [[WebDataSource _repTypesAllowImageTypeOmission:NO] _webkit_objectForMIMEType:MIMEType]; 861 } 862 863 if (viewClass && repClass) { 864 // Special-case WebHTMLView for text types that shouldn't be shown. 865 if (viewClass == [WebHTMLView class] && 866 repClass == [WebHTMLRepresentation class] && 867 [[WebHTMLView unsupportedTextMIMETypes] containsObject:MIMEType]) { 868 return NO; 869 } 870 if (vClass) 871 *vClass = viewClass; 872 if (rClass) 873 *rClass = repClass; 874 return YES; 875 } 876 877 return NO; 878} 879 880- (BOOL)_viewClass:(Class *)vClass andRepresentationClass:(Class *)rClass forMIMEType:(NSString *)MIMEType 881{ 882 if ([[self class] _viewClass:vClass andRepresentationClass:rClass forMIMEType:MIMEType allowingPlugins:[[[self _webView] preferences] arePlugInsEnabled]]) 883 return YES; 884 885 if (_private->pluginDatabase) { 886 WebBasePluginPackage *pluginPackage = [_private->pluginDatabase pluginForMIMEType:MIMEType]; 887 if (pluginPackage) { 888 if (vClass) 889 *vClass = [WebHTMLView class]; 890 if (rClass) 891 *rClass = [WebHTMLRepresentation class]; 892 return YES; 893 } 894 } 895 896 return NO; 897} 898 899+ (void)_setAlwaysUseATSU:(BOOL)f 900{ 901 [self _setAlwaysUsesComplexTextCodePath:f]; 902} 903 904+ (void)_setAlwaysUsesComplexTextCodePath:(BOOL)f 905{ 906 Font::setCodePath(f ? Font::Complex : Font::Auto); 907} 908 909+ (BOOL)canCloseAllWebViews 910{ 911 return DOMWindow::dispatchAllPendingBeforeUnloadEvents(); 912} 913 914+ (void)closeAllWebViews 915{ 916 DOMWindow::dispatchAllPendingUnloadEvents(); 917 918 // This will close the WebViews in a random order. Change this if close order is important. 919 NSEnumerator *enumerator = [(NSMutableSet *)allWebViewsSet objectEnumerator]; 920 while (WebView *webView = [enumerator nextObject]) 921 [webView close]; 922} 923 924+ (BOOL)canShowFile:(NSString *)path 925{ 926 return [[self class] canShowMIMEType:[WebView _MIMETypeForFile:path]]; 927} 928 929+ (NSString *)suggestedFileExtensionForMIMEType:(NSString *)type 930{ 931 return WKGetPreferredExtensionForMIMEType(type); 932} 933 934- (BOOL)_isClosed 935{ 936 return !_private || _private->closed; 937} 938 939- (void)_closePluginDatabases 940{ 941 pluginDatabaseClientCount--; 942 943 // Close both sets of plug-in databases because plug-ins need an opportunity to clean up files, etc. 944 945 // Unload the WebView local plug-in database. 946 if (_private->pluginDatabase) { 947 [_private->pluginDatabase destroyAllPluginInstanceViews]; 948 [_private->pluginDatabase close]; 949 [_private->pluginDatabase release]; 950 _private->pluginDatabase = nil; 951 } 952 953 // Keep the global plug-in database active until the app terminates to avoid having to reload plug-in bundles. 954 if (!pluginDatabaseClientCount && applicationIsTerminating) 955 [WebPluginDatabase closeSharedDatabase]; 956} 957 958- (void)_closeWithFastTeardown 959{ 960#ifndef NDEBUG 961 WTF::RefCountedLeakCounter::suppressMessages("At least one WebView was closed with fast teardown."); 962#endif 963 964 _private->closed = YES; 965 966 [[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; 967 [[NSNotificationCenter defaultCenter] removeObserver:self]; 968 969 [self _closePluginDatabases]; 970} 971 972static bool fastDocumentTeardownEnabled() 973{ 974#ifdef NDEBUG 975 static bool enabled = ![[NSUserDefaults standardUserDefaults] boolForKey:WebKitEnableFullDocumentTeardownPreferenceKey]; 976#else 977 static bool initialized = false; 978 static bool enabled = false; 979 if (!initialized) { 980 // This allows debug builds to default to not have fast teardown, so leak checking still works. 981 // But still allow the WebKitEnableFullDocumentTeardown default to override it if present. 982 NSNumber *setting = [[NSUserDefaults standardUserDefaults] objectForKey:WebKitEnableFullDocumentTeardownPreferenceKey]; 983 if (setting) 984 enabled = ![setting boolValue]; 985 initialized = true; 986 } 987#endif 988 return enabled; 989} 990 991// _close is here only for backward compatibility; clients and subclasses should use 992// public method -close instead. 993- (void)_close 994{ 995 if (!_private || _private->closed) 996 return; 997 998 [self _closingEventHandling]; 999 1000#ifndef NDEBUG 1001 WTF::RefCountedLeakCounter::cancelMessageSuppression(webViewIsOpen); 1002#endif 1003 1004 // To quit the apps fast we skip document teardown, except plugins 1005 // need to be destroyed and unloaded. 1006 if (applicationIsTerminating && fastDocumentTeardownEnabled()) { 1007 [self _closeWithFastTeardown]; 1008 return; 1009 } 1010 1011#if ENABLE(VIDEO) 1012 [self _exitFullscreen]; 1013#endif 1014 1015 if (Frame* mainFrame = [self _mainCoreFrame]) 1016 mainFrame->loader()->detachFromParent(); 1017 1018 [self _removeFromAllWebViewsSet]; 1019 [self setHostWindow:nil]; 1020 1021 [self setDownloadDelegate:nil]; 1022 [self setEditingDelegate:nil]; 1023 [self setFrameLoadDelegate:nil]; 1024 [self setPolicyDelegate:nil]; 1025 [self setResourceLoadDelegate:nil]; 1026 [self setScriptDebugDelegate:nil]; 1027 [self setUIDelegate:nil]; 1028 1029 [_private->inspector webViewClosed]; 1030 1031 // setHostWindow:nil must be called before this value is set (see 5408186) 1032 _private->closed = YES; 1033 1034 // To avoid leaks, call removeDragCaret in case it wasn't called after moveDragCaretToPoint. 1035 [self removeDragCaret]; 1036 1037 // Deleteing the WebCore::Page will clear the page cache so we call destroy on 1038 // all the plug-ins in the page cache to break any retain cycles. 1039 // See comment in HistoryItem::releaseAllPendingPageCaches() for more information. 1040 delete _private->page; 1041 _private->page = 0; 1042 1043 if (_private->hasSpellCheckerDocumentTag) { 1044 [[NSSpellChecker sharedSpellChecker] closeSpellDocumentWithTag:_private->spellCheckerDocumentTag]; 1045 _private->hasSpellCheckerDocumentTag = NO; 1046 } 1047 1048#if USE(ACCELERATED_COMPOSITING) 1049 [self _clearLayerSyncLoopObserver]; 1050#endif 1051 1052 [[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; 1053 [[NSNotificationCenter defaultCenter] removeObserver:self]; 1054 1055 [WebPreferences _removeReferenceForIdentifier:[self preferencesIdentifier]]; 1056 1057 WebPreferences *preferences = _private->preferences; 1058 _private->preferences = nil; 1059 [preferences didRemoveFromWebView]; 1060 [preferences release]; 1061 1062 [self _closePluginDatabases]; 1063 1064#ifndef NDEBUG 1065 // Need this to make leak messages accurate. 1066 if (applicationIsTerminating) { 1067 gcController().garbageCollectNow(); 1068 [WebCache setDisabled:YES]; 1069 } 1070#endif 1071} 1072 1073// Indicates if the WebView is in the midst of a user gesture. 1074- (BOOL)_isProcessingUserGesture 1075{ 1076 WebFrame *frame = [self mainFrame]; 1077 return core(frame)->loader()->isProcessingUserGesture(); 1078} 1079 1080+ (NSString *)_MIMETypeForFile:(NSString *)path 1081{ 1082 NSString *extension = [path pathExtension]; 1083 NSString *MIMEType = nil; 1084 1085 // Get the MIME type from the extension. 1086 if ([extension length] != 0) { 1087 MIMEType = WKGetMIMETypeForExtension(extension); 1088 } 1089 1090 // If we can't get a known MIME type from the extension, sniff. 1091 if ([MIMEType length] == 0 || [MIMEType isEqualToString:@"application/octet-stream"]) { 1092 NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path]; 1093 NSData *data = [handle readDataOfLength:WEB_GUESS_MIME_TYPE_PEEK_LENGTH]; 1094 [handle closeFile]; 1095 if ([data length] != 0) { 1096 MIMEType = [data _webkit_guessedMIMEType]; 1097 } 1098 if ([MIMEType length] == 0) { 1099 MIMEType = @"application/octet-stream"; 1100 } 1101 } 1102 1103 return MIMEType; 1104} 1105 1106- (WebDownload *)_downloadURL:(NSURL *)URL 1107{ 1108 ASSERT(URL); 1109 1110 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:URL]; 1111 WebDownload *download = [WebDownload _downloadWithRequest:request 1112 delegate:_private->downloadDelegate 1113 directory:nil]; 1114 [request release]; 1115 1116 return download; 1117} 1118 1119- (WebView *)_openNewWindowWithRequest:(NSURLRequest *)request 1120{ 1121 NSDictionary *features = [[NSDictionary alloc] init]; 1122 WebView *newWindowWebView = [[self _UIDelegateForwarder] webView:self 1123 createWebViewWithRequest:nil 1124 windowFeatures:features]; 1125 [features release]; 1126 if (!newWindowWebView) 1127 return nil; 1128 1129 CallUIDelegate(newWindowWebView, @selector(webViewShow:)); 1130 return newWindowWebView; 1131} 1132 1133- (WebInspector *)inspector 1134{ 1135 if (!_private->inspector) 1136 _private->inspector = [[WebInspector alloc] initWithWebView:self]; 1137 return _private->inspector; 1138} 1139 1140- (WebCore::Page*)page 1141{ 1142 return _private->page; 1143} 1144 1145- (NSMenu *)_menuForElement:(NSDictionary *)element defaultItems:(NSArray *)items 1146{ 1147 NSArray *defaultMenuItems = [[WebDefaultUIDelegate sharedUIDelegate] webView:self contextMenuItemsForElement:element defaultMenuItems:items]; 1148 1149 NSArray *menuItems = CallUIDelegate(self, @selector(webView:contextMenuItemsForElement:defaultMenuItems:), element, defaultMenuItems); 1150 if (!menuItems) 1151 return nil; 1152 1153 unsigned count = [menuItems count]; 1154 if (!count) 1155 return nil; 1156 1157 NSMenu *menu = [[NSMenu alloc] init]; 1158 for (unsigned i = 0; i < count; i++) 1159 [menu addItem:[menuItems objectAtIndex:i]]; 1160 1161 return [menu autorelease]; 1162} 1163 1164- (void)_mouseDidMoveOverElement:(NSDictionary *)dictionary modifierFlags:(NSUInteger)modifierFlags 1165{ 1166 // We originally intended to call this delegate method sometimes with a nil dictionary, but due to 1167 // a bug dating back to WebKit 1.0 this delegate was never called with nil! Unfortunately we can't 1168 // start calling this with nil since it will break Adobe Help Viewer, and possibly other clients. 1169 if (!dictionary) 1170 return; 1171 CallUIDelegate(self, @selector(webView:mouseDidMoveOverElement:modifierFlags:), dictionary, modifierFlags); 1172} 1173 1174- (void)_loadBackForwardListFromOtherView:(WebView *)otherView 1175{ 1176 if (!_private->page) 1177 return; 1178 1179 if (!otherView->_private->page) 1180 return; 1181 1182 // It turns out the right combination of behavior is done with the back/forward load 1183 // type. (See behavior matrix at the top of WebFramePrivate.) So we copy all the items 1184 // in the back forward list, and go to the current one. 1185 1186 BackForwardList* backForwardList = _private->page->backForwardList(); 1187 ASSERT(!backForwardList->currentItem()); // destination list should be empty 1188 1189 BackForwardList* otherBackForwardList = otherView->_private->page->backForwardList(); 1190 if (!otherBackForwardList->currentItem()) 1191 return; // empty back forward list, bail 1192 1193 HistoryItem* newItemToGoTo = 0; 1194 1195 int lastItemIndex = otherBackForwardList->forwardListCount(); 1196 for (int i = -otherBackForwardList->backListCount(); i <= lastItemIndex; ++i) { 1197 if (i == 0) { 1198 // If this item is showing , save away its current scroll and form state, 1199 // since that might have changed since loading and it is normally not saved 1200 // until we leave that page. 1201 otherView->_private->page->mainFrame()->loader()->history()->saveDocumentAndScrollState(); 1202 } 1203 RefPtr<HistoryItem> newItem = otherBackForwardList->itemAtIndex(i)->copy(); 1204 if (i == 0) 1205 newItemToGoTo = newItem.get(); 1206 backForwardList->addItem(newItem.release()); 1207 } 1208 1209 ASSERT(newItemToGoTo); 1210 _private->page->goToItem(newItemToGoTo, FrameLoadTypeIndexedBackForward); 1211} 1212 1213- (void)_setFormDelegate: (id<WebFormDelegate>)delegate 1214{ 1215 _private->formDelegate = delegate; 1216} 1217 1218- (id<WebFormDelegate>)_formDelegate 1219{ 1220 return _private->formDelegate; 1221} 1222 1223- (BOOL)_needsAdobeFrameReloadingQuirk 1224{ 1225 static BOOL needsQuirk = WKAppVersionCheckLessThan(@"com.adobe.Acrobat", -1, 9.0) 1226 || WKAppVersionCheckLessThan(@"com.adobe.Acrobat.Pro", -1, 9.0) 1227 || WKAppVersionCheckLessThan(@"com.adobe.Reader", -1, 9.0) 1228 || WKAppVersionCheckLessThan(@"com.adobe.distiller", -1, 9.0) 1229 || WKAppVersionCheckLessThan(@"com.adobe.Contribute", -1, 4.2) 1230 || WKAppVersionCheckLessThan(@"com.adobe.dreamweaver-9.0", -1, 9.1) 1231 || WKAppVersionCheckLessThan(@"com.macromedia.fireworks", -1, 9.1) 1232 || WKAppVersionCheckLessThan(@"com.adobe.InCopy", -1, 5.1) 1233 || WKAppVersionCheckLessThan(@"com.adobe.InDesign", -1, 5.1) 1234 || WKAppVersionCheckLessThan(@"com.adobe.Soundbooth", -1, 2); 1235 1236 return needsQuirk; 1237} 1238 1239- (BOOL)_needsLinkElementTextCSSQuirk 1240{ 1241 static BOOL needsQuirk = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_LINK_ELEMENT_TEXT_CSS_QUIRK) 1242 && WKAppVersionCheckLessThan(@"com.e-frontier.shade10", -1, 10.6); 1243 return needsQuirk; 1244} 1245 1246- (BOOL)_needsKeyboardEventDisambiguationQuirks 1247{ 1248 static BOOL needsQuirks = !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_IE_COMPATIBLE_KEYBOARD_EVENT_DISPATCH) && !applicationIsSafari(); 1249 return needsQuirks; 1250} 1251 1252- (BOOL)_needsFrameLoadDelegateRetainQuirk 1253{ 1254 static BOOL needsQuirk = WKAppVersionCheckLessThan(@"com.equinux.iSale5", -1, 5.6); 1255 return needsQuirk; 1256} 1257 1258- (void)_preferencesChangedNotification:(NSNotification *)notification 1259{ 1260 WebPreferences *preferences = (WebPreferences *)[notification object]; 1261 ASSERT(preferences == [self preferences]); 1262 1263 if (!_private->userAgentOverridden) 1264 _private->userAgent = String(); 1265 1266 // Cache this value so we don't have to read NSUserDefaults on each page load 1267 _private->useSiteSpecificSpoofing = [preferences _useSiteSpecificSpoofing]; 1268 1269 // Update corresponding WebCore Settings object. 1270 if (!_private->page) 1271 return; 1272 1273 Settings* settings = _private->page->settings(); 1274 1275 settings->setCursiveFontFamily([preferences cursiveFontFamily]); 1276 settings->setDefaultFixedFontSize([preferences defaultFixedFontSize]); 1277 settings->setDefaultFontSize([preferences defaultFontSize]); 1278 settings->setDefaultTextEncodingName([preferences defaultTextEncodingName]); 1279 settings->setUsesEncodingDetector([preferences usesEncodingDetector]); 1280 settings->setFantasyFontFamily([preferences fantasyFontFamily]); 1281 settings->setFixedFontFamily([preferences fixedFontFamily]); 1282 settings->setForceFTPDirectoryListings([preferences _forceFTPDirectoryListings]); 1283 settings->setFTPDirectoryTemplatePath([preferences _ftpDirectoryTemplatePath]); 1284 settings->setLocalStorageDatabasePath([preferences _localStorageDatabasePath]); 1285 settings->setJavaEnabled([preferences isJavaEnabled]); 1286 settings->setJavaScriptEnabled([preferences isJavaScriptEnabled]); 1287 settings->setWebSecurityEnabled([preferences isWebSecurityEnabled]); 1288 settings->setAllowUniversalAccessFromFileURLs([preferences allowUniversalAccessFromFileURLs]); 1289 settings->setJavaScriptCanOpenWindowsAutomatically([preferences javaScriptCanOpenWindowsAutomatically]); 1290 settings->setMinimumFontSize([preferences minimumFontSize]); 1291 settings->setMinimumLogicalFontSize([preferences minimumLogicalFontSize]); 1292 settings->setPluginsEnabled([preferences arePlugInsEnabled]); 1293 settings->setDatabasesEnabled([preferences databasesEnabled]); 1294 settings->setLocalStorageEnabled([preferences localStorageEnabled]); 1295 settings->setExperimentalNotificationsEnabled([preferences experimentalNotificationsEnabled]); 1296 settings->setPrivateBrowsingEnabled([preferences privateBrowsingEnabled]); 1297 settings->setSansSerifFontFamily([preferences sansSerifFontFamily]); 1298 settings->setSerifFontFamily([preferences serifFontFamily]); 1299 settings->setStandardFontFamily([preferences standardFontFamily]); 1300 settings->setLoadsImagesAutomatically([preferences loadsImagesAutomatically]); 1301 settings->setShouldPrintBackgrounds([preferences shouldPrintBackgrounds]); 1302 settings->setTextAreasAreResizable([preferences textAreasAreResizable]); 1303 settings->setShrinksStandaloneImagesToFit([preferences shrinksStandaloneImagesToFit]); 1304 settings->setEditableLinkBehavior(core([preferences editableLinkBehavior])); 1305 settings->setTextDirectionSubmenuInclusionBehavior(core([preferences textDirectionSubmenuInclusionBehavior])); 1306 settings->setDOMPasteAllowed([preferences isDOMPasteAllowed]); 1307 settings->setUsesPageCache([self usesPageCache]); 1308 settings->setShowsURLsInToolTips([preferences showsURLsInToolTips]); 1309 settings->setDeveloperExtrasEnabled([preferences developerExtrasEnabled]); 1310 settings->setAuthorAndUserStylesEnabled([preferences authorAndUserStylesEnabled]); 1311 settings->setApplicationChromeMode([preferences applicationChromeModeEnabled]); 1312 if ([preferences userStyleSheetEnabled]) { 1313 NSString* location = [[preferences userStyleSheetLocation] _web_originalDataAsString]; 1314 if ([location isEqualToString:@"apple-dashboard://stylesheet"]) 1315 location = @"file:///System/Library/PrivateFrameworks/DashboardClient.framework/Resources/widget.css"; 1316 settings->setUserStyleSheetLocation([NSURL URLWithString:(location ? location : @"")]); 1317 } else 1318 settings->setUserStyleSheetLocation([NSURL URLWithString:@""]); 1319 settings->setNeedsAdobeFrameReloadingQuirk([self _needsAdobeFrameReloadingQuirk]); 1320 settings->setTreatsAnyTextCSSLinkAsStylesheet([self _needsLinkElementTextCSSQuirk]); 1321 settings->setNeedsKeyboardEventDisambiguationQuirks([self _needsKeyboardEventDisambiguationQuirks]); 1322 settings->setNeedsLeopardMailQuirks(runningLeopardMail()); 1323 settings->setNeedsTigerMailQuirks(runningTigerMail()); 1324 settings->setNeedsSiteSpecificQuirks(_private->useSiteSpecificSpoofing); 1325 settings->setWebArchiveDebugModeEnabled([preferences webArchiveDebugModeEnabled]); 1326 settings->setLocalFileContentSniffingEnabled([preferences localFileContentSniffingEnabled]); 1327 settings->setOfflineWebApplicationCacheEnabled([preferences offlineWebApplicationCacheEnabled]); 1328 settings->setZoomsTextOnly([preferences zoomsTextOnly]); 1329 settings->setXSSAuditorEnabled([preferences isXSSAuditorEnabled]); 1330 settings->setEnforceCSSMIMETypeInStrictMode(!WKAppVersionCheckLessThan(@"com.apple.iWeb", -1, 2.1)); 1331 settings->setAcceleratedCompositingEnabled([preferences acceleratedCompositingEnabled]); 1332 settings->setShowDebugBorders([preferences showDebugBorders]); 1333 settings->setShowRepaintCounter([preferences showRepaintCounter]); 1334 settings->setPluginAllowedRunTime([preferences pluginAllowedRunTime]); 1335 settings->setWebGLEnabled([preferences webGLEnabled]); 1336 settings->setLoadDeferringEnabled(shouldEnableLoadDeferring()); 1337 settings->setFrameSetFlatteningEnabled([preferences isFrameSetFlatteningEnabled]); 1338} 1339 1340static inline IMP getMethod(id o, SEL s) 1341{ 1342 return [o respondsToSelector:s] ? [o methodForSelector:s] : 0; 1343} 1344 1345- (void)_cacheResourceLoadDelegateImplementations 1346{ 1347 WebResourceDelegateImplementationCache *cache = &_private->resourceLoadDelegateImplementations; 1348 id delegate = _private->resourceProgressDelegate; 1349 1350 if (!delegate) { 1351 bzero(cache, sizeof(WebResourceDelegateImplementationCache)); 1352 return; 1353 } 1354 1355 cache->didCancelAuthenticationChallengeFunc = getMethod(delegate, @selector(webView:resource:didReceiveAuthenticationChallenge:fromDataSource:)); 1356 cache->didFailLoadingWithErrorFromDataSourceFunc = getMethod(delegate, @selector(webView:resource:didFailLoadingWithError:fromDataSource:)); 1357 cache->didFinishLoadingFromDataSourceFunc = getMethod(delegate, @selector(webView:resource:didFinishLoadingFromDataSource:)); 1358 cache->didLoadResourceFromMemoryCacheFunc = getMethod(delegate, @selector(webView:didLoadResourceFromMemoryCache:response:length:fromDataSource:)); 1359 cache->didReceiveAuthenticationChallengeFunc = getMethod(delegate, @selector(webView:resource:didReceiveAuthenticationChallenge:fromDataSource:)); 1360 cache->didReceiveContentLengthFunc = getMethod(delegate, @selector(webView:resource:didReceiveContentLength:fromDataSource:)); 1361 cache->didReceiveResponseFunc = getMethod(delegate, @selector(webView:resource:didReceiveResponse:fromDataSource:)); 1362 cache->identifierForRequestFunc = getMethod(delegate, @selector(webView:identifierForInitialRequest:fromDataSource:)); 1363 cache->plugInFailedWithErrorFunc = getMethod(delegate, @selector(webView:plugInFailedWithError:dataSource:)); 1364 cache->willCacheResponseFunc = getMethod(delegate, @selector(webView:resource:willCacheResponse:fromDataSource:)); 1365 cache->willSendRequestFunc = getMethod(delegate, @selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:)); 1366 cache->shouldUseCredentialStorageFunc = getMethod(delegate, @selector(webView:resource:shouldUseCredentialStorageForDataSource:)); 1367} 1368 1369- (void)_cacheFrameLoadDelegateImplementations 1370{ 1371 WebFrameLoadDelegateImplementationCache *cache = &_private->frameLoadDelegateImplementations; 1372 id delegate = _private->frameLoadDelegate; 1373 1374 if (!delegate) { 1375 bzero(cache, sizeof(WebFrameLoadDelegateImplementationCache)); 1376 return; 1377 } 1378 1379 cache->didCancelClientRedirectForFrameFunc = getMethod(delegate, @selector(webView:didCancelClientRedirectForFrame:)); 1380 cache->didChangeLocationWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didChangeLocationWithinPageForFrame:)); 1381 cache->didPushStateWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didPushStateWithinPageForFrame:)); 1382 cache->didReplaceStateWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didReplaceStateWithinPageForFrame:)); 1383 cache->didPopStateWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didPopStateWithinPageForFrame:)); 1384 cache->didClearWindowObjectForFrameFunc = getMethod(delegate, @selector(webView:didClearWindowObject:forFrame:)); 1385 cache->didClearWindowObjectForFrameInScriptWorldFunc = getMethod(delegate, @selector(webView:didClearWindowObjectForFrame:inScriptWorld:)); 1386 cache->didClearInspectorWindowObjectForFrameFunc = getMethod(delegate, @selector(webView:didClearInspectorWindowObject:forFrame:)); 1387 cache->didCommitLoadForFrameFunc = getMethod(delegate, @selector(webView:didCommitLoadForFrame:)); 1388 cache->didFailLoadWithErrorForFrameFunc = getMethod(delegate, @selector(webView:didFailLoadWithError:forFrame:)); 1389 cache->didFailProvisionalLoadWithErrorForFrameFunc = getMethod(delegate, @selector(webView:didFailProvisionalLoadWithError:forFrame:)); 1390 cache->didFinishDocumentLoadForFrameFunc = getMethod(delegate, @selector(webView:didFinishDocumentLoadForFrame:)); 1391 cache->didFinishLoadForFrameFunc = getMethod(delegate, @selector(webView:didFinishLoadForFrame:)); 1392 cache->didFirstLayoutInFrameFunc = getMethod(delegate, @selector(webView:didFirstLayoutInFrame:)); 1393 cache->didFirstVisuallyNonEmptyLayoutInFrameFunc = getMethod(delegate, @selector(webView:didFirstVisuallyNonEmptyLayoutInFrame:)); 1394 cache->didHandleOnloadEventsForFrameFunc = getMethod(delegate, @selector(webView:didHandleOnloadEventsForFrame:)); 1395 cache->didReceiveIconForFrameFunc = getMethod(delegate, @selector(webView:didReceiveIcon:forFrame:)); 1396 cache->didReceiveServerRedirectForProvisionalLoadForFrameFunc = getMethod(delegate, @selector(webView:didReceiveServerRedirectForProvisionalLoadForFrame:)); 1397 cache->didReceiveTitleForFrameFunc = getMethod(delegate, @selector(webView:didReceiveTitle:forFrame:)); 1398 cache->didStartProvisionalLoadForFrameFunc = getMethod(delegate, @selector(webView:didStartProvisionalLoadForFrame:)); 1399 cache->willCloseFrameFunc = getMethod(delegate, @selector(webView:willCloseFrame:)); 1400 cache->willPerformClientRedirectToURLDelayFireDateForFrameFunc = getMethod(delegate, @selector(webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:)); 1401 cache->windowScriptObjectAvailableFunc = getMethod(delegate, @selector(webView:windowScriptObjectAvailable:)); 1402 cache->didDisplayInsecureContentFunc = getMethod(delegate, @selector(webViewDidDisplayInsecureContent:)); 1403 cache->didRunInsecureContentFunc = getMethod(delegate, @selector(webView:didRunInsecureContent:)); 1404} 1405 1406- (void)_cacheScriptDebugDelegateImplementations 1407{ 1408 WebScriptDebugDelegateImplementationCache *cache = &_private->scriptDebugDelegateImplementations; 1409 id delegate = _private->scriptDebugDelegate; 1410 1411 if (!delegate) { 1412 bzero(cache, sizeof(WebScriptDebugDelegateImplementationCache)); 1413 return; 1414 } 1415 1416 cache->didParseSourceFunc = getMethod(delegate, @selector(webView:didParseSource:baseLineNumber:fromURL:sourceId:forWebFrame:)); 1417 if (cache->didParseSourceFunc) 1418 cache->didParseSourceExpectsBaseLineNumber = YES; 1419 else 1420 cache->didParseSourceFunc = getMethod(delegate, @selector(webView:didParseSource:fromURL:sourceId:forWebFrame:)); 1421 1422 cache->failedToParseSourceFunc = getMethod(delegate, @selector(webView:failedToParseSource:baseLineNumber:fromURL:withError:forWebFrame:)); 1423 cache->didEnterCallFrameFunc = getMethod(delegate, @selector(webView:didEnterCallFrame:sourceId:line:forWebFrame:)); 1424 cache->willExecuteStatementFunc = getMethod(delegate, @selector(webView:willExecuteStatement:sourceId:line:forWebFrame:)); 1425 cache->willLeaveCallFrameFunc = getMethod(delegate, @selector(webView:willLeaveCallFrame:sourceId:line:forWebFrame:)); 1426 cache->exceptionWasRaisedFunc = getMethod(delegate, @selector(webView:exceptionWasRaised:sourceId:line:forWebFrame:)); 1427} 1428 1429- (void)_cacheHistoryDelegateImplementations 1430{ 1431 WebHistoryDelegateImplementationCache *cache = &_private->historyDelegateImplementations; 1432 id delegate = _private->historyDelegate; 1433 1434 if (!delegate) { 1435 bzero(cache, sizeof(WebHistoryDelegateImplementationCache)); 1436 return; 1437 } 1438 1439 cache->navigatedFunc = getMethod(delegate, @selector(webView:didNavigateWithNavigationData:inFrame:)); 1440 cache->clientRedirectFunc = getMethod(delegate, @selector(webView:didPerformClientRedirectFromURL:toURL:inFrame:)); 1441 cache->serverRedirectFunc = getMethod(delegate, @selector(webView:didPerformServerRedirectFromURL:toURL:inFrame:)); 1442 cache->setTitleFunc = getMethod(delegate, @selector(webView:updateHistoryTitle:forURL:)); 1443 cache->populateVisitedLinksFunc = getMethod(delegate, @selector(populateVisitedLinksForWebView:)); 1444} 1445 1446- (id)_policyDelegateForwarder 1447{ 1448 if (!_private->policyDelegateForwarder) 1449 _private->policyDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->policyDelegate defaultTarget:[WebDefaultPolicyDelegate sharedPolicyDelegate] catchExceptions:_private->catchesDelegateExceptions]; 1450 return _private->policyDelegateForwarder; 1451} 1452 1453- (id)_UIDelegateForwarder 1454{ 1455 if (!_private->UIDelegateForwarder) 1456 _private->UIDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->UIDelegate defaultTarget:[WebDefaultUIDelegate sharedUIDelegate] catchExceptions:_private->catchesDelegateExceptions]; 1457 return _private->UIDelegateForwarder; 1458} 1459 1460- (id)_editingDelegateForwarder 1461{ 1462 // This can be called during window deallocation by QTMovieView in the QuickTime Cocoa Plug-in. 1463 // Not sure if that is a bug or not. 1464 if (!_private) 1465 return nil; 1466 1467 if (!_private->editingDelegateForwarder) 1468 _private->editingDelegateForwarder = [[_WebSafeForwarder alloc] initWithTarget:_private->editingDelegate defaultTarget:[WebDefaultEditingDelegate sharedEditingDelegate] catchExceptions:_private->catchesDelegateExceptions]; 1469 return _private->editingDelegateForwarder; 1470} 1471 1472- (void)_closeWindow 1473{ 1474 [[self _UIDelegateForwarder] webViewClose:self]; 1475} 1476 1477+ (void)_unregisterViewClassAndRepresentationClassForMIMEType:(NSString *)MIMEType 1478{ 1479 [[WebFrameView _viewTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType]; 1480 [[WebDataSource _repTypesAllowImageTypeOmission:NO] removeObjectForKey:MIMEType]; 1481 1482 // FIXME: We also need to maintain MIMEType registrations (which can be dynamically changed) 1483 // in the WebCore MIMEType registry. For now we're doing this in a safe, limited manner 1484 // to fix <rdar://problem/5372989> - a future revamping of the entire system is neccesary for future robustness 1485 MIMETypeRegistry::getSupportedNonImageMIMETypes().remove(MIMEType); 1486} 1487 1488+ (void)_registerViewClass:(Class)viewClass representationClass:(Class)representationClass forURLScheme:(NSString *)URLScheme 1489{ 1490 NSString *MIMEType = [self _generatedMIMETypeForURLScheme:URLScheme]; 1491 [self registerViewClass:viewClass representationClass:representationClass forMIMEType:MIMEType]; 1492 1493 // FIXME: We also need to maintain MIMEType registrations (which can be dynamically changed) 1494 // in the WebCore MIMEType registry. For now we're doing this in a safe, limited manner 1495 // to fix <rdar://problem/5372989> - a future revamping of the entire system is neccesary for future robustness 1496 if ([viewClass class] == [WebHTMLView class]) 1497 MIMETypeRegistry::getSupportedNonImageMIMETypes().add(MIMEType); 1498 1499 // This is used to make _representationExistsForURLScheme faster. 1500 // Without this set, we'd have to create the MIME type each time. 1501 if (schemesWithRepresentationsSet == nil) { 1502 schemesWithRepresentationsSet = [[NSMutableSet alloc] init]; 1503 } 1504 [schemesWithRepresentationsSet addObject:[[[URLScheme lowercaseString] copy] autorelease]]; 1505} 1506 1507+ (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme 1508{ 1509 return [@"x-apple-web-kit/" stringByAppendingString:[URLScheme lowercaseString]]; 1510} 1511 1512+ (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme 1513{ 1514 return [schemesWithRepresentationsSet containsObject:[URLScheme lowercaseString]]; 1515} 1516 1517+ (BOOL)_canHandleRequest:(NSURLRequest *)request forMainFrame:(BOOL)forMainFrame 1518{ 1519 // FIXME: If <rdar://problem/5217309> gets fixed, this check can be removed. 1520 if (!request) 1521 return NO; 1522 1523 if ([NSURLConnection canHandleRequest:request]) 1524 return YES; 1525 1526 NSString *scheme = [[request URL] scheme]; 1527 1528 // Representations for URL schemes work at the top level. 1529 if (forMainFrame && [self _representationExistsForURLScheme:scheme]) 1530 return YES; 1531 1532 return [scheme _webkit_isCaseInsensitiveEqualToString:@"applewebdata"]; 1533} 1534 1535+ (BOOL)_canHandleRequest:(NSURLRequest *)request 1536{ 1537 return [self _canHandleRequest:request forMainFrame:YES]; 1538} 1539 1540+ (NSString *)_decodeData:(NSData *)data 1541{ 1542 HTMLNames::init(); // this method is used for importing bookmarks at startup, so HTMLNames are likely to be uninitialized yet 1543 RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/html"); // bookmark files are HTML 1544 String result = decoder->decode(static_cast<const char*>([data bytes]), [data length]); 1545 result += decoder->flush(); 1546 return result; 1547} 1548 1549- (void)_pushPerformingProgrammaticFocus 1550{ 1551 _private->programmaticFocusCount++; 1552} 1553 1554- (void)_popPerformingProgrammaticFocus 1555{ 1556 _private->programmaticFocusCount--; 1557} 1558 1559- (BOOL)_isPerformingProgrammaticFocus 1560{ 1561 return _private->programmaticFocusCount != 0; 1562} 1563 1564- (void)_didChangeValueForKey: (NSString *)key 1565{ 1566 LOG (Bindings, "calling didChangeValueForKey: %@", key); 1567 [self didChangeValueForKey: key]; 1568} 1569 1570- (void)_willChangeValueForKey: (NSString *)key 1571{ 1572 LOG (Bindings, "calling willChangeValueForKey: %@", key); 1573 [self willChangeValueForKey: key]; 1574} 1575 1576+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key { 1577 static NSSet *manualNotifyKeys = nil; 1578 if (!manualNotifyKeys) 1579 manualNotifyKeys = [[NSSet alloc] initWithObjects:_WebMainFrameURLKey, _WebIsLoadingKey, _WebEstimatedProgressKey, 1580 _WebCanGoBackKey, _WebCanGoForwardKey, _WebMainFrameTitleKey, _WebMainFrameIconKey, _WebMainFrameDocumentKey, 1581 nil]; 1582 if ([manualNotifyKeys containsObject:key]) 1583 return NO; 1584 return YES; 1585} 1586 1587- (NSArray *)_declaredKeys { 1588 static NSArray *declaredKeys = nil; 1589 if (!declaredKeys) 1590 declaredKeys = [[NSArray alloc] initWithObjects:_WebMainFrameURLKey, _WebIsLoadingKey, _WebEstimatedProgressKey, 1591 _WebCanGoBackKey, _WebCanGoForwardKey, _WebMainFrameTitleKey, _WebMainFrameIconKey, _WebMainFrameDocumentKey, nil]; 1592 return declaredKeys; 1593} 1594 1595- (void)setObservationInfo:(void *)info 1596{ 1597 _private->observationInfo = info; 1598} 1599 1600- (void *)observationInfo 1601{ 1602 return _private->observationInfo; 1603} 1604 1605- (void)_willChangeBackForwardKeys 1606{ 1607 [self _willChangeValueForKey: _WebCanGoBackKey]; 1608 [self _willChangeValueForKey: _WebCanGoForwardKey]; 1609} 1610 1611- (void)_didChangeBackForwardKeys 1612{ 1613 [self _didChangeValueForKey: _WebCanGoBackKey]; 1614 [self _didChangeValueForKey: _WebCanGoForwardKey]; 1615} 1616 1617- (void)_didStartProvisionalLoadForFrame:(WebFrame *)frame 1618{ 1619 [self _willChangeBackForwardKeys]; 1620 if (frame == [self mainFrame]){ 1621 // Force an observer update by sending a will/did. 1622 [self _willChangeValueForKey: _WebIsLoadingKey]; 1623 [self _didChangeValueForKey: _WebIsLoadingKey]; 1624 1625 [self _willChangeValueForKey: _WebMainFrameURLKey]; 1626 } 1627 1628 [NSApp setWindowsNeedUpdate:YES]; 1629} 1630 1631- (void)_didCommitLoadForFrame:(WebFrame *)frame 1632{ 1633 if (frame == [self mainFrame]) 1634 [self _didChangeValueForKey: _WebMainFrameURLKey]; 1635 [NSApp setWindowsNeedUpdate:YES]; 1636} 1637 1638- (void)_didFinishLoadForFrame:(WebFrame *)frame 1639{ 1640 [self _didChangeBackForwardKeys]; 1641 if (frame == [self mainFrame]){ 1642 // Force an observer update by sending a will/did. 1643 [self _willChangeValueForKey: _WebIsLoadingKey]; 1644 [self _didChangeValueForKey: _WebIsLoadingKey]; 1645 } 1646 [NSApp setWindowsNeedUpdate:YES]; 1647} 1648 1649- (void)_didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame 1650{ 1651 [self _didChangeBackForwardKeys]; 1652 if (frame == [self mainFrame]){ 1653 // Force an observer update by sending a will/did. 1654 [self _willChangeValueForKey: _WebIsLoadingKey]; 1655 [self _didChangeValueForKey: _WebIsLoadingKey]; 1656 } 1657 [NSApp setWindowsNeedUpdate:YES]; 1658} 1659 1660- (void)_didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame 1661{ 1662 [self _didChangeBackForwardKeys]; 1663 if (frame == [self mainFrame]){ 1664 // Force an observer update by sending a will/did. 1665 [self _willChangeValueForKey: _WebIsLoadingKey]; 1666 [self _didChangeValueForKey: _WebIsLoadingKey]; 1667 1668 [self _didChangeValueForKey: _WebMainFrameURLKey]; 1669 } 1670 [NSApp setWindowsNeedUpdate:YES]; 1671} 1672 1673- (NSCachedURLResponse *)_cachedResponseForURL:(NSURL *)URL 1674{ 1675 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL]; 1676 [request _web_setHTTPUserAgent:[self userAgentForURL:URL]]; 1677 NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request]; 1678 [request release]; 1679 return cachedResponse; 1680} 1681 1682- (void)_writeImageForElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard 1683{ 1684 NSURL *linkURL = [element objectForKey:WebElementLinkURLKey]; 1685 DOMElement *domElement = [element objectForKey:WebElementDOMNodeKey]; 1686 [pasteboard _web_writeImage:(NSImage *)(domElement ? nil : [element objectForKey:WebElementImageKey]) 1687 element:domElement 1688 URL:linkURL ? linkURL : (NSURL *)[element objectForKey:WebElementImageURLKey] 1689 title:[element objectForKey:WebElementImageAltStringKey] 1690 archive:[[element objectForKey:WebElementDOMNodeKey] webArchive] 1691 types:types 1692 source:nil]; 1693} 1694 1695- (void)_writeLinkElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard 1696{ 1697 [pasteboard _web_writeURL:[element objectForKey:WebElementLinkURLKey] 1698 andTitle:[element objectForKey:WebElementLinkLabelKey] 1699 types:types]; 1700} 1701 1702- (void)_setInitiatedDrag:(BOOL)initiatedDrag 1703{ 1704 if (!_private->page) 1705 return; 1706 _private->page->dragController()->setDidInitiateDrag(initiatedDrag); 1707} 1708 1709#if ENABLE(DASHBOARD_SUPPORT) 1710 1711#define DASHBOARD_CONTROL_LABEL @"control" 1712 1713- (void)_addControlRect:(NSRect)bounds clip:(NSRect)clip fromView:(NSView *)view toDashboardRegions:(NSMutableDictionary *)regions 1714{ 1715 NSRect adjustedBounds = bounds; 1716 adjustedBounds.origin = [self convertPoint:bounds.origin fromView:view]; 1717 adjustedBounds.origin.y = [self bounds].size.height - adjustedBounds.origin.y; 1718 adjustedBounds.size = bounds.size; 1719 1720 NSRect adjustedClip; 1721 adjustedClip.origin = [self convertPoint:clip.origin fromView:view]; 1722 adjustedClip.origin.y = [self bounds].size.height - adjustedClip.origin.y; 1723 adjustedClip.size = clip.size; 1724 1725 WebDashboardRegion *region = [[WebDashboardRegion alloc] initWithRect:adjustedBounds 1726 clip:adjustedClip type:WebDashboardRegionTypeScrollerRectangle]; 1727 NSMutableArray *scrollerRegions = [regions objectForKey:DASHBOARD_CONTROL_LABEL]; 1728 if (!scrollerRegions) { 1729 scrollerRegions = [[NSMutableArray alloc] init]; 1730 [regions setObject:scrollerRegions forKey:DASHBOARD_CONTROL_LABEL]; 1731 [scrollerRegions release]; 1732 } 1733 [scrollerRegions addObject:region]; 1734 [region release]; 1735} 1736 1737- (void)_addScrollerDashboardRegionsForFrameView:(FrameView*)frameView dashboardRegions:(NSMutableDictionary *)regions 1738{ 1739 NSView *documentView = [[kit(frameView->frame()) frameView] documentView]; 1740 1741 const HashSet<RefPtr<Widget> >* children = frameView->children(); 1742 HashSet<RefPtr<Widget> >::const_iterator end = children->end(); 1743 for (HashSet<RefPtr<Widget> >::const_iterator it = children->begin(); it != end; ++it) { 1744 Widget* widget = (*it).get(); 1745 if (widget->isFrameView()) { 1746 [self _addScrollerDashboardRegionsForFrameView:static_cast<FrameView*>(widget) dashboardRegions:regions]; 1747 continue; 1748 } 1749 1750 if (!widget->isScrollbar()) 1751 continue; 1752 1753 // FIXME: This should really pass an appropriate clip, but our first try got it wrong, and 1754 // it's not common to need this to be correct in Dashboard widgets. 1755 NSRect bounds = widget->frameRect(); 1756 [self _addControlRect:bounds clip:bounds fromView:documentView toDashboardRegions:regions]; 1757 } 1758} 1759 1760- (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions from:(NSArray *)views 1761{ 1762 // Add scroller regions for NSScroller and WebCore scrollbars 1763 NSUInteger count = [views count]; 1764 for (NSUInteger i = 0; i < count; i++) { 1765 NSView *view = [views objectAtIndex:i]; 1766 1767 if ([view isKindOfClass:[WebHTMLView class]]) { 1768 if (Frame* coreFrame = core([(WebHTMLView*)view _frame])) { 1769 if (FrameView* coreView = coreFrame->view()) 1770 [self _addScrollerDashboardRegionsForFrameView:coreView dashboardRegions:regions]; 1771 } 1772 } else if ([view isKindOfClass:[NSScroller class]]) { 1773 // AppKit places absent scrollers at -100,-100 1774 if ([view frame].origin.y < 0) 1775 continue; 1776 [self _addControlRect:[view bounds] clip:[view visibleRect] fromView:view toDashboardRegions:regions]; 1777 } 1778 [self _addScrollerDashboardRegions:regions from:[view subviews]]; 1779 } 1780} 1781 1782- (void)_addScrollerDashboardRegions:(NSMutableDictionary *)regions 1783{ 1784 [self _addScrollerDashboardRegions:regions from:[self subviews]]; 1785} 1786 1787- (NSDictionary *)_dashboardRegions 1788{ 1789 // Only return regions from main frame. 1790 Frame* mainFrame = [self _mainCoreFrame]; 1791 if (!mainFrame) 1792 return nil; 1793 NSMutableDictionary *regions = mainFrame->dashboardRegionsDictionary(); 1794 [self _addScrollerDashboardRegions:regions]; 1795 return regions; 1796} 1797 1798- (void)_setDashboardBehavior:(WebDashboardBehavior)behavior to:(BOOL)flag 1799{ 1800 // FIXME: Remove this blanket assignment once Dashboard and Dashcode implement 1801 // specific support for the backward compatibility mode flag. 1802 if (behavior == WebDashboardBehaviorAllowWheelScrolling && flag == NO && _private->page) 1803 _private->page->settings()->setUsesDashboardBackwardCompatibilityMode(true); 1804 1805 switch (behavior) { 1806 case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: { 1807 _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows = flag; 1808 break; 1809 } 1810 case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: { 1811 _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns = flag; 1812 break; 1813 } 1814 case WebDashboardBehaviorAlwaysAcceptsFirstMouse: { 1815 _private->dashboardBehaviorAlwaysAcceptsFirstMouse = flag; 1816 break; 1817 } 1818 case WebDashboardBehaviorAllowWheelScrolling: { 1819 _private->dashboardBehaviorAllowWheelScrolling = flag; 1820 break; 1821 } 1822 case WebDashboardBehaviorUseBackwardCompatibilityMode: { 1823 if (_private->page) 1824 _private->page->settings()->setUsesDashboardBackwardCompatibilityMode(flag); 1825 break; 1826 } 1827 } 1828} 1829 1830- (BOOL)_dashboardBehavior:(WebDashboardBehavior)behavior 1831{ 1832 switch (behavior) { 1833 case WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows: { 1834 return _private->dashboardBehaviorAlwaysSendMouseEventsToAllWindows; 1835 } 1836 case WebDashboardBehaviorAlwaysSendActiveNullEventsToPlugIns: { 1837 return _private->dashboardBehaviorAlwaysSendActiveNullEventsToPlugIns; 1838 } 1839 case WebDashboardBehaviorAlwaysAcceptsFirstMouse: { 1840 return _private->dashboardBehaviorAlwaysAcceptsFirstMouse; 1841 } 1842 case WebDashboardBehaviorAllowWheelScrolling: { 1843 return _private->dashboardBehaviorAllowWheelScrolling; 1844 } 1845 case WebDashboardBehaviorUseBackwardCompatibilityMode: { 1846 return _private->page && _private->page->settings()->usesDashboardBackwardCompatibilityMode(); 1847 } 1848 } 1849 return NO; 1850} 1851 1852#endif /* ENABLE(DASHBOARD_SUPPORT) */ 1853 1854+ (void)_setShouldUseFontSmoothing:(BOOL)f 1855{ 1856 Font::setShouldUseSmoothing(f); 1857} 1858 1859+ (BOOL)_shouldUseFontSmoothing 1860{ 1861 return Font::shouldUseSmoothing(); 1862} 1863 1864+ (void)_setUsesTestModeFocusRingColor:(BOOL)f 1865{ 1866 setUsesTestModeFocusRingColor(f); 1867} 1868 1869+ (BOOL)_usesTestModeFocusRingColor 1870{ 1871 return usesTestModeFocusRingColor(); 1872} 1873 1874- (void)setAlwaysShowVerticalScroller:(BOOL)flag 1875{ 1876 WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView]; 1877 if (flag) { 1878 [scrollview setVerticalScrollingMode:ScrollbarAlwaysOn andLock:YES]; 1879 } else { 1880 [scrollview setVerticalScrollingModeLocked:NO]; 1881 [scrollview setVerticalScrollingMode:ScrollbarAuto andLock:NO]; 1882 } 1883} 1884 1885- (BOOL)alwaysShowVerticalScroller 1886{ 1887 WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView]; 1888 return [scrollview verticalScrollingModeLocked] && [scrollview verticalScrollingMode] == ScrollbarAlwaysOn; 1889} 1890 1891- (void)setAlwaysShowHorizontalScroller:(BOOL)flag 1892{ 1893 WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView]; 1894 if (flag) { 1895 [scrollview setHorizontalScrollingMode:ScrollbarAlwaysOn andLock:YES]; 1896 } else { 1897 [scrollview setHorizontalScrollingModeLocked:NO]; 1898 [scrollview setHorizontalScrollingMode:ScrollbarAuto andLock:NO]; 1899 } 1900} 1901 1902- (void)setProhibitsMainFrameScrolling:(BOOL)prohibits 1903{ 1904 if (Frame* mainFrame = [self _mainCoreFrame]) 1905 mainFrame->view()->setProhibitsScrolling(prohibits); 1906} 1907 1908- (BOOL)alwaysShowHorizontalScroller 1909{ 1910 WebDynamicScrollBarsView *scrollview = [[[self mainFrame] frameView] _scrollView]; 1911 return [scrollview horizontalScrollingModeLocked] && [scrollview horizontalScrollingMode] == ScrollbarAlwaysOn; 1912} 1913 1914- (void)_setInViewSourceMode:(BOOL)flag 1915{ 1916 if (Frame* mainFrame = [self _mainCoreFrame]) 1917 mainFrame->setInViewSourceMode(flag); 1918} 1919 1920- (BOOL)_inViewSourceMode 1921{ 1922 Frame* mainFrame = [self _mainCoreFrame]; 1923 return mainFrame && mainFrame->inViewSourceMode(); 1924} 1925 1926- (void)_setUseFastImageScalingMode:(BOOL)flag 1927{ 1928 if (_private->page && _private->page->inLowQualityImageInterpolationMode() != flag) { 1929 _private->page->setInLowQualityImageInterpolationMode(flag); 1930 [self setNeedsDisplay:YES]; 1931 } 1932} 1933 1934- (BOOL)_inFastImageScalingMode 1935{ 1936 if (_private->page) 1937 return _private->page->inLowQualityImageInterpolationMode(); 1938 return NO; 1939} 1940 1941- (BOOL)_cookieEnabled 1942{ 1943 if (_private->page) 1944 return _private->page->cookieEnabled(); 1945 return YES; 1946} 1947 1948- (void)_setCookieEnabled:(BOOL)enable 1949{ 1950 if (_private->page) 1951 _private->page->setCookieEnabled(enable); 1952} 1953 1954- (void)_setAdditionalWebPlugInPaths:(NSArray *)newPaths 1955{ 1956 if (!_private->pluginDatabase) 1957 _private->pluginDatabase = [[WebPluginDatabase alloc] init]; 1958 1959 [_private->pluginDatabase setPlugInPaths:newPaths]; 1960 [_private->pluginDatabase refresh]; 1961} 1962 1963- (void)_attachScriptDebuggerToAllFrames 1964{ 1965 for (Frame* frame = [self _mainCoreFrame]; frame; frame = frame->tree()->traverseNext()) 1966 [kit(frame) _attachScriptDebugger]; 1967} 1968 1969- (void)_detachScriptDebuggerFromAllFrames 1970{ 1971 for (Frame* frame = [self _mainCoreFrame]; frame; frame = frame->tree()->traverseNext()) 1972 [kit(frame) _detachScriptDebugger]; 1973} 1974 1975- (void)setBackgroundColor:(NSColor *)backgroundColor 1976{ 1977 if ([_private->backgroundColor isEqual:backgroundColor]) 1978 return; 1979 1980 id old = _private->backgroundColor; 1981 _private->backgroundColor = [backgroundColor retain]; 1982 [old release]; 1983 1984 [[self mainFrame] _updateBackgroundAndUpdatesWhileOffscreen]; 1985} 1986 1987- (NSColor *)backgroundColor 1988{ 1989 return _private->backgroundColor; 1990} 1991 1992- (BOOL)defersCallbacks 1993{ 1994 if (!_private->page) 1995 return NO; 1996 return _private->page->defersLoading(); 1997} 1998 1999- (void)setDefersCallbacks:(BOOL)defer 2000{ 2001 if (!_private->page) 2002 return; 2003 return _private->page->setDefersLoading(defer); 2004} 2005 2006// For backwards compatibility with the WebBackForwardList API, we honor both 2007// a per-WebView and a per-preferences setting for whether to use the page cache. 2008 2009- (BOOL)usesPageCache 2010{ 2011 return _private->usesPageCache && [[self preferences] usesPageCache]; 2012} 2013 2014- (void)setUsesPageCache:(BOOL)usesPageCache 2015{ 2016 _private->usesPageCache = usesPageCache; 2017 2018 // Post a notification so the WebCore settings update. 2019 [[self preferences] _postPreferencesChangesNotification]; 2020} 2021 2022- (WebHistoryItem *)_globalHistoryItem 2023{ 2024 if (!_private->page) 2025 return nil; 2026 return kit(_private->page->globalHistoryItem()); 2027} 2028 2029- (WebTextIterator *)textIteratorForRect:(NSRect)rect 2030{ 2031 IntPoint rectStart(rect.origin.x, rect.origin.y); 2032 IntPoint rectEnd(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height); 2033 2034 Frame* coreFrame = [self _mainCoreFrame]; 2035 if (!coreFrame) 2036 return nil; 2037 2038 VisibleSelection selectionInsideRect(coreFrame->visiblePositionForPoint(rectStart), coreFrame->visiblePositionForPoint(rectEnd)); 2039 2040 return [[[WebTextIterator alloc] initWithRange:kit(selectionInsideRect.toNormalizedRange().get())] autorelease]; 2041} 2042 2043- (void)handleAuthenticationForResource:(id)identifier challenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource 2044{ 2045 NSWindow *window = [self hostWindow] ? [self hostWindow] : [self window]; 2046 [[WebPanelAuthenticationHandler sharedHandler] startAuthentication:challenge window:window]; 2047} 2048 2049- (void)_clearUndoRedoOperations 2050{ 2051 if (!_private->page) 2052 return; 2053 _private->page->clearUndoRedoOperations(); 2054} 2055 2056- (void)_setCatchesDelegateExceptions:(BOOL)f 2057{ 2058 _private->catchesDelegateExceptions = f; 2059} 2060 2061- (BOOL)_catchesDelegateExceptions 2062{ 2063 return _private->catchesDelegateExceptions; 2064} 2065 2066- (void)_executeCoreCommandByName:(NSString *)name value:(NSString *)value 2067{ 2068 Frame* coreFrame = [self _mainCoreFrame]; 2069 if (!coreFrame) 2070 return; 2071 coreFrame->editor()->command(name).execute(value); 2072} 2073 2074- (void)_setCustomHTMLTokenizerTimeDelay:(double)timeDelay 2075{ 2076 if (!_private->page) 2077 return; 2078 return _private->page->setCustomHTMLTokenizerTimeDelay(timeDelay); 2079} 2080 2081- (void)_setCustomHTMLTokenizerChunkSize:(int)chunkSize 2082{ 2083 if (!_private->page) 2084 return; 2085 return _private->page->setCustomHTMLTokenizerChunkSize(chunkSize); 2086} 2087 2088- (void)_clearMainFrameName 2089{ 2090 _private->page->mainFrame()->tree()->clearName(); 2091} 2092 2093- (void)setSelectTrailingWhitespaceEnabled:(BOOL)flag 2094{ 2095 _private->selectTrailingWhitespaceEnabled = flag; 2096 if (flag) 2097 [self setSmartInsertDeleteEnabled:false]; 2098} 2099 2100- (BOOL)isSelectTrailingWhitespaceEnabled 2101{ 2102 return _private->selectTrailingWhitespaceEnabled; 2103} 2104 2105- (void)setMemoryCacheDelegateCallsEnabled:(BOOL)enabled 2106{ 2107 _private->page->setMemoryCacheClientCallsEnabled(enabled); 2108} 2109 2110- (BOOL)areMemoryCacheDelegateCallsEnabled 2111{ 2112 return _private->page->areMemoryCacheClientCallsEnabled(); 2113} 2114 2115- (void)_setJavaScriptURLsAreAllowed:(BOOL)areAllowed 2116{ 2117 _private->page->setJavaScriptURLsAreAllowed(areAllowed); 2118} 2119 2120+ (NSCursor *)_pointingHandCursor 2121{ 2122 return handCursor().impl(); 2123} 2124 2125- (BOOL)_postsAcceleratedCompositingNotifications 2126{ 2127#if USE(ACCELERATED_COMPOSITING) 2128 return _private->postsAcceleratedCompositingNotifications; 2129#else 2130 return NO; 2131#endif 2132 2133} 2134- (void)_setPostsAcceleratedCompositingNotifications:(BOOL)flag 2135{ 2136#if USE(ACCELERATED_COMPOSITING) 2137 _private->postsAcceleratedCompositingNotifications = flag; 2138#endif 2139} 2140 2141- (BOOL)_isUsingAcceleratedCompositing 2142{ 2143#if USE(ACCELERATED_COMPOSITING) 2144 Frame* coreFrame = [self _mainCoreFrame]; 2145 if (_private->usesDocumentViews) { 2146 for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) { 2147 NSView *documentView = [[kit(frame) frameView] documentView]; 2148 if ([documentView isKindOfClass:[WebHTMLView class]] && [(WebHTMLView *)documentView _isUsingAcceleratedCompositing]) 2149 return YES; 2150 } 2151 } 2152 2153 return NO; 2154#else 2155 return NO; 2156#endif 2157} 2158 2159static WebBaseNetscapePluginView *_pluginViewForNode(DOMNode *node) 2160{ 2161 if (!node) 2162 return nil; 2163 2164 Node* coreNode = core(node); 2165 if (!coreNode) 2166 return nil; 2167 2168 RenderObject* renderer = coreNode->renderer(); 2169 if (!renderer || !renderer->isWidget()) 2170 return nil; 2171 2172 Widget* widget = toRenderWidget(renderer)->widget(); 2173 if (!widget || !widget->platformWidget()) 2174 return nil; 2175 2176 NSView *view = widget->platformWidget(); 2177 if (![view isKindOfClass:[WebBaseNetscapePluginView class]]) 2178 return nil; 2179 2180 return (WebBaseNetscapePluginView *)view; 2181} 2182 2183+ (BOOL)_isNodeHaltedPlugin:(DOMNode *)node 2184{ 2185 return [_pluginViewForNode(node) isHalted]; 2186} 2187 2188+ (BOOL)_hasPluginForNodeBeenHalted:(DOMNode *)node 2189{ 2190 return [_pluginViewForNode(node) hasBeenHalted]; 2191} 2192+ (void)_restartHaltedPluginForNode:(DOMNode *)node 2193{ 2194 if (!node) 2195 return; 2196 2197 [_pluginViewForNode(node) resumeFromHalt]; 2198} 2199 2200- (NSPasteboard *)_insertionPasteboard 2201{ 2202 return _private ? _private->insertionPasteboard : nil; 2203} 2204 2205+ (void)_whiteListAccessFromOrigin:(NSString *)sourceOrigin destinationProtocol:(NSString *)destinationProtocol destinationHost:(NSString *)destinationHost allowDestinationSubdomains:(BOOL)allowDestinationSubdomains 2206{ 2207 SecurityOrigin::whiteListAccessFromOrigin(*SecurityOrigin::createFromString(sourceOrigin), destinationProtocol, destinationHost, allowDestinationSubdomains); 2208} 2209 2210+(void)_resetOriginAccessWhiteLists 2211{ 2212 SecurityOrigin::resetOriginAccessWhiteLists(); 2213} 2214 2215- (void)_updateActiveState 2216{ 2217 if (_private && _private->page) 2218 _private->page->focusController()->setActive([[self window] isKeyWindow]); 2219} 2220 2221static PassOwnPtr<Vector<String> > toStringVector(NSArray* patterns) 2222{ 2223 // Convert the patterns into Vectors. 2224 NSUInteger count = [patterns count]; 2225 if (count == 0) 2226 return 0; 2227 Vector<String>* patternsVector = new Vector<String>; 2228 for (NSUInteger i = 0; i < count; ++i) { 2229 id entry = [patterns objectAtIndex:i]; 2230 if ([entry isKindOfClass:[NSString class]]) 2231 patternsVector->append(String((NSString*)entry)); 2232 } 2233 return patternsVector; 2234} 2235 2236+ (void)_addUserScriptToGroup:(NSString *)groupName world:(WebScriptWorld *)world source:(NSString *)source url:(NSURL *)url 2237 whitelist:(NSArray *)whitelist blacklist:(NSArray *)blacklist injectionTime:(WebUserScriptInjectionTime)injectionTime 2238{ 2239 String group(groupName); 2240 if (group.isEmpty()) 2241 return; 2242 2243 PageGroup* pageGroup = PageGroup::pageGroup(group); 2244 if (!pageGroup) 2245 return; 2246 2247 pageGroup->addUserScriptToWorld(core(world), source, url, toStringVector(whitelist), toStringVector(blacklist), 2248 injectionTime == WebInjectAtDocumentStart ? InjectAtDocumentStart : InjectAtDocumentEnd); 2249} 2250 2251+ (void)_addUserStyleSheetToGroup:(NSString *)groupName world:(WebScriptWorld *)world source:(NSString *)source url:(NSURL *)url 2252 whitelist:(NSArray *)whitelist blacklist:(NSArray *)blacklist 2253{ 2254 String group(groupName); 2255 if (group.isEmpty()) 2256 return; 2257 2258 PageGroup* pageGroup = PageGroup::pageGroup(group); 2259 if (!pageGroup) 2260 return; 2261 2262 pageGroup->addUserStyleSheetToWorld(core(world), source, url, toStringVector(whitelist), toStringVector(blacklist)); 2263} 2264 2265+ (void)_removeUserScriptFromGroup:(NSString *)groupName world:(WebScriptWorld *)world url:(NSURL *)url 2266{ 2267 String group(groupName); 2268 if (group.isEmpty()) 2269 return; 2270 2271 PageGroup* pageGroup = PageGroup::pageGroup(group); 2272 if (!pageGroup) 2273 return; 2274 2275 pageGroup->removeUserScriptFromWorld(core(world), url); 2276} 2277 2278+ (void)_removeUserStyleSheetFromGroup:(NSString *)groupName world:(WebScriptWorld *)world url:(NSURL *)url 2279{ 2280 String group(groupName); 2281 if (group.isEmpty()) 2282 return; 2283 2284 PageGroup* pageGroup = PageGroup::pageGroup(group); 2285 if (!pageGroup) 2286 return; 2287 2288 pageGroup->removeUserStyleSheetFromWorld(core(world), url); 2289} 2290 2291+ (void)_removeUserScriptsFromGroup:(NSString *)groupName world:(WebScriptWorld *)world 2292{ 2293 String group(groupName); 2294 if (group.isEmpty()) 2295 return; 2296 2297 PageGroup* pageGroup = PageGroup::pageGroup(group); 2298 if (!pageGroup) 2299 return; 2300 2301 pageGroup->removeUserScriptsFromWorld(core(world)); 2302} 2303 2304+ (void)_removeUserStyleSheetsFromGroup:(NSString *)groupName world:(WebScriptWorld *)world 2305{ 2306 String group(groupName); 2307 if (group.isEmpty()) 2308 return; 2309 2310 PageGroup* pageGroup = PageGroup::pageGroup(group); 2311 if (!pageGroup) 2312 return; 2313 2314 pageGroup->removeUserStyleSheetsFromWorld(core(world)); 2315} 2316 2317+ (void)_removeAllUserContentFromGroup:(NSString *)groupName 2318{ 2319 String group(groupName); 2320 if (group.isEmpty()) 2321 return; 2322 2323 PageGroup* pageGroup = PageGroup::pageGroup(group); 2324 if (!pageGroup) 2325 return; 2326 2327 pageGroup->removeAllUserContent(); 2328} 2329 2330- (BOOL)cssAnimationsSuspended 2331{ 2332 return _private->cssAnimationsSuspended; 2333} 2334 2335- (void)setCSSAnimationsSuspended:(BOOL)suspended 2336{ 2337 if (suspended == _private->cssAnimationsSuspended) 2338 return; 2339 2340 _private->cssAnimationsSuspended = suspended; 2341 2342 Frame* frame = core([self mainFrame]); 2343 if (suspended) 2344 frame->animation()->suspendAnimations(frame->document()); 2345 else 2346 frame->animation()->resumeAnimations(frame->document()); 2347} 2348 2349+ (void)_setDomainRelaxationForbidden:(BOOL)forbidden forURLScheme:(NSString *)scheme 2350{ 2351 SecurityOrigin::setDomainRelaxationForbiddenForURLScheme(forbidden, scheme); 2352} 2353 2354@end 2355 2356@implementation _WebSafeForwarder 2357 2358// Used to send messages to delegates that implement informal protocols. 2359 2360- (id)initWithTarget:(id)t defaultTarget:(id)dt catchExceptions:(BOOL)c 2361{ 2362 self = [super init]; 2363 if (!self) 2364 return nil; 2365 target = t; // Non retained. 2366 defaultTarget = dt; 2367 catchExceptions = c; 2368 return self; 2369} 2370 2371- (void)forwardInvocation:(NSInvocation *)invocation 2372{ 2373 if ([target respondsToSelector:[invocation selector]]) { 2374 if (catchExceptions) { 2375 @try { 2376 [invocation invokeWithTarget:target]; 2377 } @catch(id exception) { 2378 ReportDiscardedDelegateException([invocation selector], exception); 2379 } 2380 } else 2381 [invocation invokeWithTarget:target]; 2382 return; 2383 } 2384 2385 if ([defaultTarget respondsToSelector:[invocation selector]]) 2386 [invocation invokeWithTarget:defaultTarget]; 2387 2388 // Do nothing quietly if method not implemented. 2389} 2390 2391- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector 2392{ 2393 return [defaultTarget methodSignatureForSelector:aSelector]; 2394} 2395 2396@end 2397 2398@implementation WebView 2399 2400+ (void)initialize 2401{ 2402 static BOOL initialized = NO; 2403 if (initialized) 2404 return; 2405 initialized = YES; 2406 2407 InitWebCoreSystemInterface(); 2408 2409 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_applicationWillTerminate) name:NSApplicationWillTerminateNotification object:NSApp]; 2410 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:) name:WebPreferencesChangedNotification object:nil]; 2411 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesRemovedNotification:) name:WebPreferencesRemovedNotification object:nil]; 2412 2413 continuousSpellCheckingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebContinuousSpellCheckingEnabled]; 2414#ifndef BUILDING_ON_TIGER 2415 grammarCheckingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebGrammarCheckingEnabled]; 2416#endif 2417 2418#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 2419 automaticQuoteSubstitutionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticQuoteSubstitutionEnabled]; 2420 automaticLinkDetectionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticLinkDetectionEnabled]; 2421 automaticDashSubstitutionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticDashSubstitutionEnabled]; 2422 automaticTextReplacementEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticTextReplacementEnabled]; 2423 automaticSpellingCorrectionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticSpellingCorrectionEnabled]; 2424#endif 2425} 2426 2427+ (void)_applicationWillTerminate 2428{ 2429 applicationIsTerminating = YES; 2430 2431 if (fastDocumentTeardownEnabled()) 2432 [self closeAllWebViews]; 2433 2434 if (!pluginDatabaseClientCount) 2435 [WebPluginDatabase closeSharedDatabase]; 2436 2437 PageGroup::closeLocalStorage(); 2438} 2439 2440+ (BOOL)_canShowMIMEType:(NSString *)MIMEType allowingPlugins:(BOOL)allowPlugins 2441{ 2442 return [self _viewClass:nil andRepresentationClass:nil forMIMEType:MIMEType allowingPlugins:allowPlugins]; 2443} 2444 2445+ (BOOL)canShowMIMEType:(NSString *)MIMEType 2446{ 2447 return [self _canShowMIMEType:MIMEType allowingPlugins:YES]; 2448} 2449 2450- (BOOL)_canShowMIMEType:(NSString *)MIMEType 2451{ 2452 return [[self class] _canShowMIMEType:MIMEType allowingPlugins:[[[self _webView] preferences] arePlugInsEnabled]]; 2453} 2454 2455- (WebBasePluginPackage *)_pluginForMIMEType:(NSString *)MIMEType 2456{ 2457 if (![_private->preferences arePlugInsEnabled]) 2458 return nil; 2459 2460 WebBasePluginPackage *pluginPackage = [[WebPluginDatabase sharedDatabase] pluginForMIMEType:MIMEType]; 2461 if (pluginPackage) 2462 return pluginPackage; 2463 2464 if (_private->pluginDatabase) 2465 return [_private->pluginDatabase pluginForMIMEType:MIMEType]; 2466 2467 return nil; 2468} 2469 2470- (WebBasePluginPackage *)_pluginForExtension:(NSString *)extension 2471{ 2472 if (![_private->preferences arePlugInsEnabled]) 2473 return nil; 2474 2475 WebBasePluginPackage *pluginPackage = [[WebPluginDatabase sharedDatabase] pluginForExtension:extension]; 2476 if (pluginPackage) 2477 return pluginPackage; 2478 2479 if (_private->pluginDatabase) 2480 return [_private->pluginDatabase pluginForExtension:extension]; 2481 2482 return nil; 2483} 2484 2485- (void)addPluginInstanceView:(NSView *)view 2486{ 2487 if (!_private->pluginDatabase) 2488 _private->pluginDatabase = [[WebPluginDatabase alloc] init]; 2489 [_private->pluginDatabase addPluginInstanceView:view]; 2490} 2491 2492- (void)removePluginInstanceView:(NSView *)view 2493{ 2494 if (_private->pluginDatabase) 2495 [_private->pluginDatabase removePluginInstanceView:view]; 2496} 2497 2498- (void)removePluginInstanceViewsFor:(WebFrame*)webFrame 2499{ 2500 if (_private->pluginDatabase) 2501 [_private->pluginDatabase removePluginInstanceViewsFor:webFrame]; 2502} 2503 2504- (BOOL)_isMIMETypeRegisteredAsPlugin:(NSString *)MIMEType 2505{ 2506 if (![_private->preferences arePlugInsEnabled]) 2507 return NO; 2508 2509 if ([[WebPluginDatabase sharedDatabase] isMIMETypeRegistered:MIMEType]) 2510 return YES; 2511 2512 if (_private->pluginDatabase && [_private->pluginDatabase isMIMETypeRegistered:MIMEType]) 2513 return YES; 2514 2515 return NO; 2516} 2517 2518+ (BOOL)canShowMIMETypeAsHTML:(NSString *)MIMEType 2519{ 2520 return [WebFrameView _canShowMIMETypeAsHTML:MIMEType]; 2521} 2522 2523+ (NSArray *)MIMETypesShownAsHTML 2524{ 2525 NSMutableDictionary *viewTypes = [WebFrameView _viewTypesAllowImageTypeOmission:YES]; 2526 NSEnumerator *enumerator = [viewTypes keyEnumerator]; 2527 id key; 2528 NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease]; 2529 2530 while ((key = [enumerator nextObject])) { 2531 if ([viewTypes objectForKey:key] == [WebHTMLView class]) 2532 [array addObject:key]; 2533 } 2534 2535 return array; 2536} 2537 2538+ (void)setMIMETypesShownAsHTML:(NSArray *)MIMETypes 2539{ 2540 NSDictionary *viewTypes = [[WebFrameView _viewTypesAllowImageTypeOmission:YES] copy]; 2541 NSEnumerator *enumerator = [viewTypes keyEnumerator]; 2542 id key; 2543 while ((key = [enumerator nextObject])) { 2544 if ([viewTypes objectForKey:key] == [WebHTMLView class]) 2545 [WebView _unregisterViewClassAndRepresentationClassForMIMEType:key]; 2546 } 2547 2548 int i, count = [MIMETypes count]; 2549 for (i = 0; i < count; i++) { 2550 [WebView registerViewClass:[WebHTMLView class] 2551 representationClass:[WebHTMLRepresentation class] 2552 forMIMEType:[MIMETypes objectAtIndex:i]]; 2553 } 2554 [viewTypes release]; 2555} 2556 2557+ (NSURL *)URLFromPasteboard:(NSPasteboard *)pasteboard 2558{ 2559 return [pasteboard _web_bestURL]; 2560} 2561 2562+ (NSString *)URLTitleFromPasteboard:(NSPasteboard *)pasteboard 2563{ 2564 return [pasteboard stringForType:WebURLNamePboardType]; 2565} 2566 2567+ (void)registerURLSchemeAsLocal:(NSString *)protocol 2568{ 2569 SecurityOrigin::registerURLSchemeAsLocal(protocol); 2570} 2571 2572- (id)_initWithArguments:(NSDictionary *) arguments 2573{ 2574 NSCoder *decoder = [arguments objectForKey:@"decoder"]; 2575 if (decoder) { 2576 self = [self initWithCoder:decoder]; 2577 } else { 2578 ASSERT([arguments objectForKey:@"frame"]); 2579 NSValue *frameValue = [arguments objectForKey:@"frame"]; 2580 NSRect frame = (frameValue ? [frameValue rectValue] : NSZeroRect); 2581 NSString *frameName = [arguments objectForKey:@"frameName"]; 2582 NSString *groupName = [arguments objectForKey:@"groupName"]; 2583 self = [self initWithFrame:frame frameName:frameName groupName:groupName]; 2584 } 2585 2586 return self; 2587} 2588 2589static bool clientNeedsWebViewInitThreadWorkaround() 2590{ 2591 if (WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_WEBVIEW_INIT_THREAD_WORKAROUND)) 2592 return false; 2593 2594 NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; 2595 2596 // Installer. 2597 if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.installer"]) 2598 return true; 2599 2600 // Automator. 2601 if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.Automator"]) 2602 return true; 2603 2604 // Automator Runner. 2605 if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.AutomatorRunner"]) 2606 return true; 2607 2608 // Automator workflows. 2609 if ([bundleIdentifier _webkit_hasCaseInsensitivePrefix:@"com.apple.Automator."]) 2610 return true; 2611 2612#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) 2613 // Mail. 2614 if ([bundleIdentifier _webkit_isCaseInsensitiveEqualToString:@"com.apple.Mail"]) 2615 return true; 2616#endif 2617 2618 return false; 2619} 2620 2621static bool needsWebViewInitThreadWorkaround() 2622{ 2623 static bool isOldClient = clientNeedsWebViewInitThreadWorkaround(); 2624 return isOldClient && !pthread_main_np(); 2625} 2626 2627- (id)initWithFrame:(NSRect)f 2628{ 2629 return [self initWithFrame:f frameName:nil groupName:nil]; 2630} 2631 2632- (id)initWithFrame:(NSRect)f frameName:(NSString *)frameName groupName:(NSString *)groupName 2633{ 2634 if (needsWebViewInitThreadWorkaround()) 2635 return [[self _webkit_invokeOnMainThread] initWithFrame:f frameName:frameName groupName:groupName]; 2636 2637 WebCoreThreadViolationCheckRoundTwo(); 2638 return [self _initWithFrame:f frameName:frameName groupName:groupName usesDocumentViews:YES]; 2639} 2640 2641- (id)initWithCoder:(NSCoder *)decoder 2642{ 2643 if (needsWebViewInitThreadWorkaround()) 2644 return [[self _webkit_invokeOnMainThread] initWithCoder:decoder]; 2645 2646 WebCoreThreadViolationCheckRoundTwo(); 2647 WebView *result = nil; 2648 2649 @try { 2650 NSString *frameName; 2651 NSString *groupName; 2652 WebPreferences *preferences; 2653 BOOL useBackForwardList = NO; 2654 BOOL allowsUndo = YES; 2655 2656 result = [super initWithCoder:decoder]; 2657 result->_private = [[WebViewPrivate alloc] init]; 2658 2659 // We don't want any of the archived subviews. The subviews will always 2660 // be created in _commonInitializationFrameName:groupName:. 2661 [[result subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)]; 2662 2663 if ([decoder allowsKeyedCoding]) { 2664 frameName = [decoder decodeObjectForKey:@"FrameName"]; 2665 groupName = [decoder decodeObjectForKey:@"GroupName"]; 2666 preferences = [decoder decodeObjectForKey:@"Preferences"]; 2667 useBackForwardList = [decoder decodeBoolForKey:@"UseBackForwardList"]; 2668 if ([decoder containsValueForKey:@"AllowsUndo"]) 2669 allowsUndo = [decoder decodeBoolForKey:@"AllowsUndo"]; 2670 } else { 2671 int version; 2672 [decoder decodeValueOfObjCType:@encode(int) at:&version]; 2673 frameName = [decoder decodeObject]; 2674 groupName = [decoder decodeObject]; 2675 preferences = [decoder decodeObject]; 2676 if (version > 1) 2677 [decoder decodeValuesOfObjCTypes:"c", &useBackForwardList]; 2678 // The allowsUndo field is no longer written out in encodeWithCoder, but since there are 2679 // version 3 NIBs that have this field encoded, we still need to read it in. 2680 if (version == 3) 2681 [decoder decodeValuesOfObjCTypes:"c", &allowsUndo]; 2682 } 2683 2684 if (![frameName isKindOfClass:[NSString class]]) 2685 frameName = nil; 2686 if (![groupName isKindOfClass:[NSString class]]) 2687 groupName = nil; 2688 if (![preferences isKindOfClass:[WebPreferences class]]) 2689 preferences = nil; 2690 2691 LOG(Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", frameName, groupName, (int)useBackForwardList); 2692 [result _commonInitializationWithFrameName:frameName groupName:groupName usesDocumentViews:YES]; 2693 [result page]->backForwardList()->setEnabled(useBackForwardList); 2694 result->_private->allowsUndo = allowsUndo; 2695 if (preferences) 2696 [result setPreferences:preferences]; 2697 } @catch (NSException *localException) { 2698 result = nil; 2699 [self release]; 2700 } 2701 2702 return result; 2703} 2704 2705- (void)encodeWithCoder:(NSCoder *)encoder 2706{ 2707 // Set asside the subviews before we archive. We don't want to archive any subviews. 2708 // The subviews will always be created in _commonInitializationFrameName:groupName:. 2709 id originalSubviews = _subviews; 2710 _subviews = nil; 2711 2712 [super encodeWithCoder:encoder]; 2713 2714 // Restore the subviews we set aside. 2715 _subviews = originalSubviews; 2716 2717 BOOL useBackForwardList = _private->page && _private->page->backForwardList()->enabled(); 2718 if ([encoder allowsKeyedCoding]) { 2719 [encoder encodeObject:[[self mainFrame] name] forKey:@"FrameName"]; 2720 [encoder encodeObject:[self groupName] forKey:@"GroupName"]; 2721 [encoder encodeObject:[self preferences] forKey:@"Preferences"]; 2722 [encoder encodeBool:useBackForwardList forKey:@"UseBackForwardList"]; 2723 [encoder encodeBool:_private->allowsUndo forKey:@"AllowsUndo"]; 2724 } else { 2725 int version = WebViewVersion; 2726 [encoder encodeValueOfObjCType:@encode(int) at:&version]; 2727 [encoder encodeObject:[[self mainFrame] name]]; 2728 [encoder encodeObject:[self groupName]]; 2729 [encoder encodeObject:[self preferences]]; 2730 [encoder encodeValuesOfObjCTypes:"c", &useBackForwardList]; 2731 // DO NOT encode any new fields here, doing so will break older WebKit releases. 2732 } 2733 2734 LOG(Encoding, "FrameName = %@, GroupName = %@, useBackForwardList = %d\n", [[self mainFrame] name], [self groupName], (int)useBackForwardList); 2735} 2736 2737- (void)dealloc 2738{ 2739 if (WebCoreObjCScheduleDeallocateOnMainThread([WebView class], self)) 2740 return; 2741 2742 // call close to ensure we tear-down completely 2743 // this maintains our old behavior for existing applications 2744 [self close]; 2745 2746 --WebViewCount; 2747 2748 if ([self _needsFrameLoadDelegateRetainQuirk]) 2749 [_private->frameLoadDelegate release]; 2750 2751 [_private release]; 2752 // [super dealloc] can end up dispatching against _private (3466082) 2753 _private = nil; 2754 2755 [super dealloc]; 2756} 2757 2758- (void)finalize 2759{ 2760 ASSERT(_private->closed); 2761 2762 --WebViewCount; 2763 2764 [super finalize]; 2765} 2766 2767- (void)close 2768{ 2769 // _close existed first, and some clients might be calling or overriding it, so call through. 2770 [self _close]; 2771} 2772 2773- (void)setShouldCloseWithWindow:(BOOL)close 2774{ 2775 _private->shouldCloseWithWindow = close; 2776} 2777 2778- (BOOL)shouldCloseWithWindow 2779{ 2780 return _private->shouldCloseWithWindow; 2781} 2782 2783- (void)addWindowObserversForWindow:(NSWindow *)window 2784{ 2785 if (window) { 2786 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidBecomeKey:) 2787 name:NSWindowDidBecomeKeyNotification object:nil]; 2788 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidResignKey:) 2789 name:NSWindowDidResignKeyNotification object:nil]; 2790 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillOrderOnScreen:) 2791 name:WKWindowWillOrderOnScreenNotification() object:window]; 2792 } 2793} 2794 2795- (void)removeWindowObservers 2796{ 2797 NSWindow *window = [self window]; 2798 if (window) { 2799 [[NSNotificationCenter defaultCenter] removeObserver:self 2800 name:NSWindowDidBecomeKeyNotification object:nil]; 2801 [[NSNotificationCenter defaultCenter] removeObserver:self 2802 name:NSWindowDidResignKeyNotification object:nil]; 2803 [[NSNotificationCenter defaultCenter] removeObserver:self 2804 name:WKWindowWillOrderOnScreenNotification() object:window]; 2805 } 2806} 2807 2808- (void)viewWillMoveToWindow:(NSWindow *)window 2809{ 2810 // Don't do anything if the WebView isn't initialized. 2811 // This happens when decoding a WebView in a nib. 2812 // FIXME: What sets up the observer of NSWindowWillCloseNotification in this case? 2813 if (!_private || _private->closed) 2814 return; 2815 2816 if ([self window] && [self window] != [self hostWindow]) 2817 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:[self window]]; 2818 2819 if (window) { 2820 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillClose:) name:NSWindowWillCloseNotification object:window]; 2821 2822 // Ensure that we will receive the events that WebHTMLView (at least) needs. 2823 // The following are expensive enough that we don't want to call them over 2824 // and over, so do them when we move into a window. 2825 [window setAcceptsMouseMovedEvents:YES]; 2826 WKSetNSWindowShouldPostEventNotifications(window, YES); 2827 } else 2828 _private->page->willMoveOffscreen(); 2829 2830 if (window != [self window]) { 2831 [self removeWindowObservers]; 2832 [self addWindowObserversForWindow:window]; 2833 } 2834} 2835 2836- (void)viewDidMoveToWindow 2837{ 2838 // Don't do anything if we aren't initialized. This happens 2839 // when decoding a WebView. When WebViews are decoded their subviews 2840 // are created by initWithCoder: and so won't be normally 2841 // initialized. The stub views are discarded by WebView. 2842 if (!_private || _private->closed) 2843 return; 2844 2845 if ([self window]) 2846 _private->page->didMoveOnscreen(); 2847 2848 [self _updateActiveState]; 2849} 2850 2851- (void)_windowDidBecomeKey:(NSNotification *)notification 2852{ 2853 NSWindow *keyWindow = [notification object]; 2854 if (keyWindow == [self window] || keyWindow == [[self window] attachedSheet]) 2855 [self _updateActiveState]; 2856} 2857 2858- (void)_windowDidResignKey:(NSNotification *)notification 2859{ 2860 NSWindow *formerKeyWindow = [notification object]; 2861 if (formerKeyWindow == [self window] || formerKeyWindow == [[self window] attachedSheet]) 2862 [self _updateActiveState]; 2863} 2864 2865- (void)_windowWillOrderOnScreen:(NSNotification *)notification 2866{ 2867 if (![self shouldUpdateWhileOffscreen]) 2868 [self setNeedsDisplay:YES]; 2869} 2870 2871- (void)_windowWillClose:(NSNotification *)notification 2872{ 2873 if ([self shouldCloseWithWindow] && ([self window] == [self hostWindow] || ([self window] && ![self hostWindow]) || (![self window] && [self hostWindow]))) 2874 [self close]; 2875} 2876 2877- (void)setPreferences:(WebPreferences *)prefs 2878{ 2879 if (!prefs) 2880 prefs = [WebPreferences standardPreferences]; 2881 2882 if (_private->preferences == prefs) 2883 return; 2884 2885 [prefs willAddToWebView]; 2886 2887 WebPreferences *oldPrefs = _private->preferences; 2888 2889 [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:[self preferences]]; 2890 [WebPreferences _removeReferenceForIdentifier:[oldPrefs identifier]]; 2891 2892 _private->preferences = [prefs retain]; 2893 2894 // After registering for the notification, post it so the WebCore settings update. 2895 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:) 2896 name:WebPreferencesChangedNotification object:[self preferences]]; 2897 [[self preferences] _postPreferencesChangesNotification]; 2898 2899 [oldPrefs didRemoveFromWebView]; 2900 [oldPrefs release]; 2901} 2902 2903- (WebPreferences *)preferences 2904{ 2905 return _private->preferences; 2906} 2907 2908- (void)setPreferencesIdentifier:(NSString *)anIdentifier 2909{ 2910 if (!_private->closed && ![anIdentifier isEqual:[[self preferences] identifier]]) { 2911 WebPreferences *prefs = [[WebPreferences alloc] initWithIdentifier:anIdentifier]; 2912 [self setPreferences:prefs]; 2913 [prefs release]; 2914 } 2915} 2916 2917- (NSString *)preferencesIdentifier 2918{ 2919 return [[self preferences] identifier]; 2920} 2921 2922 2923- (void)setUIDelegate:delegate 2924{ 2925 _private->UIDelegate = delegate; 2926 [_private->UIDelegateForwarder release]; 2927 _private->UIDelegateForwarder = nil; 2928} 2929 2930- UIDelegate 2931{ 2932 return _private->UIDelegate; 2933} 2934 2935- (void)setResourceLoadDelegate: delegate 2936{ 2937 _private->resourceProgressDelegate = delegate; 2938 [self _cacheResourceLoadDelegateImplementations]; 2939} 2940 2941- resourceLoadDelegate 2942{ 2943 return _private->resourceProgressDelegate; 2944} 2945 2946- (void)setDownloadDelegate: delegate 2947{ 2948 _private->downloadDelegate = delegate; 2949} 2950 2951 2952- downloadDelegate 2953{ 2954 return _private->downloadDelegate; 2955} 2956 2957- (void)setPolicyDelegate:delegate 2958{ 2959 _private->policyDelegate = delegate; 2960 [_private->policyDelegateForwarder release]; 2961 _private->policyDelegateForwarder = nil; 2962} 2963 2964- policyDelegate 2965{ 2966 return _private->policyDelegate; 2967} 2968 2969- (void)setFrameLoadDelegate:delegate 2970{ 2971 // <rdar://problem/6950660> - Due to some subtle WebKit changes - presumably to delegate callback behavior - we've 2972 // unconvered a latent bug in at least one WebKit app where the delegate wasn't properly retained by the app and 2973 // was dealloc'ed before being cleared. 2974 // This is an effort to keep such apps working for now. 2975 if ([self _needsFrameLoadDelegateRetainQuirk]) { 2976 [delegate retain]; 2977 [_private->frameLoadDelegate release]; 2978 } 2979 2980 _private->frameLoadDelegate = delegate; 2981 [self _cacheFrameLoadDelegateImplementations]; 2982 2983#if ENABLE(ICONDATABASE) 2984 // If this delegate wants callbacks for icons, fire up the icon database. 2985 if (_private->frameLoadDelegateImplementations.didReceiveIconForFrameFunc) 2986 [WebIconDatabase sharedIconDatabase]; 2987#endif 2988} 2989 2990- frameLoadDelegate 2991{ 2992 return _private->frameLoadDelegate; 2993} 2994 2995- (WebFrame *)mainFrame 2996{ 2997 // This can be called in initialization, before _private has been set up (3465613) 2998 if (!_private || !_private->page) 2999 return nil; 3000 return kit(_private->page->mainFrame()); 3001} 3002 3003- (WebFrame *)selectedFrame 3004{ 3005 if (_private->usesDocumentViews) { 3006 // If the first responder is a view in our tree, we get the frame containing the first responder. 3007 // This is faster than searching the frame hierarchy, and will give us a result even in the case 3008 // where the focused frame doesn't actually contain a selection. 3009 WebFrame *focusedFrame = [self _focusedFrame]; 3010 if (focusedFrame) 3011 return focusedFrame; 3012 } 3013 3014 // If the first responder is outside of our view tree, we search for a frame containing a selection. 3015 // There should be at most only one of these. 3016 return [[self mainFrame] _findFrameWithSelection]; 3017} 3018 3019- (WebBackForwardList *)backForwardList 3020{ 3021 if (!_private->page) 3022 return nil; 3023 if (!_private->page->backForwardList()->enabled()) 3024 return nil; 3025 return kit(_private->page->backForwardList()); 3026} 3027 3028- (void)setMaintainsBackForwardList:(BOOL)flag 3029{ 3030 if (!_private->page) 3031 return; 3032 _private->page->backForwardList()->setEnabled(flag); 3033} 3034 3035- (BOOL)goBack 3036{ 3037 if (!_private->page) 3038 return NO; 3039 3040 return _private->page->goBack(); 3041} 3042 3043- (BOOL)goForward 3044{ 3045 if (!_private->page) 3046 return NO; 3047 3048 return _private->page->goForward(); 3049} 3050 3051- (BOOL)goToBackForwardItem:(WebHistoryItem *)item 3052{ 3053 if (!_private->page) 3054 return NO; 3055 3056 _private->page->goToItem(core(item), FrameLoadTypeIndexedBackForward); 3057 return YES; 3058} 3059 3060- (void)setTextSizeMultiplier:(float)m 3061{ 3062 [self _setZoomMultiplier:m isTextOnly:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]]; 3063} 3064 3065- (float)textSizeMultiplier 3066{ 3067 return [self _realZoomMultiplierIsTextOnly] ? _private->zoomMultiplier : 1.0f; 3068} 3069 3070- (void)_setZoomMultiplier:(float)m isTextOnly:(BOOL)isTextOnly 3071{ 3072 // NOTE: This has no visible effect when viewing a PDF (see <rdar://problem/4737380>) 3073 _private->zoomMultiplier = m; 3074 ASSERT(_private->page); 3075 if (_private->page) 3076 _private->page->settings()->setZoomsTextOnly(isTextOnly); 3077 3078 // FIXME: it would be nice to rework this code so that _private->zoomMultiplier doesn't exist and callers 3079 // all access _private->page->settings(). 3080 Frame* coreFrame = [self _mainCoreFrame]; 3081 if (coreFrame) 3082 coreFrame->setZoomFactor(m, isTextOnly); 3083} 3084 3085- (float)_zoomMultiplier:(BOOL)isTextOnly 3086{ 3087 if (isTextOnly != [self _realZoomMultiplierIsTextOnly]) 3088 return 1.0f; 3089 return _private->zoomMultiplier; 3090} 3091 3092- (float)_realZoomMultiplier 3093{ 3094 return _private->zoomMultiplier; 3095} 3096 3097- (BOOL)_realZoomMultiplierIsTextOnly 3098{ 3099 if (!_private->page) 3100 return NO; 3101 3102 return _private->page->settings()->zoomsTextOnly(); 3103} 3104 3105#define MinimumZoomMultiplier 0.5f 3106#define MaximumZoomMultiplier 3.0f 3107#define ZoomMultiplierRatio 1.2f 3108 3109- (BOOL)_canZoomOut:(BOOL)isTextOnly 3110{ 3111 id docView = [[[self mainFrame] frameView] documentView]; 3112 if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) { 3113 id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView; 3114 return [zoomingDocView _canZoomOut]; 3115 } 3116 return [self _zoomMultiplier:isTextOnly] / ZoomMultiplierRatio > MinimumZoomMultiplier; 3117} 3118 3119 3120- (BOOL)_canZoomIn:(BOOL)isTextOnly 3121{ 3122 id docView = [[[self mainFrame] frameView] documentView]; 3123 if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) { 3124 id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView; 3125 return [zoomingDocView _canZoomIn]; 3126 } 3127 return [self _zoomMultiplier:isTextOnly] * ZoomMultiplierRatio < MaximumZoomMultiplier; 3128} 3129 3130- (IBAction)_zoomOut:(id)sender isTextOnly:(BOOL)isTextOnly 3131{ 3132 id docView = [[[self mainFrame] frameView] documentView]; 3133 if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) { 3134 id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView; 3135 return [zoomingDocView _zoomOut:sender]; 3136 } 3137 float newScale = [self _zoomMultiplier:isTextOnly] / ZoomMultiplierRatio; 3138 if (newScale > MinimumZoomMultiplier) 3139 [self _setZoomMultiplier:newScale isTextOnly:isTextOnly]; 3140} 3141 3142- (IBAction)_zoomIn:(id)sender isTextOnly:(BOOL)isTextOnly 3143{ 3144 id docView = [[[self mainFrame] frameView] documentView]; 3145 if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) { 3146 id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView; 3147 return [zoomingDocView _zoomIn:sender]; 3148 } 3149 float newScale = [self _zoomMultiplier:isTextOnly] * ZoomMultiplierRatio; 3150 if (newScale < MaximumZoomMultiplier) 3151 [self _setZoomMultiplier:newScale isTextOnly:isTextOnly]; 3152} 3153 3154- (BOOL)_canResetZoom:(BOOL)isTextOnly 3155{ 3156 id docView = [[[self mainFrame] frameView] documentView]; 3157 if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) { 3158 id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView; 3159 return [zoomingDocView _canResetZoom]; 3160 } 3161 return [self _zoomMultiplier:isTextOnly] != 1.0f; 3162} 3163 3164- (IBAction)_resetZoom:(id)sender isTextOnly:(BOOL)isTextOnly 3165{ 3166 id docView = [[[self mainFrame] frameView] documentView]; 3167 if ([docView conformsToProtocol:@protocol(_WebDocumentZooming)]) { 3168 id <_WebDocumentZooming> zoomingDocView = (id <_WebDocumentZooming>)docView; 3169 return [zoomingDocView _resetZoom:sender]; 3170 } 3171 if ([self _zoomMultiplier:isTextOnly] != 1.0f) 3172 [self _setZoomMultiplier:1.0f isTextOnly:isTextOnly]; 3173} 3174 3175- (void)setApplicationNameForUserAgent:(NSString *)applicationName 3176{ 3177 NSString *name = [applicationName copy]; 3178 [_private->applicationNameForUserAgent release]; 3179 _private->applicationNameForUserAgent = name; 3180 if (!_private->userAgentOverridden) 3181 _private->userAgent = String(); 3182} 3183 3184- (NSString *)applicationNameForUserAgent 3185{ 3186 return [[_private->applicationNameForUserAgent retain] autorelease]; 3187} 3188 3189- (void)setCustomUserAgent:(NSString *)userAgentString 3190{ 3191 _private->userAgent = userAgentString; 3192 _private->userAgentOverridden = userAgentString != nil; 3193} 3194 3195- (NSString *)customUserAgent 3196{ 3197 if (!_private->userAgentOverridden) 3198 return nil; 3199 return _private->userAgent; 3200} 3201 3202- (void)setMediaStyle:(NSString *)mediaStyle 3203{ 3204 if (_private->mediaStyle != mediaStyle) { 3205 [_private->mediaStyle release]; 3206 _private->mediaStyle = [mediaStyle copy]; 3207 } 3208} 3209 3210- (NSString *)mediaStyle 3211{ 3212 return _private->mediaStyle; 3213} 3214 3215- (BOOL)supportsTextEncoding 3216{ 3217 id documentView = [[[self mainFrame] frameView] documentView]; 3218 return [documentView conformsToProtocol:@protocol(WebDocumentText)] 3219 && [documentView supportsTextEncoding]; 3220} 3221 3222- (void)setCustomTextEncodingName:(NSString *)encoding 3223{ 3224 NSString *oldEncoding = [self customTextEncodingName]; 3225 if (encoding == oldEncoding || [encoding isEqualToString:oldEncoding]) 3226 return; 3227 if (Frame* mainFrame = [self _mainCoreFrame]) 3228 mainFrame->loader()->reloadWithOverrideEncoding(encoding); 3229} 3230 3231- (NSString *)_mainFrameOverrideEncoding 3232{ 3233 WebDataSource *dataSource = [[self mainFrame] provisionalDataSource]; 3234 if (dataSource == nil) 3235 dataSource = [[self mainFrame] _dataSource]; 3236 if (dataSource == nil) 3237 return nil; 3238 return nsStringNilIfEmpty([dataSource _documentLoader]->overrideEncoding()); 3239} 3240 3241- (NSString *)customTextEncodingName 3242{ 3243 return [self _mainFrameOverrideEncoding]; 3244} 3245 3246- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script 3247{ 3248 // Return statements are only valid in a function but some applications pass in scripts 3249 // prefixed with return (<rdar://problems/5103720&4616860>) since older WebKit versions 3250 // silently ignored the return. If the application is linked against an earlier version 3251 // of WebKit we will strip the return so the script wont fail. 3252 if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_JAVASCRIPT_RETURN_QUIRK)) { 3253 NSRange returnStringRange = [script rangeOfString:@"return "]; 3254 if (returnStringRange.length && !returnStringRange.location) 3255 script = [script substringFromIndex:returnStringRange.location + returnStringRange.length]; 3256 } 3257 3258 NSString *result = [[self mainFrame] _stringByEvaluatingJavaScriptFromString:script]; 3259 // The only way stringByEvaluatingJavaScriptFromString can return nil is if the frame was removed by the script 3260 // Since there's no way to get rid of the main frame, result will never ever be nil here. 3261 ASSERT(result); 3262 3263 return result; 3264} 3265 3266- (WebScriptObject *)windowScriptObject 3267{ 3268 Frame* coreFrame = [self _mainCoreFrame]; 3269 if (!coreFrame) 3270 return nil; 3271 return coreFrame->script()->windowScriptObject(); 3272} 3273 3274// Get the appropriate user-agent string for a particular URL. 3275- (NSString *)userAgentForURL:(NSURL *)url 3276{ 3277 if (_private->useSiteSpecificSpoofing) { 3278 // No current site-specific spoofs. 3279 } 3280 3281 if (_private->userAgent.isNull()) 3282 _private->userAgent = [[self class] _standardUserAgentWithApplicationName:_private->applicationNameForUserAgent]; 3283 3284 return _private->userAgent; 3285} 3286 3287- (void)setHostWindow:(NSWindow *)hostWindow 3288{ 3289 if (_private->closed) 3290 return; 3291 if (hostWindow == _private->hostWindow) 3292 return; 3293 3294 Frame* coreFrame = [self _mainCoreFrame]; 3295 if (_private->usesDocumentViews) { 3296 for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) 3297 [[[kit(frame) frameView] documentView] viewWillMoveToHostWindow:hostWindow]; 3298 } 3299 if (_private->hostWindow && [self window] != _private->hostWindow) 3300 [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:_private->hostWindow]; 3301 if (hostWindow) 3302 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillClose:) name:NSWindowWillCloseNotification object:hostWindow]; 3303 [_private->hostWindow release]; 3304 _private->hostWindow = [hostWindow retain]; 3305 if (_private->usesDocumentViews) { 3306 for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) 3307 [[[kit(frame) frameView] documentView] viewDidMoveToHostWindow]; 3308 } 3309} 3310 3311- (NSWindow *)hostWindow 3312{ 3313 // -[WebView hostWindow] can sometimes be called from the WebView's [super dealloc] method 3314 // so we check here to make sure it's not null. 3315 if (!_private) 3316 return nil; 3317 3318 return _private->hostWindow; 3319} 3320 3321- (NSView <WebDocumentView> *)documentViewAtWindowPoint:(NSPoint)point 3322{ 3323 return [[self _frameViewAtWindowPoint:point] documentView]; 3324} 3325 3326- (NSDictionary *)_elementAtWindowPoint:(NSPoint)windowPoint 3327{ 3328 WebFrameView *frameView = [self _frameViewAtWindowPoint:windowPoint]; 3329 if (!frameView) 3330 return nil; 3331 NSView <WebDocumentView> *documentView = [frameView documentView]; 3332 if ([documentView conformsToProtocol:@protocol(WebDocumentElement)]) { 3333 NSPoint point = [documentView convertPoint:windowPoint fromView:nil]; 3334 return [(NSView <WebDocumentElement> *)documentView elementAtPoint:point]; 3335 } 3336 return [NSDictionary dictionaryWithObject:[frameView webFrame] forKey:WebElementFrameKey]; 3337} 3338 3339- (NSDictionary *)elementAtPoint:(NSPoint)point 3340{ 3341 return [self _elementAtWindowPoint:[self convertPoint:point toView:nil]]; 3342} 3343 3344// The following 2 internal NSView methods are called on the drag destination to make scrolling while dragging work. 3345// Scrolling while dragging will only work if the drag destination is in a scroll view. The WebView is the drag destination. 3346// When dragging to a WebView, the document subview should scroll, but it doesn't because it is not the drag destination. 3347// Forward these calls to the document subview to make its scroll view scroll. 3348- (void)_autoscrollForDraggingInfo:(id)draggingInfo timeDelta:(NSTimeInterval)repeatDelta 3349{ 3350 NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]]; 3351 [documentView _autoscrollForDraggingInfo:draggingInfo timeDelta:repeatDelta]; 3352} 3353 3354- (BOOL)_shouldAutoscrollForDraggingInfo:(id)draggingInfo 3355{ 3356 NSView <WebDocumentView> *documentView = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]]; 3357 return [documentView _shouldAutoscrollForDraggingInfo:draggingInfo]; 3358} 3359 3360- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)draggingInfo 3361{ 3362 NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]]; 3363 WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]] ? (WebHTMLView*)view : nil); 3364 IntPoint client([draggingInfo draggingLocation]); 3365 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window])); 3366 DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper); 3367 return core(self)->dragController()->dragEntered(&dragData); 3368} 3369 3370- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)draggingInfo 3371{ 3372 Page* page = core(self); 3373 if (!page) 3374 return NSDragOperationNone; 3375 3376 NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]]; 3377 WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]] ? (WebHTMLView*)view : nil); 3378 IntPoint client([draggingInfo draggingLocation]); 3379 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window])); 3380 DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper); 3381 return page->dragController()->dragUpdated(&dragData); 3382} 3383 3384- (void)draggingExited:(id <NSDraggingInfo>)draggingInfo 3385{ 3386 Page* page = core(self); 3387 if (!page) 3388 return; 3389 3390 NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]]; 3391 WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]] ? (WebHTMLView*)view : nil); 3392 IntPoint client([draggingInfo draggingLocation]); 3393 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window])); 3394 DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper); 3395 page->dragController()->dragExited(&dragData); 3396} 3397 3398- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)draggingInfo 3399{ 3400 return YES; 3401} 3402 3403- (BOOL)performDragOperation:(id <NSDraggingInfo>)draggingInfo 3404{ 3405 NSView <WebDocumentView>* view = [self documentViewAtWindowPoint:[draggingInfo draggingLocation]]; 3406 WebPasteboardHelper helper([view isKindOfClass:[WebHTMLView class]]? (WebHTMLView*)view : nil); 3407 IntPoint client([draggingInfo draggingLocation]); 3408 IntPoint global(globalPoint([draggingInfo draggingLocation], [self window])); 3409 DragData dragData(draggingInfo, client, global, (DragOperation)[draggingInfo draggingSourceOperationMask], &helper); 3410 return core(self)->dragController()->performDrag(&dragData); 3411} 3412 3413- (NSView *)_hitTest:(NSPoint *)point dragTypes:(NSSet *)types 3414{ 3415 NSView *hitView = [super _hitTest:point dragTypes:types]; 3416 if (!hitView && [[self superview] mouse:*point inRect:[self frame]]) 3417 return self; 3418 return hitView; 3419} 3420 3421- (BOOL)acceptsFirstResponder 3422{ 3423 if (_private->usesDocumentViews) 3424 return [[[self mainFrame] frameView] acceptsFirstResponder]; 3425 3426 // FIXME (Viewless): Need more code from WebHTMLView here. 3427 return YES; 3428} 3429 3430- (BOOL)becomeFirstResponder 3431{ 3432 if (_private->usesDocumentViews) { 3433 if (_private->becomingFirstResponder) { 3434 // Fix for unrepro infinite recursion reported in Radar 4448181. If we hit this assert on 3435 // a debug build, we should figure out what causes the problem and do a better fix. 3436 ASSERT_NOT_REACHED(); 3437 return NO; 3438 } 3439 3440 // This works together with setNextKeyView to splice the WebView into 3441 // the key loop similar to the way NSScrollView does this. Note that 3442 // WebFrameView has very similar code. 3443 NSWindow *window = [self window]; 3444 WebFrameView *mainFrameView = [[self mainFrame] frameView]; 3445 3446 NSResponder *previousFirstResponder = [[self window] _oldFirstResponderBeforeBecoming]; 3447 BOOL fromOutside = ![previousFirstResponder isKindOfClass:[NSView class]] || (![(NSView *)previousFirstResponder isDescendantOf:self] && previousFirstResponder != self); 3448 3449 if ([window keyViewSelectionDirection] == NSSelectingPrevious) { 3450 NSView *previousValidKeyView = [self previousValidKeyView]; 3451 if (previousValidKeyView != self && previousValidKeyView != mainFrameView) { 3452 _private->becomingFirstResponder = YES; 3453 _private->becomingFirstResponderFromOutside = fromOutside; 3454 [window makeFirstResponder:previousValidKeyView]; 3455 _private->becomingFirstResponderFromOutside = NO; 3456 _private->becomingFirstResponder = NO; 3457 return YES; 3458 } 3459 return NO; 3460 } 3461 3462 if ([mainFrameView acceptsFirstResponder]) { 3463 _private->becomingFirstResponder = YES; 3464 _private->becomingFirstResponderFromOutside = fromOutside; 3465 [window makeFirstResponder:mainFrameView]; 3466 _private->becomingFirstResponderFromOutside = NO; 3467 _private->becomingFirstResponder = NO; 3468 return YES; 3469 } 3470 3471 return NO; 3472 } 3473 3474 // FIXME (Viewless): Need more code from WebHTMLView here. 3475 return YES; 3476} 3477 3478- (NSView *)_webcore_effectiveFirstResponder 3479{ 3480 if (_private && _private->usesDocumentViews) { 3481 if (WebFrameView *frameView = [[self mainFrame] frameView]) 3482 return [frameView _webcore_effectiveFirstResponder]; 3483 } 3484 return [super _webcore_effectiveFirstResponder]; 3485} 3486 3487- (void)setNextKeyView:(NSView *)view 3488{ 3489 if (_private && _private->usesDocumentViews) { 3490 // This works together with becomeFirstResponder to splice the WebView into 3491 // the key loop similar to the way NSScrollView does this. Note that 3492 // WebFrameView has similar code. 3493 if (WebFrameView *mainFrameView = [[self mainFrame] frameView]) { 3494 [mainFrameView setNextKeyView:view]; 3495 return; 3496 } 3497 } 3498 3499 [super setNextKeyView:view]; 3500} 3501 3502static WebFrame *incrementFrame(WebFrame *frame, BOOL forward, BOOL wrapFlag) 3503{ 3504 Frame* coreFrame = core(frame); 3505 return kit(forward 3506 ? coreFrame->tree()->traverseNextWithWrap(wrapFlag) 3507 : coreFrame->tree()->traversePreviousWithWrap(wrapFlag)); 3508} 3509 3510- (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag 3511{ 3512 return [self searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapFlag startInSelection:NO]; 3513} 3514 3515+ (void)registerViewClass:(Class)viewClass representationClass:(Class)representationClass forMIMEType:(NSString *)MIMEType 3516{ 3517 [[WebFrameView _viewTypesAllowImageTypeOmission:YES] setObject:viewClass forKey:MIMEType]; 3518 [[WebDataSource _repTypesAllowImageTypeOmission:YES] setObject:representationClass forKey:MIMEType]; 3519 3520 // FIXME: We also need to maintain MIMEType registrations (which can be dynamically changed) 3521 // in the WebCore MIMEType registry. For now we're doing this in a safe, limited manner 3522 // to fix <rdar://problem/5372989> - a future revamping of the entire system is neccesary for future robustness 3523 if ([viewClass class] == [WebHTMLView class]) 3524 MIMETypeRegistry::getSupportedNonImageMIMETypes().add(MIMEType); 3525} 3526 3527- (void)setGroupName:(NSString *)groupName 3528{ 3529 if (!_private->page) 3530 return; 3531 _private->page->setGroupName(groupName); 3532} 3533 3534- (NSString *)groupName 3535{ 3536 if (!_private->page) 3537 return nil; 3538 return _private->page->groupName(); 3539} 3540 3541- (double)estimatedProgress 3542{ 3543 if (!_private->page) 3544 return 0.0; 3545 return _private->page->progress()->estimatedProgress(); 3546} 3547 3548- (NSArray *)pasteboardTypesForSelection 3549{ 3550 NSView <WebDocumentView> *documentView = [[[self _selectedOrMainFrame] frameView] documentView]; 3551 if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) { 3552 return [(NSView <WebDocumentSelection> *)documentView pasteboardTypesForSelection]; 3553 } 3554 return [NSArray array]; 3555} 3556 3557- (void)writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard 3558{ 3559 WebFrame *frame = [self _selectedOrMainFrame]; 3560 if (frame && [frame _hasSelection]) { 3561 NSView <WebDocumentView> *documentView = [[frame frameView] documentView]; 3562 if ([documentView conformsToProtocol:@protocol(WebDocumentSelection)]) 3563 [(NSView <WebDocumentSelection> *)documentView writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard]; 3564 } 3565} 3566 3567- (NSArray *)pasteboardTypesForElement:(NSDictionary *)element 3568{ 3569 if ([element objectForKey:WebElementImageURLKey] != nil) { 3570 return [NSPasteboard _web_writableTypesForImageIncludingArchive:([element objectForKey:WebElementDOMNodeKey] != nil)]; 3571 } else if ([element objectForKey:WebElementLinkURLKey] != nil) { 3572 return [NSPasteboard _web_writableTypesForURL]; 3573 } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) { 3574 return [self pasteboardTypesForSelection]; 3575 } 3576 return [NSArray array]; 3577} 3578 3579- (void)writeElement:(NSDictionary *)element withPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard 3580{ 3581 if ([element objectForKey:WebElementImageURLKey] != nil) { 3582 [self _writeImageForElement:element withPasteboardTypes:types toPasteboard:pasteboard]; 3583 } else if ([element objectForKey:WebElementLinkURLKey] != nil) { 3584 [self _writeLinkElement:element withPasteboardTypes:types toPasteboard:pasteboard]; 3585 } else if ([[element objectForKey:WebElementIsSelectedKey] boolValue]) { 3586 [self writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard]; 3587 } 3588} 3589 3590- (void)moveDragCaretToPoint:(NSPoint)point 3591{ 3592 if (Page* page = core(self)) 3593 page->dragController()->placeDragCaret(IntPoint([self convertPoint:point toView:nil])); 3594} 3595 3596- (void)removeDragCaret 3597{ 3598 if (Page* page = core(self)) 3599 page->dragController()->dragEnded(); 3600} 3601 3602- (void)setMainFrameURL:(NSString *)URLString 3603{ 3604 [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]]; 3605} 3606 3607- (NSString *)mainFrameURL 3608{ 3609 WebDataSource *ds; 3610 ds = [[self mainFrame] provisionalDataSource]; 3611 if (!ds) 3612 ds = [[self mainFrame] _dataSource]; 3613 return [[[ds request] URL] _web_originalDataAsString]; 3614} 3615 3616- (BOOL)isLoading 3617{ 3618 LOG (Bindings, "isLoading = %d", (int)[self _isLoading]); 3619 return [self _isLoading]; 3620} 3621 3622- (NSString *)mainFrameTitle 3623{ 3624 NSString *mainFrameTitle = [[[self mainFrame] _dataSource] pageTitle]; 3625 return (mainFrameTitle != nil) ? mainFrameTitle : (NSString *)@""; 3626} 3627 3628- (NSImage *)mainFrameIcon 3629{ 3630 return [[WebIconDatabase sharedIconDatabase] iconForURL:[[[[self mainFrame] _dataSource] _URL] _web_originalDataAsString] withSize:WebIconSmallSize]; 3631} 3632 3633- (DOMDocument *)mainFrameDocument 3634{ 3635 // only return the actual value if the state we're in gives NSTreeController 3636 // enough time to release its observers on the old model 3637 if (_private->mainFrameDocumentReady) 3638 return [[self mainFrame] DOMDocument]; 3639 return nil; 3640} 3641 3642- (void)setDrawsBackground:(BOOL)drawsBackground 3643{ 3644 if (_private->drawsBackground == drawsBackground) 3645 return; 3646 _private->drawsBackground = drawsBackground; 3647 [[self mainFrame] _updateBackgroundAndUpdatesWhileOffscreen]; 3648} 3649 3650- (BOOL)drawsBackground 3651{ 3652 // This method can be called beneath -[NSView dealloc] after we have cleared _private, 3653 // indirectly via -[WebFrameView viewDidMoveToWindow]. 3654 return !_private || _private->drawsBackground; 3655} 3656 3657- (void)setShouldUpdateWhileOffscreen:(BOOL)updateWhileOffscreen 3658{ 3659 if (_private->shouldUpdateWhileOffscreen == updateWhileOffscreen) 3660 return; 3661 _private->shouldUpdateWhileOffscreen = updateWhileOffscreen; 3662 [[self mainFrame] _updateBackgroundAndUpdatesWhileOffscreen]; 3663} 3664 3665- (BOOL)shouldUpdateWhileOffscreen 3666{ 3667 return _private->shouldUpdateWhileOffscreen; 3668} 3669 3670- (void)setCurrentNodeHighlight:(WebNodeHighlight *)nodeHighlight 3671{ 3672 id old = _private->currentNodeHighlight; 3673 _private->currentNodeHighlight = [nodeHighlight retain]; 3674 [old release]; 3675} 3676 3677- (WebNodeHighlight *)currentNodeHighlight 3678{ 3679 return _private->currentNodeHighlight; 3680} 3681 3682- (NSView *)previousValidKeyView 3683{ 3684 NSView *result = [super previousValidKeyView]; 3685 3686 // Work around AppKit bug 6905484. If the result is a view that's inside this one, it's 3687 // possible it is the wrong answer, because the fact that it's a descendant causes the 3688 // code that implements key view redirection to fail; this means we won't redirect to 3689 // the toolbar, for example, when we hit the edge of a window. Since the bug is specific 3690 // to cases where the receiver of previousValidKeyView is an ancestor of the last valid 3691 // key view in the loop, we can sidestep it by walking along previous key views until 3692 // we find one that is not a superview, then using that to call previousValidKeyView. 3693 3694 if (![result isDescendantOf:self]) 3695 return result; 3696 3697 // Use a visited set so we don't loop indefinitely when walking crazy key loops. 3698 // AppKit uses such sets internally and we want our loop to be as robust as its loops. 3699 RetainPtr<CFMutableSetRef> visitedViews = CFSetCreateMutable(0, 0, 0); 3700 CFSetAddValue(visitedViews.get(), result); 3701 3702 NSView *previousView = self; 3703 do { 3704 CFSetAddValue(visitedViews.get(), previousView); 3705 previousView = [previousView previousKeyView]; 3706 if (!previousView || CFSetGetValue(visitedViews.get(), previousView)) 3707 return result; 3708 } while ([result isDescendantOf:previousView]); 3709 return [previousView previousValidKeyView]; 3710} 3711 3712@end 3713 3714@implementation WebView (WebIBActions) 3715 3716- (IBAction)takeStringURLFrom: sender 3717{ 3718 NSString *URLString = [sender stringValue]; 3719 3720 [[self mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL _web_URLWithDataAsString: URLString]]]; 3721} 3722 3723- (BOOL)canGoBack 3724{ 3725 if (!_private->page) 3726 return NO; 3727 3728 return !!_private->page->backForwardList()->backItem(); 3729} 3730 3731- (BOOL)canGoForward 3732{ 3733 if (!_private->page) 3734 return NO; 3735 3736 return !!_private->page->backForwardList()->forwardItem(); 3737} 3738 3739- (IBAction)goBack:(id)sender 3740{ 3741 [self goBack]; 3742} 3743 3744- (IBAction)goForward:(id)sender 3745{ 3746 [self goForward]; 3747} 3748 3749- (IBAction)stopLoading:(id)sender 3750{ 3751 [[self mainFrame] stopLoading]; 3752} 3753 3754- (IBAction)reload:(id)sender 3755{ 3756 [[self mainFrame] reload]; 3757} 3758 3759- (IBAction)reloadFromOrigin:(id)sender 3760{ 3761 [[self mainFrame] reloadFromOrigin]; 3762} 3763 3764// FIXME: This code should move into WebCore so that it is not duplicated in each WebKit. 3765// (This includes canMakeTextSmaller/Larger, makeTextSmaller/Larger, and canMakeTextStandardSize/makeTextStandardSize) 3766- (BOOL)canMakeTextSmaller 3767{ 3768 return [self _canZoomOut:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]]; 3769} 3770 3771- (IBAction)makeTextSmaller:(id)sender 3772{ 3773 return [self _zoomOut:sender isTextOnly:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]]; 3774} 3775 3776- (BOOL)canMakeTextLarger 3777{ 3778 return [self _canZoomIn:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]]; 3779} 3780 3781- (IBAction)makeTextLarger:(id)sender 3782{ 3783 return [self _zoomIn:sender isTextOnly:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]]; 3784} 3785 3786- (BOOL)canMakeTextStandardSize 3787{ 3788 return [self _canResetZoom:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]]; 3789} 3790 3791- (IBAction)makeTextStandardSize:(id)sender 3792{ 3793 return [self _resetZoom:sender isTextOnly:![[NSUserDefaults standardUserDefaults] boolForKey:WebKitDebugFullPageZoomPreferenceKey]]; 3794} 3795 3796- (IBAction)toggleSmartInsertDelete:(id)sender 3797{ 3798 [self setSmartInsertDeleteEnabled:![self smartInsertDeleteEnabled]]; 3799} 3800 3801- (IBAction)toggleContinuousSpellChecking:(id)sender 3802{ 3803 [self setContinuousSpellCheckingEnabled:![self isContinuousSpellCheckingEnabled]]; 3804} 3805 3806- (BOOL)_responderValidateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item 3807{ 3808 id responder = [self _responderForResponderOperations]; 3809 if (responder != self && [responder respondsToSelector:[item action]]) { 3810 if ([responder respondsToSelector:@selector(validateUserInterfaceItemWithoutDelegate:)]) 3811 return [responder validateUserInterfaceItemWithoutDelegate:item]; 3812 if ([responder respondsToSelector:@selector(validateUserInterfaceItem:)]) 3813 return [responder validateUserInterfaceItem:item]; 3814 return YES; 3815 } 3816 return NO; 3817} 3818 3819#define VALIDATE(name) \ 3820 else if (action == @selector(name:)) { return [self _responderValidateUserInterfaceItem:item]; } 3821 3822- (BOOL)validateUserInterfaceItemWithoutDelegate:(id <NSValidatedUserInterfaceItem>)item 3823{ 3824 SEL action = [item action]; 3825 3826 if (action == @selector(goBack:)) { 3827 return [self canGoBack]; 3828 } else if (action == @selector(goForward:)) { 3829 return [self canGoForward]; 3830 } else if (action == @selector(makeTextLarger:)) { 3831 return [self canMakeTextLarger]; 3832 } else if (action == @selector(makeTextSmaller:)) { 3833 return [self canMakeTextSmaller]; 3834 } else if (action == @selector(makeTextStandardSize:)) { 3835 return [self canMakeTextStandardSize]; 3836 } else if (action == @selector(reload:)) { 3837 return [[self mainFrame] _dataSource] != nil; 3838 } else if (action == @selector(stopLoading:)) { 3839 return [self _isLoading]; 3840 } else if (action == @selector(toggleContinuousSpellChecking:)) { 3841 BOOL checkMark = NO; 3842 BOOL retVal = NO; 3843 if ([self _continuousCheckingAllowed]) { 3844 checkMark = [self isContinuousSpellCheckingEnabled]; 3845 retVal = YES; 3846 } 3847 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { 3848 NSMenuItem *menuItem = (NSMenuItem *)item; 3849 [menuItem setState:checkMark ? NSOnState : NSOffState]; 3850 } 3851 return retVal; 3852 } else if (action == @selector(toggleSmartInsertDelete:)) { 3853 BOOL checkMark = [self smartInsertDeleteEnabled]; 3854 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { 3855 NSMenuItem *menuItem = (NSMenuItem *)item; 3856 [menuItem setState:checkMark ? NSOnState : NSOffState]; 3857 } 3858 return YES; 3859#ifndef BUILDING_ON_TIGER 3860 } else if (action == @selector(toggleGrammarChecking:)) { 3861 BOOL checkMark = [self isGrammarCheckingEnabled]; 3862 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { 3863 NSMenuItem *menuItem = (NSMenuItem *)item; 3864 [menuItem setState:checkMark ? NSOnState : NSOffState]; 3865 } 3866 return YES; 3867#endif 3868#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 3869 } else if (action == @selector(toggleAutomaticQuoteSubstitution:)) { 3870 BOOL checkMark = [self isAutomaticQuoteSubstitutionEnabled]; 3871 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { 3872 NSMenuItem *menuItem = (NSMenuItem *)item; 3873 [menuItem setState:checkMark ? NSOnState : NSOffState]; 3874 } 3875 return YES; 3876 } else if (action == @selector(toggleAutomaticLinkDetection:)) { 3877 BOOL checkMark = [self isAutomaticLinkDetectionEnabled]; 3878 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { 3879 NSMenuItem *menuItem = (NSMenuItem *)item; 3880 [menuItem setState:checkMark ? NSOnState : NSOffState]; 3881 } 3882 return YES; 3883 } else if (action == @selector(toggleAutomaticDashSubstitution:)) { 3884 BOOL checkMark = [self isAutomaticDashSubstitutionEnabled]; 3885 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { 3886 NSMenuItem *menuItem = (NSMenuItem *)item; 3887 [menuItem setState:checkMark ? NSOnState : NSOffState]; 3888 } 3889 return YES; 3890 } else if (action == @selector(toggleAutomaticTextReplacement:)) { 3891 BOOL checkMark = [self isAutomaticTextReplacementEnabled]; 3892 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { 3893 NSMenuItem *menuItem = (NSMenuItem *)item; 3894 [menuItem setState:checkMark ? NSOnState : NSOffState]; 3895 } 3896 return YES; 3897 } else if (action == @selector(toggleAutomaticSpellingCorrection:)) { 3898 BOOL checkMark = [self isAutomaticSpellingCorrectionEnabled]; 3899 if ([(NSObject *)item isKindOfClass:[NSMenuItem class]]) { 3900 NSMenuItem *menuItem = (NSMenuItem *)item; 3901 [menuItem setState:checkMark ? NSOnState : NSOffState]; 3902 } 3903 return YES; 3904#endif 3905 } 3906 FOR_EACH_RESPONDER_SELECTOR(VALIDATE) 3907 3908 return YES; 3909} 3910 3911- (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item 3912{ 3913 BOOL result = [self validateUserInterfaceItemWithoutDelegate:item]; 3914 return CallUIDelegateReturningBoolean(result, self, @selector(webView:validateUserInterfaceItem:defaultValidation:), item, result); 3915} 3916 3917@end 3918 3919@implementation WebView (WebPendingPublic) 3920 3921- (void)scheduleInRunLoop:(NSRunLoop *)runLoop forMode:(NSString *)mode 3922{ 3923 if (runLoop && mode) 3924 core(self)->addSchedulePair(SchedulePair::create(runLoop, (CFStringRef)mode)); 3925} 3926 3927- (void)unscheduleFromRunLoop:(NSRunLoop *)runLoop forMode:(NSString *)mode 3928{ 3929 if (runLoop && mode) 3930 core(self)->removeSchedulePair(SchedulePair::create(runLoop, (CFStringRef)mode)); 3931} 3932 3933- (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag startInSelection:(BOOL)startInSelection 3934{ 3935 if (_private->closed) 3936 return NO; 3937 3938 // Get the frame holding the selection, or start with the main frame 3939 WebFrame *startFrame = [self _selectedOrMainFrame]; 3940 3941 // Search the first frame, then all the other frames, in order 3942 NSView <WebDocumentSearching> *startSearchView = nil; 3943 WebFrame *frame = startFrame; 3944 do { 3945 WebFrame *nextFrame = incrementFrame(frame, forward, wrapFlag); 3946 3947 BOOL onlyOneFrame = (frame == nextFrame); 3948 ASSERT(!onlyOneFrame || frame == startFrame); 3949 3950 id <WebDocumentView> view = [[frame frameView] documentView]; 3951 if ([view conformsToProtocol:@protocol(WebDocumentSearching)]) { 3952 NSView <WebDocumentSearching> *searchView = (NSView <WebDocumentSearching> *)view; 3953 3954 if (frame == startFrame) 3955 startSearchView = searchView; 3956 3957 BOOL foundString; 3958 // In some cases we have to search some content twice; see comment later in this method. 3959 // We can avoid ever doing this in the common one-frame case by passing YES for wrapFlag 3960 // here, and then bailing out before we get to the code that would search again in the 3961 // same content. 3962 BOOL wrapOnThisPass = wrapFlag && onlyOneFrame; 3963 if ([searchView conformsToProtocol:@protocol(WebDocumentIncrementalSearching)]) 3964 foundString = [(NSView <WebDocumentIncrementalSearching> *)searchView searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapOnThisPass startInSelection:startInSelection]; 3965 else 3966 foundString = [searchView searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapOnThisPass]; 3967 3968 if (foundString) { 3969 if (frame != startFrame) 3970 [startFrame _clearSelection]; 3971 [[self window] makeFirstResponder:searchView]; 3972 return YES; 3973 } 3974 3975 if (onlyOneFrame) 3976 return NO; 3977 } 3978 frame = nextFrame; 3979 } while (frame && frame != startFrame); 3980 3981 // If there are multiple frames and wrapFlag is true and we've visited each one without finding a result, we still need to search in the 3982 // first-searched frame up to the selection. However, the API doesn't provide a way to search only up to a particular point. The only 3983 // way to make sure the entire frame is searched is to pass YES for the wrapFlag. When there are no matches, this will search again 3984 // some content that we already searched on the first pass. In the worst case, we could search the entire contents of this frame twice. 3985 // To fix this, we'd need to add a mechanism to specify a range in which to search. 3986 if (wrapFlag && startSearchView) { 3987 BOOL foundString; 3988 if ([startSearchView conformsToProtocol:@protocol(WebDocumentIncrementalSearching)]) 3989 foundString = [(NSView <WebDocumentIncrementalSearching> *)startSearchView searchFor:string direction:forward caseSensitive:caseFlag wrap:YES startInSelection:startInSelection]; 3990 else 3991 foundString = [startSearchView searchFor:string direction:forward caseSensitive:caseFlag wrap:YES]; 3992 if (foundString) { 3993 [[self window] makeFirstResponder:startSearchView]; 3994 return YES; 3995 } 3996 } 3997 return NO; 3998} 3999 4000- (void)setHoverFeedbackSuspended:(BOOL)newValue 4001{ 4002 if (_private->hoverFeedbackSuspended == newValue) 4003 return; 4004 4005 _private->hoverFeedbackSuspended = newValue; 4006 4007 if (_private->usesDocumentViews) { 4008 id <WebDocumentView> documentView = [[[self mainFrame] frameView] documentView]; 4009 // FIXME: in a perfect world we'd do this in a general way that worked with any document view, 4010 // such as by calling a protocol method or using respondsToSelector or sending a notification. 4011 // But until there is any need for these more general solutions, we'll just hardwire it to work 4012 // with WebHTMLView. 4013 // Note that _hoverFeedbackSuspendedChanged needs to be called only on the main WebHTMLView, not 4014 // on each subframe separately. 4015 if ([documentView isKindOfClass:[WebHTMLView class]]) 4016 [(WebHTMLView *)documentView _hoverFeedbackSuspendedChanged]; 4017 return; 4018 } 4019 4020 [self _updateMouseoverWithFakeEvent]; 4021} 4022 4023- (BOOL)isHoverFeedbackSuspended 4024{ 4025 return _private->hoverFeedbackSuspended; 4026} 4027 4028- (void)setMainFrameDocumentReady:(BOOL)mainFrameDocumentReady 4029{ 4030 // by setting this to NO, calls to mainFrameDocument are forced to return nil 4031 // setting this to YES lets it return the actual DOMDocument value 4032 // we use this to tell NSTreeController to reset its observers and clear its state 4033 if (_private->mainFrameDocumentReady == mainFrameDocumentReady) 4034 return; 4035 [self _willChangeValueForKey:_WebMainFrameDocumentKey]; 4036 _private->mainFrameDocumentReady = mainFrameDocumentReady; 4037 [self _didChangeValueForKey:_WebMainFrameDocumentKey]; 4038 // this will cause observers to call mainFrameDocument where this flag will be checked 4039} 4040 4041// This method name is used by Mail on Tiger (but not post-Tiger), so we shouldn't delete it 4042// until the day comes when we're no longer supporting Mail on Tiger. 4043- (WebFrame *)_frameForCurrentSelection 4044{ 4045 return [self _selectedOrMainFrame]; 4046} 4047 4048- (void)setTabKeyCyclesThroughElements:(BOOL)cyclesElements 4049{ 4050 _private->tabKeyCyclesThroughElementsChanged = YES; 4051 if (_private->page) 4052 _private->page->setTabKeyCyclesThroughElements(cyclesElements); 4053} 4054 4055- (BOOL)tabKeyCyclesThroughElements 4056{ 4057 return _private->page && _private->page->tabKeyCyclesThroughElements(); 4058} 4059 4060- (void)setScriptDebugDelegate:(id)delegate 4061{ 4062 _private->scriptDebugDelegate = delegate; 4063 [self _cacheScriptDebugDelegateImplementations]; 4064 4065 if (delegate) 4066 [self _attachScriptDebuggerToAllFrames]; 4067 else 4068 [self _detachScriptDebuggerFromAllFrames]; 4069} 4070 4071- (id)scriptDebugDelegate 4072{ 4073 return _private->scriptDebugDelegate; 4074} 4075 4076- (void)setHistoryDelegate:(id)delegate 4077{ 4078 _private->historyDelegate = delegate; 4079 [self _cacheHistoryDelegateImplementations]; 4080} 4081 4082- (id)historyDelegate 4083{ 4084 return _private->historyDelegate; 4085} 4086 4087- (BOOL)shouldClose 4088{ 4089 Frame* coreFrame = [self _mainCoreFrame]; 4090 if (!coreFrame) 4091 return YES; 4092 return coreFrame->shouldClose(); 4093} 4094 4095static NSAppleEventDescriptor* aeDescFromJSValue(ExecState* exec, JSValue jsValue) 4096{ 4097 NSAppleEventDescriptor* aeDesc = 0; 4098 if (jsValue.isBoolean()) 4099 return [NSAppleEventDescriptor descriptorWithBoolean:jsValue.getBoolean()]; 4100 if (jsValue.isString()) 4101 return [NSAppleEventDescriptor descriptorWithString:String(jsValue.getString(exec))]; 4102 if (jsValue.isNumber()) { 4103 double value = jsValue.uncheckedGetNumber(); 4104 int intValue = value; 4105 if (value == intValue) 4106 return [NSAppleEventDescriptor descriptorWithDescriptorType:typeSInt32 bytes:&intValue length:sizeof(intValue)]; 4107 return [NSAppleEventDescriptor descriptorWithDescriptorType:typeIEEE64BitFloatingPoint bytes:&value length:sizeof(value)]; 4108 } 4109 if (jsValue.isObject()) { 4110 JSObject* object = jsValue.getObject(); 4111 if (object->inherits(&DateInstance::info)) { 4112 DateInstance* date = static_cast<DateInstance*>(object); 4113 double ms = date->internalNumber(); 4114 if (!isnan(ms)) { 4115 CFAbsoluteTime utcSeconds = ms / 1000 - kCFAbsoluteTimeIntervalSince1970; 4116 LongDateTime ldt; 4117 if (noErr == UCConvertCFAbsoluteTimeToLongDateTime(utcSeconds, &ldt)) 4118 return [NSAppleEventDescriptor descriptorWithDescriptorType:typeLongDateTime bytes:&ldt length:sizeof(ldt)]; 4119 } 4120 } 4121 else if (object->inherits(&JSArray::info)) { 4122 DEFINE_STATIC_LOCAL(HashSet<JSObject*>, visitedElems, ()); 4123 if (!visitedElems.contains(object)) { 4124 visitedElems.add(object); 4125 4126 JSArray* array = static_cast<JSArray*>(object); 4127 aeDesc = [NSAppleEventDescriptor listDescriptor]; 4128 unsigned numItems = array->length(); 4129 for (unsigned i = 0; i < numItems; ++i) 4130 [aeDesc insertDescriptor:aeDescFromJSValue(exec, array->get(exec, i)) atIndex:0]; 4131 4132 visitedElems.remove(object); 4133 return aeDesc; 4134 } 4135 } 4136 JSValue primitive = object->toPrimitive(exec); 4137 if (exec->hadException()) { 4138 exec->clearException(); 4139 return [NSAppleEventDescriptor nullDescriptor]; 4140 } 4141 return aeDescFromJSValue(exec, primitive); 4142 } 4143 if (jsValue.isUndefined()) 4144 return [NSAppleEventDescriptor descriptorWithTypeCode:cMissingValue]; 4145 ASSERT(jsValue.isNull()); 4146 return [NSAppleEventDescriptor nullDescriptor]; 4147} 4148 4149- (NSAppleEventDescriptor *)aeDescByEvaluatingJavaScriptFromString:(NSString *)script 4150{ 4151 Frame* coreFrame = [self _mainCoreFrame]; 4152 if (!coreFrame) 4153 return nil; 4154 if (!coreFrame->document()) 4155 return nil; 4156 JSValue result = coreFrame->script()->executeScript(script, true).jsValue(); 4157 if (!result) // FIXME: pass errors 4158 return 0; 4159 JSLock lock(SilenceAssertionsOnly); 4160 return aeDescFromJSValue(coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec(), result); 4161} 4162 4163- (BOOL)canMarkAllTextMatches 4164{ 4165 WebFrame *frame = [self mainFrame]; 4166 do { 4167 id <WebDocumentView> view = [[frame frameView] documentView]; 4168 if (view && ![view conformsToProtocol:@protocol(WebMultipleTextMatches)]) 4169 return NO; 4170 4171 frame = incrementFrame(frame, YES, NO); 4172 } while (frame); 4173 4174 return YES; 4175} 4176 4177- (NSUInteger)markAllMatchesForText:(NSString *)string caseSensitive:(BOOL)caseFlag highlight:(BOOL)highlight limit:(NSUInteger)limit 4178{ 4179 WebFrame *frame = [self mainFrame]; 4180 unsigned matchCount = 0; 4181 do { 4182 id <WebDocumentView> view = [[frame frameView] documentView]; 4183 if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)]) { 4184 [(NSView <WebMultipleTextMatches>*)view setMarkedTextMatchesAreHighlighted:highlight]; 4185 4186 ASSERT(limit == 0 || matchCount < limit); 4187 matchCount += [(NSView <WebMultipleTextMatches>*)view markAllMatchesForText:string caseSensitive:caseFlag limit:limit == 0 ? 0 : limit - matchCount]; 4188 4189 // Stop looking if we've reached the limit. A limit of 0 means no limit. 4190 if (limit > 0 && matchCount >= limit) 4191 break; 4192 } 4193 4194 frame = incrementFrame(frame, YES, NO); 4195 } while (frame); 4196 4197 return matchCount; 4198} 4199 4200- (void)unmarkAllTextMatches 4201{ 4202 WebFrame *frame = [self mainFrame]; 4203 do { 4204 id <WebDocumentView> view = [[frame frameView] documentView]; 4205 if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)]) 4206 [(NSView <WebMultipleTextMatches>*)view unmarkAllTextMatches]; 4207 4208 frame = incrementFrame(frame, YES, NO); 4209 } while (frame); 4210} 4211 4212- (NSArray *)rectsForTextMatches 4213{ 4214 NSMutableArray *result = [NSMutableArray array]; 4215 WebFrame *frame = [self mainFrame]; 4216 do { 4217 id <WebDocumentView> view = [[frame frameView] documentView]; 4218 if ([view conformsToProtocol:@protocol(WebMultipleTextMatches)]) { 4219 NSView <WebMultipleTextMatches> *documentView = (NSView <WebMultipleTextMatches> *)view; 4220 NSRect documentViewVisibleRect = [documentView visibleRect]; 4221 NSArray *originalRects = [documentView rectsForTextMatches]; 4222 unsigned rectCount = [originalRects count]; 4223 unsigned rectIndex; 4224 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 4225 for (rectIndex = 0; rectIndex < rectCount; ++rectIndex) { 4226 NSRect r = [[originalRects objectAtIndex:rectIndex] rectValue]; 4227 // Clip rect to document view's visible rect so rect is confined to subframe 4228 r = NSIntersectionRect(r, documentViewVisibleRect); 4229 if (NSIsEmptyRect(r)) 4230 continue; 4231 4232 // Convert rect to our coordinate system 4233 r = [documentView convertRect:r toView:self]; 4234 [result addObject:[NSValue valueWithRect:r]]; 4235 if (rectIndex % 10 == 0) { 4236 [pool drain]; 4237 pool = [[NSAutoreleasePool alloc] init]; 4238 } 4239 } 4240 [pool drain]; 4241 } 4242 4243 frame = incrementFrame(frame, YES, NO); 4244 } while (frame); 4245 4246 return result; 4247} 4248 4249- (void)scrollDOMRangeToVisible:(DOMRange *)range 4250{ 4251 [[[[range startContainer] ownerDocument] webFrame] _scrollDOMRangeToVisible:range]; 4252} 4253 4254- (BOOL)allowsUndo 4255{ 4256 return _private->allowsUndo; 4257} 4258 4259- (void)setAllowsUndo:(BOOL)flag 4260{ 4261 _private->allowsUndo = flag; 4262} 4263 4264- (void)setPageSizeMultiplier:(float)m 4265{ 4266 [self _setZoomMultiplier:m isTextOnly:NO]; 4267} 4268 4269- (float)pageSizeMultiplier 4270{ 4271 return ![self _realZoomMultiplierIsTextOnly] ? _private->zoomMultiplier : 1.0f; 4272} 4273 4274- (BOOL)canZoomPageIn 4275{ 4276 return [self _canZoomIn:NO]; 4277} 4278 4279- (IBAction)zoomPageIn:(id)sender 4280{ 4281 return [self _zoomIn:sender isTextOnly:NO]; 4282} 4283 4284- (BOOL)canZoomPageOut 4285{ 4286 return [self _canZoomOut:NO]; 4287} 4288 4289- (IBAction)zoomPageOut:(id)sender 4290{ 4291 return [self _zoomOut:sender isTextOnly:NO]; 4292} 4293 4294- (BOOL)canResetPageZoom 4295{ 4296 return [self _canResetZoom:NO]; 4297} 4298 4299- (IBAction)resetPageZoom:(id)sender 4300{ 4301 return [self _resetZoom:sender isTextOnly:NO]; 4302} 4303 4304- (void)setMediaVolume:(float)volume 4305{ 4306 if (_private->page) 4307 _private->page->setMediaVolume(volume); 4308} 4309 4310- (float)mediaVolume 4311{ 4312 if (!_private->page) 4313 return 0; 4314 4315 return _private->page->mediaVolume(); 4316} 4317 4318- (void)addVisitedLinks:(NSArray *)visitedLinks 4319{ 4320 PageGroup& group = core(self)->group(); 4321 4322 NSEnumerator *enumerator = [visitedLinks objectEnumerator]; 4323 while (NSString *url = [enumerator nextObject]) { 4324 size_t length = [url length]; 4325 const UChar* characters = CFStringGetCharactersPtr(reinterpret_cast<CFStringRef>(url)); 4326 if (characters) 4327 group.addVisitedLink(characters, length); 4328 else { 4329 Vector<UChar, 512> buffer(length); 4330 [url getCharacters:buffer.data()]; 4331 group.addVisitedLink(buffer.data(), length); 4332 } 4333 } 4334} 4335 4336@end 4337 4338@implementation WebView (WebViewPrintingPrivate) 4339 4340- (float)_headerHeight 4341{ 4342 return CallUIDelegateReturningFloat(self, @selector(webViewHeaderHeight:)); 4343} 4344 4345- (float)_footerHeight 4346{ 4347 return CallUIDelegateReturningFloat(self, @selector(webViewFooterHeight:)); 4348} 4349 4350- (void)_drawHeaderInRect:(NSRect)rect 4351{ 4352#ifdef DEBUG_HEADER_AND_FOOTER 4353 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext]; 4354 [currentContext saveGraphicsState]; 4355 [[NSColor yellowColor] set]; 4356 NSRectFill(rect); 4357 [currentContext restoreGraphicsState]; 4358#endif 4359 4360 SEL selector = @selector(webView:drawHeaderInRect:); 4361 if (![_private->UIDelegate respondsToSelector:selector]) 4362 return; 4363 4364 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext]; 4365 [currentContext saveGraphicsState]; 4366 4367 NSRectClip(rect); 4368 CallUIDelegate(self, selector, rect); 4369 4370 [currentContext restoreGraphicsState]; 4371} 4372 4373- (void)_drawFooterInRect:(NSRect)rect 4374{ 4375#ifdef DEBUG_HEADER_AND_FOOTER 4376 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext]; 4377 [currentContext saveGraphicsState]; 4378 [[NSColor cyanColor] set]; 4379 NSRectFill(rect); 4380 [currentContext restoreGraphicsState]; 4381#endif 4382 4383 SEL selector = @selector(webView:drawFooterInRect:); 4384 if (![_private->UIDelegate respondsToSelector:selector]) 4385 return; 4386 4387 NSGraphicsContext *currentContext = [NSGraphicsContext currentContext]; 4388 [currentContext saveGraphicsState]; 4389 4390 NSRectClip(rect); 4391 CallUIDelegate(self, selector, rect); 4392 4393 [currentContext restoreGraphicsState]; 4394} 4395 4396- (void)_adjustPrintingMarginsForHeaderAndFooter 4397{ 4398 NSPrintOperation *op = [NSPrintOperation currentOperation]; 4399 NSPrintInfo *info = [op printInfo]; 4400 NSMutableDictionary *infoDictionary = [info dictionary]; 4401 4402 // We need to modify the top and bottom margins in the NSPrintInfo to account for the space needed by the 4403 // header and footer. Because this method can be called more than once on the same NSPrintInfo (see 5038087), 4404 // we stash away the unmodified top and bottom margins the first time this method is called, and we read from 4405 // those stashed-away values on subsequent calls. 4406 float originalTopMargin; 4407 float originalBottomMargin; 4408 NSNumber *originalTopMarginNumber = [infoDictionary objectForKey:WebKitOriginalTopPrintingMarginKey]; 4409 if (!originalTopMarginNumber) { 4410 ASSERT(![infoDictionary objectForKey:WebKitOriginalBottomPrintingMarginKey]); 4411 originalTopMargin = [info topMargin]; 4412 originalBottomMargin = [info bottomMargin]; 4413 [infoDictionary setObject:[NSNumber numberWithFloat:originalTopMargin] forKey:WebKitOriginalTopPrintingMarginKey]; 4414 [infoDictionary setObject:[NSNumber numberWithFloat:originalBottomMargin] forKey:WebKitOriginalBottomPrintingMarginKey]; 4415 } else { 4416 ASSERT([originalTopMarginNumber isKindOfClass:[NSNumber class]]); 4417 ASSERT([[infoDictionary objectForKey:WebKitOriginalBottomPrintingMarginKey] isKindOfClass:[NSNumber class]]); 4418 originalTopMargin = [originalTopMarginNumber floatValue]; 4419 originalBottomMargin = [[infoDictionary objectForKey:WebKitOriginalBottomPrintingMarginKey] floatValue]; 4420 } 4421 4422 float scale = [op _web_pageSetupScaleFactor]; 4423 [info setTopMargin:originalTopMargin + [self _headerHeight] * scale]; 4424 [info setBottomMargin:originalBottomMargin + [self _footerHeight] * scale]; 4425} 4426 4427- (void)_drawHeaderAndFooter 4428{ 4429 // The header and footer rect height scales with the page, but the width is always 4430 // all the way across the printed page (inset by printing margins). 4431 NSPrintOperation *op = [NSPrintOperation currentOperation]; 4432 float scale = [op _web_pageSetupScaleFactor]; 4433 NSPrintInfo *printInfo = [op printInfo]; 4434 NSSize paperSize = [printInfo paperSize]; 4435 float headerFooterLeft = [printInfo leftMargin]/scale; 4436 float headerFooterWidth = (paperSize.width - ([printInfo leftMargin] + [printInfo rightMargin]))/scale; 4437 NSRect footerRect = NSMakeRect(headerFooterLeft, [printInfo bottomMargin]/scale - [self _footerHeight] , 4438 headerFooterWidth, [self _footerHeight]); 4439 NSRect headerRect = NSMakeRect(headerFooterLeft, (paperSize.height - [printInfo topMargin])/scale, 4440 headerFooterWidth, [self _headerHeight]); 4441 4442 [self _drawHeaderInRect:headerRect]; 4443 [self _drawFooterInRect:footerRect]; 4444} 4445@end 4446 4447@implementation WebView (WebDebugBinding) 4448 4449- (void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context 4450{ 4451 LOG (Bindings, "addObserver:%p forKeyPath:%@ options:%x context:%p", anObserver, keyPath, options, context); 4452 [super addObserver:anObserver forKeyPath:keyPath options:options context:context]; 4453} 4454 4455- (void)removeObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath 4456{ 4457 LOG (Bindings, "removeObserver:%p forKeyPath:%@", anObserver, keyPath); 4458 [super removeObserver:anObserver forKeyPath:keyPath]; 4459} 4460 4461@end 4462 4463//========================================================================================== 4464// Editing 4465 4466@implementation WebView (WebViewCSS) 4467 4468- (DOMCSSStyleDeclaration *)computedStyleForElement:(DOMElement *)element pseudoElement:(NSString *)pseudoElement 4469{ 4470 // FIXME: is this the best level for this conversion? 4471 if (pseudoElement == nil) 4472 pseudoElement = @""; 4473 4474 return [[element ownerDocument] getComputedStyle:element pseudoElement:pseudoElement]; 4475} 4476 4477@end 4478 4479@implementation WebView (WebViewEditing) 4480 4481- (DOMRange *)editableDOMRangeForPoint:(NSPoint)point 4482{ 4483 Page* page = core(self); 4484 if (!page) 4485 return nil; 4486 return kit(page->mainFrame()->editor()->rangeForPoint(IntPoint([self convertPoint:point toView:nil])).get()); 4487} 4488 4489- (BOOL)_shouldChangeSelectedDOMRange:(DOMRange *)currentRange toDOMRange:(DOMRange *)proposedRange affinity:(NSSelectionAffinity)selectionAffinity stillSelecting:(BOOL)flag 4490{ 4491 // FIXME: This quirk is needed due to <rdar://problem/4985321> - We can phase it out once Aperture can adopt the new behavior on their end 4492 if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_APERTURE_QUIRK) && [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Aperture"]) 4493 return YES; 4494 return [[self _editingDelegateForwarder] webView:self shouldChangeSelectedDOMRange:currentRange toDOMRange:proposedRange affinity:selectionAffinity stillSelecting:flag]; 4495} 4496 4497- (BOOL)maintainsInactiveSelection 4498{ 4499 return NO; 4500} 4501 4502- (void)setSelectedDOMRange:(DOMRange *)range affinity:(NSSelectionAffinity)selectionAffinity 4503{ 4504 Frame* coreFrame = core([self _selectedOrMainFrame]); 4505 if (!coreFrame) 4506 return; 4507 4508 if (range == nil) 4509 coreFrame->selection()->clear(); 4510 else { 4511 // Derive the frame to use from the range passed in. 4512 // Using _selectedOrMainFrame could give us a different document than 4513 // the one the range uses. 4514 coreFrame = core([range startContainer])->document()->frame(); 4515 if (!coreFrame) 4516 return; 4517 4518 coreFrame->selection()->setSelectedRange(core(range), core(selectionAffinity), true); 4519 } 4520} 4521 4522- (DOMRange *)selectedDOMRange 4523{ 4524 Frame* coreFrame = core([self _selectedOrMainFrame]); 4525 if (!coreFrame) 4526 return nil; 4527 return kit(coreFrame->selection()->toNormalizedRange().get()); 4528} 4529 4530- (NSSelectionAffinity)selectionAffinity 4531{ 4532 Frame* coreFrame = core([self _selectedOrMainFrame]); 4533 if (!coreFrame) 4534 return NSSelectionAffinityDownstream; 4535 return kit(coreFrame->selection()->affinity()); 4536} 4537 4538- (void)setEditable:(BOOL)flag 4539{ 4540 if (_private->editable != flag) { 4541 _private->editable = flag; 4542 if (!_private->tabKeyCyclesThroughElementsChanged && _private->page) 4543 _private->page->setTabKeyCyclesThroughElements(!flag); 4544 Frame* mainFrame = [self _mainCoreFrame]; 4545 if (mainFrame) { 4546 if (flag) { 4547 mainFrame->applyEditingStyleToBodyElement(); 4548 // If the WebView is made editable and the selection is empty, set it to something. 4549 if (![self selectedDOMRange]) 4550 mainFrame->setSelectionFromNone(); 4551 } else 4552 mainFrame->removeEditingStyleFromBodyElement(); 4553 } 4554 } 4555} 4556 4557- (BOOL)isEditable 4558{ 4559 return _private->editable; 4560} 4561 4562- (void)setTypingStyle:(DOMCSSStyleDeclaration *)style 4563{ 4564 // We don't know enough at thls level to pass in a relevant WebUndoAction; we'd have to 4565 // change the API to allow this. 4566 [[self _selectedOrMainFrame] _setTypingStyle:style withUndoAction:EditActionUnspecified]; 4567} 4568 4569- (DOMCSSStyleDeclaration *)typingStyle 4570{ 4571 return [[self _selectedOrMainFrame] _typingStyle]; 4572} 4573 4574- (void)setSmartInsertDeleteEnabled:(BOOL)flag 4575{ 4576 if (_private->smartInsertDeleteEnabled != flag) { 4577 _private->smartInsertDeleteEnabled = flag; 4578 [[NSUserDefaults standardUserDefaults] setBool:_private->smartInsertDeleteEnabled forKey:WebSmartInsertDeleteEnabled]; 4579 } 4580 if (flag) 4581 [self setSelectTrailingWhitespaceEnabled:false]; 4582} 4583 4584- (BOOL)smartInsertDeleteEnabled 4585{ 4586 return _private->smartInsertDeleteEnabled; 4587} 4588 4589- (void)setContinuousSpellCheckingEnabled:(BOOL)flag 4590{ 4591 if (continuousSpellCheckingEnabled != flag) { 4592 continuousSpellCheckingEnabled = flag; 4593 [[NSUserDefaults standardUserDefaults] setBool:continuousSpellCheckingEnabled forKey:WebContinuousSpellCheckingEnabled]; 4594 } 4595 4596 if ([self isContinuousSpellCheckingEnabled]) { 4597 [[self class] _preflightSpellChecker]; 4598 } else { 4599 [[self mainFrame] _unmarkAllMisspellings]; 4600 } 4601} 4602 4603- (BOOL)isContinuousSpellCheckingEnabled 4604{ 4605 return (continuousSpellCheckingEnabled && [self _continuousCheckingAllowed]); 4606} 4607 4608- (NSInteger)spellCheckerDocumentTag 4609{ 4610 if (!_private->hasSpellCheckerDocumentTag) { 4611 _private->spellCheckerDocumentTag = [NSSpellChecker uniqueSpellDocumentTag]; 4612 _private->hasSpellCheckerDocumentTag = YES; 4613 } 4614 return _private->spellCheckerDocumentTag; 4615} 4616 4617- (NSUndoManager *)undoManager 4618{ 4619 if (!_private->allowsUndo) 4620 return nil; 4621 4622 NSUndoManager *undoManager = [[self _editingDelegateForwarder] undoManagerForWebView:self]; 4623 if (undoManager) 4624 return undoManager; 4625 4626 return [super undoManager]; 4627} 4628 4629- (void)registerForEditingDelegateNotification:(NSString *)name selector:(SEL)selector 4630{ 4631 NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; 4632 if ([_private->editingDelegate respondsToSelector:selector]) 4633 [defaultCenter addObserver:_private->editingDelegate selector:selector name:name object:self]; 4634} 4635 4636- (void)setEditingDelegate:(id)delegate 4637{ 4638 if (_private->editingDelegate == delegate) 4639 return; 4640 4641 NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; 4642 4643 // remove notifications from current delegate 4644 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidBeginEditingNotification object:self]; 4645 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeNotification object:self]; 4646 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidEndEditingNotification object:self]; 4647 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeTypingStyleNotification object:self]; 4648 [defaultCenter removeObserver:_private->editingDelegate name:WebViewDidChangeSelectionNotification object:self]; 4649 4650 _private->editingDelegate = delegate; 4651 [_private->editingDelegateForwarder release]; 4652 _private->editingDelegateForwarder = nil; 4653 4654 // add notifications for new delegate 4655 [self registerForEditingDelegateNotification:WebViewDidBeginEditingNotification selector:@selector(webViewDidBeginEditing:)]; 4656 [self registerForEditingDelegateNotification:WebViewDidChangeNotification selector:@selector(webViewDidChange:)]; 4657 [self registerForEditingDelegateNotification:WebViewDidEndEditingNotification selector:@selector(webViewDidEndEditing:)]; 4658 [self registerForEditingDelegateNotification:WebViewDidChangeTypingStyleNotification selector:@selector(webViewDidChangeTypingStyle:)]; 4659 [self registerForEditingDelegateNotification:WebViewDidChangeSelectionNotification selector:@selector(webViewDidChangeSelection:)]; 4660} 4661 4662- (id)editingDelegate 4663{ 4664 return _private->editingDelegate; 4665} 4666 4667- (DOMCSSStyleDeclaration *)styleDeclarationWithText:(NSString *)text 4668{ 4669 // FIXME: Should this really be attached to the document with the current selection? 4670 DOMCSSStyleDeclaration *decl = [[[self _selectedOrMainFrame] DOMDocument] createCSSStyleDeclaration]; 4671 [decl setCssText:text]; 4672 return decl; 4673} 4674 4675@end 4676 4677@implementation WebView (WebViewGrammarChecking) 4678 4679// FIXME: This method should be merged into WebViewEditing when we're not in API freeze 4680- (BOOL)isGrammarCheckingEnabled 4681{ 4682#ifdef BUILDING_ON_TIGER 4683 return NO; 4684#else 4685 return grammarCheckingEnabled; 4686#endif 4687} 4688 4689#ifndef BUILDING_ON_TIGER 4690// FIXME: This method should be merged into WebViewEditing when we're not in API freeze 4691- (void)setGrammarCheckingEnabled:(BOOL)flag 4692{ 4693 if (grammarCheckingEnabled == flag) 4694 return; 4695 4696 grammarCheckingEnabled = flag; 4697 [[NSUserDefaults standardUserDefaults] setBool:grammarCheckingEnabled forKey:WebGrammarCheckingEnabled]; 4698 4699#ifndef BUILDING_ON_LEOPARD 4700 [[NSSpellChecker sharedSpellChecker] updatePanels]; 4701#else 4702 NSSpellChecker *spellChecker = [NSSpellChecker sharedSpellChecker]; 4703 if ([spellChecker respondsToSelector:@selector(_updateGrammar)]) 4704 [spellChecker performSelector:@selector(_updateGrammar)]; 4705#endif 4706 4707 // We call _preflightSpellChecker when turning continuous spell checking on, but we don't need to do that here 4708 // because grammar checking only occurs on code paths that already preflight spell checking appropriately. 4709 4710 if (![self isGrammarCheckingEnabled]) 4711 [[self mainFrame] _unmarkAllBadGrammar]; 4712} 4713 4714// FIXME: This method should be merged into WebIBActions when we're not in API freeze 4715- (void)toggleGrammarChecking:(id)sender 4716{ 4717 [self setGrammarCheckingEnabled:![self isGrammarCheckingEnabled]]; 4718} 4719#endif 4720 4721@end 4722 4723@implementation WebView (WebViewTextChecking) 4724 4725- (BOOL)isAutomaticQuoteSubstitutionEnabled 4726{ 4727#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) 4728 return NO; 4729#else 4730 return automaticQuoteSubstitutionEnabled; 4731#endif 4732} 4733 4734- (BOOL)isAutomaticLinkDetectionEnabled 4735{ 4736#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) 4737 return NO; 4738#else 4739 return automaticLinkDetectionEnabled; 4740#endif 4741} 4742 4743- (BOOL)isAutomaticDashSubstitutionEnabled 4744{ 4745#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) 4746 return NO; 4747#else 4748 return automaticDashSubstitutionEnabled; 4749#endif 4750} 4751 4752- (BOOL)isAutomaticTextReplacementEnabled 4753{ 4754#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) 4755 return NO; 4756#else 4757 return automaticTextReplacementEnabled; 4758#endif 4759} 4760 4761- (BOOL)isAutomaticSpellingCorrectionEnabled 4762{ 4763#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) 4764 return NO; 4765#else 4766 return automaticSpellingCorrectionEnabled; 4767#endif 4768} 4769 4770#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 4771 4772- (void)setAutomaticQuoteSubstitutionEnabled:(BOOL)flag 4773{ 4774 if (automaticQuoteSubstitutionEnabled == flag) 4775 return; 4776 automaticQuoteSubstitutionEnabled = flag; 4777 [[NSUserDefaults standardUserDefaults] setBool:automaticQuoteSubstitutionEnabled forKey:WebAutomaticQuoteSubstitutionEnabled]; 4778 [[NSSpellChecker sharedSpellChecker] updatePanels]; 4779} 4780 4781- (void)toggleAutomaticQuoteSubstitution:(id)sender 4782{ 4783 [self setAutomaticQuoteSubstitutionEnabled:![self isAutomaticQuoteSubstitutionEnabled]]; 4784} 4785 4786- (void)setAutomaticLinkDetectionEnabled:(BOOL)flag 4787{ 4788 if (automaticLinkDetectionEnabled == flag) 4789 return; 4790 automaticLinkDetectionEnabled = flag; 4791 [[NSUserDefaults standardUserDefaults] setBool:automaticLinkDetectionEnabled forKey:WebAutomaticLinkDetectionEnabled]; 4792 [[NSSpellChecker sharedSpellChecker] updatePanels]; 4793} 4794 4795- (void)toggleAutomaticLinkDetection:(id)sender 4796{ 4797 [self setAutomaticLinkDetectionEnabled:![self isAutomaticLinkDetectionEnabled]]; 4798} 4799 4800- (void)setAutomaticDashSubstitutionEnabled:(BOOL)flag 4801{ 4802 if (automaticDashSubstitutionEnabled == flag) 4803 return; 4804 automaticDashSubstitutionEnabled = flag; 4805 [[NSUserDefaults standardUserDefaults] setBool:automaticDashSubstitutionEnabled forKey:WebAutomaticDashSubstitutionEnabled]; 4806 [[NSSpellChecker sharedSpellChecker] updatePanels]; 4807} 4808 4809- (void)toggleAutomaticDashSubstitution:(id)sender 4810{ 4811 [self setAutomaticDashSubstitutionEnabled:![self isAutomaticDashSubstitutionEnabled]]; 4812} 4813 4814- (void)setAutomaticTextReplacementEnabled:(BOOL)flag 4815{ 4816 if (automaticTextReplacementEnabled == flag) 4817 return; 4818 automaticTextReplacementEnabled = flag; 4819 [[NSUserDefaults standardUserDefaults] setBool:automaticTextReplacementEnabled forKey:WebAutomaticTextReplacementEnabled]; 4820 [[NSSpellChecker sharedSpellChecker] updatePanels]; 4821} 4822 4823- (void)toggleAutomaticTextReplacement:(id)sender 4824{ 4825 [self setAutomaticTextReplacementEnabled:![self isAutomaticTextReplacementEnabled]]; 4826} 4827 4828- (void)setAutomaticSpellingCorrectionEnabled:(BOOL)flag 4829{ 4830 if (automaticSpellingCorrectionEnabled == flag) 4831 return; 4832 automaticSpellingCorrectionEnabled = flag; 4833 [[NSUserDefaults standardUserDefaults] setBool:automaticSpellingCorrectionEnabled forKey:WebAutomaticSpellingCorrectionEnabled]; 4834 [[NSSpellChecker sharedSpellChecker] updatePanels]; 4835} 4836 4837- (void)toggleAutomaticSpellingCorrection:(id)sender 4838{ 4839 [self setAutomaticSpellingCorrectionEnabled:![self isAutomaticSpellingCorrectionEnabled]]; 4840} 4841 4842#endif 4843 4844@end 4845 4846@implementation WebView (WebViewUndoableEditing) 4847 4848- (void)replaceSelectionWithNode:(DOMNode *)node 4849{ 4850 [[self _selectedOrMainFrame] _replaceSelectionWithNode:node selectReplacement:YES smartReplace:NO matchStyle:NO]; 4851} 4852 4853- (void)replaceSelectionWithText:(NSString *)text 4854{ 4855 [[self _selectedOrMainFrame] _replaceSelectionWithText:text selectReplacement:YES smartReplace:NO]; 4856} 4857 4858- (void)replaceSelectionWithMarkupString:(NSString *)markupString 4859{ 4860 [[self _selectedOrMainFrame] _replaceSelectionWithMarkupString:markupString baseURLString:nil selectReplacement:YES smartReplace:NO]; 4861} 4862 4863- (void)replaceSelectionWithArchive:(WebArchive *)archive 4864{ 4865 [[[self _selectedOrMainFrame] _dataSource] _replaceSelectionWithArchive:archive selectReplacement:YES]; 4866} 4867 4868- (void)deleteSelection 4869{ 4870 WebFrame *webFrame = [self _selectedOrMainFrame]; 4871 Frame* coreFrame = core(webFrame); 4872 if (coreFrame) 4873 coreFrame->editor()->deleteSelectionWithSmartDelete([(WebHTMLView *)[[webFrame frameView] documentView] _canSmartCopyOrDelete]); 4874} 4875 4876- (void)applyStyle:(DOMCSSStyleDeclaration *)style 4877{ 4878 // We don't know enough at thls level to pass in a relevant WebUndoAction; we'd have to 4879 // change the API to allow this. 4880 WebFrame *webFrame = [self _selectedOrMainFrame]; 4881 Frame* coreFrame = core(webFrame); 4882 if (coreFrame) 4883 coreFrame->editor()->applyStyle(core(style)); 4884} 4885 4886@end 4887 4888@implementation WebView (WebViewEditingActions) 4889 4890- (void)_performResponderOperation:(SEL)selector with:(id)parameter 4891{ 4892 static BOOL reentered = NO; 4893 if (reentered) { 4894 [[self nextResponder] tryToPerform:selector with:parameter]; 4895 return; 4896 } 4897 4898 // There are two possibilities here. 4899 // 4900 // One is that WebView has been called in its role as part of the responder chain. 4901 // In that case, it's fine to call the first responder and end up calling down the 4902 // responder chain again. Later we will return here with reentered = YES and continue 4903 // past the WebView. 4904 // 4905 // The other is that we are being called directly, in which case we want to pass the 4906 // selector down to the view inside us that can handle it, and continue down the 4907 // responder chain as usual. 4908 4909 // Pass this selector down to the first responder. 4910 NSResponder *responder = [self _responderForResponderOperations]; 4911 reentered = YES; 4912 [responder tryToPerform:selector with:parameter]; 4913 reentered = NO; 4914} 4915 4916#define FORWARD(name) \ 4917 - (void)name:(id)sender { [self _performResponderOperation:_cmd with:sender]; } 4918 4919FOR_EACH_RESPONDER_SELECTOR(FORWARD) 4920 4921- (void)insertText:(NSString *)text 4922{ 4923 [self _performResponderOperation:_cmd with:text]; 4924} 4925 4926@end 4927 4928@implementation WebView (WebViewEditingInMail) 4929 4930- (void)_insertNewlineInQuotedContent 4931{ 4932 [[self _selectedOrMainFrame] _insertParagraphSeparatorInQuotedContent]; 4933} 4934 4935- (void)_replaceSelectionWithNode:(DOMNode *)node matchStyle:(BOOL)matchStyle 4936{ 4937 [[self _selectedOrMainFrame] _replaceSelectionWithNode:node selectReplacement:YES smartReplace:NO matchStyle:matchStyle]; 4938} 4939 4940- (BOOL)_selectionIsCaret 4941{ 4942 Frame* coreFrame = core([self _selectedOrMainFrame]); 4943 if (!coreFrame) 4944 return NO; 4945 return coreFrame->selection()->isCaret(); 4946} 4947 4948- (BOOL)_selectionIsAll 4949{ 4950 Frame* coreFrame = core([self _selectedOrMainFrame]); 4951 if (!coreFrame) 4952 return NO; 4953 return coreFrame->selection()->isAll(MayLeaveEditableContent); 4954} 4955 4956@end 4957 4958static WebFrameView *containingFrameView(NSView *view) 4959{ 4960 while (view && ![view isKindOfClass:[WebFrameView class]]) 4961 view = [view superview]; 4962 return (WebFrameView *)view; 4963} 4964 4965@implementation WebView (WebFileInternal) 4966 4967+ (void)_setCacheModel:(WebCacheModel)cacheModel 4968{ 4969 if (s_didSetCacheModel && cacheModel == s_cacheModel) 4970 return; 4971 4972 NSString *nsurlCacheDirectory = (NSString *)WebCFAutorelease(WKCopyFoundationCacheDirectory()); 4973 if (!nsurlCacheDirectory) 4974 nsurlCacheDirectory = NSHomeDirectory(); 4975 4976 // As a fudge factor, use 1000 instead of 1024, in case the reported byte 4977 // count doesn't align exactly to a megabyte boundary. 4978 uint64_t memSize = WebMemorySize() / 1024 / 1000; 4979 unsigned long long diskFreeSize = WebVolumeFreeSize(nsurlCacheDirectory) / 1024 / 1000; 4980 NSURLCache *nsurlCache = [NSURLCache sharedURLCache]; 4981 4982 unsigned cacheTotalCapacity = 0; 4983 unsigned cacheMinDeadCapacity = 0; 4984 unsigned cacheMaxDeadCapacity = 0; 4985 double deadDecodedDataDeletionInterval = 0; 4986 4987 unsigned pageCacheCapacity = 0; 4988 4989 NSUInteger nsurlCacheMemoryCapacity = 0; 4990 NSUInteger nsurlCacheDiskCapacity = 0; 4991 4992 switch (cacheModel) { 4993 case WebCacheModelDocumentViewer: { 4994 // Page cache capacity (in pages) 4995 pageCacheCapacity = 0; 4996 4997 // Object cache capacities (in bytes) 4998 if (memSize >= 2048) 4999 cacheTotalCapacity = 96 * 1024 * 1024; 5000 else if (memSize >= 1536) 5001 cacheTotalCapacity = 64 * 1024 * 1024; 5002 else if (memSize >= 1024) 5003 cacheTotalCapacity = 32 * 1024 * 1024; 5004 else if (memSize >= 512) 5005 cacheTotalCapacity = 16 * 1024 * 1024; 5006 5007 cacheMinDeadCapacity = 0; 5008 cacheMaxDeadCapacity = 0; 5009 5010 // Foundation memory cache capacity (in bytes) 5011 nsurlCacheMemoryCapacity = 0; 5012 5013 // Foundation disk cache capacity (in bytes) 5014 nsurlCacheDiskCapacity = [nsurlCache diskCapacity]; 5015 5016 break; 5017 } 5018 case WebCacheModelDocumentBrowser: { 5019 // Page cache capacity (in pages) 5020 if (memSize >= 1024) 5021 pageCacheCapacity = 3; 5022 else if (memSize >= 512) 5023 pageCacheCapacity = 2; 5024 else if (memSize >= 256) 5025 pageCacheCapacity = 1; 5026 else 5027 pageCacheCapacity = 0; 5028 5029 // Object cache capacities (in bytes) 5030 if (memSize >= 2048) 5031 cacheTotalCapacity = 96 * 1024 * 1024; 5032 else if (memSize >= 1536) 5033 cacheTotalCapacity = 64 * 1024 * 1024; 5034 else if (memSize >= 1024) 5035 cacheTotalCapacity = 32 * 1024 * 1024; 5036 else if (memSize >= 512) 5037 cacheTotalCapacity = 16 * 1024 * 1024; 5038 5039 cacheMinDeadCapacity = cacheTotalCapacity / 8; 5040 cacheMaxDeadCapacity = cacheTotalCapacity / 4; 5041 5042 // Foundation memory cache capacity (in bytes) 5043 if (memSize >= 2048) 5044 nsurlCacheMemoryCapacity = 4 * 1024 * 1024; 5045 else if (memSize >= 1024) 5046 nsurlCacheMemoryCapacity = 2 * 1024 * 1024; 5047 else if (memSize >= 512) 5048 nsurlCacheMemoryCapacity = 1 * 1024 * 1024; 5049 else 5050 nsurlCacheMemoryCapacity = 512 * 1024; 5051 5052 // Foundation disk cache capacity (in bytes) 5053 if (diskFreeSize >= 16384) 5054 nsurlCacheDiskCapacity = 50 * 1024 * 1024; 5055 else if (diskFreeSize >= 8192) 5056 nsurlCacheDiskCapacity = 40 * 1024 * 1024; 5057 else if (diskFreeSize >= 4096) 5058 nsurlCacheDiskCapacity = 30 * 1024 * 1024; 5059 else 5060 nsurlCacheDiskCapacity = 20 * 1024 * 1024; 5061 5062 break; 5063 } 5064 case WebCacheModelPrimaryWebBrowser: { 5065 // Page cache capacity (in pages) 5066 // (Research indicates that value / page drops substantially after 3 pages.) 5067 if (memSize >= 2048) 5068 pageCacheCapacity = 5; 5069 else if (memSize >= 1024) 5070 pageCacheCapacity = 4; 5071 else if (memSize >= 512) 5072 pageCacheCapacity = 3; 5073 else if (memSize >= 256) 5074 pageCacheCapacity = 2; 5075 else 5076 pageCacheCapacity = 1; 5077 5078 // Object cache capacities (in bytes) 5079 // (Testing indicates that value / MB depends heavily on content and 5080 // browsing pattern. Even growth above 128MB can have substantial 5081 // value / MB for some content / browsing patterns.) 5082 if (memSize >= 2048) 5083 cacheTotalCapacity = 128 * 1024 * 1024; 5084 else if (memSize >= 1536) 5085 cacheTotalCapacity = 96 * 1024 * 1024; 5086 else if (memSize >= 1024) 5087 cacheTotalCapacity = 64 * 1024 * 1024; 5088 else if (memSize >= 512) 5089 cacheTotalCapacity = 32 * 1024 * 1024; 5090 5091 cacheMinDeadCapacity = cacheTotalCapacity / 4; 5092 cacheMaxDeadCapacity = cacheTotalCapacity / 2; 5093 5094 // This code is here to avoid a PLT regression. We can remove it if we 5095 // can prove that the overall system gain would justify the regression. 5096 cacheMaxDeadCapacity = max(24u, cacheMaxDeadCapacity); 5097 5098 deadDecodedDataDeletionInterval = 60; 5099 5100 // Foundation memory cache capacity (in bytes) 5101 // (These values are small because WebCore does most caching itself.) 5102 if (memSize >= 1024) 5103 nsurlCacheMemoryCapacity = 4 * 1024 * 1024; 5104 else if (memSize >= 512) 5105 nsurlCacheMemoryCapacity = 2 * 1024 * 1024; 5106 else if (memSize >= 256) 5107 nsurlCacheMemoryCapacity = 1 * 1024 * 1024; 5108 else 5109 nsurlCacheMemoryCapacity = 512 * 1024; 5110 5111 // Foundation disk cache capacity (in bytes) 5112 if (diskFreeSize >= 16384) 5113 nsurlCacheDiskCapacity = 175 * 1024 * 1024; 5114 else if (diskFreeSize >= 8192) 5115 nsurlCacheDiskCapacity = 150 * 1024 * 1024; 5116 else if (diskFreeSize >= 4096) 5117 nsurlCacheDiskCapacity = 125 * 1024 * 1024; 5118 else if (diskFreeSize >= 2048) 5119 nsurlCacheDiskCapacity = 100 * 1024 * 1024; 5120 else if (diskFreeSize >= 1024) 5121 nsurlCacheDiskCapacity = 75 * 1024 * 1024; 5122 else 5123 nsurlCacheDiskCapacity = 50 * 1024 * 1024; 5124 5125 break; 5126 } 5127 default: 5128 ASSERT_NOT_REACHED(); 5129 }; 5130 5131#ifdef BUILDING_ON_TIGER 5132 // Don't use a big Foundation disk cache on Tiger because, according to the 5133 // PLT, the Foundation disk cache on Tiger is slower than the network. 5134 nsurlCacheDiskCapacity = [nsurlCache diskCapacity]; 5135#endif 5136 5137 // Don't shrink a big disk cache, since that would cause churn. 5138 nsurlCacheDiskCapacity = max(nsurlCacheDiskCapacity, [nsurlCache diskCapacity]); 5139 5140 cache()->setCapacities(cacheMinDeadCapacity, cacheMaxDeadCapacity, cacheTotalCapacity); 5141 cache()->setDeadDecodedDataDeletionInterval(deadDecodedDataDeletionInterval); 5142 pageCache()->setCapacity(pageCacheCapacity); 5143 [nsurlCache setMemoryCapacity:nsurlCacheMemoryCapacity]; 5144 [nsurlCache setDiskCapacity:nsurlCacheDiskCapacity]; 5145 5146 s_cacheModel = cacheModel; 5147 s_didSetCacheModel = YES; 5148} 5149 5150+ (WebCacheModel)_cacheModel 5151{ 5152 return s_cacheModel; 5153} 5154 5155+ (WebCacheModel)_didSetCacheModel 5156{ 5157 return s_didSetCacheModel; 5158} 5159 5160+ (WebCacheModel)_maxCacheModelInAnyInstance 5161{ 5162 WebCacheModel cacheModel = WebCacheModelDocumentViewer; 5163 NSEnumerator *enumerator = [(NSMutableSet *)allWebViewsSet objectEnumerator]; 5164 while (WebPreferences *preferences = [[enumerator nextObject] preferences]) 5165 cacheModel = max(cacheModel, [preferences cacheModel]); 5166 return cacheModel; 5167} 5168 5169+ (void)_preferencesChangedNotification:(NSNotification *)notification 5170{ 5171 WebPreferences *preferences = (WebPreferences *)[notification object]; 5172 ASSERT([preferences isKindOfClass:[WebPreferences class]]); 5173 5174 WebCacheModel cacheModel = [preferences cacheModel]; 5175 if (![self _didSetCacheModel] || cacheModel > [self _cacheModel]) 5176 [self _setCacheModel:cacheModel]; 5177 else if (cacheModel < [self _cacheModel]) 5178 [self _setCacheModel:max([[WebPreferences standardPreferences] cacheModel], [self _maxCacheModelInAnyInstance])]; 5179} 5180 5181+ (void)_preferencesRemovedNotification:(NSNotification *)notification 5182{ 5183 WebPreferences *preferences = (WebPreferences *)[notification object]; 5184 ASSERT([preferences isKindOfClass:[WebPreferences class]]); 5185 5186 if ([preferences cacheModel] == [self _cacheModel]) 5187 [self _setCacheModel:max([[WebPreferences standardPreferences] cacheModel], [self _maxCacheModelInAnyInstance])]; 5188} 5189 5190- (WebFrame *)_focusedFrame 5191{ 5192 NSResponder *resp = [[self window] firstResponder]; 5193 if (resp && [resp isKindOfClass:[NSView class]] && [(NSView *)resp isDescendantOf:[[self mainFrame] frameView]]) { 5194 WebFrameView *frameView = containingFrameView((NSView *)resp); 5195 ASSERT(frameView != nil); 5196 return [frameView webFrame]; 5197 } 5198 5199 return nil; 5200} 5201 5202- (BOOL)_isLoading 5203{ 5204 WebFrame *mainFrame = [self mainFrame]; 5205 return [[mainFrame _dataSource] isLoading] 5206 || [[mainFrame provisionalDataSource] isLoading]; 5207} 5208 5209- (WebFrameView *)_frameViewAtWindowPoint:(NSPoint)point 5210{ 5211 if (_private->closed) 5212 return nil; 5213 ASSERT(_private->usesDocumentViews); 5214 NSView *view = [self hitTest:[[self superview] convertPoint:point fromView:nil]]; 5215 if (![view isDescendantOf:[[self mainFrame] frameView]]) 5216 return nil; 5217 WebFrameView *frameView = containingFrameView(view); 5218 ASSERT(frameView); 5219 return frameView; 5220} 5221 5222+ (void)_preflightSpellCheckerNow:(id)sender 5223{ 5224 [[NSSpellChecker sharedSpellChecker] _preflightChosenSpellServer]; 5225} 5226 5227+ (void)_preflightSpellChecker 5228{ 5229 // As AppKit does, we wish to delay tickling the shared spellchecker into existence on application launch. 5230 if ([NSSpellChecker sharedSpellCheckerExists]) { 5231 [self _preflightSpellCheckerNow:self]; 5232 } else { 5233 [self performSelector:@selector(_preflightSpellCheckerNow:) withObject:self afterDelay:2.0]; 5234 } 5235} 5236 5237- (BOOL)_continuousCheckingAllowed 5238{ 5239 static BOOL allowContinuousSpellChecking = YES; 5240 static BOOL readAllowContinuousSpellCheckingDefault = NO; 5241 if (!readAllowContinuousSpellCheckingDefault) { 5242 if ([[NSUserDefaults standardUserDefaults] objectForKey:@"NSAllowContinuousSpellChecking"]) { 5243 allowContinuousSpellChecking = [[NSUserDefaults standardUserDefaults] boolForKey:@"NSAllowContinuousSpellChecking"]; 5244 } 5245 readAllowContinuousSpellCheckingDefault = YES; 5246 } 5247 return allowContinuousSpellChecking; 5248} 5249 5250- (NSResponder *)_responderForResponderOperations 5251{ 5252 NSResponder *responder = [[self window] firstResponder]; 5253 WebFrameView *mainFrameView = [[self mainFrame] frameView]; 5254 5255 // If the current responder is outside of the webview, use our main frameView or its 5256 // document view. We also do this for subviews of self that are siblings of the main 5257 // frameView since clients might insert non-webview-related views there (see 4552713). 5258 if (responder != self && ![mainFrameView _web_firstResponderIsSelfOrDescendantView]) { 5259 responder = [mainFrameView documentView]; 5260 if (!responder) 5261 responder = mainFrameView; 5262 } 5263 return responder; 5264} 5265 5266- (void)_openFrameInNewWindowFromMenu:(NSMenuItem *)sender 5267{ 5268 ASSERT_ARG(sender, [sender isKindOfClass:[NSMenuItem class]]); 5269 5270 NSDictionary *element = [sender representedObject]; 5271 ASSERT([element isKindOfClass:[NSDictionary class]]); 5272 5273 WebDataSource *dataSource = [[element objectForKey:WebElementFrameKey] dataSource]; 5274 NSURLRequest *request = [[dataSource request] copy]; 5275 ASSERT(request); 5276 5277 [self _openNewWindowWithRequest:request]; 5278 [request release]; 5279} 5280 5281- (void)_searchWithGoogleFromMenu:(id)sender 5282{ 5283 id documentView = [[[self selectedFrame] frameView] documentView]; 5284 if (![documentView conformsToProtocol:@protocol(WebDocumentText)]) { 5285 return; 5286 } 5287 5288 NSString *selectedString = [(id <WebDocumentText>)documentView selectedString]; 5289 if ([selectedString length] == 0) { 5290 return; 5291 } 5292 5293 NSPasteboard *pasteboard = [NSPasteboard pasteboardWithUniqueName]; 5294 [pasteboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil]; 5295 NSMutableString *s = [selectedString mutableCopy]; 5296 const unichar nonBreakingSpaceCharacter = 0xA0; 5297 NSString *nonBreakingSpaceString = [NSString stringWithCharacters:&nonBreakingSpaceCharacter length:1]; 5298 [s replaceOccurrencesOfString:nonBreakingSpaceString withString:@" " options:0 range:NSMakeRange(0, [s length])]; 5299 [pasteboard setString:s forType:NSStringPboardType]; 5300 [s release]; 5301 5302 // FIXME: seems fragile to use the service by name, but this is what AppKit does 5303 NSPerformService(@"Search With Google", pasteboard); 5304} 5305 5306- (void)_searchWithSpotlightFromMenu:(id)sender 5307{ 5308 id documentView = [[[self selectedFrame] frameView] documentView]; 5309 if (![documentView conformsToProtocol:@protocol(WebDocumentText)]) 5310 return; 5311 5312 NSString *selectedString = [(id <WebDocumentText>)documentView selectedString]; 5313 if (![selectedString length]) 5314 return; 5315 5316#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 5317 [[NSWorkspace sharedWorkspace] showSearchResultsForQueryString:selectedString]; 5318#else 5319 (void)HISearchWindowShow((CFStringRef)selectedString, kNilOptions); 5320#endif 5321} 5322 5323#if USE(ACCELERATED_COMPOSITING) 5324- (void)_clearLayerSyncLoopObserver 5325{ 5326 if (!_private->layerSyncRunLoopObserver) 5327 return; 5328 5329 CFRunLoopObserverInvalidate(_private->layerSyncRunLoopObserver); 5330 CFRelease(_private->layerSyncRunLoopObserver); 5331 _private->layerSyncRunLoopObserver = 0; 5332} 5333#endif 5334@end 5335 5336@implementation WebView (WebViewInternal) 5337 5338- (BOOL)_becomingFirstResponderFromOutside 5339{ 5340 return _private->becomingFirstResponderFromOutside; 5341} 5342 5343#if ENABLE(ICONDATABASE) 5344- (void)_receivedIconChangedNotification:(NSNotification *)notification 5345{ 5346 // Get the URL for this notification 5347 NSDictionary *userInfo = [notification userInfo]; 5348 ASSERT([userInfo isKindOfClass:[NSDictionary class]]); 5349 NSString *urlString = [userInfo objectForKey:WebIconNotificationUserInfoURLKey]; 5350 ASSERT([urlString isKindOfClass:[NSString class]]); 5351 5352 // If that URL matches the current main frame, dispatch the delegate call, which will also unregister 5353 // us for this notification 5354 if ([[self mainFrameURL] isEqualTo:urlString]) 5355 [self _dispatchDidReceiveIconFromWebFrame:[self mainFrame]]; 5356} 5357 5358- (void)_registerForIconNotification:(BOOL)listen 5359{ 5360 if (listen) 5361 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_receivedIconChangedNotification:) name:WebIconDatabaseDidAddIconNotification object:nil]; 5362 else 5363 [[NSNotificationCenter defaultCenter] removeObserver:self name:WebIconDatabaseDidAddIconNotification object:nil]; 5364} 5365 5366- (void)_dispatchDidReceiveIconFromWebFrame:(WebFrame *)webFrame 5367{ 5368 // FIXME: This willChangeValueForKey call is too late, because the icon has already changed by now. 5369 [self _willChangeValueForKey:_WebMainFrameIconKey]; 5370 5371 // Since we definitely have an icon and are about to send out the delegate call for that, this WebView doesn't need to listen for the general 5372 // notification any longer 5373 [self _registerForIconNotification:NO]; 5374 5375 WebFrameLoadDelegateImplementationCache* cache = &_private->frameLoadDelegateImplementations; 5376 if (cache->didReceiveIconForFrameFunc) { 5377 Image* image = iconDatabase()->iconForPageURL(core(webFrame)->loader()->url().string(), IntSize(16, 16)); 5378 if (NSImage *icon = webGetNSImage(image, NSMakeSize(16, 16))) 5379 CallFrameLoadDelegate(cache->didReceiveIconForFrameFunc, self, @selector(webView:didReceiveIcon:forFrame:), icon, webFrame); 5380 } 5381 5382 [self _didChangeValueForKey:_WebMainFrameIconKey]; 5383} 5384#endif // ENABLE(ICONDATABASE) 5385 5386- (void)_addObject:(id)object forIdentifier:(unsigned long)identifier 5387{ 5388 ASSERT(!_private->identifierMap.contains(identifier)); 5389 5390 // If the identifier map is initially empty it means we're starting a load 5391 // of something. The semantic is that the web view should be around as long 5392 // as something is loading. Because of that we retain the web view. 5393 if (_private->identifierMap.isEmpty()) 5394 CFRetain(self); 5395 5396 _private->identifierMap.set(identifier, object); 5397} 5398 5399- (id)_objectForIdentifier:(unsigned long)identifier 5400{ 5401 return _private->identifierMap.get(identifier).get(); 5402} 5403 5404- (void)_removeObjectForIdentifier:(unsigned long)identifier 5405{ 5406 ASSERT(_private->identifierMap.contains(identifier)); 5407 _private->identifierMap.remove(identifier); 5408 5409 // If the identifier map is now empty it means we're no longer loading anything 5410 // and we should release the web view. 5411 if (_private->identifierMap.isEmpty()) 5412 CFRelease(self); 5413} 5414 5415- (void)_retrieveKeyboardUIModeFromPreferences:(NSNotification *)notification 5416{ 5417 CFPreferencesAppSynchronize(UniversalAccessDomain); 5418 5419 Boolean keyExistsAndHasValidFormat; 5420 int mode = CFPreferencesGetAppIntegerValue(AppleKeyboardUIMode, UniversalAccessDomain, &keyExistsAndHasValidFormat); 5421 5422 // The keyboard access mode is reported by two bits: 5423 // Bit 0 is set if feature is on 5424 // Bit 1 is set if full keyboard access works for any control, not just text boxes and lists 5425 // We require both bits to be on. 5426 // I do not know that we would ever get one bit on and the other off since 5427 // checking the checkbox in system preferences which is marked as "Turn on full keyboard access" 5428 // turns on both bits. 5429 _private->_keyboardUIMode = (mode & 0x2) ? KeyboardAccessFull : KeyboardAccessDefault; 5430 5431 // check for tabbing to links 5432 if ([_private->preferences tabsToLinks]) 5433 _private->_keyboardUIMode = (KeyboardUIMode)(_private->_keyboardUIMode | KeyboardAccessTabsToLinks); 5434} 5435 5436- (KeyboardUIMode)_keyboardUIMode 5437{ 5438 if (!_private->_keyboardUIModeAccessed) { 5439 _private->_keyboardUIModeAccessed = YES; 5440 5441 [self _retrieveKeyboardUIModeFromPreferences:nil]; 5442 5443 [[NSDistributedNotificationCenter defaultCenter] 5444 addObserver:self selector:@selector(_retrieveKeyboardUIModeFromPreferences:) 5445 name:KeyboardUIModeDidChangeNotification object:nil]; 5446 5447 [[NSNotificationCenter defaultCenter] 5448 addObserver:self selector:@selector(_retrieveKeyboardUIModeFromPreferences:) 5449 name:WebPreferencesChangedNotification object:nil]; 5450 } 5451 return _private->_keyboardUIMode; 5452} 5453 5454- (void)_setInsertionPasteboard:(NSPasteboard *)pasteboard 5455{ 5456 _private->insertionPasteboard = pasteboard; 5457} 5458 5459- (void)_selectionChanged 5460{ 5461 if (_private->usesDocumentViews) { 5462 id documentView = [[[self _selectedOrMainFrame] frameView] documentView]; 5463 if ([documentView isKindOfClass:[WebHTMLView class]]) 5464 [documentView _selectionChanged]; 5465 return; 5466 } 5467 5468 // FIXME (Viewless): We'll need code here. 5469} 5470 5471- (Frame*)_mainCoreFrame 5472{ 5473 return (_private && _private->page) ? _private->page->mainFrame() : 0; 5474} 5475 5476- (WebFrame *)_selectedOrMainFrame 5477{ 5478 WebFrame *result = [self selectedFrame]; 5479 if (result == nil) 5480 result = [self mainFrame]; 5481 return result; 5482} 5483 5484#if USE(ACCELERATED_COMPOSITING) 5485 5486- (BOOL)_needsOneShotDrawingSynchronization 5487{ 5488 return _private->needsOneShotDrawingSynchronization; 5489} 5490 5491- (void)_setNeedsOneShotDrawingSynchronization:(BOOL)needsSynchronization 5492{ 5493 _private->needsOneShotDrawingSynchronization = needsSynchronization; 5494} 5495 5496- (BOOL)_syncCompositingChanges 5497{ 5498 Frame* frame = [self _mainCoreFrame]; 5499 if (frame && frame->view()) 5500 return frame->view()->syncCompositingStateRecursive(); 5501 5502 return YES; 5503} 5504 5505/* 5506 The order of events with compositing updates is this: 5507 5508 Start of runloop End of runloop 5509 | | 5510 --|-------------------------------------------------------|-- 5511 ^ ^ ^ 5512 | | | 5513 NSWindow update, | CA commit 5514 NSView drawing | 5515 flush | 5516 layerSyncRunLoopObserverCallBack 5517 5518 To avoid flashing, we have to ensure that compositing changes (rendered via 5519 the CoreAnimation rendering display link) appear on screen at the same time 5520 as content painted into the window via the normal WebCore rendering path. 5521 5522 CoreAnimation will commit any layer changes at the end of the runloop via 5523 its "CA commit" observer. Those changes can then appear onscreen at any time 5524 when the display link fires, which can result in unsynchronized rendering. 5525 5526 To fix this, the GraphicsLayerCA code in WebCore does not change the CA 5527 layer tree during style changes and layout; it stores up all changes and 5528 commits them via syncCompositingState(). There are then two situations in 5529 which we can call syncCompositingState(): 5530 5531 1. When painting. FrameView::paintContents() makes a call to syncCompositingState(). 5532 5533 2. When style changes/layout have made changes to the layer tree which do not 5534 result in painting. In this case we need a run loop observer to do a 5535 syncCompositingState() at an appropriate time. The observer will keep firing 5536 until the time is right (essentially when there are no more pending layouts). 5537 5538*/ 5539 5540static void layerSyncRunLoopObserverCallBack(CFRunLoopObserverRef, CFRunLoopActivity, void* info) 5541{ 5542 WebView* webView = reinterpret_cast<WebView*>(info); 5543 if ([webView _syncCompositingChanges]) 5544 [webView _clearLayerSyncLoopObserver]; 5545} 5546 5547- (void)_scheduleCompositingLayerSync 5548{ 5549 if (_private->layerSyncRunLoopObserver) 5550 return; 5551 5552 // Run after AppKit does its window update. If we do any painting, we'll commit 5553 // layer changes from FrameView::paintContents(), otherwise we'll commit via 5554 // _syncCompositingChanges when this observer fires. 5555 const CFIndex runLoopOrder = NSDisplayWindowRunLoopOrdering + 1; 5556 5557 // The WebView always outlives the observer, so no need to retain/release. 5558 CFRunLoopObserverContext context = { 0, self, 0, 0, 0 }; 5559 5560 _private->layerSyncRunLoopObserver = CFRunLoopObserverCreate(NULL, 5561 kCFRunLoopBeforeWaiting | kCFRunLoopExit, true /* repeats */, 5562 runLoopOrder, layerSyncRunLoopObserverCallBack, &context); 5563 5564 CFRunLoopAddObserver(CFRunLoopGetCurrent(), _private->layerSyncRunLoopObserver, kCFRunLoopCommonModes); 5565} 5566 5567#endif 5568 5569#if ENABLE(VIDEO) 5570 5571- (void)_enterFullscreenForNode:(WebCore::Node*)node 5572{ 5573 ASSERT(node->hasTagName(WebCore::HTMLNames::videoTag)); 5574 HTMLMediaElement* videoElement = static_cast<HTMLMediaElement*>(node); 5575 5576 if (_private->fullscreenController) { 5577 if ([_private->fullscreenController mediaElement] == videoElement) { 5578 // The backend may just warn us that the underlaying plaftormMovie() 5579 // has changed. Just force an update. 5580 [_private->fullscreenController setMediaElement:videoElement]; 5581 return; // No more to do. 5582 } 5583 5584 // First exit Fullscreen for the old mediaElement. 5585 [_private->fullscreenController mediaElement]->exitFullscreen(); 5586 // This previous call has to trigger _exitFullscreen, 5587 // which has to clear _private->fullscreenController. 5588 ASSERT(!_private->fullscreenController); 5589 } 5590 if (!_private->fullscreenController) { 5591 _private->fullscreenController = [[WebVideoFullscreenController alloc] init]; 5592 [_private->fullscreenController setMediaElement:videoElement]; 5593 [_private->fullscreenController enterFullscreen:[[self window] screen]]; 5594 } 5595 else 5596 [_private->fullscreenController setMediaElement:videoElement]; 5597} 5598 5599- (void)_exitFullscreen 5600{ 5601 if (!_private->fullscreenController) 5602 return; 5603 [_private->fullscreenController exitFullscreen]; 5604 [_private->fullscreenController release]; 5605 _private->fullscreenController = nil; 5606} 5607 5608#endif 5609 5610@end 5611 5612@implementation WebView (WebViewGeolocation) 5613 5614- (void)_setGeolocationProvider:(id<WebGeolocationProvider>)geolocationProvider 5615{ 5616 if (_private) 5617 _private->_geolocationProvider = geolocationProvider; 5618} 5619 5620- (id<WebGeolocationProvider>)_geolocationProvider 5621{ 5622 if (_private) 5623 return _private->_geolocationProvider; 5624 return nil; 5625} 5626 5627- (void)_geolocationDidChangePosition:(WebGeolocationPosition *)position; 5628{ 5629#if ENABLE(CLIENT_BASED_GEOLOCATION) 5630 if (_private && _private->page) 5631 _private->page->geolocationController()->positionChanged(core(position)); 5632#endif 5633} 5634 5635- (void)_geolocationDidFailWithError:(NSError *)error 5636{ 5637#if ENABLE(CLIENT_BASED_GEOLOCATION) 5638 if (_private && _private->page) { 5639 RefPtr<GeolocationError> geolocatioError = GeolocationError::create(GeolocationError::PositionUnavailable, [error localizedDescription]); 5640 _private->page->geolocationController()->errorOccurred(geolocatioError.get()); 5641 } 5642#endif 5643} 5644 5645@end 5646 5647#ifdef BUILDING_ON_LEOPARD 5648 5649static IMP originalRecursivelyRemoveMailAttributesImp; 5650 5651static id objectElementDataAttribute(DOMHTMLObjectElement *self, SEL) 5652{ 5653 return [self getAttribute:@"data"]; 5654} 5655 5656static void recursivelyRemoveMailAttributes(DOMNode *self, SEL selector, BOOL a, BOOL b, BOOL c) 5657{ 5658 // While inside this Mail function, change the behavior of -[DOMHTMLObjectElement data] back to what it used to be 5659 // before we fixed a bug in it (see http://trac.webkit.org/changeset/30044 for that change). 5660 5661 // It's a little bit strange to patch a method defined by WebKit, but it helps keep this workaround self-contained. 5662 5663 Method methodToPatch = class_getInstanceMethod(objc_getRequiredClass("DOMHTMLObjectElement"), @selector(data)); 5664 IMP originalDataImp = method_setImplementation(methodToPatch, reinterpret_cast<IMP>(objectElementDataAttribute)); 5665 originalRecursivelyRemoveMailAttributesImp(self, selector, a, b, c); 5666 method_setImplementation(methodToPatch, originalDataImp); 5667} 5668 5669#endif 5670 5671static void patchMailRemoveAttributesMethod() 5672{ 5673#ifdef BUILDING_ON_LEOPARD 5674 if (!WKAppVersionCheckLessThan(@"com.apple.mail", -1, 4.0)) 5675 return; 5676 Method methodToPatch = class_getInstanceMethod(objc_getRequiredClass("DOMNode"), @selector(recursivelyRemoveMailAttributes:convertObjectsToImages:convertEditableElements:)); 5677 if (!methodToPatch) 5678 return; 5679 originalRecursivelyRemoveMailAttributesImp = method_setImplementation(methodToPatch, reinterpret_cast<IMP>(recursivelyRemoveMailAttributes)); 5680#endif 5681} 5682